Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
d6461dac
Commit
d6461dac
authored
Mar 18, 2023
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement new DSL for HTTP servers
parent
ebcddbb6
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
412 additions
and
156 deletions
+412
-156
examples/CMakeLists.txt
examples/CMakeLists.txt
+0
-1
examples/http/secure-time-server.cpp
examples/http/secure-time-server.cpp
+0
-78
examples/http/time-server.cpp
examples/http/time-server.cpp
+59
-30
libcaf_net/CMakeLists.txt
libcaf_net/CMakeLists.txt
+1
-2
libcaf_net/caf/net/http/serve.hpp
libcaf_net/caf/net/http/serve.hpp
+0
-45
libcaf_net/caf/net/http/server_factory.hpp
libcaf_net/caf/net/http/server_factory.hpp
+200
-0
libcaf_net/caf/net/http/with.hpp
libcaf_net/caf/net/http/with.hpp
+66
-0
libcaf_net/src/net/http/server_factory.cpp
libcaf_net/src/net/http/server_factory.cpp
+86
-0
No files found.
examples/CMakeLists.txt
View file @
d6461dac
...
@@ -107,7 +107,6 @@ else()
...
@@ -107,7 +107,6 @@ else()
endfunction
()
endfunction
()
endif
()
endif
()
add_net_example
(
http secure-time-server
)
add_net_example
(
http time-server
)
add_net_example
(
http time-server
)
add_net_example
(
length_prefix_framing chat-client
)
add_net_example
(
length_prefix_framing chat-client
)
...
...
examples/http/secure-time-server.cpp
deleted
100644 → 0
View file @
ebcddbb6
// Simple HTTPS server that tells the time.
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/caf_main.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/net/http/serve.hpp"
#include "caf/net/middleman.hpp"
#include "caf/net/ssl/acceptor.hpp"
#include "caf/net/ssl/context.hpp"
#include "caf/net/stream_transport.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include "caf/net/tcp_stream_socket.hpp"
#include "caf/scheduled_actor/flow.hpp"
#include <iostream>
#include <string>
#include <string_view>
#include <utility>
using
namespace
std
::
literals
;
static
constexpr
uint16_t
default_port
=
8080
;
struct
config
:
caf
::
actor_system_config
{
config
()
{
opt_group
{
custom_options_
,
"global"
}
//
.
add
<
uint16_t
>
(
"port,p"
,
"port to listen for incoming connections"
)
.
add
<
std
::
string
>
(
"cert-file"
,
"PEM server certificate file"
)
.
add
<
std
::
string
>
(
"key-file"
,
"PEM key file for the certificate"
);
}
};
int
caf_main
(
caf
::
actor_system
&
sys
,
const
config
&
cfg
)
{
using
namespace
caf
;
// Sanity checking.
auto
cert_file
=
get_or
(
cfg
,
"cert-file"
,
""
sv
);
auto
key_file
=
get_or
(
cfg
,
"key-file"
,
""
sv
);
if
(
cert_file
.
empty
())
{
std
::
cerr
<<
"*** mandatory parameter 'cert-file' missing or empty
\n
"
;
return
EXIT_FAILURE
;
}
if
(
key_file
.
empty
())
{
std
::
cerr
<<
"*** mandatory parameter 'key-file' missing or empty
\n
"
;
return
EXIT_FAILURE
;
}
// Open up a TCP port for incoming connections.
auto
port
=
caf
::
get_or
(
cfg
,
"port"
,
default_port
);
auto
acc
=
net
::
ssl
::
acceptor
::
make_with_cert_file
(
port
,
cert_file
,
key_file
);
if
(
!
acc
)
{
std
::
cerr
<<
"*** unable to initialize TLS: "
<<
to_string
(
acc
.
error
())
<<
'\n'
;
return
EXIT_FAILURE
;
}
std
::
cout
<<
"*** started listening for incoming connections on port "
<<
port
<<
'\n'
;
// Create buffers to signal events from the WebSocket server to the worker.
auto
[
worker_pull
,
server_push
]
=
net
::
http
::
make_request_resource
();
// Spin up the HTTP server.
net
::
http
::
serve
(
sys
,
std
::
move
(
*
acc
),
std
::
move
(
server_push
));
// Spin up a worker to handle the HTTP requests.
auto
worker
=
sys
.
spawn
([
wres
=
worker_pull
](
event_based_actor
*
self
)
{
// For each incoming request ...
wres
.
observe_on
(
self
)
//
.
for_each
([](
const
net
::
http
::
request
&
req
)
{
// ... we simply return the current time as string.
// Note: we cannot respond more than once to a request.
auto
str
=
caf
::
deep_to_string
(
make_timestamp
());
req
.
respond
(
net
::
http
::
status
::
ok
,
"text/plain"
,
str
);
});
});
sys
.
await_all_actors_done
();
return
EXIT_SUCCESS
;
}
CAF_MAIN
(
caf
::
net
::
middleman
)
examples/http/time-server.cpp
View file @
d6461dac
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
#include "caf/caf_main.hpp"
#include "caf/caf_main.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/net/http/
serve
.hpp"
#include "caf/net/http/
with
.hpp"
#include "caf/net/middleman.hpp"
#include "caf/net/middleman.hpp"
#include "caf/net/stream_transport.hpp"
#include "caf/net/stream_transport.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include "caf/net/tcp_accept_socket.hpp"
...
@@ -16,47 +16,76 @@
...
@@ -16,47 +16,76 @@
#include <string>
#include <string>
#include <utility>
#include <utility>
// -- constants ----------------------------------------------------------------
static
constexpr
uint16_t
default_port
=
8080
;
static
constexpr
uint16_t
default_port
=
8080
;
static
constexpr
size_t
default_max_connections
=
128
;
// -- configuration ------------------------------------------------------------
struct
config
:
caf
::
actor_system_config
{
struct
config
:
caf
::
actor_system_config
{
config
()
{
config
()
{
opt_group
{
custom_options_
,
"global"
}
//
opt_group
{
custom_options_
,
"global"
}
//
.
add
<
uint16_t
>
(
"port,p"
,
"port to listen for incoming connections"
);
.
add
<
uint16_t
>
(
"port,p"
,
"port to listen for incoming connections"
)
.
add
<
size_t
>
(
"max-connections,m"
,
"limit for concurrent clients"
);
opt_group
{
custom_options_
,
"tls"
}
//
.
add
<
std
::
string
>
(
"key-file,k"
,
"path to the private key file"
)
.
add
<
std
::
string
>
(
"cert-file,c"
,
"path to the certificate file"
);
}
}
};
};
// -- main ---------------------------------------------------------------------
int
caf_main
(
caf
::
actor_system
&
sys
,
const
config
&
cfg
)
{
int
caf_main
(
caf
::
actor_system
&
sys
,
const
config
&
cfg
)
{
using
namespace
caf
;
namespace
http
=
caf
::
net
::
http
;
// Open up a TCP port for incoming connections.
namespace
ssl
=
caf
::
net
::
ssl
;
// Read the configuration.
auto
port
=
caf
::
get_or
(
cfg
,
"port"
,
default_port
);
auto
port
=
caf
::
get_or
(
cfg
,
"port"
,
default_port
);
net
::
tcp_accept_socket
fd
;
auto
pem
=
ssl
::
format
::
pem
;
if
(
auto
maybe_fd
=
net
::
make_tcp_accept_socket
({
ipv4_address
{},
port
},
auto
key_file
=
caf
::
get_as
<
std
::
string
>
(
cfg
,
"tls.key-file"
);
true
))
{
auto
cert_file
=
caf
::
get_as
<
std
::
string
>
(
cfg
,
"tls.cert-file"
);
std
::
cout
<<
"*** started listening for incoming connections on port "
auto
max_connections
=
caf
::
get_or
(
cfg
,
"max-connections"
,
<<
port
<<
'\n'
;
default_max_connections
);
fd
=
std
::
move
(
*
maybe_fd
);
if
(
!
key_file
!=
!
cert_file
)
{
}
else
{
std
::
cerr
<<
"*** inconsistent TLS config: declare neither file or both
\n
"
;
std
::
cerr
<<
"*** unable to open port "
<<
port
<<
": "
return
EXIT_FAILURE
;
<<
to_string
(
maybe_fd
.
error
())
<<
'\n'
;
}
// Open up a TCP port for incoming connections and start the server.
auto
server
=
caf
::
net
::
http
::
with
(
sys
)
// Optionally enable TLS.
.
context
(
ssl
::
context
::
enable
(
key_file
&&
cert_file
)
.
and_then
(
ssl
::
emplace_server
(
ssl
::
tls
::
v1_2
))
.
and_then
(
ssl
::
use_private_key_file
(
key_file
,
pem
))
.
and_then
(
ssl
::
use_certificate_file
(
cert_file
,
pem
)))
// Bind to the user-defined port.
.
accept
(
port
)
// Limit how many clients may be connected at any given time.
.
max_connections
(
max_connections
)
// When started, run our worker actor to handle incoming connections.
.
start
([
&
sys
](
auto
requests
)
{
// Note: requests is an async::consumer_resource<http::request>.
sys
.
spawn
([
requests
](
caf
::
event_based_actor
*
self
)
{
// For each incoming HTTP request ...
requests
.
observe_on
(
self
)
//
.
for_each
([](
const
http
::
request
&
req
)
{
// ... respond with the current time as string.
auto
str
=
caf
::
deep_to_string
(
caf
::
make_timestamp
());
req
.
respond
(
http
::
status
::
ok
,
"text/plain"
,
str
);
// Note: we cannot respond more than once to a request.
});
});
});
// Report any error to the user.
if
(
!
server
)
{
std
::
cerr
<<
"*** unable to run at port "
<<
port
<<
": "
<<
to_string
(
server
.
error
())
<<
'\n'
;
return
EXIT_FAILURE
;
return
EXIT_FAILURE
;
}
}
// Create buffers to signal events from the WebSocket server to the worker.
// Note: the actor system will keep the application running for as long as the
auto
[
worker_pull
,
server_push
]
=
net
::
http
::
make_request_resource
();
// workers are still alive.
// Spin up the HTTP server.
net
::
http
::
serve
(
sys
,
fd
,
std
::
move
(
server_push
));
// Spin up a worker to handle the HTTP requests.
auto
worker
=
sys
.
spawn
([
wres
=
worker_pull
](
event_based_actor
*
self
)
{
// For each incoming request ...
wres
.
observe_on
(
self
)
//
.
for_each
([](
const
net
::
http
::
request
&
req
)
{
// ... we simply return the current time as string.
// Note: we cannot respond more than once to a request.
auto
str
=
caf
::
deep_to_string
(
make_timestamp
());
req
.
respond
(
net
::
http
::
status
::
ok
,
"text/plain"
,
str
);
});
});
sys
.
await_all_actors_done
();
return
EXIT_SUCCESS
;
return
EXIT_SUCCESS
;
}
}
...
...
libcaf_net/CMakeLists.txt
View file @
d6461dac
...
@@ -47,9 +47,8 @@ caf_add_component(
...
@@ -47,9 +47,8 @@ caf_add_component(
src/net/http/method.cpp
src/net/http/method.cpp
src/net/http/request.cpp
src/net/http/request.cpp
src/net/http/response.cpp
src/net/http/response.cpp
src/net/http/serve.cpp
src/net/http/serve.cpp
src/net/http/server.cpp
src/net/http/server.cpp
src/net/http/server_factory.cpp
src/net/http/status.cpp
src/net/http/status.cpp
src/net/http/upper_layer.cpp
src/net/http/upper_layer.cpp
src/net/http/v1.cpp
src/net/http/v1.cpp
...
...
libcaf_net/caf/net/http/serve.hpp
deleted
100644 → 0
View file @
ebcddbb6
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/async/spsc_buffer.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/fwd.hpp"
#include "caf/net/fwd.hpp"
#include "caf/net/http/request.hpp"
#include "caf/net/ssl/fwd.hpp"
#include <memory>
#include <type_traits>
namespace
caf
::
net
::
http
{
/// Convenience function for creating async resources for connecting the HTTP
/// server to a worker.
inline
auto
make_request_resource
()
{
return
async
::
make_spsc_buffer_resource
<
request
>
();
}
/// Listens for incoming HTTP requests.
/// @param sys The host system.
/// @param fd An accept socket in listening mode, already bound to a port.
/// @param out A buffer resource that connects the server to a listener that
/// processes the requests.
/// @param cfg Optional configuration parameters for the HTTP layer.
disposable
CAF_NET_EXPORT
serve
(
actor_system
&
sys
,
tcp_accept_socket
fd
,
async
::
producer_resource
<
request
>
out
,
const
settings
&
cfg
=
{});
/// Listens for incoming HTTPS requests.
/// @param sys The host system.
/// @param acc An SSL connection acceptor with a socket that in listening mode.
/// @param out A buffer resource that connects the server to a listener that
/// processes the requests.
/// @param cfg Optional configuration parameters for the HTTP layer.
disposable
CAF_NET_EXPORT
serve
(
actor_system
&
sys
,
ssl
::
acceptor
acc
,
async
::
producer_resource
<
request
>
out
,
const
settings
&
cfg
=
{});
}
// namespace caf::net::http
libcaf_net/
src/net/http/serve.c
pp
→
libcaf_net/
caf/net/http/server_factory.h
pp
View file @
d6461dac
...
@@ -2,29 +2,34 @@
...
@@ -2,29 +2,34 @@
// the main distribution directory for license terms and copyright or visit
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#
include "caf/net/http/serve.hpp"
#
pragma once
#include "caf/async/blocking_producer.hpp"
#include "caf/defaults.hpp"
#include "caf/detail/accept_handler.hpp"
#include "caf/detail/accept_handler.hpp"
#include "caf/detail/binary_flow_bridge.hpp"
#include "caf/detail/connection_factory.hpp"
#include "caf/detail/connection_factory.hpp"
#include "caf/logger.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/net/http/lower_layer.hpp"
#include "caf/detail/shared_ssl_acceptor.hpp"
#include "caf/fwd.hpp"
#include "caf/net/checked_socket.hpp"
#include "caf/net/dsl/server_factory_base.hpp"
#include "caf/net/http/request.hpp"
#include "caf/net/http/server.hpp"
#include "caf/net/http/server.hpp"
#include "caf/net/http/upper_layer.hpp"
#include "caf/net/http/upper_layer.hpp"
#include "caf/net/middleman.hpp"
#include "caf/net/multiplexer.hpp"
#include "caf/net/ssl/acceptor.hpp"
#include "caf/net/ssl/transport.hpp"
#include "caf/net/ssl/transport.hpp"
#include "caf/net/stream_transport.hpp"
#include "caf/net/stream_transport.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include "caf/n
et/tcp_stream_socket
.hpp"
#include "caf/n
one
.hpp"
namespace
caf
::
detail
{
#include <cstdint>
#include <memory>
// TODO: there is currently no back-pressure from the worker to the server.
// -- http_request_producer ----------------------------------------------------
namespace
caf
::
detail
{
class
http_request_producer
:
public
atomic_ref_counted
,
class
CAF_NET_EXPORT
http_request_producer
:
public
atomic_ref_counted
,
public
async
::
producer
{
public
async
::
producer
{
public:
public:
using
buffer_ptr
=
async
::
spsc_buffer_ptr
<
net
::
http
::
request
>
;
using
buffer_ptr
=
async
::
spsc_buffer_ptr
<
net
::
http
::
request
>
;
...
@@ -38,29 +43,17 @@ public:
...
@@ -38,29 +43,17 @@ public:
return
ptr
;
return
ptr
;
}
}
void
on_consumer_ready
()
override
{
void
on_consumer_ready
()
override
;
// nop
}
void
on_consumer_cancel
()
override
{
void
on_consumer_cancel
()
override
;
// nop
}
void
on_consumer_demand
(
size_t
)
override
{
void
on_consumer_demand
(
size_t
)
override
;
// nop
}
void
ref_producer
()
const
noexcept
override
{
void
ref_producer
()
const
noexcept
override
;
ref
();
}
void
deref_producer
()
const
noexcept
override
{
void
deref_producer
()
const
noexcept
override
;
deref
();
}
bool
push
(
const
net
::
http
::
request
&
item
)
{
bool
push
(
const
net
::
http
::
request
&
item
);
return
buf_
->
push
(
item
);
}
private:
private:
buffer_ptr
buf_
;
buffer_ptr
buf_
;
...
@@ -68,9 +61,7 @@ private:
...
@@ -68,9 +61,7 @@ private:
using
http_request_producer_ptr
=
intrusive_ptr
<
http_request_producer
>
;
using
http_request_producer_ptr
=
intrusive_ptr
<
http_request_producer
>
;
// -- http_flow_adapter --------------------------------------------------------
class
CAF_NET_EXPORT
http_flow_adapter
:
public
net
::
http
::
upper_layer
{
class
http_flow_adapter
:
public
net
::
http
::
upper_layer
{
public:
public:
explicit
http_flow_adapter
(
async
::
execution_context_ptr
loop
,
explicit
http_flow_adapter
(
async
::
execution_context_ptr
loop
,
http_request_producer_ptr
ptr
)
http_request_producer_ptr
ptr
)
...
@@ -78,56 +69,16 @@ public:
...
@@ -78,56 +69,16 @@ public:
// nop
// nop
}
}
void
prepare_send
()
override
{
void
prepare_send
()
override
;
// nop
}
bool
done_sending
()
override
{
bool
done_sending
()
override
;
return
true
;
}
void
abort
(
const
error
&
)
override
{
void
abort
(
const
error
&
)
override
;
for
(
auto
&
pending
:
pending_
)
pending
.
dispose
();
}
error
start
(
net
::
http
::
lower_layer
*
down
)
override
{
error
start
(
net
::
http
::
lower_layer
*
down
)
override
;
down_
=
down
;
down_
->
request_messages
();
return
none
;
}
ptrdiff_t
consume
(
const
net
::
http
::
header
&
hdr
,
ptrdiff_t
consume
(
const
net
::
http
::
header
&
hdr
,
const_byte_span
payload
)
override
{
const_byte_span
payload
)
override
;
using
namespace
net
::
http
;
if
(
!
pending_
.
empty
())
{
CAF_LOG_WARNING
(
"received multiple requests from the same HTTP client: "
"not implemented yet (drop request)"
);
return
static_cast
<
ptrdiff_t
>
(
payload
.
size
());
}
auto
prom
=
async
::
promise
<
response
>
();
auto
fut
=
prom
.
get_future
();
auto
buf
=
std
::
vector
<
std
::
byte
>
{
payload
.
begin
(),
payload
.
end
()};
auto
impl
=
request
::
impl
{
hdr
,
std
::
move
(
buf
),
std
::
move
(
prom
)};
producer_
->
push
(
request
{
std
::
make_shared
<
request
::
impl
>
(
std
::
move
(
impl
))});
auto
hdl
=
fut
.
bind_to
(
*
loop_
).
then
(
[
this
](
const
response
&
res
)
{
down_
->
begin_header
(
res
.
code
());
for
(
auto
&
[
key
,
val
]
:
res
.
header_fields
())
down_
->
add_header_field
(
key
,
val
);
std
::
ignore
=
down_
->
end_header
();
down_
->
send_payload
(
res
.
body
());
down_
->
shutdown
();
},
[
this
](
const
error
&
err
)
{
auto
description
=
to_string
(
err
);
down_
->
send_response
(
status
::
internal_server_error
,
"text/plain"
,
description
);
down_
->
shutdown
();
});
pending_
.
emplace_back
(
std
::
move
(
hdl
));
return
static_cast
<
ptrdiff_t
>
(
payload
.
size
());
}
static
auto
make
(
async
::
execution_context_ptr
loop
,
static
auto
make
(
async
::
execution_context_ptr
loop
,
http_request_producer_ptr
ptr
)
{
http_request_producer_ptr
ptr
)
{
...
@@ -141,16 +92,16 @@ private:
...
@@ -141,16 +92,16 @@ private:
http_request_producer_ptr
producer_
;
http_request_producer_ptr
producer_
;
};
};
// -- http_conn_factory --------------------------------------------------------
template
<
class
Transport
>
template
<
class
Transport
>
class
http_conn_factory
class
http_conn_factory
:
public
connection_factory
<
typename
Transport
::
connection_handle
>
{
:
public
connection_factory
<
typename
Transport
::
connection_handle
>
{
public:
public:
using
connection_handle
=
typename
Transport
::
connection_handle
;
using
connection_handle
=
typename
Transport
::
connection_handle
;
explicit
http_conn_factory
(
http_request_producer_ptr
producer
)
http_conn_factory
(
http_request_producer_ptr
producer
,
:
producer_
(
std
::
move
(
producer
))
{
size_t
max_consecutive_reads
)
:
producer_
(
std
::
move
(
producer
)),
max_consecutive_reads_
(
max_consecutive_reads
)
{
// nop
// nop
}
}
...
@@ -160,6 +111,7 @@ public:
...
@@ -160,6 +111,7 @@ public:
auto
serv
=
net
::
http
::
server
::
make
(
std
::
move
(
app
));
auto
serv
=
net
::
http
::
server
::
make
(
std
::
move
(
app
));
auto
fd
=
conn
.
fd
();
auto
fd
=
conn
.
fd
();
auto
transport
=
Transport
::
make
(
std
::
move
(
conn
),
std
::
move
(
serv
));
auto
transport
=
Transport
::
make
(
std
::
move
(
conn
),
std
::
move
(
serv
));
transport
->
max_consecutive_reads
(
max_consecutive_reads_
);
transport
->
active_policy
().
accept
(
fd
);
transport
->
active_policy
().
accept
(
fd
);
auto
res
=
net
::
socket_manager
::
make
(
mpx
,
std
::
move
(
transport
));
auto
res
=
net
::
socket_manager
::
make
(
mpx
,
std
::
move
(
transport
));
mpx
->
watch
(
res
->
as_disposable
());
mpx
->
watch
(
res
->
as_disposable
());
...
@@ -168,44 +120,81 @@ public:
...
@@ -168,44 +120,81 @@ public:
private:
private:
http_request_producer_ptr
producer_
;
http_request_producer_ptr
producer_
;
size_t
max_consecutive_reads_
;
};
};
// -- http_serve_impl ----------------------------------------------------------
template
<
class
Transport
,
class
Acceptor
>
disposable
http_serve_impl
(
actor_system
&
sys
,
Acceptor
acc
,
async
::
producer_resource
<
net
::
http
::
request
>
out
,
const
settings
&
cfg
=
{})
{
using
factory_t
=
http_conn_factory
<
Transport
>
;
using
impl_t
=
accept_handler
<
Acceptor
>
;
auto
max_conn
=
get_or
(
cfg
,
defaults
::
net
::
max_connections
);
if
(
auto
buf
=
out
.
try_open
())
{
auto
&
mpx
=
sys
.
network_manager
().
mpx
();
auto
producer
=
http_request_producer
::
make
(
std
::
move
(
buf
));
auto
factory
=
std
::
make_unique
<
factory_t
>
(
std
::
move
(
producer
));
auto
impl
=
impl_t
::
make
(
std
::
move
(
acc
),
std
::
move
(
factory
),
max_conn
);
auto
ptr
=
net
::
socket_manager
::
make
(
&
mpx
,
std
::
move
(
impl
));
mpx
.
start
(
ptr
);
return
ptr
->
as_disposable
();
}
else
{
return
disposable
{};
}
}
}
// namespace caf::detail
}
// namespace caf::detail
namespace
caf
::
net
::
http
{
namespace
caf
::
net
::
http
{
disposable
serve
(
actor_system
&
sys
,
tcp_accept_socket
fd
,
/// Factory type for the `with(...).accept(...).start(...)` DSL.
async
::
producer_resource
<
request
>
out
,
const
settings
&
cfg
)
{
class
server_factory
return
detail
::
http_serve_impl
<
stream_transport
>
(
sys
,
fd
,
std
::
move
(
out
),
:
public
dsl
::
server_factory_base
<
dsl
::
config_base
,
server_factory
>
{
cfg
);
public:
}
using
super
=
dsl
::
server_factory_base
<
dsl
::
config_base
,
server_factory
>
;
disposable
serve
(
actor_system
&
sys
,
ssl
::
acceptor
acc
,
using
config_type
=
typename
super
::
config_type
;
async
::
producer_resource
<
request
>
out
,
const
settings
&
cfg
)
{
return
detail
::
http_serve_impl
<
ssl
::
transport
>
(
sys
,
std
::
move
(
acc
),
using
super
::
super
;
std
::
move
(
out
),
cfg
);
}
/// Starts a server that accepts incoming connections with the
/// length-prefixing protocol.
template
<
class
OnStart
>
[[
nodiscard
]]
expected
<
disposable
>
start
(
OnStart
on_start
)
{
using
consumer_resource
=
async
::
consumer_resource
<
request
>
;
static_assert
(
std
::
is_invocable_v
<
OnStart
,
consumer_resource
>
);
auto
&
cfg
=
super
::
config
();
return
cfg
.
visit
([
this
,
&
cfg
,
&
on_start
](
auto
&
data
)
{
return
this
->
do_start
(
cfg
,
data
,
on_start
)
.
or_else
([
&
cfg
](
const
error
&
err
)
{
cfg
.
call_on_error
(
err
);
});
});
}
private:
template
<
class
Acceptor
,
class
OnStart
>
expected
<
disposable
>
do_start_impl
(
config_type
&
cfg
,
Acceptor
acc
,
OnStart
&
on_start
)
{
using
transport_t
=
typename
Acceptor
::
transport_type
;
using
factory_t
=
detail
::
http_conn_factory
<
transport_t
>
;
using
impl_t
=
detail
::
accept_handler
<
Acceptor
>
;
auto
[
pull
,
push
]
=
async
::
make_spsc_buffer_resource
<
request
>
();
auto
producer
=
detail
::
http_request_producer
::
make
(
push
.
try_open
());
auto
factory
=
std
::
make_unique
<
factory_t
>
(
std
::
move
(
producer
),
cfg
.
max_consecutive_reads
);
auto
impl
=
impl_t
::
make
(
std
::
move
(
acc
),
std
::
move
(
factory
),
cfg
.
max_connections
);
auto
impl_ptr
=
impl
.
get
();
auto
ptr
=
net
::
socket_manager
::
make
(
cfg
.
mpx
,
std
::
move
(
impl
));
impl_ptr
->
self_ref
(
ptr
->
as_disposable
());
cfg
.
mpx
->
start
(
ptr
);
on_start
(
std
::
move
(
pull
));
return
expected
<
disposable
>
{
disposable
{
std
::
move
(
ptr
)}};
}
template
<
class
OnStart
>
expected
<
disposable
>
do_start
(
config_type
&
cfg
,
dsl
::
server_config
::
socket
&
data
,
OnStart
&
on_start
)
{
return
checked_socket
(
data
.
take_fd
())
.
and_then
(
data
.
acceptor_with_ctx
([
this
,
&
cfg
,
&
on_start
](
auto
&
acc
)
{
return
this
->
do_start_impl
(
cfg
,
std
::
move
(
acc
),
on_start
);
}));
}
template
<
class
OnStart
>
expected
<
disposable
>
do_start
(
config_type
&
cfg
,
dsl
::
server_config
::
lazy
&
data
,
OnStart
&
on_start
)
{
return
make_tcp_accept_socket
(
data
.
port
,
data
.
bind_address
,
data
.
reuse_addr
)
.
and_then
(
data
.
acceptor_with_ctx
([
this
,
&
cfg
,
&
on_start
](
auto
&
acc
)
{
return
this
->
do_start_impl
(
cfg
,
std
::
move
(
acc
),
on_start
);
}));
}
template
<
class
OnStart
>
expected
<
disposable
>
do_start
(
config_type
&
,
error
&
err
,
OnStart
&
)
{
return
expected
<
disposable
>
{
std
::
move
(
err
)};
}
};
}
// namespace caf::net::http
}
// namespace caf::net::http
libcaf_net/caf/net/http/with.hpp
0 → 100644
View file @
d6461dac
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/fwd.hpp"
#include "caf/net/dsl/base.hpp"
#include "caf/net/dsl/generic_config.hpp"
#include "caf/net/dsl/has_accept.hpp"
#include "caf/net/dsl/has_connect.hpp"
#include "caf/net/dsl/has_context.hpp"
#include "caf/net/http/request.hpp"
#include "caf/net/http/server_factory.hpp"
#include "caf/net/multiplexer.hpp"
#include "caf/net/ssl/acceptor.hpp"
#include "caf/net/ssl/context.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include <cstdint>
namespace
caf
::
net
::
http
{
/// Entry point for the `with(...)` DSL.
class
with_t
:
public
extend
<
dsl
::
base
,
with_t
>::
//
with
<
dsl
::
has_accept
,
dsl
::
has_context
>
{
public:
using
config_type
=
dsl
::
generic_config_value
<
dsl
::
config_base
>
;
template
<
class
...
Ts
>
explicit
with_t
(
multiplexer
*
mpx
)
:
config_
(
config_type
::
make
(
mpx
))
{
// nop
}
with_t
(
with_t
&&
)
noexcept
=
default
;
with_t
(
const
with_t
&
)
noexcept
=
default
;
with_t
&
operator
=
(
with_t
&&
)
noexcept
=
default
;
with_t
&
operator
=
(
const
with_t
&
)
noexcept
=
default
;
/// @private
config_type
&
config
()
{
return
*
config_
;
}
/// @private
template
<
class
T
,
class
...
Ts
>
auto
make
(
dsl
::
server_config_tag
<
T
>
token
,
Ts
&&
...
xs
)
{
return
server_factory
{
token
,
*
config_
,
std
::
forward
<
Ts
>
(
xs
)...};
}
private:
intrusive_ptr
<
config_type
>
config_
;
};
inline
with_t
with
(
actor_system
&
sys
)
{
return
with_t
{
multiplexer
::
from
(
sys
)};
}
inline
with_t
with
(
multiplexer
*
mpx
)
{
return
with_t
{
mpx
};
}
}
// namespace caf::net::http
libcaf_net/src/net/http/server_factory.cpp
0 → 100644
View file @
d6461dac
#include "caf/net/http/server_factory.hpp"
namespace
caf
::
detail
{
// TODO: there is currently no back-pressure from the worker to the server.
// -- http_request_producer ----------------------------------------------------
void
http_request_producer
::
on_consumer_ready
()
{
// nop
}
void
http_request_producer
::
on_consumer_cancel
()
{
// nop
}
void
http_request_producer
::
on_consumer_demand
(
size_t
)
{
// nop
}
void
http_request_producer
::
ref_producer
()
const
noexcept
{
ref
();
}
void
http_request_producer
::
deref_producer
()
const
noexcept
{
deref
();
}
bool
http_request_producer
::
push
(
const
net
::
http
::
request
&
item
)
{
return
buf_
->
push
(
item
);
}
// -- http_flow_adapter --------------------------------------------------------
void
http_flow_adapter
::
prepare_send
()
{
// nop
}
bool
http_flow_adapter
::
done_sending
()
{
return
true
;
}
void
http_flow_adapter
::
abort
(
const
error
&
)
{
for
(
auto
&
pending
:
pending_
)
pending
.
dispose
();
}
error
http_flow_adapter
::
start
(
net
::
http
::
lower_layer
*
down
)
{
down_
=
down
;
down_
->
request_messages
();
return
none
;
}
ptrdiff_t
http_flow_adapter
::
consume
(
const
net
::
http
::
header
&
hdr
,
const_byte_span
payload
)
{
using
namespace
net
::
http
;
if
(
!
pending_
.
empty
())
{
CAF_LOG_WARNING
(
"received multiple requests from the same HTTP client: "
"not implemented yet (drop request)"
);
return
static_cast
<
ptrdiff_t
>
(
payload
.
size
());
}
auto
prom
=
async
::
promise
<
response
>
();
auto
fut
=
prom
.
get_future
();
auto
buf
=
std
::
vector
<
std
::
byte
>
{
payload
.
begin
(),
payload
.
end
()};
auto
impl
=
request
::
impl
{
hdr
,
std
::
move
(
buf
),
std
::
move
(
prom
)};
producer_
->
push
(
request
{
std
::
make_shared
<
request
::
impl
>
(
std
::
move
(
impl
))});
auto
hdl
=
fut
.
bind_to
(
*
loop_
).
then
(
[
this
](
const
response
&
res
)
{
down_
->
begin_header
(
res
.
code
());
for
(
auto
&
[
key
,
val
]
:
res
.
header_fields
())
down_
->
add_header_field
(
key
,
val
);
std
::
ignore
=
down_
->
end_header
();
down_
->
send_payload
(
res
.
body
());
down_
->
shutdown
();
},
[
this
](
const
error
&
err
)
{
auto
description
=
to_string
(
err
);
down_
->
send_response
(
status
::
internal_server_error
,
"text/plain"
,
description
);
down_
->
shutdown
();
});
pending_
.
emplace_back
(
std
::
move
(
hdl
));
return
static_cast
<
ptrdiff_t
>
(
payload
.
size
());
}
}
// namespace caf::detail
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment