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