1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! Riak HTTP gateway transport.
//!
//! `proto::http` is the sibling of [`crate::proto::pb`] for the Riak
//! HTTP API. It exposes the same Riak operation surface over a
//! conventional HTTP/1.1 server backed by `hyper` + `hyper-util`, so
//! operators can put a browser-friendly K/V endpoint in front of the
//! same [`dynomite::embed::Datastore`] the PBC server already uses.
//!
//! # Public surface
//!
//! * [`serve_http`] -- TCP accept loop driving a `hyper`
//! `http1::serve_connection` per accepted client.
//! * [`routes`] -- the route table and per-route handlers (internal,
//! re-exported only for testing through `pub(crate)`).
//! * [`content_type`] -- `Accept` / `Content-Type` negotiation
//! ([`content_type::select_codec`]).
//!
//! # Wire shape
//!
//! Riak's HTTP layer is a conventional REST-ish JSON API:
//!
//! ```text
//! GET /ping -> 200 OK / "OK"
//! GET /stats -> 200 OK / { name, version, ... }
//! GET /buckets/{bucket}/keys/{key} -> 200 / 404
//! PUT /buckets/{bucket}/keys/{key} -> 204
//! POST /buckets/{bucket}/keys/{key} -> 204 (server-assigned key path required)
//! DELETE /buckets/{bucket}/keys/{key} -> 204
//! GET /buckets?buckets=true -> 501 (in-memory store cannot enumerate)
//! GET /buckets/{bucket}/keys?keys=true -> 501 (in-memory store cannot enumerate)
//! GET /buckets/{bucket}/props -> 200 / { props: { ... } }
//! PUT /buckets/{bucket}/props -> 204
//! ```
//!
//! # Datastore semantics
//!
//! For the v0.0.1 slice the gateway trampolines K/V operations
//! through [`dynomite::embed::Datastore::dispatch`] in the same shape
//! the PBC server uses. The substrate's accounting ticks per
//! request; the Riak-aware K/V trait that turns a `dispatch` into a
//! real fetch / store / delete lands in a follow-up slice. List-keys
//! and list-buckets stream their response body chunk-by-chunk via
//! [`dynomite::embed::Datastore::list_buckets_stream`] and
//! [`dynomite::embed::Datastore::list_keys_stream`].
use Arc;
use http1;
use service_fn;
use TokioIo;
use TcpListener;
use TlsAcceptor;
use Datastore;
use crateRiakError;
pub use crate;
/// Run the HTTP accept loop on `listener`.
///
/// One tokio task is spawned per accepted connection. Per-connection
/// failures are logged at `tracing::warn!` and otherwise swallowed
/// so a misbehaving client cannot bring the listener down.
///
/// # Examples
///
/// ```no_run
/// use std::sync::Arc;
/// use tokio::net::TcpListener;
/// use dyniak::serve_http;
/// use dynomite::embed::{Datastore, MemoryDatastore};
///
/// # tokio::runtime::Builder::new_current_thread()
/// # .enable_all().build().unwrap().block_on(async {
/// let listener = TcpListener::bind("127.0.0.1:8098").await.unwrap();
/// let ds: Arc<dyn Datastore> = Arc::new(MemoryDatastore::new());
/// let _handle = tokio::spawn(serve_http(listener, ds));
/// # });
/// ```
///
/// # Errors
///
/// Returns the first `accept` error the listener surfaces.
pub async
/// Run the HTTP accept loop on `listener`, terminating TLS via
/// `acceptor` for every accepted connection. Per-connection
/// handshake failures are logged at `tracing::warn!` and
/// otherwise swallowed.
///
/// # Errors
///
/// Returns the first `accept` error the listener surfaces.
pub async