1use std::collections::HashMap;
16use std::convert::Infallible;
17use std::fmt::Display;
18use std::net::SocketAddr;
19use std::sync::{Arc, Mutex as StdMutex};
20use std::time::Duration;
21
22use async_trait::async_trait;
23use auth::UserProviderRef;
24use axum::extract::{DefaultBodyLimit, Request, State};
25use axum::http::StatusCode as HttpStatusCode;
26use axum::middleware::Next;
27use axum::response::{IntoResponse, Response};
28use axum::routing::Route;
29use axum::serve::ListenerExt;
30use axum::{Extension, Router, middleware, routing};
31use common_base::readable_size::ReadableSize;
32use common_recordbatch::RecordBatch;
33use common_telemetry::{error, info};
34use common_time::Timestamp;
35use common_time::timestamp::TimeUnit;
36use datatypes::data_type::DataType;
37use datatypes::schema::SchemaRef;
38use event::{LogState, LogValidatorRef};
39use futures::FutureExt;
40use http::{HeaderValue, Method};
41use serde::{Deserialize, Serialize};
42use serde_json::Value;
43use session::context::QueryContext;
44use snafu::{ResultExt, ensure};
45use tokio::sync::Mutex;
46use tokio::sync::oneshot::{self, Sender};
47use tonic::codegen::Service;
48use tower::{Layer, ServiceBuilder};
49use tower_http::compression::CompressionLayer;
50use tower_http::cors::{AllowOrigin, Any, CorsLayer};
51use tower_http::decompression::RequestDecompressionLayer;
52use tower_http::trace::TraceLayer;
53
54use self::authorize::AuthState;
55use self::result::table_result::TableResponse;
56use crate::batcher::BatchingProtocol;
57use crate::batcher::logical_table::LogicalTablePendingRowsBatcher;
58use crate::elasticsearch;
59use crate::error::{
60 AddressBindSnafu, AlreadyStartedSnafu, Error, InternalIoSnafu, InvalidHeaderValueSnafu, Result,
61};
62use crate::http::influxdb::{influxdb_health, influxdb_ping, influxdb_write_v1, influxdb_write_v2};
63use crate::http::otlp::OtlpState;
64use crate::http::prom_store::PromStoreState;
65use crate::http::prometheus::{
66 build_info_query, format_query, instant_query, label_values_query, labels_query,
67 metadata_query, parse_query, range_query, series_query,
68};
69use crate::http::result::arrow_result::ArrowResponse;
70use crate::http::result::csv_result::CsvResponse;
71use crate::http::result::error_result::ErrorResponse;
72use crate::http::result::greptime_result_v1::GreptimedbV1Response;
73use crate::http::result::influxdb_result_v1::InfluxdbV1Response;
74use crate::http::result::json_result::JsonResponse;
75use crate::http::result::null_result::NullResponse;
76use crate::interceptor::LogIngestInterceptorRef;
77use crate::metrics::http_metrics_layer;
78use crate::metrics_handler::MetricsHandler;
79use crate::prometheus_handler::PrometheusHandlerRef;
80use crate::query_handler::sql::ServerSqlQueryHandlerRef;
81use crate::query_handler::{
82 DashboardHandlerRef, InfluxdbLineProtocolHandlerRef, JaegerQueryHandlerRef, LogQueryHandlerRef,
83 OpenTelemetryProtocolHandlerRef, OpentsdbProtocolHandlerRef, PipelineHandlerRef,
84 PromStoreProtocolHandlerRef,
85};
86use crate::request_memory_limiter::ServerMemoryLimiter;
87use crate::server::Server;
88
89pub mod authorize;
90#[cfg(feature = "dashboard")]
91mod dashboard;
92pub mod dyn_log;
93pub mod dyn_trace;
94pub mod event;
95pub mod extractor;
96pub mod handler;
97pub mod header;
98pub mod influxdb;
99pub mod jaeger;
100pub mod logs;
101pub mod loki;
102pub mod mem_prof;
103mod memory_limit;
104pub mod opentsdb;
105pub mod otlp;
106pub mod pprof;
107pub mod prom_store;
108pub mod prometheus;
109pub mod result;
110pub mod splunk;
111mod timeout;
112pub mod utils;
113mod workload_scheduler;
114
115use result::HttpOutputWriter;
116pub(crate) use timeout::DynamicTimeoutLayer;
117
118mod client_ip;
119use crate::prom_remote_write::validation::PromValidationMode;
120mod hints;
121mod read_preference;
122mod skip_wal;
123#[cfg(any(test, feature = "testing"))]
124pub mod test_helpers;
125
126pub const HTTP_API_VERSION: &str = "v1";
127pub const HTTP_API_PREFIX: &str = "/v1/";
128pub const HTTP_API_PREFIX_WITHOUT_TRAILING_SLASH: &str = "/v1";
129
130pub trait ExtraHttpRouterProvider: Send + Sync {
132 fn router(&self) -> Router;
134}
135
136pub type ExtraHttpRouterProviderRef = Arc<dyn ExtraHttpRouterProvider>;
137
138#[derive(Clone, Default)]
140pub struct ExtraHttpRouterProviders {
141 providers: Vec<ExtraHttpRouterProviderRef>,
142}
143
144impl ExtraHttpRouterProviders {
145 pub fn new() -> Self {
147 Self::default()
148 }
149
150 pub fn add(&mut self, provider: ExtraHttpRouterProviderRef) {
152 self.providers.push(provider);
153 }
154
155 pub fn iter(&self) -> impl Iterator<Item = &dyn ExtraHttpRouterProvider> {
157 self.providers.iter().map(|x| x.as_ref())
158 }
159}
160
161const DEFAULT_BODY_LIMIT: ReadableSize = ReadableSize::mb(64);
163const DEFAULT_HTTP_API_ADDR_PORT: u16 = 4006;
165
166pub const AUTHORIZATION_HEADER: &str = "x-greptime-auth";
168
169pub static PUBLIC_API_PREFIX: [&str; 4] = [
172 "/v1/influxdb/ping",
173 "/v1/influxdb/health",
174 "/v1/health",
175 "/v1/splunk/services/collector/health",
176];
177
178#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
184pub(crate) enum HttpServerKind {
185 #[default]
188 Full,
189 Api,
191}
192
193#[derive(Default)]
194pub struct HttpServer {
195 router: StdMutex<Router>,
196 shutdown_tx: Mutex<Option<Sender<()>>>,
197 user_provider: Option<UserProviderRef>,
198 memory_limiter: ServerMemoryLimiter,
199
200 options: HttpOptions,
202 batching_protocols: Vec<BatchingProtocol>,
203 logical_batching_protocols: Vec<BatchingProtocol>,
204 bind_addr: Option<SocketAddr>,
205 kind: HttpServerKind,
207}
208
209pub(crate) fn is_namespace(path: &str, root: &str) -> bool {
213 path == root
214 || path
215 .strip_prefix(root)
216 .is_some_and(|suffix| suffix.starts_with('/'))
217}
218
219pub fn is_api_listener_path(path: &str) -> bool {
221 is_namespace(path, HTTP_API_PREFIX_WITHOUT_TRAILING_SLASH) || is_namespace(path, "/dashboard")
222}
223
224#[derive(Clone)]
225struct LogicalBatchingProtocols(Vec<BatchingProtocol>);
226
227async fn set_http_write_batching(
229 State(protocol): State<BatchingProtocol>,
230 mut req: Request,
231 next: Next,
232) -> Response {
233 let enabled = req
234 .extensions()
235 .get::<Arc<Vec<BatchingProtocol>>>()
236 .is_some_and(|protocols| protocols.contains(&protocol));
237 let logical_enabled = req
238 .extensions()
239 .get::<LogicalBatchingProtocols>()
240 .is_some_and(|protocols| protocols.0.contains(&protocol));
241 if let Some(ctx) = req.extensions_mut().get_mut::<QueryContext>() {
242 ctx.set_batching_enabled(enabled);
243 ctx.set_logical_batching_enabled(logical_enabled);
244 }
245 next.run(req).await
246}
247
248async fn enforce_api_surface(req: Request, next: Next) -> Response {
252 if !is_api_listener_path(req.uri().path()) {
253 return HttpStatusCode::NOT_FOUND.into_response();
254 }
255 next.run(req).await
256}
257
258impl HttpServer {
259 fn kind(&self) -> &'static str {
261 match self.kind {
262 HttpServerKind::Api => "HTTP API",
263 HttpServerKind::Full => "HTTP",
264 }
265 }
266}
267
268#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
269#[serde(default)]
270pub struct HttpOptions {
271 pub addr: String,
272
273 #[serde(with = "humantime_serde")]
276 pub timeout: Duration,
277
278 #[serde(skip)]
279 pub disable_dashboard: bool,
280
281 pub body_limit: ReadableSize,
282
283 pub cors_allowed_origins: Vec<String>,
284
285 pub enable_cors: bool,
286
287 pub enable_api_server: bool,
292 pub api_server_addr: String,
295}
296
297impl Default for HttpOptions {
298 fn default() -> Self {
299 Self {
300 addr: "127.0.0.1:4000".to_string(),
301 timeout: Duration::from_secs(0),
302 disable_dashboard: false,
303 body_limit: DEFAULT_BODY_LIMIT,
304 cors_allowed_origins: Vec::new(),
305 enable_cors: true,
306 enable_api_server: false,
307 api_server_addr: format!("127.0.0.1:{}", DEFAULT_HTTP_API_ADDR_PORT),
308 }
309 }
310}
311
312#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
313pub struct ColumnSchema {
314 name: String,
315 data_type: String,
316}
317
318impl ColumnSchema {
319 pub fn new(name: String, data_type: String) -> ColumnSchema {
320 ColumnSchema { name, data_type }
321 }
322}
323
324#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
325pub struct OutputSchema {
326 column_schemas: Vec<ColumnSchema>,
327}
328
329impl OutputSchema {
330 pub fn new(columns: Vec<ColumnSchema>) -> OutputSchema {
331 OutputSchema {
332 column_schemas: columns,
333 }
334 }
335}
336
337impl From<SchemaRef> for OutputSchema {
338 fn from(schema: SchemaRef) -> OutputSchema {
339 OutputSchema {
340 column_schemas: schema
341 .column_schemas()
342 .iter()
343 .map(|cs| ColumnSchema {
344 name: cs.name.clone(),
345 data_type: cs.data_type.name(),
346 })
347 .collect(),
348 }
349 }
350}
351
352#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
353pub struct HttpRecordsOutput {
354 schema: OutputSchema,
355 rows: Vec<Vec<Value>>,
356 #[serde(default)]
359 total_rows: usize,
360
361 #[serde(skip_serializing_if = "HashMap::is_empty")]
363 #[serde(default)]
364 metrics: HashMap<String, Value>,
365}
366
367impl HttpRecordsOutput {
368 pub fn num_rows(&self) -> usize {
369 self.rows.len()
370 }
371
372 pub fn num_cols(&self) -> usize {
373 self.schema.column_schemas.len()
374 }
375
376 pub fn schema(&self) -> &OutputSchema {
377 &self.schema
378 }
379
380 pub fn rows(&self) -> &Vec<Vec<Value>> {
381 &self.rows
382 }
383}
384
385impl HttpRecordsOutput {
386 pub fn try_new(
387 schema: SchemaRef,
388 recordbatches: Vec<RecordBatch>,
389 ) -> std::result::Result<HttpRecordsOutput, Error> {
390 if recordbatches.is_empty() {
391 Ok(HttpRecordsOutput {
392 schema: OutputSchema::from(schema),
393 rows: vec![],
394 total_rows: 0,
395 metrics: Default::default(),
396 })
397 } else {
398 let num_rows = recordbatches.iter().map(|r| r.num_rows()).sum::<usize>();
399 let mut rows = Vec::with_capacity(num_rows);
400
401 for recordbatch in recordbatches {
402 let mut writer = HttpOutputWriter::new(schema.num_columns(), None);
403 writer.write(recordbatch, &mut rows)?;
404 }
405
406 Ok(HttpRecordsOutput {
407 schema: OutputSchema::from(schema),
408 total_rows: rows.len(),
409 rows,
410 metrics: Default::default(),
411 })
412 }
413 }
414}
415
416#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
417#[serde(rename_all = "lowercase")]
418pub enum GreptimeQueryOutput {
419 AffectedRows(usize),
420 Records(HttpRecordsOutput),
421}
422
423#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
425pub enum ResponseFormat {
426 Arrow,
427 Csv(bool, bool),
429 Table,
430 #[default]
431 GreptimedbV1,
432 InfluxdbV1,
433 Json,
434 Null,
435}
436
437impl ResponseFormat {
438 pub fn parse(s: &str) -> Option<Self> {
439 match s {
440 "arrow" => Some(ResponseFormat::Arrow),
441 "csv" => Some(ResponseFormat::Csv(false, false)),
442 "csvwithnames" => Some(ResponseFormat::Csv(true, false)),
443 "csvwithnamesandtypes" => Some(ResponseFormat::Csv(true, true)),
444 "table" => Some(ResponseFormat::Table),
445 "greptimedb_v1" => Some(ResponseFormat::GreptimedbV1),
446 "influxdb_v1" => Some(ResponseFormat::InfluxdbV1),
447 "json" => Some(ResponseFormat::Json),
448 "null" => Some(ResponseFormat::Null),
449 _ => None,
450 }
451 }
452
453 pub fn as_str(&self) -> &'static str {
454 match self {
455 ResponseFormat::Arrow => "arrow",
456 ResponseFormat::Csv(_, _) => "csv",
457 ResponseFormat::Table => "table",
458 ResponseFormat::GreptimedbV1 => "greptimedb_v1",
459 ResponseFormat::InfluxdbV1 => "influxdb_v1",
460 ResponseFormat::Json => "json",
461 ResponseFormat::Null => "null",
462 }
463 }
464}
465
466#[derive(Debug, Clone, Copy, PartialEq, Eq)]
467pub enum Epoch {
468 Nanosecond,
469 Microsecond,
470 Millisecond,
471 Second,
472}
473
474impl Epoch {
475 pub fn parse(s: &str) -> Option<Epoch> {
476 match s {
481 "ns" => Some(Epoch::Nanosecond),
482 "u" | "µ" => Some(Epoch::Microsecond),
483 "ms" => Some(Epoch::Millisecond),
484 "s" => Some(Epoch::Second),
485 _ => None, }
487 }
488
489 pub fn convert_timestamp(&self, ts: Timestamp) -> Option<Timestamp> {
490 match self {
491 Epoch::Nanosecond => ts.convert_to(TimeUnit::Nanosecond),
492 Epoch::Microsecond => ts.convert_to(TimeUnit::Microsecond),
493 Epoch::Millisecond => ts.convert_to(TimeUnit::Millisecond),
494 Epoch::Second => ts.convert_to(TimeUnit::Second),
495 }
496 }
497}
498
499impl Display for Epoch {
500 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
501 match self {
502 Epoch::Nanosecond => write!(f, "Epoch::Nanosecond"),
503 Epoch::Microsecond => write!(f, "Epoch::Microsecond"),
504 Epoch::Millisecond => write!(f, "Epoch::Millisecond"),
505 Epoch::Second => write!(f, "Epoch::Second"),
506 }
507 }
508}
509
510#[derive(Serialize, Deserialize, Debug)]
511pub enum HttpResponse {
512 Arrow(ArrowResponse),
513 Csv(CsvResponse),
514 Table(TableResponse),
515 Error(ErrorResponse),
516 GreptimedbV1(GreptimedbV1Response),
517 InfluxdbV1(InfluxdbV1Response),
518 Json(JsonResponse),
519 Null(NullResponse),
520}
521
522impl HttpResponse {
523 pub fn with_execution_time(self, execution_time: u64) -> Self {
524 match self {
525 HttpResponse::Arrow(resp) => resp.with_execution_time(execution_time).into(),
526 HttpResponse::Csv(resp) => resp.with_execution_time(execution_time).into(),
527 HttpResponse::Table(resp) => resp.with_execution_time(execution_time).into(),
528 HttpResponse::GreptimedbV1(resp) => resp.with_execution_time(execution_time).into(),
529 HttpResponse::InfluxdbV1(resp) => resp.with_execution_time(execution_time).into(),
530 HttpResponse::Json(resp) => resp.with_execution_time(execution_time).into(),
531 HttpResponse::Null(resp) => resp.with_execution_time(execution_time).into(),
532 HttpResponse::Error(resp) => resp.with_execution_time(execution_time).into(),
533 }
534 }
535
536 pub fn with_limit(self, limit: usize) -> Self {
537 match self {
538 HttpResponse::Csv(resp) => resp.with_limit(limit).into(),
539 HttpResponse::Table(resp) => resp.with_limit(limit).into(),
540 HttpResponse::GreptimedbV1(resp) => resp.with_limit(limit).into(),
541 HttpResponse::Json(resp) => resp.with_limit(limit).into(),
542 _ => self,
543 }
544 }
545}
546
547pub fn process_with_limit(
548 mut outputs: Vec<GreptimeQueryOutput>,
549 limit: usize,
550) -> Vec<GreptimeQueryOutput> {
551 outputs
552 .drain(..)
553 .map(|data| match data {
554 GreptimeQueryOutput::Records(mut records) => {
555 if records.rows.len() > limit {
556 records.rows.truncate(limit);
557 records.total_rows = limit;
558 }
559 GreptimeQueryOutput::Records(records)
560 }
561 _ => data,
562 })
563 .collect()
564}
565
566impl IntoResponse for HttpResponse {
567 fn into_response(self) -> Response {
568 match self {
569 HttpResponse::Arrow(resp) => resp.into_response(),
570 HttpResponse::Csv(resp) => resp.into_response(),
571 HttpResponse::Table(resp) => resp.into_response(),
572 HttpResponse::GreptimedbV1(resp) => resp.into_response(),
573 HttpResponse::InfluxdbV1(resp) => resp.into_response(),
574 HttpResponse::Json(resp) => resp.into_response(),
575 HttpResponse::Null(resp) => resp.into_response(),
576 HttpResponse::Error(resp) => resp.into_response(),
577 }
578 }
579}
580
581impl From<ArrowResponse> for HttpResponse {
582 fn from(value: ArrowResponse) -> Self {
583 HttpResponse::Arrow(value)
584 }
585}
586
587impl From<CsvResponse> for HttpResponse {
588 fn from(value: CsvResponse) -> Self {
589 HttpResponse::Csv(value)
590 }
591}
592
593impl From<TableResponse> for HttpResponse {
594 fn from(value: TableResponse) -> Self {
595 HttpResponse::Table(value)
596 }
597}
598
599impl From<ErrorResponse> for HttpResponse {
600 fn from(value: ErrorResponse) -> Self {
601 HttpResponse::Error(value)
602 }
603}
604
605impl From<GreptimedbV1Response> for HttpResponse {
606 fn from(value: GreptimedbV1Response) -> Self {
607 HttpResponse::GreptimedbV1(value)
608 }
609}
610
611impl From<InfluxdbV1Response> for HttpResponse {
612 fn from(value: InfluxdbV1Response) -> Self {
613 HttpResponse::InfluxdbV1(value)
614 }
615}
616
617impl From<JsonResponse> for HttpResponse {
618 fn from(value: JsonResponse) -> Self {
619 HttpResponse::Json(value)
620 }
621}
622
623impl From<NullResponse> for HttpResponse {
624 fn from(value: NullResponse) -> Self {
625 HttpResponse::Null(value)
626 }
627}
628
629#[derive(Clone)]
630pub struct ApiState {
631 pub sql_handler: ServerSqlQueryHandlerRef,
632}
633
634#[derive(Clone)]
635pub struct GreptimeOptionsConfigState {
636 pub greptime_config_options: String,
637}
638
639#[derive(Clone)]
640pub struct DashboardState {
641 pub handler: DashboardHandlerRef,
642}
643
644pub struct HttpServerBuilder {
645 options: HttpOptions,
646 batching_protocols: Vec<BatchingProtocol>,
647 logical_batching_protocols: Vec<BatchingProtocol>,
648 user_provider: Option<UserProviderRef>,
649 router: Router,
650 memory_limiter: ServerMemoryLimiter,
651}
652
653impl HttpServerBuilder {
654 pub fn new(options: HttpOptions) -> Self {
655 Self {
656 options,
657 batching_protocols: Vec::new(),
658 logical_batching_protocols: Vec::new(),
659 user_provider: None,
660 router: Router::new(),
661 memory_limiter: ServerMemoryLimiter::default(),
662 }
663 }
664
665 pub fn with_logical_batching_protocols(mut self, protocols: Vec<BatchingProtocol>) -> Self {
667 self.logical_batching_protocols = protocols;
668 self
669 }
670
671 pub fn with_batching_protocols(mut self, protocols: Vec<BatchingProtocol>) -> Self {
673 self.batching_protocols = protocols;
674 self
675 }
676
677 pub fn with_memory_limiter(mut self, limiter: ServerMemoryLimiter) -> Self {
679 self.memory_limiter = limiter;
680 self
681 }
682
683 pub fn with_sql_handler(self, sql_handler: ServerSqlQueryHandlerRef) -> Self {
684 let sql_router = HttpServer::route_sql(ApiState { sql_handler });
685
686 Self {
687 router: self
688 .router
689 .nest(&format!("/{HTTP_API_VERSION}"), sql_router),
690 ..self
691 }
692 }
693
694 pub fn with_logs_handler(self, logs_handler: LogQueryHandlerRef) -> Self {
695 let logs_router = HttpServer::route_logs(logs_handler);
696
697 Self {
698 router: self
699 .router
700 .nest(&format!("/{HTTP_API_VERSION}"), logs_router),
701 ..self
702 }
703 }
704
705 pub fn with_opentsdb_handler(self, handler: OpentsdbProtocolHandlerRef) -> Self {
706 Self {
707 router: self.router.nest(
708 &format!("/{HTTP_API_VERSION}/opentsdb"),
709 HttpServer::route_opentsdb(handler),
710 ),
711 ..self
712 }
713 }
714
715 pub fn with_influxdb_handler(self, handler: InfluxdbLineProtocolHandlerRef) -> Self {
716 Self {
717 router: self.router.nest(
718 &format!("/{HTTP_API_VERSION}/influxdb"),
719 HttpServer::route_influxdb(handler, self.memory_limiter.clone()),
720 ),
721 ..self
722 }
723 }
724
725 pub fn with_prom_handler(
726 self,
727 handler: PromStoreProtocolHandlerRef,
728 pipeline_handler: Option<PipelineHandlerRef>,
729 prom_store_with_metric_engine: bool,
730 prom_validation_mode: PromValidationMode,
731 pending_rows_batcher: Option<Arc<LogicalTablePendingRowsBatcher>>,
732 ) -> Self {
733 let state = PromStoreState {
734 prom_store_handler: handler,
735 pipeline_handler,
736 prom_store_with_metric_engine,
737 prom_validation_mode,
738 pending_rows_batcher,
739 memory_limiter: self.memory_limiter.clone(),
740 };
741
742 Self {
743 router: self.router.nest(
744 &format!("/{HTTP_API_VERSION}/prometheus"),
745 HttpServer::route_prom(state),
746 ),
747 ..self
748 }
749 }
750
751 pub fn with_prometheus_handler(self, handler: PrometheusHandlerRef) -> Self {
752 Self {
753 router: self.router.nest(
754 &format!("/{HTTP_API_VERSION}/prometheus/api/v1"),
755 HttpServer::route_prometheus(handler),
756 ),
757 ..self
758 }
759 }
760
761 pub fn with_otlp_handler(
762 self,
763 handler: OpenTelemetryProtocolHandlerRef,
764 with_metric_engine: bool,
765 ) -> Self {
766 Self {
767 router: self.router.nest(
768 &format!("/{HTTP_API_VERSION}/otlp"),
769 HttpServer::route_otlp(handler, with_metric_engine, self.memory_limiter.clone()),
770 ),
771 ..self
772 }
773 }
774
775 pub fn with_user_provider(self, user_provider: UserProviderRef) -> Self {
776 Self {
777 user_provider: Some(user_provider),
778 ..self
779 }
780 }
781
782 pub fn with_metrics_handler(self, handler: MetricsHandler) -> Self {
783 Self {
784 router: self.router.merge(HttpServer::route_metrics(handler)),
785 ..self
786 }
787 }
788
789 pub fn with_log_ingest_handler(
790 self,
791 handler: PipelineHandlerRef,
792 validator: Option<LogValidatorRef>,
793 ingest_interceptor: Option<LogIngestInterceptorRef<Error>>,
794 ) -> Self {
795 let log_state = LogState {
796 log_handler: handler,
797 log_validator: validator,
798 ingest_interceptor,
799 };
800
801 let router = self.router.nest(
802 &format!("/{HTTP_API_VERSION}"),
803 HttpServer::route_pipelines(log_state.clone(), self.memory_limiter.clone()),
804 );
805 let router = router.nest(
807 &format!("/{HTTP_API_VERSION}/events"),
808 #[allow(deprecated)]
809 HttpServer::route_log_deprecated(log_state.clone(), self.memory_limiter.clone()),
810 );
811
812 let router = router.nest(
813 &format!("/{HTTP_API_VERSION}/loki"),
814 HttpServer::route_loki(log_state.clone(), self.memory_limiter.clone()),
815 );
816
817 let router = router.nest(
818 &format!("/{HTTP_API_VERSION}/elasticsearch"),
819 HttpServer::route_elasticsearch(log_state.clone(), self.memory_limiter.clone()),
820 );
821
822 let router = router.nest(
823 &format!("/{HTTP_API_VERSION}/elasticsearch/"),
824 Router::new()
825 .route("/", routing::get(elasticsearch::handle_get_version))
826 .with_state(log_state.clone()),
827 );
828
829 let router = router.nest(
830 &format!("/{HTTP_API_VERSION}/splunk"),
831 HttpServer::route_splunk(log_state, self.memory_limiter.clone()),
832 );
833
834 Self { router, ..self }
835 }
836
837 pub fn with_greptime_config_options(self, opts: String) -> Self {
838 let config_router = HttpServer::route_config(GreptimeOptionsConfigState {
839 greptime_config_options: opts,
840 });
841
842 Self {
843 router: self.router.merge(config_router),
844 ..self
845 }
846 }
847
848 pub fn with_jaeger_handler(self, handler: JaegerQueryHandlerRef) -> Self {
849 Self {
850 router: self.router.nest(
851 &format!("/{HTTP_API_VERSION}/jaeger"),
852 HttpServer::route_jaeger(handler),
853 ),
854 ..self
855 }
856 }
857
858 pub fn with_dashboard_handler(self, handler: DashboardHandlerRef) -> Self {
859 Self {
860 router: self.router.nest(
861 &format!("/{HTTP_API_VERSION}/dashboards"),
862 HttpServer::route_dashboard(handler, self.memory_limiter.clone()),
863 ),
864 ..self
865 }
866 }
867
868 pub fn with_extra_router(self, router: Router) -> Self {
869 Self {
870 router: self.router.merge(router),
871 ..self
872 }
873 }
874
875 pub fn add_layer<L>(self, layer: L) -> Self
876 where
877 L: Layer<Route> + Clone + Send + Sync + 'static,
878 L::Service: Service<Request> + Clone + Send + Sync + 'static,
879 <L::Service as Service<Request>>::Response: IntoResponse + 'static,
880 <L::Service as Service<Request>>::Error: Into<Infallible> + 'static,
881 <L::Service as Service<Request>>::Future: Send + 'static,
882 {
883 Self {
884 router: self.router.layer(layer),
885 ..self
886 }
887 }
888
889 pub fn build(self) -> HttpServer {
890 HttpServer {
891 options: self.options,
892 batching_protocols: self.batching_protocols.clone(),
893 logical_batching_protocols: self.logical_batching_protocols.clone(),
894 user_provider: self.user_provider,
895 shutdown_tx: Mutex::new(None),
896 router: StdMutex::new(self.router),
897 bind_addr: None,
898 memory_limiter: self.memory_limiter,
899 kind: HttpServerKind::Full,
900 }
901 }
902
903 pub fn build_servers(self) -> (HttpServer, Option<HttpServer>) {
922 let api_enabled = self.options.enable_api_server;
923 let api_addr = self.options.api_server_addr.clone();
924
925 let internal = HttpServer {
926 options: self.options,
927 batching_protocols: self.batching_protocols.clone(),
928 logical_batching_protocols: self.logical_batching_protocols.clone(),
929 user_provider: self.user_provider.clone(),
930 shutdown_tx: Mutex::new(None),
931 router: StdMutex::new(self.router.clone()),
932 bind_addr: None,
933 memory_limiter: self.memory_limiter.clone(),
934 kind: HttpServerKind::Full,
935 };
936
937 let api = if api_enabled {
938 let api_options = HttpOptions {
941 addr: api_addr,
942 ..internal.options.clone()
943 };
944 Some(HttpServer {
945 options: api_options,
946 batching_protocols: self.batching_protocols,
947 logical_batching_protocols: self.logical_batching_protocols,
948 user_provider: self.user_provider.clone(),
949 shutdown_tx: Mutex::new(None),
950 router: StdMutex::new(self.router),
951 bind_addr: None,
952 memory_limiter: self.memory_limiter,
953 kind: HttpServerKind::Api,
954 })
955 } else {
956 None
957 };
958
959 (internal, api)
960 }
961}
962
963impl HttpServer {
964 pub fn make_app(&self) -> Router {
974 let mut router = self.router.lock().unwrap().clone();
975
976 router = router
977 .route(
978 &format!("/{HTTP_API_VERSION}/health"),
979 routing::get(handler::health).post(handler::health),
980 )
981 .route("/", routing::get(handler::index))
982 .route(
983 "/health",
984 routing::get(handler::health).post(handler::health),
985 )
986 .route(
987 "/ready",
988 routing::get(handler::health).post(handler::health),
989 )
990 .route("/status", routing::get(handler::status));
991
992 #[cfg(feature = "dashboard")]
995 {
996 if !self.options.disable_dashboard {
997 info!("Enable dashboard service at '/dashboard'");
998 router = router.route(
1000 "/dashboard",
1001 routing::get(|uri: axum::http::uri::Uri| async move {
1002 let path = uri.path();
1003 let query = uri.query().map(|q| format!("?{}", q)).unwrap_or_default();
1004
1005 let new_uri = format!("{}/{}", path, query);
1006 axum::response::Redirect::permanent(&new_uri)
1007 }),
1008 );
1009
1010 router = router
1014 .route(
1015 "/dashboard/",
1016 routing::get(dashboard::static_handler).post(dashboard::static_handler),
1017 )
1018 .route(
1019 "/dashboard/{*x}",
1020 routing::get(dashboard::static_handler).post(dashboard::static_handler),
1021 );
1022 }
1023 }
1024
1025 router = router.route_layer(middleware::from_fn(http_metrics_layer));
1027
1028 router
1029 }
1030
1031 pub fn build(&self, router: Router) -> Result<Router> {
1034 let timeout_layer = if self.options.timeout != Duration::default() {
1035 Some(
1036 ServiceBuilder::new().layer(
1037 DynamicTimeoutLayer::new(self.options.timeout)
1038 .with_status_code_fn(Self::request_timeout_status_code),
1039 ),
1040 )
1041 } else {
1042 info!("HTTP server timeout is disabled");
1043 None
1044 };
1045 let body_limit_layer = if self.options.body_limit != ReadableSize(0) {
1046 Some(
1047 ServiceBuilder::new()
1048 .layer(DefaultBodyLimit::max(self.options.body_limit.0 as usize)),
1049 )
1050 } else {
1051 info!("HTTP server body limit is disabled");
1052 None
1053 };
1054 let cors_layer = if self.options.enable_cors {
1055 Some(
1056 CorsLayer::new()
1057 .allow_methods([
1058 Method::GET,
1059 Method::POST,
1060 Method::PUT,
1061 Method::DELETE,
1062 Method::HEAD,
1063 ])
1064 .allow_origin(cors_allow_origin(&self.options.cors_allowed_origins)?)
1065 .allow_headers(Any),
1066 )
1067 } else {
1068 info!("HTTP server cross-origin is disabled");
1069 None
1070 };
1071
1072 let router = router
1073 .layer(
1075 ServiceBuilder::new()
1076 .layer(TraceLayer::new_for_http().on_failure(()))
1079 .option_layer(cors_layer)
1080 .option_layer(timeout_layer)
1081 .option_layer(body_limit_layer)
1082 .layer(middleware::from_fn_with_state(
1084 self.memory_limiter.clone(),
1085 memory_limit::memory_limit_middleware,
1086 ))
1087 .layer(middleware::from_fn_with_state(
1089 AuthState::new(self.user_provider.clone()),
1090 authorize::check_http_auth,
1091 ))
1092 .layer(Extension(Arc::new(self.batching_protocols.clone())))
1093 .layer(Extension(LogicalBatchingProtocols(
1094 self.logical_batching_protocols.clone(),
1095 )))
1096 .layer(middleware::from_fn(hints::extract_hints))
1097 .layer(middleware::from_fn(client_ip::log_error_with_client_ip))
1098 .layer(middleware::from_fn(
1099 read_preference::extract_read_preference,
1100 ))
1101 .layer(middleware::from_fn(skip_wal::extract_skip_wal)),
1102 );
1103
1104 let router = router.nest(
1107 "/debug",
1108 Router::new()
1109 .route("/log_level", routing::post(dyn_log::dyn_log_handler))
1111 .route(
1112 "/workload_scheduler",
1113 routing::get(workload_scheduler::get_status_handler),
1114 )
1115 .route(
1116 "/workload_scheduler/enabled",
1117 routing::post(workload_scheduler::set_enabled_handler),
1118 )
1119 .route(
1120 "/workload_scheduler/weights",
1121 routing::post(workload_scheduler::set_weights_handler),
1122 )
1123 .route("/enable_trace", routing::post(dyn_trace::dyn_trace_handler))
1124 .nest(
1125 "/prof",
1126 Router::new()
1127 .route("/cpu", routing::post(pprof::pprof_handler))
1128 .route("/mem", routing::post(mem_prof::mem_prof_handler))
1129 .route("/mem/symbol", routing::post(mem_prof::symbolicate_handler))
1130 .route(
1131 "/mem/activate",
1132 routing::post(mem_prof::activate_heap_prof_handler),
1133 )
1134 .route(
1135 "/mem/deactivate",
1136 routing::post(mem_prof::deactivate_heap_prof_handler),
1137 )
1138 .route(
1139 "/mem/status",
1140 routing::get(mem_prof::heap_prof_status_handler),
1141 ) .route(
1143 "/mem/gdump",
1144 routing::get(mem_prof::gdump_status_handler)
1145 .post(mem_prof::gdump_toggle_handler),
1146 ),
1147 ),
1148 );
1149
1150 if self.kind == HttpServerKind::Api {
1155 Ok(router.layer(middleware::from_fn(enforce_api_surface)))
1156 } else {
1157 Ok(router)
1158 }
1159 }
1160
1161 fn request_timeout_status_code(request: &Request) -> HttpStatusCode {
1162 if request.uri().path() == "/v1/prometheus/write" {
1163 HttpStatusCode::GATEWAY_TIMEOUT
1164 } else {
1165 HttpStatusCode::REQUEST_TIMEOUT
1166 }
1167 }
1168
1169 fn route_metrics<S>(metrics_handler: MetricsHandler) -> Router<S> {
1170 Router::new()
1171 .route("/metrics", routing::get(handler::metrics))
1172 .with_state(metrics_handler)
1173 }
1174
1175 fn route_loki<S>(log_state: LogState, memory_limiter: ServerMemoryLimiter) -> Router<S> {
1176 Router::new()
1177 .route("/api/v1/push", routing::post(loki::loki_ingest))
1178 .layer(middleware::from_fn_with_state(
1179 memory_limiter,
1180 memory_limit::decoded_body_accounting_middleware,
1181 ))
1182 .layer(
1183 ServiceBuilder::new()
1184 .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1185 )
1186 .layer(middleware::from_fn_with_state(
1187 BatchingProtocol::Loki,
1188 set_http_write_batching,
1189 ))
1190 .with_state(log_state)
1191 }
1192
1193 fn route_splunk<S>(log_state: LogState, memory_limiter: ServerMemoryLimiter) -> Router<S> {
1194 Router::new()
1195 .route(
1196 "/services/collector/health",
1197 routing::get(splunk::handle_health),
1198 )
1199 .route(
1200 "/services/collector/health/1.0",
1201 routing::get(splunk::handle_health),
1202 )
1203 .route(
1206 "/services/collector/event",
1207 routing::post(splunk::handle_event),
1208 )
1209 .route("/services/collector", routing::post(splunk::handle_event))
1210 .route(
1211 "/services/collector/event/1.0",
1212 routing::post(splunk::handle_event),
1213 )
1214 .route("/services/collector/raw", routing::post(splunk::handle_raw))
1217 .route(
1218 "/services/collector/raw/1.0",
1219 routing::post(splunk::handle_raw),
1220 )
1221 .layer(middleware::from_fn_with_state(
1222 memory_limiter,
1223 memory_limit::decoded_body_accounting_middleware,
1224 ))
1225 .layer(
1226 ServiceBuilder::new()
1227 .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1228 )
1229 .layer(middleware::from_fn_with_state(
1230 BatchingProtocol::Splunk,
1231 set_http_write_batching,
1232 ))
1233 .with_state(log_state)
1234 }
1235
1236 fn route_elasticsearch<S>(
1237 log_state: LogState,
1238 memory_limiter: ServerMemoryLimiter,
1239 ) -> Router<S> {
1240 Router::new()
1241 .route(
1243 "/",
1244 routing::head((HttpStatusCode::OK, elasticsearch::elasticsearch_headers())),
1245 )
1246 .route("/", routing::get(elasticsearch::handle_get_version))
1248 .route("/_license", routing::get(elasticsearch::handle_get_license))
1250 .route("/_bulk", routing::post(elasticsearch::handle_bulk_api))
1251 .route(
1252 "/{index}/_bulk",
1253 routing::post(elasticsearch::handle_bulk_api_with_index),
1254 )
1255 .route(
1257 "/_ilm/policy/{*path}",
1258 routing::any((
1259 HttpStatusCode::OK,
1260 elasticsearch::elasticsearch_headers(),
1261 axum::Json(serde_json::json!({})),
1262 )),
1263 )
1264 .route(
1266 "/_index_template/{*path}",
1267 routing::any((
1268 HttpStatusCode::OK,
1269 elasticsearch::elasticsearch_headers(),
1270 axum::Json(serde_json::json!({})),
1271 )),
1272 )
1273 .route(
1276 "/_ingest/{*path}",
1277 routing::any((
1278 HttpStatusCode::OK,
1279 elasticsearch::elasticsearch_headers(),
1280 axum::Json(serde_json::json!({})),
1281 )),
1282 )
1283 .route(
1286 "/_nodes/{*path}",
1287 routing::any((
1288 HttpStatusCode::OK,
1289 elasticsearch::elasticsearch_headers(),
1290 axum::Json(serde_json::json!({})),
1291 )),
1292 )
1293 .route(
1296 "/logstash/{*path}",
1297 routing::any((
1298 HttpStatusCode::OK,
1299 elasticsearch::elasticsearch_headers(),
1300 axum::Json(serde_json::json!({})),
1301 )),
1302 )
1303 .route(
1304 "/_logstash/{*path}",
1305 routing::any((
1306 HttpStatusCode::OK,
1307 elasticsearch::elasticsearch_headers(),
1308 axum::Json(serde_json::json!({})),
1309 )),
1310 )
1311 .layer(middleware::from_fn_with_state(
1312 memory_limiter,
1313 memory_limit::decoded_body_accounting_middleware,
1314 ))
1315 .layer(ServiceBuilder::new().layer(RequestDecompressionLayer::new()))
1316 .layer(middleware::from_fn_with_state(
1317 BatchingProtocol::Elasticsearch,
1318 set_http_write_batching,
1319 ))
1320 .with_state(log_state)
1321 }
1322
1323 #[deprecated(since = "0.11.0", note = "Use `route_pipelines()` instead.")]
1324 fn route_log_deprecated<S>(
1325 log_state: LogState,
1326 memory_limiter: ServerMemoryLimiter,
1327 ) -> Router<S> {
1328 Router::new()
1329 .route("/logs", routing::post(event::log_ingester))
1330 .route(
1331 "/pipelines/{pipeline_name}",
1332 routing::get(event::query_pipeline),
1333 )
1334 .route(
1335 "/pipelines/{pipeline_name}",
1336 routing::post(event::add_pipeline),
1337 )
1338 .route(
1339 "/pipelines/{pipeline_name}",
1340 routing::delete(event::delete_pipeline),
1341 )
1342 .route("/pipelines/dryrun", routing::post(event::pipeline_dryrun))
1343 .layer(middleware::from_fn_with_state(
1344 memory_limiter,
1345 memory_limit::decoded_body_accounting_middleware,
1346 ))
1347 .layer(
1348 ServiceBuilder::new()
1349 .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1350 )
1351 .layer(middleware::from_fn_with_state(
1352 BatchingProtocol::Logs,
1353 set_http_write_batching,
1354 ))
1355 .with_state(log_state)
1356 }
1357
1358 fn route_pipelines<S>(log_state: LogState, memory_limiter: ServerMemoryLimiter) -> Router<S> {
1359 Router::new()
1360 .route("/ingest", routing::post(event::log_ingester))
1361 .route(
1362 "/pipelines/{pipeline_name}",
1363 routing::get(event::query_pipeline),
1364 )
1365 .route(
1366 "/pipelines/{pipeline_name}/ddl",
1367 routing::get(event::query_pipeline_ddl),
1368 )
1369 .route(
1370 "/pipelines/{pipeline_name}",
1371 routing::post(event::add_pipeline),
1372 )
1373 .route(
1374 "/pipelines/{pipeline_name}",
1375 routing::delete(event::delete_pipeline),
1376 )
1377 .route("/pipelines/_dryrun", routing::post(event::pipeline_dryrun))
1378 .layer(middleware::from_fn_with_state(
1379 memory_limiter,
1380 memory_limit::decoded_body_accounting_middleware,
1381 ))
1382 .layer(
1383 ServiceBuilder::new()
1384 .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1385 )
1386 .layer(middleware::from_fn_with_state(
1387 BatchingProtocol::Logs,
1388 set_http_write_batching,
1389 ))
1390 .with_state(log_state)
1391 }
1392
1393 fn route_sql<S>(api_state: ApiState) -> Router<S> {
1394 Router::new()
1395 .route(
1396 "/capabilities",
1397 routing::get(|| async {
1398 axum::Json(
1399 serde_json::json!({"metric_packed_import": 1, "metric_packed_export": 1}),
1400 )
1401 }),
1402 )
1403 .route(
1404 "/sql",
1405 routing::get(handler::sql).post(handler::sql).layer(
1406 middleware::from_fn_with_state(
1407 BatchingProtocol::HttpSql,
1408 set_http_write_batching,
1409 ),
1410 ),
1411 )
1412 .route(
1413 "/sql/parse",
1414 routing::get(handler::sql_parse).post(handler::sql_parse),
1415 )
1416 .route(
1417 "/sql/format",
1418 routing::get(handler::sql_format).post(handler::sql_format),
1419 )
1420 .route(
1421 "/promql",
1422 routing::get(handler::promql).post(handler::promql),
1423 )
1424 .route(
1425 "/sql/analyze/stream",
1426 routing::post(handler::sql_analyze_stream),
1427 )
1428 .with_state(api_state)
1429 }
1430
1431 fn route_logs<S>(log_handler: LogQueryHandlerRef) -> Router<S> {
1432 Router::new()
1433 .route("/logs", routing::get(logs::logs).post(logs::logs))
1434 .with_state(log_handler)
1435 }
1436
1437 pub fn route_prometheus<S>(prometheus_handler: PrometheusHandlerRef) -> Router<S> {
1441 Router::new()
1442 .route(
1443 "/format_query",
1444 routing::post(format_query).get(format_query),
1445 )
1446 .route("/status/buildinfo", routing::get(build_info_query))
1447 .route("/query", routing::post(instant_query).get(instant_query))
1448 .route("/query_range", routing::post(range_query).get(range_query))
1449 .route("/labels", routing::post(labels_query).get(labels_query))
1450 .route("/metadata", routing::get(metadata_query))
1451 .route("/series", routing::post(series_query).get(series_query))
1452 .route("/parse_query", routing::post(parse_query).get(parse_query))
1453 .route(
1454 "/label/{label_name}/values",
1455 routing::get(label_values_query),
1456 )
1457 .layer(ServiceBuilder::new().layer(CompressionLayer::new()))
1458 .with_state(prometheus_handler)
1459 }
1460
1461 fn route_prom<S>(state: PromStoreState) -> Router<S> {
1467 let write = routing::post(prom_store::remote_write);
1468 let write = if state.prom_store_with_metric_engine {
1469 write
1470 } else {
1471 write.layer(middleware::from_fn_with_state(
1472 BatchingProtocol::Prom,
1473 set_http_write_batching,
1474 ))
1475 };
1476 Router::new()
1477 .route("/read", routing::post(prom_store::remote_read))
1478 .route("/write", write)
1479 .with_state(state)
1480 }
1481
1482 fn route_influxdb<S>(
1483 influxdb_handler: InfluxdbLineProtocolHandlerRef,
1484 memory_limiter: ServerMemoryLimiter,
1485 ) -> Router<S> {
1486 Router::new()
1487 .route("/write", routing::post(influxdb_write_v1))
1488 .route("/api/v2/write", routing::post(influxdb_write_v2))
1489 .layer(middleware::from_fn_with_state(
1490 memory_limiter,
1491 memory_limit::decoded_body_accounting_middleware,
1492 ))
1493 .layer(
1494 ServiceBuilder::new()
1495 .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1496 )
1497 .route("/ping", routing::get(influxdb_ping))
1498 .route("/health", routing::get(influxdb_health))
1499 .layer(middleware::from_fn_with_state(
1500 BatchingProtocol::Influxdb,
1501 set_http_write_batching,
1502 ))
1503 .with_state(influxdb_handler)
1504 }
1505
1506 fn route_opentsdb<S>(opentsdb_handler: OpentsdbProtocolHandlerRef) -> Router<S> {
1507 Router::new()
1508 .route("/api/put", routing::post(opentsdb::put))
1509 .layer(middleware::from_fn_with_state(
1510 BatchingProtocol::Opentsdb,
1511 set_http_write_batching,
1512 ))
1513 .with_state(opentsdb_handler)
1514 }
1515
1516 fn route_otlp<S>(
1517 otlp_handler: OpenTelemetryProtocolHandlerRef,
1518 with_metric_engine: bool,
1519 memory_limiter: ServerMemoryLimiter,
1520 ) -> Router<S> {
1521 Router::new()
1522 .route("/v1/metrics", routing::post(otlp::metrics))
1523 .route("/v1/traces", routing::post(otlp::traces))
1524 .route("/v1/logs", routing::post(otlp::logs))
1525 .layer(middleware::from_fn_with_state(
1526 memory_limiter,
1527 memory_limit::decoded_body_accounting_middleware,
1528 ))
1529 .layer(
1530 ServiceBuilder::new()
1531 .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1532 )
1533 .layer(middleware::from_fn_with_state(
1534 BatchingProtocol::Otlp,
1535 set_http_write_batching,
1536 ))
1537 .with_state(OtlpState {
1538 with_metric_engine,
1539 handler: otlp_handler,
1540 })
1541 }
1542
1543 fn route_config<S>(state: GreptimeOptionsConfigState) -> Router<S> {
1544 Router::new()
1545 .route("/config", routing::get(handler::config))
1546 .with_state(state)
1547 }
1548
1549 fn route_jaeger<S>(handler: JaegerQueryHandlerRef) -> Router<S> {
1550 Router::new()
1551 .route("/api/services", routing::get(jaeger::handle_get_services))
1552 .route(
1553 "/api/services/{service_name}/operations",
1554 routing::get(jaeger::handle_get_operations_by_service),
1555 )
1556 .route(
1557 "/api/operations",
1558 routing::get(jaeger::handle_get_operations),
1559 )
1560 .route("/api/traces", routing::get(jaeger::handle_find_traces))
1561 .route(
1562 "/api/traces/{trace_id}",
1563 routing::get(jaeger::handle_get_trace),
1564 )
1565 .with_state(handler)
1566 }
1567
1568 #[cfg(feature = "dashboard")]
1569 fn route_dashboard<S>(
1570 handler: DashboardHandlerRef,
1571 memory_limiter: ServerMemoryLimiter,
1572 ) -> Router<S> {
1573 use crate::http::dashboard::{add_dashboard, delete_dashboard, list_dashboards};
1574
1575 Router::new()
1576 .route("/", routing::get(list_dashboards))
1577 .route("/{dashboard_name}", routing::post(add_dashboard))
1578 .route("/{dashboard_name}", routing::delete(delete_dashboard))
1579 .layer(middleware::from_fn_with_state(
1580 memory_limiter,
1581 memory_limit::decoded_body_accounting_middleware,
1582 ))
1583 .layer(
1584 ServiceBuilder::new()
1585 .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1586 )
1587 .with_state(DashboardState { handler })
1588 }
1589
1590 #[cfg(not(feature = "dashboard"))]
1591 fn route_dashboard<S>(
1592 handler: DashboardHandlerRef,
1593 _memory_limiter: ServerMemoryLimiter,
1594 ) -> Router<S> {
1595 Router::new().with_state(DashboardState { handler })
1596 }
1597}
1598
1599pub const HTTP_SERVER: &str = "HTTP_SERVER";
1600pub const HTTP_API_SERVER: &str = "HTTP_API_SERVER";
1601
1602pub(crate) fn cors_allow_origin(origins: &[String]) -> Result<AllowOrigin> {
1604 if origins.is_empty() {
1605 return Ok(AllowOrigin::any());
1606 }
1607 let origins = origins
1608 .iter()
1609 .map(|origin| HeaderValue::from_str(origin).context(InvalidHeaderValueSnafu))
1610 .collect::<Result<Vec<_>>>()?;
1611 Ok(AllowOrigin::list(origins))
1612}
1613
1614#[async_trait]
1615impl Server for HttpServer {
1616 async fn shutdown(&self) -> Result<()> {
1617 let mut shutdown_tx = self.shutdown_tx.lock().await;
1618 if let Some(tx) = shutdown_tx.take()
1619 && tx.send(()).is_err()
1620 {
1621 info!("Receiver dropped, the HTTP server has already exited");
1622 }
1623 info!("Shutdown {}", self.kind());
1624
1625 Ok(())
1626 }
1627
1628 async fn start(&mut self, listening: SocketAddr) -> Result<()> {
1629 let (tx, rx) = oneshot::channel();
1630 let serve = {
1631 let mut shutdown_tx = self.shutdown_tx.lock().await;
1632 ensure!(
1633 shutdown_tx.is_none(),
1634 AlreadyStartedSnafu {
1635 server: self.kind()
1636 }
1637 );
1638
1639 let app = self.build(self.make_app())?;
1640 let listener = tokio::net::TcpListener::bind(listening)
1641 .await
1642 .context(AddressBindSnafu { addr: listening })?
1643 .tap_io(|tcp_stream| {
1644 if let Err(e) = tcp_stream.set_nodelay(true) {
1645 error!(e; "Failed to set TCP_NODELAY on incoming connection");
1646 }
1647 });
1648 let serve = axum::serve(
1649 listener,
1650 app.into_make_service_with_connect_info::<SocketAddr>(),
1651 );
1652
1653 *shutdown_tx = Some(tx);
1670
1671 serve
1672 };
1673 let listening = serve.local_addr().context(InternalIoSnafu)?;
1674 info!("{} server is bound to {}", self.kind(), listening);
1675
1676 common_runtime::spawn_global(async move {
1677 if let Err(e) = serve
1678 .with_graceful_shutdown(rx.map(drop))
1679 .await
1680 .context(InternalIoSnafu)
1681 {
1682 error!(e; "Failed to shutdown http server");
1683 }
1684 });
1685
1686 self.bind_addr = Some(listening);
1687 Ok(())
1688 }
1689
1690 fn name(&self) -> &str {
1691 match self.kind {
1692 HttpServerKind::Api => HTTP_API_SERVER,
1693 HttpServerKind::Full => HTTP_SERVER,
1694 }
1695 }
1696
1697 fn bind_addr(&self) -> Option<SocketAddr> {
1698 self.bind_addr
1699 }
1700
1701 fn as_any(&self) -> &dyn std::any::Any {
1702 self
1703 }
1704}
1705
1706#[cfg(test)]
1707mod test {
1708 use std::future::pending;
1709 use std::io::Cursor;
1710 use std::sync::Arc;
1711
1712 use arrow_ipc::reader::StreamReader;
1713 use arrow_schema::DataType;
1714 use axum::http::StatusCode;
1715 use axum::routing::{get, post};
1716 use common_query::{Output, OutputData};
1717 use common_recordbatch::RecordBatches;
1718 use datafusion_expr::LogicalPlan;
1719 use datatypes::prelude::*;
1720 use datatypes::schema::{ColumnSchema, Schema};
1721 use datatypes::vectors::{StringVector, UInt32Vector};
1722 use header::constants::GREPTIME_DB_HEADER_TIMEOUT;
1723 use query::parser::PromQuery;
1724 use query::query_engine::DescribeResult;
1725 use session::context::QueryContextRef;
1726 use sql::statements::statement::Statement;
1727 use tokio::sync::mpsc;
1728 use tokio::time::Instant;
1729
1730 use crate::http::test_helpers::TestClient;
1731 use crate::http::*;
1732 use crate::prom_remote_write::validation::validate_label_name;
1733 use crate::query_handler::sql::SqlQueryHandler;
1734
1735 struct DummyInstance {
1736 _tx: mpsc::Sender<(String, Vec<u8>)>,
1737 }
1738
1739 #[async_trait]
1740 impl SqlQueryHandler for DummyInstance {
1741 async fn do_query(&self, _: &str, _: QueryContextRef) -> Vec<Result<Output>> {
1742 unimplemented!()
1743 }
1744
1745 async fn do_analyze_stream_query(&self, _: &str, _: QueryContextRef) -> Result<Output> {
1746 let stream = common_recordbatch::RecordBatches::empty().as_stream();
1747 Ok(Output::new(OutputData::Stream(stream), Default::default()))
1748 }
1749
1750 async fn do_promql_query(&self, _: &PromQuery, _: QueryContextRef) -> Vec<Result<Output>> {
1751 unimplemented!()
1752 }
1753
1754 async fn do_exec_plan(
1755 &self,
1756 _plan: LogicalPlan,
1757 _stmt: Option<Statement>,
1758 _query_ctx: QueryContextRef,
1759 ) -> Result<Output> {
1760 unimplemented!()
1761 }
1762
1763 async fn do_describe(
1764 &self,
1765 _stmt: sql::statements::statement::Statement,
1766 _query_ctx: QueryContextRef,
1767 ) -> Result<Option<DescribeResult>> {
1768 unimplemented!()
1769 }
1770
1771 async fn is_valid_schema(&self, _catalog: &str, _schema: &str) -> Result<bool> {
1772 Ok(true)
1773 }
1774 }
1775
1776 async fn forever() {
1777 pending().await
1778 }
1779
1780 fn make_test_app(tx: mpsc::Sender<(String, Vec<u8>)>) -> Router {
1781 make_test_app_custom(tx, HttpOptions::default())
1782 }
1783
1784 fn make_test_app_custom(tx: mpsc::Sender<(String, Vec<u8>)>, options: HttpOptions) -> Router {
1785 let instance = Arc::new(DummyInstance { _tx: tx });
1786 let server = HttpServerBuilder::new(options)
1787 .with_sql_handler(instance.clone())
1788 .build();
1789 let app = server
1790 .make_app()
1791 .route("/test/timeout", get(forever))
1792 .route("/v1/prometheus/write", post(forever));
1793 server.build(app).unwrap()
1794 }
1795
1796 fn make_split_builder() -> HttpServerBuilder {
1797 let (tx, _rx) = mpsc::channel(100);
1798 let instance = Arc::new(DummyInstance { _tx: tx });
1799 let options = HttpOptions {
1801 enable_api_server: true,
1802 ..HttpOptions::default()
1803 };
1804 HttpServerBuilder::new(options)
1805 .with_sql_handler(instance)
1806 .with_metrics_handler(MetricsHandler)
1807 .with_greptime_config_options("dummy = \"value\"".to_string())
1808 }
1809
1810 #[tokio::test]
1811 pub async fn test_http_api_options_defaults() {
1812 let opts = HttpOptions::default();
1813 assert!(!opts.enable_api_server);
1815 assert_eq!(opts.api_server_addr, "127.0.0.1:4006");
1816 }
1817
1818 #[tokio::test]
1819 pub async fn test_build_serves_all_routes() {
1820 let server = make_split_builder().build();
1824 assert_eq!(server.name(), HTTP_SERVER);
1825
1826 let app = server.build(server.make_app()).unwrap();
1827 let client = TestClient::new(app).await;
1828
1829 for path in ["/v1/health", "/health", "/status", "/metrics", "/config"] {
1830 let res = client.get(path).send().await;
1831 assert_eq!(
1832 res.status(),
1833 StatusCode::OK,
1834 "internal/full server should serve {path}"
1835 );
1836 }
1837 }
1838
1839 #[tokio::test]
1840 pub async fn test_build_servers_separates_api_and_internal_routes() {
1841 let (internal, api) = make_split_builder().build_servers();
1844 let api = api.expect("API server is explicitly enabled in make_split_builder");
1845 assert_eq!(internal.name(), HTTP_SERVER);
1846 assert_eq!(api.name(), HTTP_API_SERVER);
1847
1848 let internal_app = internal.build(internal.make_app()).unwrap();
1849 let api_app = api.build(api.make_app()).unwrap();
1850
1851 let internal_client = TestClient::new(internal_app).await;
1852 let api_client = TestClient::new(api_app).await;
1853
1854 assert_eq!(
1856 internal_client.get("/v1/health").send().await.status(),
1857 StatusCode::OK
1858 );
1859 assert_eq!(
1860 api_client.get("/v1/health").send().await.status(),
1861 StatusCode::OK
1862 );
1863
1864 for path in ["/health", "/status", "/metrics", "/config"] {
1866 assert_eq!(
1867 internal_client.get(path).send().await.status(),
1868 StatusCode::OK,
1869 "internal/full server should serve {path}"
1870 );
1871 assert_eq!(
1873 api_client.get(path).send().await.status(),
1874 StatusCode::NOT_FOUND,
1875 "API server should NOT serve {path}"
1876 );
1877 }
1878 }
1879
1880 #[test]
1881 fn test_build_servers_api_inherits_http_options() {
1882 let http_opts = HttpOptions {
1884 timeout: Duration::from_secs(42),
1885 body_limit: ReadableSize::mb(128),
1886 cors_allowed_origins: vec!["https://example.com".to_string()],
1887 enable_api_server: true,
1888 ..HttpOptions::default()
1889 };
1890 let (internal, api) = HttpServerBuilder::new(http_opts.clone()).build_servers();
1891 let api = api.expect("API server is explicitly enabled");
1892
1893 assert_eq!(internal.options.addr, http_opts.addr);
1895 assert_eq!(api.options.addr, "127.0.0.1:4006");
1896 assert_eq!(api.options.timeout, http_opts.timeout);
1898 assert_eq!(api.options.body_limit, http_opts.body_limit);
1899 assert_eq!(
1900 api.options.cors_allowed_origins,
1901 http_opts.cors_allowed_origins
1902 );
1903 }
1904
1905 #[test]
1906 fn test_is_api_listener_path() {
1907 assert!(is_api_listener_path("/v1"));
1909 assert!(is_api_listener_path("/v1/"));
1910 assert!(is_api_listener_path("/v1/sql"));
1911 assert!(!is_api_listener_path("/v10/sql"));
1912 assert!(!is_api_listener_path("/v1-internal"));
1913 assert!(is_api_listener_path("/dashboard"));
1915 assert!(is_api_listener_path("/dashboard/app.js"));
1916 assert!(!is_api_listener_path("/dashboard-admin"));
1917 assert!(!is_api_listener_path("/metrics"));
1919 assert!(!is_api_listener_path("/status/plugin"));
1920 assert!(!is_api_listener_path("/health"));
1921 }
1922
1923 #[tokio::test]
1924 async fn packed_capability_requires_auth_on_full_and_api_listeners() {
1925 let (tx, _rx) = mpsc::channel(1);
1926 let provider =
1927 auth::static_user_provider_from_option("static_user_provider:cmd:user=password")
1928 .unwrap();
1929 let (full, api) = HttpServerBuilder::new(HttpOptions {
1930 enable_api_server: true,
1931 ..Default::default()
1932 })
1933 .with_sql_handler(Arc::new(DummyInstance { _tx: tx }))
1934 .with_user_provider(Arc::new(provider))
1935 .build_servers();
1936 for server in [full, api.unwrap()] {
1937 let client = TestClient::new(server.build(server.make_app()).unwrap()).await;
1938 assert_eq!(
1939 client.get("/v1/capabilities").send().await.status(),
1940 StatusCode::UNAUTHORIZED
1941 );
1942 let response = client
1943 .get("/v1/capabilities")
1944 .header("Authorization", "Basic dXNlcjpwYXNzd29yZA==")
1945 .send()
1946 .await;
1947 assert_eq!(response.status(), StatusCode::OK);
1948 assert_eq!(
1949 response.json::<serde_json::Value>().await,
1950 serde_json::json!({"metric_packed_import": 1, "metric_packed_export": 1})
1951 );
1952 }
1953 }
1954
1955 #[tokio::test]
1956 pub async fn test_extra_router_respects_api_surface() {
1957 let (tx, _rx) = mpsc::channel(100);
1963 let instance = Arc::new(DummyInstance { _tx: tx });
1964 let options = HttpOptions {
1965 enable_api_server: true,
1966 ..HttpOptions::default()
1967 };
1968 let builder = HttpServerBuilder::new(options)
1969 .with_sql_handler(instance)
1970 .with_extra_router(
1971 Router::new()
1972 .route("/status/plugin", routing::get(|| async { "ok" }))
1973 .route("/v1/plugin", routing::get(|| async { "ok" })),
1974 );
1975 let (full, api) = builder.build_servers();
1976 let api = api.expect("API server is explicitly enabled");
1977
1978 let full_client = TestClient::new(full.build(full.make_app()).unwrap()).await;
1979 let api_client = TestClient::new(api.build(api.make_app()).unwrap()).await;
1980
1981 assert_eq!(
1983 full_client.get("/status/plugin").send().await.status(),
1984 StatusCode::OK
1985 );
1986 assert_eq!(
1988 api_client.get("/status/plugin").send().await.status(),
1989 StatusCode::NOT_FOUND
1990 );
1991
1992 assert_eq!(
1994 full_client.get("/v1/plugin").send().await.status(),
1995 StatusCode::OK
1996 );
1997 assert_eq!(
1998 api_client.get("/v1/plugin").send().await.status(),
1999 StatusCode::OK
2000 );
2001
2002 assert_eq!(
2004 api_client.get("/v10/plugin").send().await.status(),
2005 StatusCode::NOT_FOUND
2006 );
2007 }
2008
2009 #[test]
2010 fn test_build_servers_api_disabled_by_default() {
2011 let (_internal, api) = HttpServerBuilder::new(HttpOptions::default()).build_servers();
2014 assert!(api.is_none());
2015 }
2016
2017 #[tokio::test]
2018 pub async fn test_cors() {
2019 let (tx, _rx) = mpsc::channel(100);
2021 let app = make_test_app(tx);
2022 let client = TestClient::new(app).await;
2023
2024 let res = client.get("/health").send().await;
2025
2026 assert_eq!(res.status(), StatusCode::OK);
2027 assert_eq!(
2028 res.headers()
2029 .get(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
2030 .expect("expect cors header origin"),
2031 "*"
2032 );
2033
2034 let res = client.get("/v1/health").send().await;
2035
2036 assert_eq!(res.status(), StatusCode::OK);
2037 assert_eq!(
2038 res.headers()
2039 .get(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
2040 .expect("expect cors header origin"),
2041 "*"
2042 );
2043
2044 let res = client
2045 .options("/health")
2046 .header("Access-Control-Request-Headers", "x-greptime-auth")
2047 .header("Access-Control-Request-Method", "DELETE")
2048 .header("Origin", "https://example.com")
2049 .send()
2050 .await;
2051 assert_eq!(res.status(), StatusCode::OK);
2052 assert_eq!(
2053 res.headers()
2054 .get(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
2055 .expect("expect cors header origin"),
2056 "*"
2057 );
2058 assert_eq!(
2059 res.headers()
2060 .get(http::header::ACCESS_CONTROL_ALLOW_HEADERS)
2061 .expect("expect cors header headers"),
2062 "*"
2063 );
2064 assert_eq!(
2065 res.headers()
2066 .get(http::header::ACCESS_CONTROL_ALLOW_METHODS)
2067 .expect("expect cors header methods"),
2068 "GET,POST,PUT,DELETE,HEAD"
2069 );
2070 }
2071
2072 #[tokio::test]
2073 pub async fn test_cors_custom_origins() {
2074 let (tx, _rx) = mpsc::channel(100);
2076 let origin = "https://example.com";
2077
2078 let options = HttpOptions {
2079 cors_allowed_origins: vec![origin.to_string()],
2080 ..Default::default()
2081 };
2082
2083 let app = make_test_app_custom(tx, options);
2084 let client = TestClient::new(app).await;
2085
2086 let res = client.get("/health").header("Origin", origin).send().await;
2087
2088 assert_eq!(res.status(), StatusCode::OK);
2089 assert_eq!(
2090 res.headers()
2091 .get(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
2092 .expect("expect cors header origin"),
2093 origin
2094 );
2095
2096 let res = client
2097 .get("/health")
2098 .header("Origin", "https://notallowed.com")
2099 .send()
2100 .await;
2101
2102 assert_eq!(res.status(), StatusCode::OK);
2103 assert!(
2104 !res.headers()
2105 .contains_key(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
2106 );
2107 }
2108
2109 #[tokio::test]
2110 pub async fn test_cors_disabled() {
2111 let (tx, _rx) = mpsc::channel(100);
2113
2114 let options = HttpOptions {
2115 enable_cors: false,
2116 ..Default::default()
2117 };
2118
2119 let app = make_test_app_custom(tx, options);
2120 let client = TestClient::new(app).await;
2121
2122 let res = client.get("/health").send().await;
2123
2124 assert_eq!(res.status(), StatusCode::OK);
2125 assert!(
2126 !res.headers()
2127 .contains_key(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
2128 );
2129 }
2130
2131 #[test]
2132 fn test_http_options_default() {
2133 let default = HttpOptions::default();
2134 assert_eq!("127.0.0.1:4000".to_string(), default.addr);
2135 assert_eq!(Duration::from_secs(0), default.timeout)
2136 }
2137
2138 #[tokio::test]
2139 async fn test_http_options_legacy_analyze_stream_config_is_ignored() {
2140 let options: HttpOptions = serde_json::from_value(serde_json::json!({
2141 "addr": "127.0.0.1:4000",
2142 "timeout": "0s",
2143 "body_limit": "64MiB",
2144 "cors_allowed_origins": [],
2145 "enable_cors": true,
2146 "experimental_enable_explain_analyze_stream": false,
2147 "enable_api_server": false,
2148 "api_server_addr": "127.0.0.1:4006"
2149 }))
2150 .unwrap();
2151 let serialized = serde_json::to_string(&options).unwrap();
2152 assert!(!serialized.contains("experimental_enable_explain_analyze_stream"));
2153
2154 let (tx, _rx) = mpsc::channel(100);
2155 let app = make_test_app_custom(tx, options);
2156 let client = TestClient::new(app).await;
2157 let response = client
2158 .post("/v1/sql/analyze/stream")
2159 .form(&handler::SqlQuery {
2160 sql: Some("EXPLAIN ANALYZE VERBOSE SELECT 1".to_string()),
2161 ..Default::default()
2162 })
2163 .send()
2164 .await;
2165 assert_ne!(response.status(), StatusCode::NOT_FOUND);
2166 }
2167
2168 #[tokio::test]
2169 async fn test_http_server_request_timeout() {
2170 common_telemetry::init_default_ut_logging();
2171
2172 let (tx, _rx) = mpsc::channel(100);
2173 let options = HttpOptions {
2174 timeout: Duration::from_millis(10),
2175 ..Default::default()
2176 };
2177 let app = make_test_app_custom(tx, options);
2178 let client = TestClient::new(app).await;
2179 let res = client.get("/test/timeout").send().await;
2180 assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
2181
2182 let res = client.post("/v1/prometheus/write").send().await;
2183 assert_eq!(res.status(), StatusCode::GATEWAY_TIMEOUT);
2184
2185 let now = Instant::now();
2186 let res = client
2187 .get("/test/timeout")
2188 .header(GREPTIME_DB_HEADER_TIMEOUT, "20ms")
2189 .send()
2190 .await;
2191 assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
2192 let elapsed = now.elapsed();
2193 assert!(elapsed > Duration::from_millis(15));
2194
2195 tokio::time::timeout(
2196 Duration::from_millis(15),
2197 client
2198 .get("/test/timeout")
2199 .header(GREPTIME_DB_HEADER_TIMEOUT, "0s")
2200 .send(),
2201 )
2202 .await
2203 .unwrap_err();
2204
2205 tokio::time::timeout(
2206 Duration::from_millis(15),
2207 client
2208 .get("/test/timeout")
2209 .header(
2210 GREPTIME_DB_HEADER_TIMEOUT,
2211 humantime::format_duration(Duration::default()).to_string(),
2212 )
2213 .send(),
2214 )
2215 .await
2216 .unwrap_err();
2217 }
2218
2219 #[tokio::test]
2220 async fn test_schema_for_empty_response() {
2221 let column_schemas = vec![
2222 ColumnSchema::new("numbers", ConcreteDataType::uint32_datatype(), false),
2223 ColumnSchema::new("strings", ConcreteDataType::string_datatype(), true),
2224 ];
2225 let schema = Arc::new(Schema::new(column_schemas));
2226
2227 let recordbatches = RecordBatches::try_new(schema.clone(), vec![]).unwrap();
2228 let outputs = vec![Ok(Output::new_with_record_batches(recordbatches))];
2229
2230 let json_resp = GreptimedbV1Response::from_output(outputs).await;
2231 if let HttpResponse::GreptimedbV1(json_resp) = json_resp {
2232 let json_output = &json_resp.output[0];
2233 if let GreptimeQueryOutput::Records(r) = json_output {
2234 assert_eq!(r.num_rows(), 0);
2235 assert_eq!(r.num_cols(), 2);
2236 assert_eq!(r.schema.column_schemas[0].name, "numbers");
2237 assert_eq!(r.schema.column_schemas[0].data_type, "UInt32");
2238 } else {
2239 panic!("invalid output type");
2240 }
2241 } else {
2242 panic!("invalid format")
2243 }
2244 }
2245
2246 #[tokio::test]
2247 async fn test_recordbatches_conversion() {
2248 let column_schemas = vec![
2249 ColumnSchema::new("numbers", ConcreteDataType::uint32_datatype(), false),
2250 ColumnSchema::new("strings", ConcreteDataType::string_datatype(), true),
2251 ];
2252 let schema = Arc::new(Schema::new(column_schemas));
2253 let columns: Vec<VectorRef> = vec![
2254 Arc::new(UInt32Vector::from_slice(vec![1, 2, 3, 4])),
2255 Arc::new(StringVector::from(vec![
2256 None,
2257 Some("hello"),
2258 Some("greptime"),
2259 None,
2260 ])),
2261 ];
2262 let recordbatch = RecordBatch::new(schema.clone(), columns).unwrap();
2263
2264 for format in [
2265 ResponseFormat::GreptimedbV1,
2266 ResponseFormat::InfluxdbV1,
2267 ResponseFormat::Csv(true, true),
2268 ResponseFormat::Table,
2269 ResponseFormat::Arrow,
2270 ResponseFormat::Json,
2271 ResponseFormat::Null,
2272 ] {
2273 let recordbatches =
2274 RecordBatches::try_new(schema.clone(), vec![recordbatch.clone()]).unwrap();
2275 let outputs = vec![Ok(Output::new_with_record_batches(recordbatches))];
2276 let json_resp = match format {
2277 ResponseFormat::Arrow => ArrowResponse::from_output(outputs, None).await,
2278 ResponseFormat::Csv(with_names, with_types) => {
2279 CsvResponse::from_output(outputs, with_names, with_types).await
2280 }
2281 ResponseFormat::Table => TableResponse::from_output(outputs).await,
2282 ResponseFormat::GreptimedbV1 => GreptimedbV1Response::from_output(outputs).await,
2283 ResponseFormat::InfluxdbV1 => InfluxdbV1Response::from_output(outputs, None).await,
2284 ResponseFormat::Json => JsonResponse::from_output(outputs).await,
2285 ResponseFormat::Null => NullResponse::from_output(outputs).await,
2286 };
2287
2288 match json_resp {
2289 HttpResponse::GreptimedbV1(resp) => {
2290 let json_output = &resp.output[0];
2291 if let GreptimeQueryOutput::Records(r) = json_output {
2292 assert_eq!(r.num_rows(), 4);
2293 assert_eq!(r.num_cols(), 2);
2294 assert_eq!(r.schema.column_schemas[0].name, "numbers");
2295 assert_eq!(r.schema.column_schemas[0].data_type, "UInt32");
2296 assert_eq!(r.rows[0][0], serde_json::Value::from(1));
2297 assert_eq!(r.rows[0][1], serde_json::Value::Null);
2298 } else {
2299 panic!("invalid output type");
2300 }
2301 }
2302 HttpResponse::InfluxdbV1(resp) => {
2303 let json_output = &resp.results()[0];
2304 assert_eq!(json_output.num_rows(), 4);
2305 assert_eq!(json_output.num_cols(), 2);
2306 assert_eq!(json_output.series[0].columns.clone()[0], "numbers");
2307 assert_eq!(
2308 json_output.series[0].values[0][0],
2309 serde_json::Value::from(1)
2310 );
2311 assert_eq!(json_output.series[0].values[0][1], serde_json::Value::Null);
2312 }
2313 HttpResponse::Csv(resp) => {
2314 let output = &resp.output()[0];
2315 if let GreptimeQueryOutput::Records(r) = output {
2316 assert_eq!(r.num_rows(), 4);
2317 assert_eq!(r.num_cols(), 2);
2318 assert_eq!(r.schema.column_schemas[0].name, "numbers");
2319 assert_eq!(r.schema.column_schemas[0].data_type, "UInt32");
2320 assert_eq!(r.rows[0][0], serde_json::Value::from(1));
2321 assert_eq!(r.rows[0][1], serde_json::Value::Null);
2322 } else {
2323 panic!("invalid output type");
2324 }
2325 }
2326
2327 HttpResponse::Table(resp) => {
2328 let output = &resp.output()[0];
2329 if let GreptimeQueryOutput::Records(r) = output {
2330 assert_eq!(r.num_rows(), 4);
2331 assert_eq!(r.num_cols(), 2);
2332 assert_eq!(r.schema.column_schemas[0].name, "numbers");
2333 assert_eq!(r.schema.column_schemas[0].data_type, "UInt32");
2334 assert_eq!(r.rows[0][0], serde_json::Value::from(1));
2335 assert_eq!(r.rows[0][1], serde_json::Value::Null);
2336 } else {
2337 panic!("invalid output type");
2338 }
2339 }
2340
2341 HttpResponse::Arrow(resp) => {
2342 let output = resp.data;
2343 let mut reader = StreamReader::try_new(Cursor::new(output), None)
2344 .expect("Arrow reader error");
2345 let schema = reader.schema();
2346 assert_eq!(schema.fields[0].name(), "numbers");
2347 assert_eq!(schema.fields[0].data_type(), &DataType::UInt32);
2348 assert_eq!(schema.fields[1].name(), "strings");
2349 assert_eq!(schema.fields[1].data_type(), &DataType::Utf8);
2350
2351 let rb = reader.next().unwrap().expect("read record batch failed");
2352 assert_eq!(rb.num_columns(), 2);
2353 assert_eq!(rb.num_rows(), 4);
2354 }
2355
2356 HttpResponse::Json(resp) => {
2357 let output = &resp.output()[0];
2358 if let GreptimeQueryOutput::Records(r) = output {
2359 assert_eq!(r.num_rows(), 4);
2360 assert_eq!(r.num_cols(), 2);
2361 assert_eq!(r.schema.column_schemas[0].name, "numbers");
2362 assert_eq!(r.schema.column_schemas[0].data_type, "UInt32");
2363 assert_eq!(r.rows[0][0], serde_json::Value::from(1));
2364 assert_eq!(r.rows[0][1], serde_json::Value::Null);
2365 } else {
2366 panic!("invalid output type");
2367 }
2368 }
2369
2370 HttpResponse::Null(resp) => {
2371 assert_eq!(resp.rows(), 4);
2372 }
2373
2374 HttpResponse::Error(err) => unreachable!("{err:?}"),
2375 }
2376 }
2377 }
2378
2379 #[test]
2380 fn test_response_format_misc() {
2381 assert_eq!(ResponseFormat::default(), ResponseFormat::GreptimedbV1);
2382 assert_eq!(ResponseFormat::parse("arrow"), Some(ResponseFormat::Arrow));
2383 assert_eq!(
2384 ResponseFormat::parse("csv"),
2385 Some(ResponseFormat::Csv(false, false))
2386 );
2387 assert_eq!(
2388 ResponseFormat::parse("csvwithnames"),
2389 Some(ResponseFormat::Csv(true, false))
2390 );
2391 assert_eq!(
2392 ResponseFormat::parse("csvwithnamesandtypes"),
2393 Some(ResponseFormat::Csv(true, true))
2394 );
2395 assert_eq!(ResponseFormat::parse("table"), Some(ResponseFormat::Table));
2396 assert_eq!(
2397 ResponseFormat::parse("greptimedb_v1"),
2398 Some(ResponseFormat::GreptimedbV1)
2399 );
2400 assert_eq!(
2401 ResponseFormat::parse("influxdb_v1"),
2402 Some(ResponseFormat::InfluxdbV1)
2403 );
2404 assert_eq!(ResponseFormat::parse("json"), Some(ResponseFormat::Json));
2405 assert_eq!(ResponseFormat::parse("null"), Some(ResponseFormat::Null));
2406
2407 assert_eq!(ResponseFormat::parse("invalid"), None);
2409 assert_eq!(ResponseFormat::parse(""), None);
2410 assert_eq!(ResponseFormat::parse("CSV"), None); assert_eq!(ResponseFormat::Arrow.as_str(), "arrow");
2414 assert_eq!(ResponseFormat::Csv(false, false).as_str(), "csv");
2415 assert_eq!(ResponseFormat::Csv(true, true).as_str(), "csv");
2416 assert_eq!(ResponseFormat::Table.as_str(), "table");
2417 assert_eq!(ResponseFormat::GreptimedbV1.as_str(), "greptimedb_v1");
2418 assert_eq!(ResponseFormat::InfluxdbV1.as_str(), "influxdb_v1");
2419 assert_eq!(ResponseFormat::Json.as_str(), "json");
2420 assert_eq!(ResponseFormat::Null.as_str(), "null");
2421 assert_eq!(ResponseFormat::default().as_str(), "greptimedb_v1");
2422 }
2423
2424 #[test]
2425 fn test_decode_label_name_strict() {
2426 let strict = PromValidationMode::Strict;
2427
2428 assert!(strict.decode_label_name(b"__name__").is_ok());
2430 assert!(strict.decode_label_name(b"job").is_ok());
2431 assert!(strict.decode_label_name(b"instance").is_ok());
2432 assert!(strict.decode_label_name(b"_private").is_ok());
2433 assert!(strict.decode_label_name(b"label_with_underscores").is_ok());
2434 assert!(strict.decode_label_name(b"abc123").is_ok());
2435 assert!(strict.decode_label_name(b"A").is_ok());
2436 assert!(strict.decode_label_name(b"_").is_ok());
2437
2438 assert!(strict.decode_label_name(b"0abc").is_err());
2440 assert!(strict.decode_label_name(b"123").is_err());
2441
2442 assert!(strict.decode_label_name(b"label-name").is_err());
2444 assert!(strict.decode_label_name(b"label.name").is_err());
2445 assert!(strict.decode_label_name(b"label name").is_err());
2446 assert!(strict.decode_label_name(b"label/name").is_err());
2447
2448 assert!(strict.decode_label_name(b"").is_err());
2450
2451 assert!(strict.decode_label_name("ラベル".as_bytes()).is_err());
2453
2454 assert!(strict.decode_label_name(&[0xff, 0xfe]).is_err());
2456 }
2457
2458 #[test]
2459 fn test_decode_label_name_lossy() {
2460 let lossy = PromValidationMode::Lossy;
2461
2462 assert!(lossy.decode_label_name(b"__name__").is_ok());
2464 assert!(lossy.decode_label_name(b"label-name").is_err());
2465 assert!(lossy.decode_label_name(b"0abc").is_err());
2466
2467 assert!(lossy.decode_label_name(&[0xff, 0xfe]).is_err());
2469 }
2470
2471 #[test]
2472 fn test_decode_label_name_unchecked() {
2473 let unchecked = PromValidationMode::Unchecked;
2474
2475 assert!(unchecked.decode_label_name(b"__name__").is_ok());
2477 assert!(unchecked.decode_label_name(b"label-name").is_err());
2478 assert!(unchecked.decode_label_name(b"0abc").is_err());
2479 }
2480
2481 #[test]
2482 fn test_is_valid_prom_label_name_bytes() {
2483 assert!(validate_label_name(b"__name__"));
2484 assert!(validate_label_name(b"job"));
2485 assert!(validate_label_name(b"_"));
2486 assert!(validate_label_name(b"A"));
2487 assert!(validate_label_name(b"abc123"));
2488 assert!(validate_label_name(b"_leading_underscore"));
2489
2490 assert!(!validate_label_name(b""));
2491 assert!(!validate_label_name(b"0starts_with_digit"));
2492 assert!(!validate_label_name(b"has-dash"));
2493 assert!(!validate_label_name(b"has.dot"));
2494 assert!(!validate_label_name(b"has space"));
2495 assert!(!validate_label_name(&[0xff, 0xfe]));
2496 }
2497}
2498
2499#[cfg(test)]
2500mod batching_tests {
2501 use std::sync::{Arc, Mutex};
2502
2503 use axum::http::StatusCode;
2504 use common_query::Output;
2505 use session::context::QueryContextRef;
2506
2507 use crate::batcher::BatchingProtocol;
2508 use crate::error::Result as ServerResult;
2509 use crate::http::test_helpers::TestClient;
2510 use crate::http::{HttpOptions, HttpServerBuilder};
2511 use crate::influxdb::InfluxdbRequest;
2512 use crate::opentsdb::codec::DataPoint;
2513 use crate::query_handler::{InfluxdbLineProtocolHandler, OpentsdbProtocolHandler};
2514
2515 #[tokio::test]
2516 async fn test_batching_selectors_are_independent() {
2517 use axum::routing::post;
2518 use axum::{Extension, Json, Router, middleware};
2519 use session::context::{QueryContext, QueryContextBuilder};
2520
2521 use crate::http::{LogicalBatchingProtocols, set_http_write_batching};
2522 for table in [false, true] {
2523 for logical in [false, true] {
2524 let app = Router::new()
2525 .route(
2526 "/",
2527 post(|Extension(ctx): Extension<QueryContext>| async move {
2528 Json([ctx.batching_enabled(), ctx.logical_batching_enabled()])
2529 }),
2530 )
2531 .route_layer(middleware::from_fn_with_state(
2532 BatchingProtocol::Otlp,
2533 set_http_write_batching,
2534 ))
2535 .layer(Extension(QueryContextBuilder::default().build()))
2536 .layer(Extension(Arc::new(if table {
2537 vec![BatchingProtocol::Otlp]
2538 } else {
2539 vec![]
2540 })))
2541 .layer(Extension(LogicalBatchingProtocols(if logical {
2542 vec![BatchingProtocol::Otlp]
2543 } else {
2544 vec![]
2545 })));
2546 let client = TestClient::new(app).await;
2547 let actual: [bool; 2] = client.post("/").send().await.json().await;
2548 assert_eq!(actual, [table, logical]);
2549 }
2550 }
2551 }
2552
2553 #[derive(Default)]
2554 struct RecordingWriteHandler {
2555 selections: Mutex<Vec<bool>>,
2556 }
2557
2558 #[async_trait::async_trait]
2559 impl OpentsdbProtocolHandler for RecordingWriteHandler {
2560 async fn preflight(&self, _: &[DataPoint], _: QueryContextRef) -> ServerResult<()> {
2561 Ok(())
2562 }
2563
2564 async fn exec(&self, points: Vec<DataPoint>, ctx: QueryContextRef) -> ServerResult<usize> {
2565 self.selections.lock().unwrap().push(ctx.batching_enabled());
2566 Ok(points.len())
2567 }
2568 }
2569
2570 #[async_trait::async_trait]
2571 impl InfluxdbLineProtocolHandler for RecordingWriteHandler {
2572 async fn exec(&self, _: InfluxdbRequest, ctx: QueryContextRef) -> ServerResult<Output> {
2573 self.selections.lock().unwrap().push(ctx.batching_enabled());
2574 Ok(Output::new_with_affected_rows(1))
2575 }
2576 }
2577
2578 #[tokio::test]
2579 async fn test_real_influx_and_opentsdb_routes_keep_selection() {
2580 for protocols in [
2581 vec![],
2582 vec![BatchingProtocol::Influxdb],
2583 vec![BatchingProtocol::Opentsdb],
2584 vec![BatchingProtocol::Influxdb, BatchingProtocol::Opentsdb],
2585 ] {
2586 let handler = Arc::new(RecordingWriteHandler::default());
2587 let influx_enabled = protocols.contains(&BatchingProtocol::Influxdb);
2588 let opentsdb_enabled = protocols.contains(&BatchingProtocol::Opentsdb);
2589 let server = HttpServerBuilder::new(HttpOptions::default())
2590 .with_batching_protocols(protocols)
2591 .with_influxdb_handler(handler.clone())
2592 .with_opentsdb_handler(handler.clone())
2593 .build();
2594 let client = TestClient::new(server.build(server.make_app()).unwrap()).await;
2595 for path in [
2596 "/v1/influxdb/write",
2597 "/v1/influxdb/api/v2/write?bucket=public",
2598 ] {
2599 assert_eq!(
2600 client
2601 .post(path)
2602 .body("cpu value=1 42")
2603 .send()
2604 .await
2605 .status(),
2606 StatusCode::NO_CONTENT
2607 );
2608 }
2609 let point =
2610 serde_json::json!({"metric":"cpu", "timestamp":42, "value":1, "tags":{"host":"a"}});
2611 for query in ["", "?summary", "?details"] {
2612 let response = client
2613 .post(&format!("/v1/opentsdb/api/put{query}"))
2614 .json(&point)
2615 .send()
2616 .await;
2617 assert_eq!(
2618 response.status(),
2619 if query.is_empty() {
2620 StatusCode::NO_CONTENT
2621 } else {
2622 StatusCode::OK
2623 }
2624 );
2625 }
2626 assert_eq!(
2627 *handler.selections.lock().unwrap(),
2628 vec![
2629 influx_enabled,
2630 influx_enabled,
2631 opentsdb_enabled,
2632 opentsdb_enabled,
2633 opentsdb_enabled
2634 ]
2635 );
2636 }
2637 }
2638}