Skip to main content

servers/
http.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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};
25use axum::http::StatusCode as HttpStatusCode;
26use axum::response::{IntoResponse, Response};
27use axum::routing::Route;
28use axum::serve::ListenerExt;
29use axum::{Router, middleware, routing};
30use common_base::readable_size::ReadableSize;
31use common_recordbatch::RecordBatch;
32use common_telemetry::{error, info};
33use common_time::Timestamp;
34use common_time::timestamp::TimeUnit;
35use datatypes::data_type::DataType;
36use datatypes::schema::SchemaRef;
37use event::{LogState, LogValidatorRef};
38use futures::FutureExt;
39use http::{HeaderValue, Method};
40use serde::{Deserialize, Serialize};
41use serde_json::Value;
42use snafu::{ResultExt, ensure};
43use tokio::sync::Mutex;
44use tokio::sync::oneshot::{self, Sender};
45use tonic::codegen::Service;
46use tower::{Layer, ServiceBuilder};
47use tower_http::compression::CompressionLayer;
48use tower_http::cors::{AllowOrigin, Any, CorsLayer};
49use tower_http::decompression::RequestDecompressionLayer;
50use tower_http::trace::TraceLayer;
51
52use self::authorize::AuthState;
53use self::result::table_result::TableResponse;
54use crate::elasticsearch;
55use crate::error::{
56    AddressBindSnafu, AlreadyStartedSnafu, Error, InternalIoSnafu, InvalidHeaderValueSnafu, Result,
57};
58use crate::http::influxdb::{influxdb_health, influxdb_ping, influxdb_write_v1, influxdb_write_v2};
59use crate::http::otlp::OtlpState;
60use crate::http::prom_store::PromStoreState;
61use crate::http::prometheus::{
62    build_info_query, format_query, instant_query, label_values_query, labels_query, parse_query,
63    range_query, series_query,
64};
65use crate::http::result::arrow_result::ArrowResponse;
66use crate::http::result::csv_result::CsvResponse;
67use crate::http::result::error_result::ErrorResponse;
68use crate::http::result::greptime_result_v1::GreptimedbV1Response;
69use crate::http::result::influxdb_result_v1::InfluxdbV1Response;
70use crate::http::result::json_result::JsonResponse;
71use crate::http::result::null_result::NullResponse;
72use crate::interceptor::LogIngestInterceptorRef;
73use crate::metrics::http_metrics_layer;
74use crate::metrics_handler::MetricsHandler;
75use crate::pending_rows_batcher::PendingRowsBatcher;
76use crate::prometheus_handler::PrometheusHandlerRef;
77use crate::query_handler::sql::ServerSqlQueryHandlerRef;
78use crate::query_handler::{
79    DashboardHandlerRef, InfluxdbLineProtocolHandlerRef, JaegerQueryHandlerRef, LogQueryHandlerRef,
80    OpenTelemetryProtocolHandlerRef, OpentsdbProtocolHandlerRef, PipelineHandlerRef,
81    PromStoreProtocolHandlerRef,
82};
83use crate::request_memory_limiter::ServerMemoryLimiter;
84use crate::server::Server;
85
86pub mod authorize;
87#[cfg(feature = "dashboard")]
88mod dashboard;
89pub mod dyn_log;
90pub mod dyn_trace;
91pub mod event;
92pub mod extractor;
93pub mod handler;
94pub mod header;
95pub mod influxdb;
96pub mod jaeger;
97pub mod logs;
98pub mod loki;
99pub mod mem_prof;
100mod memory_limit;
101pub mod opentsdb;
102pub mod otlp;
103pub mod pprof;
104pub mod prom_store;
105pub mod prometheus;
106pub mod result;
107pub mod splunk;
108mod timeout;
109pub mod utils;
110
111use result::HttpOutputWriter;
112pub(crate) use timeout::DynamicTimeoutLayer;
113
114mod client_ip;
115use crate::prom_remote_write::validation::PromValidationMode;
116mod hints;
117mod read_preference;
118#[cfg(any(test, feature = "testing"))]
119pub mod test_helpers;
120
121pub const HTTP_API_VERSION: &str = "v1";
122pub const HTTP_API_PREFIX: &str = "/v1/";
123pub const HTTP_API_PREFIX_WITHOUT_TRAILING_SLASH: &str = "/v1";
124/// Default http body limit (64M).
125const DEFAULT_BODY_LIMIT: ReadableSize = ReadableSize::mb(64);
126
127/// Authorization header
128pub const AUTHORIZATION_HEADER: &str = "x-greptime-auth";
129
130// TODO(fys): This is a temporary workaround, it will be improved later
131pub static PUBLIC_API_PREFIX: [&str; 4] = [
132    "/v1/influxdb/ping",
133    "/v1/influxdb/health",
134    "/v1/health",
135    "/v1/splunk/services/collector/health",
136];
137
138#[derive(Default)]
139pub struct HttpServer {
140    router: StdMutex<Router>,
141    shutdown_tx: Mutex<Option<Sender<()>>>,
142    user_provider: Option<UserProviderRef>,
143    memory_limiter: ServerMemoryLimiter,
144
145    // server configs
146    options: HttpOptions,
147    bind_addr: Option<SocketAddr>,
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
151#[serde(default)]
152pub struct HttpOptions {
153    pub addr: String,
154
155    #[serde(with = "humantime_serde")]
156    pub timeout: Duration,
157
158    #[serde(skip)]
159    pub disable_dashboard: bool,
160
161    pub body_limit: ReadableSize,
162
163    /// Validation mode while decoding Prometheus remote write requests.
164    pub prom_validation_mode: PromValidationMode,
165
166    /// Enables experimental Prometheus remote write v2 native histogram ingestion.
167    pub experimental_enable_prometheus_native_histogram: bool,
168
169    pub cors_allowed_origins: Vec<String>,
170
171    pub enable_cors: bool,
172
173    pub experimental_enable_explain_analyze_stream: bool,
174}
175
176impl Default for HttpOptions {
177    fn default() -> Self {
178        Self {
179            addr: "127.0.0.1:4000".to_string(),
180            timeout: Duration::from_secs(0),
181            disable_dashboard: false,
182            body_limit: DEFAULT_BODY_LIMIT,
183            cors_allowed_origins: Vec::new(),
184            enable_cors: true,
185            prom_validation_mode: PromValidationMode::Strict,
186            experimental_enable_prometheus_native_histogram: false,
187            experimental_enable_explain_analyze_stream: true,
188        }
189    }
190}
191
192#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
193pub struct ColumnSchema {
194    name: String,
195    data_type: String,
196}
197
198impl ColumnSchema {
199    pub fn new(name: String, data_type: String) -> ColumnSchema {
200        ColumnSchema { name, data_type }
201    }
202}
203
204#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
205pub struct OutputSchema {
206    column_schemas: Vec<ColumnSchema>,
207}
208
209impl OutputSchema {
210    pub fn new(columns: Vec<ColumnSchema>) -> OutputSchema {
211        OutputSchema {
212            column_schemas: columns,
213        }
214    }
215}
216
217impl From<SchemaRef> for OutputSchema {
218    fn from(schema: SchemaRef) -> OutputSchema {
219        OutputSchema {
220            column_schemas: schema
221                .column_schemas()
222                .iter()
223                .map(|cs| ColumnSchema {
224                    name: cs.name.clone(),
225                    data_type: cs.data_type.name(),
226                })
227                .collect(),
228        }
229    }
230}
231
232#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
233pub struct HttpRecordsOutput {
234    schema: OutputSchema,
235    rows: Vec<Vec<Value>>,
236    // total_rows is equal to rows.len() in most cases,
237    // the Dashboard query result may be truncated, so we need to return the total_rows.
238    #[serde(default)]
239    total_rows: usize,
240
241    // plan level execution metrics
242    #[serde(skip_serializing_if = "HashMap::is_empty")]
243    #[serde(default)]
244    metrics: HashMap<String, Value>,
245}
246
247impl HttpRecordsOutput {
248    pub fn num_rows(&self) -> usize {
249        self.rows.len()
250    }
251
252    pub fn num_cols(&self) -> usize {
253        self.schema.column_schemas.len()
254    }
255
256    pub fn schema(&self) -> &OutputSchema {
257        &self.schema
258    }
259
260    pub fn rows(&self) -> &Vec<Vec<Value>> {
261        &self.rows
262    }
263}
264
265impl HttpRecordsOutput {
266    pub fn try_new(
267        schema: SchemaRef,
268        recordbatches: Vec<RecordBatch>,
269    ) -> std::result::Result<HttpRecordsOutput, Error> {
270        if recordbatches.is_empty() {
271            Ok(HttpRecordsOutput {
272                schema: OutputSchema::from(schema),
273                rows: vec![],
274                total_rows: 0,
275                metrics: Default::default(),
276            })
277        } else {
278            let num_rows = recordbatches.iter().map(|r| r.num_rows()).sum::<usize>();
279            let mut rows = Vec::with_capacity(num_rows);
280
281            for recordbatch in recordbatches {
282                let mut writer = HttpOutputWriter::new(schema.num_columns(), None);
283                writer.write(recordbatch, &mut rows)?;
284            }
285
286            Ok(HttpRecordsOutput {
287                schema: OutputSchema::from(schema),
288                total_rows: rows.len(),
289                rows,
290                metrics: Default::default(),
291            })
292        }
293    }
294}
295
296#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
297#[serde(rename_all = "lowercase")]
298pub enum GreptimeQueryOutput {
299    AffectedRows(usize),
300    Records(HttpRecordsOutput),
301}
302
303/// It allows the results of SQL queries to be presented in different formats.
304#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
305pub enum ResponseFormat {
306    Arrow,
307    // (with_names, with_types)
308    Csv(bool, bool),
309    Table,
310    #[default]
311    GreptimedbV1,
312    InfluxdbV1,
313    Json,
314    Null,
315}
316
317impl ResponseFormat {
318    pub fn parse(s: &str) -> Option<Self> {
319        match s {
320            "arrow" => Some(ResponseFormat::Arrow),
321            "csv" => Some(ResponseFormat::Csv(false, false)),
322            "csvwithnames" => Some(ResponseFormat::Csv(true, false)),
323            "csvwithnamesandtypes" => Some(ResponseFormat::Csv(true, true)),
324            "table" => Some(ResponseFormat::Table),
325            "greptimedb_v1" => Some(ResponseFormat::GreptimedbV1),
326            "influxdb_v1" => Some(ResponseFormat::InfluxdbV1),
327            "json" => Some(ResponseFormat::Json),
328            "null" => Some(ResponseFormat::Null),
329            _ => None,
330        }
331    }
332
333    pub fn as_str(&self) -> &'static str {
334        match self {
335            ResponseFormat::Arrow => "arrow",
336            ResponseFormat::Csv(_, _) => "csv",
337            ResponseFormat::Table => "table",
338            ResponseFormat::GreptimedbV1 => "greptimedb_v1",
339            ResponseFormat::InfluxdbV1 => "influxdb_v1",
340            ResponseFormat::Json => "json",
341            ResponseFormat::Null => "null",
342        }
343    }
344}
345
346#[derive(Debug, Clone, Copy, PartialEq, Eq)]
347pub enum Epoch {
348    Nanosecond,
349    Microsecond,
350    Millisecond,
351    Second,
352}
353
354impl Epoch {
355    pub fn parse(s: &str) -> Option<Epoch> {
356        // Both u and µ indicate microseconds.
357        // epoch = [ns,u,µ,ms,s],
358        // For details, see the Influxdb documents.
359        // https://docs.influxdata.com/influxdb/v1/tools/api/#query-string-parameters-1
360        match s {
361            "ns" => Some(Epoch::Nanosecond),
362            "u" | "µ" => Some(Epoch::Microsecond),
363            "ms" => Some(Epoch::Millisecond),
364            "s" => Some(Epoch::Second),
365            _ => None, // just returns None for other cases
366        }
367    }
368
369    pub fn convert_timestamp(&self, ts: Timestamp) -> Option<Timestamp> {
370        match self {
371            Epoch::Nanosecond => ts.convert_to(TimeUnit::Nanosecond),
372            Epoch::Microsecond => ts.convert_to(TimeUnit::Microsecond),
373            Epoch::Millisecond => ts.convert_to(TimeUnit::Millisecond),
374            Epoch::Second => ts.convert_to(TimeUnit::Second),
375        }
376    }
377}
378
379impl Display for Epoch {
380    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
381        match self {
382            Epoch::Nanosecond => write!(f, "Epoch::Nanosecond"),
383            Epoch::Microsecond => write!(f, "Epoch::Microsecond"),
384            Epoch::Millisecond => write!(f, "Epoch::Millisecond"),
385            Epoch::Second => write!(f, "Epoch::Second"),
386        }
387    }
388}
389
390#[derive(Serialize, Deserialize, Debug)]
391pub enum HttpResponse {
392    Arrow(ArrowResponse),
393    Csv(CsvResponse),
394    Table(TableResponse),
395    Error(ErrorResponse),
396    GreptimedbV1(GreptimedbV1Response),
397    InfluxdbV1(InfluxdbV1Response),
398    Json(JsonResponse),
399    Null(NullResponse),
400}
401
402impl HttpResponse {
403    pub fn with_execution_time(self, execution_time: u64) -> Self {
404        match self {
405            HttpResponse::Arrow(resp) => resp.with_execution_time(execution_time).into(),
406            HttpResponse::Csv(resp) => resp.with_execution_time(execution_time).into(),
407            HttpResponse::Table(resp) => resp.with_execution_time(execution_time).into(),
408            HttpResponse::GreptimedbV1(resp) => resp.with_execution_time(execution_time).into(),
409            HttpResponse::InfluxdbV1(resp) => resp.with_execution_time(execution_time).into(),
410            HttpResponse::Json(resp) => resp.with_execution_time(execution_time).into(),
411            HttpResponse::Null(resp) => resp.with_execution_time(execution_time).into(),
412            HttpResponse::Error(resp) => resp.with_execution_time(execution_time).into(),
413        }
414    }
415
416    pub fn with_limit(self, limit: usize) -> Self {
417        match self {
418            HttpResponse::Csv(resp) => resp.with_limit(limit).into(),
419            HttpResponse::Table(resp) => resp.with_limit(limit).into(),
420            HttpResponse::GreptimedbV1(resp) => resp.with_limit(limit).into(),
421            HttpResponse::Json(resp) => resp.with_limit(limit).into(),
422            _ => self,
423        }
424    }
425}
426
427pub fn process_with_limit(
428    mut outputs: Vec<GreptimeQueryOutput>,
429    limit: usize,
430) -> Vec<GreptimeQueryOutput> {
431    outputs
432        .drain(..)
433        .map(|data| match data {
434            GreptimeQueryOutput::Records(mut records) => {
435                if records.rows.len() > limit {
436                    records.rows.truncate(limit);
437                    records.total_rows = limit;
438                }
439                GreptimeQueryOutput::Records(records)
440            }
441            _ => data,
442        })
443        .collect()
444}
445
446impl IntoResponse for HttpResponse {
447    fn into_response(self) -> Response {
448        match self {
449            HttpResponse::Arrow(resp) => resp.into_response(),
450            HttpResponse::Csv(resp) => resp.into_response(),
451            HttpResponse::Table(resp) => resp.into_response(),
452            HttpResponse::GreptimedbV1(resp) => resp.into_response(),
453            HttpResponse::InfluxdbV1(resp) => resp.into_response(),
454            HttpResponse::Json(resp) => resp.into_response(),
455            HttpResponse::Null(resp) => resp.into_response(),
456            HttpResponse::Error(resp) => resp.into_response(),
457        }
458    }
459}
460
461impl From<ArrowResponse> for HttpResponse {
462    fn from(value: ArrowResponse) -> Self {
463        HttpResponse::Arrow(value)
464    }
465}
466
467impl From<CsvResponse> for HttpResponse {
468    fn from(value: CsvResponse) -> Self {
469        HttpResponse::Csv(value)
470    }
471}
472
473impl From<TableResponse> for HttpResponse {
474    fn from(value: TableResponse) -> Self {
475        HttpResponse::Table(value)
476    }
477}
478
479impl From<ErrorResponse> for HttpResponse {
480    fn from(value: ErrorResponse) -> Self {
481        HttpResponse::Error(value)
482    }
483}
484
485impl From<GreptimedbV1Response> for HttpResponse {
486    fn from(value: GreptimedbV1Response) -> Self {
487        HttpResponse::GreptimedbV1(value)
488    }
489}
490
491impl From<InfluxdbV1Response> for HttpResponse {
492    fn from(value: InfluxdbV1Response) -> Self {
493        HttpResponse::InfluxdbV1(value)
494    }
495}
496
497impl From<JsonResponse> for HttpResponse {
498    fn from(value: JsonResponse) -> Self {
499        HttpResponse::Json(value)
500    }
501}
502
503impl From<NullResponse> for HttpResponse {
504    fn from(value: NullResponse) -> Self {
505        HttpResponse::Null(value)
506    }
507}
508
509#[derive(Clone)]
510pub struct ApiState {
511    pub sql_handler: ServerSqlQueryHandlerRef,
512    pub experimental_enable_explain_analyze_stream: bool,
513}
514
515#[derive(Clone)]
516pub struct GreptimeOptionsConfigState {
517    pub greptime_config_options: String,
518}
519
520#[derive(Clone)]
521pub struct DashboardState {
522    pub handler: DashboardHandlerRef,
523}
524
525pub struct HttpServerBuilder {
526    options: HttpOptions,
527    user_provider: Option<UserProviderRef>,
528    router: Router,
529    memory_limiter: ServerMemoryLimiter,
530}
531
532impl HttpServerBuilder {
533    pub fn new(options: HttpOptions) -> Self {
534        Self {
535            options,
536            user_provider: None,
537            router: Router::new(),
538            memory_limiter: ServerMemoryLimiter::default(),
539        }
540    }
541
542    /// Set a global memory limiter for all server protocols.
543    pub fn with_memory_limiter(mut self, limiter: ServerMemoryLimiter) -> Self {
544        self.memory_limiter = limiter;
545        self
546    }
547
548    pub fn with_sql_handler(self, sql_handler: ServerSqlQueryHandlerRef) -> Self {
549        let sql_router = HttpServer::route_sql(ApiState {
550            sql_handler,
551            experimental_enable_explain_analyze_stream: self
552                .options
553                .experimental_enable_explain_analyze_stream,
554        });
555
556        Self {
557            router: self
558                .router
559                .nest(&format!("/{HTTP_API_VERSION}"), sql_router),
560            ..self
561        }
562    }
563
564    pub fn with_logs_handler(self, logs_handler: LogQueryHandlerRef) -> Self {
565        let logs_router = HttpServer::route_logs(logs_handler);
566
567        Self {
568            router: self
569                .router
570                .nest(&format!("/{HTTP_API_VERSION}"), logs_router),
571            ..self
572        }
573    }
574
575    pub fn with_opentsdb_handler(self, handler: OpentsdbProtocolHandlerRef) -> Self {
576        Self {
577            router: self.router.nest(
578                &format!("/{HTTP_API_VERSION}/opentsdb"),
579                HttpServer::route_opentsdb(handler),
580            ),
581            ..self
582        }
583    }
584
585    pub fn with_influxdb_handler(self, handler: InfluxdbLineProtocolHandlerRef) -> Self {
586        Self {
587            router: self.router.nest(
588                &format!("/{HTTP_API_VERSION}/influxdb"),
589                HttpServer::route_influxdb(handler),
590            ),
591            ..self
592        }
593    }
594
595    pub fn with_prom_handler(
596        self,
597        handler: PromStoreProtocolHandlerRef,
598        pipeline_handler: Option<PipelineHandlerRef>,
599        prom_store_with_metric_engine: bool,
600        prom_validation_mode: PromValidationMode,
601        pending_rows_batcher: Option<Arc<PendingRowsBatcher>>,
602    ) -> Self {
603        let state = PromStoreState {
604            prom_store_handler: handler,
605            pipeline_handler,
606            prom_store_with_metric_engine,
607            prom_validation_mode,
608            experimental_enable_prometheus_native_histogram: self
609                .options
610                .experimental_enable_prometheus_native_histogram,
611            pending_rows_batcher,
612        };
613
614        Self {
615            router: self.router.nest(
616                &format!("/{HTTP_API_VERSION}/prometheus"),
617                HttpServer::route_prom(state),
618            ),
619            ..self
620        }
621    }
622
623    pub fn with_prometheus_handler(self, handler: PrometheusHandlerRef) -> Self {
624        Self {
625            router: self.router.nest(
626                &format!("/{HTTP_API_VERSION}/prometheus/api/v1"),
627                HttpServer::route_prometheus(handler),
628            ),
629            ..self
630        }
631    }
632
633    pub fn with_otlp_handler(
634        self,
635        handler: OpenTelemetryProtocolHandlerRef,
636        with_metric_engine: bool,
637    ) -> Self {
638        Self {
639            router: self.router.nest(
640                &format!("/{HTTP_API_VERSION}/otlp"),
641                HttpServer::route_otlp(handler, with_metric_engine),
642            ),
643            ..self
644        }
645    }
646
647    pub fn with_user_provider(self, user_provider: UserProviderRef) -> Self {
648        Self {
649            user_provider: Some(user_provider),
650            ..self
651        }
652    }
653
654    pub fn with_metrics_handler(self, handler: MetricsHandler) -> Self {
655        Self {
656            router: self.router.merge(HttpServer::route_metrics(handler)),
657            ..self
658        }
659    }
660
661    pub fn with_log_ingest_handler(
662        self,
663        handler: PipelineHandlerRef,
664        validator: Option<LogValidatorRef>,
665        ingest_interceptor: Option<LogIngestInterceptorRef<Error>>,
666    ) -> Self {
667        let log_state = LogState {
668            log_handler: handler,
669            log_validator: validator,
670            ingest_interceptor,
671        };
672
673        let router = self.router.nest(
674            &format!("/{HTTP_API_VERSION}"),
675            HttpServer::route_pipelines(log_state.clone()),
676        );
677        // deprecated since v0.11.0. Use `/logs` and `/pipelines` instead.
678        let router = router.nest(
679            &format!("/{HTTP_API_VERSION}/events"),
680            #[allow(deprecated)]
681            HttpServer::route_log_deprecated(log_state.clone()),
682        );
683
684        let router = router.nest(
685            &format!("/{HTTP_API_VERSION}/loki"),
686            HttpServer::route_loki(log_state.clone()),
687        );
688
689        let router = router.nest(
690            &format!("/{HTTP_API_VERSION}/elasticsearch"),
691            HttpServer::route_elasticsearch(log_state.clone()),
692        );
693
694        let router = router.nest(
695            &format!("/{HTTP_API_VERSION}/elasticsearch/"),
696            Router::new()
697                .route("/", routing::get(elasticsearch::handle_get_version))
698                .with_state(log_state.clone()),
699        );
700
701        let router = router.nest(
702            &format!("/{HTTP_API_VERSION}/splunk"),
703            HttpServer::route_splunk(log_state),
704        );
705
706        Self { router, ..self }
707    }
708
709    pub fn with_greptime_config_options(self, opts: String) -> Self {
710        let config_router = HttpServer::route_config(GreptimeOptionsConfigState {
711            greptime_config_options: opts,
712        });
713
714        Self {
715            router: self.router.merge(config_router),
716            ..self
717        }
718    }
719
720    pub fn with_jaeger_handler(self, handler: JaegerQueryHandlerRef) -> Self {
721        Self {
722            router: self.router.nest(
723                &format!("/{HTTP_API_VERSION}/jaeger"),
724                HttpServer::route_jaeger(handler),
725            ),
726            ..self
727        }
728    }
729
730    pub fn with_dashboard_handler(self, handler: DashboardHandlerRef) -> Self {
731        Self {
732            router: self.router.nest(
733                &format!("/{HTTP_API_VERSION}/dashboards"),
734                HttpServer::route_dashboard(handler),
735            ),
736            ..self
737        }
738    }
739
740    pub fn with_extra_router(self, router: Router) -> Self {
741        Self {
742            router: self.router.merge(router),
743            ..self
744        }
745    }
746
747    pub fn add_layer<L>(self, layer: L) -> Self
748    where
749        L: Layer<Route> + Clone + Send + Sync + 'static,
750        L::Service: Service<Request> + Clone + Send + Sync + 'static,
751        <L::Service as Service<Request>>::Response: IntoResponse + 'static,
752        <L::Service as Service<Request>>::Error: Into<Infallible> + 'static,
753        <L::Service as Service<Request>>::Future: Send + 'static,
754    {
755        Self {
756            router: self.router.layer(layer),
757            ..self
758        }
759    }
760
761    pub fn build(self) -> HttpServer {
762        HttpServer {
763            options: self.options,
764            user_provider: self.user_provider,
765            shutdown_tx: Mutex::new(None),
766            router: StdMutex::new(self.router),
767            bind_addr: None,
768            memory_limiter: self.memory_limiter,
769        }
770    }
771}
772
773impl HttpServer {
774    /// Gets the router and adds necessary root routes (health, status, dashboard).
775    pub fn make_app(&self) -> Router {
776        let mut router = {
777            let router = self.router.lock().unwrap();
778            router.clone()
779        };
780
781        router = router
782            .route("/", routing::get(handler::index))
783            .route(
784                "/health",
785                routing::get(handler::health).post(handler::health),
786            )
787            .route(
788                &format!("/{HTTP_API_VERSION}/health"),
789                routing::get(handler::health).post(handler::health),
790            )
791            .route(
792                "/ready",
793                routing::get(handler::health).post(handler::health),
794            );
795
796        router = router.route("/status", routing::get(handler::status));
797
798        #[cfg(feature = "dashboard")]
799        {
800            if !self.options.disable_dashboard {
801                info!("Enable dashboard service at '/dashboard'");
802                // redirect /dashboard to /dashboard/
803                router = router.route(
804                    "/dashboard",
805                    routing::get(|uri: axum::http::uri::Uri| async move {
806                        let path = uri.path();
807                        let query = uri.query().map(|q| format!("?{}", q)).unwrap_or_default();
808
809                        let new_uri = format!("{}/{}", path, query);
810                        axum::response::Redirect::permanent(&new_uri)
811                    }),
812                );
813
814                // "/dashboard" and "/dashboard/" are two different paths in Axum.
815                // We cannot nest "/dashboard/", because we already mapping "/dashboard/{*x}" while nesting "/dashboard".
816                // So we explicitly route "/dashboard/" here.
817                router = router
818                    .route(
819                        "/dashboard/",
820                        routing::get(dashboard::static_handler).post(dashboard::static_handler),
821                    )
822                    .route(
823                        "/dashboard/{*x}",
824                        routing::get(dashboard::static_handler).post(dashboard::static_handler),
825                    );
826            }
827        }
828
829        // Add a layer to collect HTTP metrics for axum.
830        router = router.route_layer(middleware::from_fn(http_metrics_layer));
831
832        router
833    }
834
835    /// Attaches middlewares and debug routes to the router.
836    /// Callers should call this method after [HttpServer::make_app()].
837    pub fn build(&self, router: Router) -> Result<Router> {
838        let timeout_layer = if self.options.timeout != Duration::default() {
839            Some(ServiceBuilder::new().layer(DynamicTimeoutLayer::new(self.options.timeout)))
840        } else {
841            info!("HTTP server timeout is disabled");
842            None
843        };
844        let body_limit_layer = if self.options.body_limit != ReadableSize(0) {
845            Some(
846                ServiceBuilder::new()
847                    .layer(DefaultBodyLimit::max(self.options.body_limit.0 as usize)),
848            )
849        } else {
850            info!("HTTP server body limit is disabled");
851            None
852        };
853        let cors_layer = if self.options.enable_cors {
854            Some(
855                CorsLayer::new()
856                    .allow_methods([
857                        Method::GET,
858                        Method::POST,
859                        Method::PUT,
860                        Method::DELETE,
861                        Method::HEAD,
862                    ])
863                    .allow_origin(if self.options.cors_allowed_origins.is_empty() {
864                        AllowOrigin::from(Any)
865                    } else {
866                        AllowOrigin::from(
867                            self.options
868                                .cors_allowed_origins
869                                .iter()
870                                .map(|s| {
871                                    HeaderValue::from_str(s.as_str())
872                                        .context(InvalidHeaderValueSnafu)
873                                })
874                                .collect::<Result<Vec<HeaderValue>>>()?,
875                        )
876                    })
877                    .allow_headers(Any),
878            )
879        } else {
880            info!("HTTP server cross-origin is disabled");
881            None
882        };
883
884        Ok(router
885            // middlewares
886            .layer(
887                ServiceBuilder::new()
888                    // disable on failure tracing. because printing out isn't very helpful,
889                    // and we have impl IntoResponse for Error. It will print out more detailed error messages
890                    .layer(TraceLayer::new_for_http().on_failure(()))
891                    .option_layer(cors_layer)
892                    .option_layer(timeout_layer)
893                    .option_layer(body_limit_layer)
894                    // memory limit layer - must be before body is consumed
895                    .layer(middleware::from_fn_with_state(
896                        self.memory_limiter.clone(),
897                        memory_limit::memory_limit_middleware,
898                    ))
899                    // auth layer
900                    .layer(middleware::from_fn_with_state(
901                        AuthState::new(self.user_provider.clone()),
902                        authorize::check_http_auth,
903                    ))
904                    .layer(middleware::from_fn(hints::extract_hints))
905                    .layer(middleware::from_fn(client_ip::log_error_with_client_ip))
906                    .layer(middleware::from_fn(
907                        read_preference::extract_read_preference,
908                    )),
909            )
910            // Handlers for debug, we don't expect a timeout.
911            .nest(
912                "/debug",
913                Router::new()
914                    // handler for changing log level dynamically
915                    .route("/log_level", routing::post(dyn_log::dyn_log_handler))
916                    .route("/enable_trace", routing::post(dyn_trace::dyn_trace_handler))
917                    .nest(
918                        "/prof",
919                        Router::new()
920                            .route("/cpu", routing::post(pprof::pprof_handler))
921                            .route("/mem", routing::post(mem_prof::mem_prof_handler))
922                            .route("/mem/symbol", routing::post(mem_prof::symbolicate_handler))
923                            .route(
924                                "/mem/activate",
925                                routing::post(mem_prof::activate_heap_prof_handler),
926                            )
927                            .route(
928                                "/mem/deactivate",
929                                routing::post(mem_prof::deactivate_heap_prof_handler),
930                            )
931                            .route(
932                                "/mem/status",
933                                routing::get(mem_prof::heap_prof_status_handler),
934                            ) // jemalloc gdump flag status and toggle
935                            .route(
936                                "/mem/gdump",
937                                routing::get(mem_prof::gdump_status_handler)
938                                    .post(mem_prof::gdump_toggle_handler),
939                            ),
940                    ),
941            ))
942    }
943
944    fn route_metrics<S>(metrics_handler: MetricsHandler) -> Router<S> {
945        Router::new()
946            .route("/metrics", routing::get(handler::metrics))
947            .with_state(metrics_handler)
948    }
949
950    fn route_loki<S>(log_state: LogState) -> Router<S> {
951        Router::new()
952            .route("/api/v1/push", routing::post(loki::loki_ingest))
953            .layer(
954                ServiceBuilder::new()
955                    .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
956            )
957            .with_state(log_state)
958    }
959
960    fn route_splunk<S>(log_state: LogState) -> Router<S> {
961        Router::new()
962            .route(
963                "/services/collector/health",
964                routing::get(splunk::handle_health),
965            )
966            .route(
967                "/services/collector/health/1.0",
968                routing::get(splunk::handle_health),
969            )
970            // The event endpoint plus its base and versioned aliases all serve
971            // the same handler (Splunk JSON event protocol).
972            .route(
973                "/services/collector/event",
974                routing::post(splunk::handle_event),
975            )
976            .route("/services/collector", routing::post(splunk::handle_event))
977            .route(
978                "/services/collector/event/1.0",
979                routing::post(splunk::handle_event),
980            )
981            // The raw endpoint (plain-text body, one event per line) plus its
982            // versioned alias.
983            .route("/services/collector/raw", routing::post(splunk::handle_raw))
984            .route(
985                "/services/collector/raw/1.0",
986                routing::post(splunk::handle_raw),
987            )
988            .layer(
989                ServiceBuilder::new()
990                    .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
991            )
992            .with_state(log_state)
993    }
994
995    fn route_elasticsearch<S>(log_state: LogState) -> Router<S> {
996        Router::new()
997            // Return fake responsefor HEAD '/' request.
998            .route(
999                "/",
1000                routing::head((HttpStatusCode::OK, elasticsearch::elasticsearch_headers())),
1001            )
1002            // Return fake response for Elasticsearch version request.
1003            .route("/", routing::get(elasticsearch::handle_get_version))
1004            // Return fake response for Elasticsearch license request.
1005            .route("/_license", routing::get(elasticsearch::handle_get_license))
1006            .route("/_bulk", routing::post(elasticsearch::handle_bulk_api))
1007            .route(
1008                "/{index}/_bulk",
1009                routing::post(elasticsearch::handle_bulk_api_with_index),
1010            )
1011            // Return fake response for Elasticsearch ilm request.
1012            .route(
1013                "/_ilm/policy/{*path}",
1014                routing::any((
1015                    HttpStatusCode::OK,
1016                    elasticsearch::elasticsearch_headers(),
1017                    axum::Json(serde_json::json!({})),
1018                )),
1019            )
1020            // Return fake response for Elasticsearch index template request.
1021            .route(
1022                "/_index_template/{*path}",
1023                routing::any((
1024                    HttpStatusCode::OK,
1025                    elasticsearch::elasticsearch_headers(),
1026                    axum::Json(serde_json::json!({})),
1027                )),
1028            )
1029            // Return fake response for Elasticsearch ingest pipeline request.
1030            // See: https://www.elastic.co/guide/en/elasticsearch/reference/8.8/put-pipeline-api.html.
1031            .route(
1032                "/_ingest/{*path}",
1033                routing::any((
1034                    HttpStatusCode::OK,
1035                    elasticsearch::elasticsearch_headers(),
1036                    axum::Json(serde_json::json!({})),
1037                )),
1038            )
1039            // Return fake response for Elasticsearch nodes discovery request.
1040            // See: https://www.elastic.co/guide/en/elasticsearch/reference/8.8/cluster.html.
1041            .route(
1042                "/_nodes/{*path}",
1043                routing::any((
1044                    HttpStatusCode::OK,
1045                    elasticsearch::elasticsearch_headers(),
1046                    axum::Json(serde_json::json!({})),
1047                )),
1048            )
1049            // Return fake response for Logstash APIs requests.
1050            // See: https://www.elastic.co/guide/en/elasticsearch/reference/8.8/logstash-apis.html
1051            .route(
1052                "/logstash/{*path}",
1053                routing::any((
1054                    HttpStatusCode::OK,
1055                    elasticsearch::elasticsearch_headers(),
1056                    axum::Json(serde_json::json!({})),
1057                )),
1058            )
1059            .route(
1060                "/_logstash/{*path}",
1061                routing::any((
1062                    HttpStatusCode::OK,
1063                    elasticsearch::elasticsearch_headers(),
1064                    axum::Json(serde_json::json!({})),
1065                )),
1066            )
1067            .layer(ServiceBuilder::new().layer(RequestDecompressionLayer::new()))
1068            .with_state(log_state)
1069    }
1070
1071    #[deprecated(since = "0.11.0", note = "Use `route_pipelines()` instead.")]
1072    fn route_log_deprecated<S>(log_state: LogState) -> Router<S> {
1073        Router::new()
1074            .route("/logs", routing::post(event::log_ingester))
1075            .route(
1076                "/pipelines/{pipeline_name}",
1077                routing::get(event::query_pipeline),
1078            )
1079            .route(
1080                "/pipelines/{pipeline_name}",
1081                routing::post(event::add_pipeline),
1082            )
1083            .route(
1084                "/pipelines/{pipeline_name}",
1085                routing::delete(event::delete_pipeline),
1086            )
1087            .route("/pipelines/dryrun", routing::post(event::pipeline_dryrun))
1088            .layer(
1089                ServiceBuilder::new()
1090                    .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1091            )
1092            .with_state(log_state)
1093    }
1094
1095    fn route_pipelines<S>(log_state: LogState) -> Router<S> {
1096        Router::new()
1097            .route("/ingest", routing::post(event::log_ingester))
1098            .route(
1099                "/pipelines/{pipeline_name}",
1100                routing::get(event::query_pipeline),
1101            )
1102            .route(
1103                "/pipelines/{pipeline_name}/ddl",
1104                routing::get(event::query_pipeline_ddl),
1105            )
1106            .route(
1107                "/pipelines/{pipeline_name}",
1108                routing::post(event::add_pipeline),
1109            )
1110            .route(
1111                "/pipelines/{pipeline_name}",
1112                routing::delete(event::delete_pipeline),
1113            )
1114            .route("/pipelines/_dryrun", routing::post(event::pipeline_dryrun))
1115            .layer(
1116                ServiceBuilder::new()
1117                    .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1118            )
1119            .with_state(log_state)
1120    }
1121
1122    fn route_sql<S>(api_state: ApiState) -> Router<S> {
1123        let mut router = Router::new()
1124            .route("/sql", routing::get(handler::sql).post(handler::sql))
1125            .route(
1126                "/sql/parse",
1127                routing::get(handler::sql_parse).post(handler::sql_parse),
1128            )
1129            .route(
1130                "/sql/format",
1131                routing::get(handler::sql_format).post(handler::sql_format),
1132            )
1133            .route(
1134                "/promql",
1135                routing::get(handler::promql).post(handler::promql),
1136            );
1137
1138        if api_state.experimental_enable_explain_analyze_stream {
1139            router = router.route(
1140                "/sql/analyze/stream",
1141                routing::post(handler::sql_analyze_stream),
1142            );
1143        }
1144
1145        router.with_state(api_state)
1146    }
1147
1148    fn route_logs<S>(log_handler: LogQueryHandlerRef) -> Router<S> {
1149        Router::new()
1150            .route("/logs", routing::get(logs::logs).post(logs::logs))
1151            .with_state(log_handler)
1152    }
1153
1154    /// Route Prometheus [HTTP API].
1155    ///
1156    /// [HTTP API]: https://prometheus.io/docs/prometheus/latest/querying/api/
1157    pub fn route_prometheus<S>(prometheus_handler: PrometheusHandlerRef) -> Router<S> {
1158        Router::new()
1159            .route(
1160                "/format_query",
1161                routing::post(format_query).get(format_query),
1162            )
1163            .route("/status/buildinfo", routing::get(build_info_query))
1164            .route("/query", routing::post(instant_query).get(instant_query))
1165            .route("/query_range", routing::post(range_query).get(range_query))
1166            .route("/labels", routing::post(labels_query).get(labels_query))
1167            .route("/series", routing::post(series_query).get(series_query))
1168            .route("/parse_query", routing::post(parse_query).get(parse_query))
1169            .route(
1170                "/label/{label_name}/values",
1171                routing::get(label_values_query),
1172            )
1173            .layer(ServiceBuilder::new().layer(CompressionLayer::new()))
1174            .with_state(prometheus_handler)
1175    }
1176
1177    /// Route Prometheus remote [read] and [write] API. In other places the related modules are
1178    /// called `prom_store`.
1179    ///
1180    /// [read]: https://prometheus.io/docs/prometheus/latest/querying/remote_read_api/
1181    /// [write]: https://prometheus.io/docs/concepts/remote_write_spec/
1182    fn route_prom<S>(state: PromStoreState) -> Router<S> {
1183        Router::new()
1184            .route("/read", routing::post(prom_store::remote_read))
1185            .route("/write", routing::post(prom_store::remote_write))
1186            .with_state(state)
1187    }
1188
1189    fn route_influxdb<S>(influxdb_handler: InfluxdbLineProtocolHandlerRef) -> Router<S> {
1190        Router::new()
1191            .route("/write", routing::post(influxdb_write_v1))
1192            .route("/api/v2/write", routing::post(influxdb_write_v2))
1193            .layer(
1194                ServiceBuilder::new()
1195                    .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1196            )
1197            .route("/ping", routing::get(influxdb_ping))
1198            .route("/health", routing::get(influxdb_health))
1199            .with_state(influxdb_handler)
1200    }
1201
1202    fn route_opentsdb<S>(opentsdb_handler: OpentsdbProtocolHandlerRef) -> Router<S> {
1203        Router::new()
1204            .route("/api/put", routing::post(opentsdb::put))
1205            .with_state(opentsdb_handler)
1206    }
1207
1208    fn route_otlp<S>(
1209        otlp_handler: OpenTelemetryProtocolHandlerRef,
1210        with_metric_engine: bool,
1211    ) -> Router<S> {
1212        Router::new()
1213            .route("/v1/metrics", routing::post(otlp::metrics))
1214            .route("/v1/traces", routing::post(otlp::traces))
1215            .route("/v1/logs", routing::post(otlp::logs))
1216            .layer(
1217                ServiceBuilder::new()
1218                    .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1219            )
1220            .with_state(OtlpState {
1221                with_metric_engine,
1222                handler: otlp_handler,
1223            })
1224    }
1225
1226    fn route_config<S>(state: GreptimeOptionsConfigState) -> Router<S> {
1227        Router::new()
1228            .route("/config", routing::get(handler::config))
1229            .with_state(state)
1230    }
1231
1232    fn route_jaeger<S>(handler: JaegerQueryHandlerRef) -> Router<S> {
1233        Router::new()
1234            .route("/api/services", routing::get(jaeger::handle_get_services))
1235            .route(
1236                "/api/services/{service_name}/operations",
1237                routing::get(jaeger::handle_get_operations_by_service),
1238            )
1239            .route(
1240                "/api/operations",
1241                routing::get(jaeger::handle_get_operations),
1242            )
1243            .route("/api/traces", routing::get(jaeger::handle_find_traces))
1244            .route(
1245                "/api/traces/{trace_id}",
1246                routing::get(jaeger::handle_get_trace),
1247            )
1248            .with_state(handler)
1249    }
1250
1251    #[cfg(feature = "dashboard")]
1252    fn route_dashboard<S>(handler: DashboardHandlerRef) -> Router<S> {
1253        use crate::http::dashboard::{add_dashboard, delete_dashboard, list_dashboards};
1254
1255        Router::new()
1256            .route("/", routing::get(list_dashboards))
1257            .route("/{dashboard_name}", routing::post(add_dashboard))
1258            .route("/{dashboard_name}", routing::delete(delete_dashboard))
1259            .layer(
1260                ServiceBuilder::new()
1261                    .layer(RequestDecompressionLayer::new().pass_through_unaccepted(true)),
1262            )
1263            .with_state(DashboardState { handler })
1264    }
1265
1266    #[cfg(not(feature = "dashboard"))]
1267    fn route_dashboard<S>(handler: DashboardHandlerRef) -> Router<S> {
1268        Router::new().with_state(DashboardState { handler })
1269    }
1270}
1271
1272pub const HTTP_SERVER: &str = "HTTP_SERVER";
1273
1274#[async_trait]
1275impl Server for HttpServer {
1276    async fn shutdown(&self) -> Result<()> {
1277        let mut shutdown_tx = self.shutdown_tx.lock().await;
1278        if let Some(tx) = shutdown_tx.take()
1279            && tx.send(()).is_err()
1280        {
1281            info!("Receiver dropped, the HTTP server has already exited");
1282        }
1283        info!("Shutdown HTTP server");
1284
1285        Ok(())
1286    }
1287
1288    async fn start(&mut self, listening: SocketAddr) -> Result<()> {
1289        let (tx, rx) = oneshot::channel();
1290        let serve = {
1291            let mut shutdown_tx = self.shutdown_tx.lock().await;
1292            ensure!(
1293                shutdown_tx.is_none(),
1294                AlreadyStartedSnafu { server: "HTTP" }
1295            );
1296
1297            let app = self.build(self.make_app())?;
1298            let listener = tokio::net::TcpListener::bind(listening)
1299                .await
1300                .context(AddressBindSnafu { addr: listening })?
1301                .tap_io(|tcp_stream| {
1302                    if let Err(e) = tcp_stream.set_nodelay(true) {
1303                        error!(e; "Failed to set TCP_NODELAY on incoming connection");
1304                    }
1305                });
1306            let serve = axum::serve(
1307                listener,
1308                app.into_make_service_with_connect_info::<SocketAddr>(),
1309            );
1310
1311            // FIXME(yingwen): Support keepalive.
1312            // See:
1313            // - https://github.com/tokio-rs/axum/discussions/2939
1314            // - https://stackoverflow.com/questions/73069718/how-do-i-keep-alive-tokiotcpstream-in-rust
1315            // let server = axum::Server::try_bind(&listening)
1316            //     .with_context(|_| AddressBindSnafu { addr: listening })?
1317            //     .tcp_nodelay(true)
1318            //     // Enable TCP keepalive to close the dangling established connections.
1319            //     // It's configured to let the keepalive probes first send after the connection sits
1320            //     // idle for 59 minutes, and then send every 10 seconds for 6 times.
1321            //     // So the connection will be closed after roughly 1 hour.
1322            //     .tcp_keepalive(Some(Duration::from_secs(59 * 60)))
1323            //     .tcp_keepalive_interval(Some(Duration::from_secs(10)))
1324            //     .tcp_keepalive_retries(Some(6))
1325            //     .serve(app.into_make_service());
1326
1327            *shutdown_tx = Some(tx);
1328
1329            serve
1330        };
1331        let listening = serve.local_addr().context(InternalIoSnafu)?;
1332        info!("HTTP server is bound to {}", listening);
1333
1334        common_runtime::spawn_global(async move {
1335            if let Err(e) = serve
1336                .with_graceful_shutdown(rx.map(drop))
1337                .await
1338                .context(InternalIoSnafu)
1339            {
1340                error!(e; "Failed to shutdown http server");
1341            }
1342        });
1343
1344        self.bind_addr = Some(listening);
1345        Ok(())
1346    }
1347
1348    fn name(&self) -> &str {
1349        HTTP_SERVER
1350    }
1351
1352    fn bind_addr(&self) -> Option<SocketAddr> {
1353        self.bind_addr
1354    }
1355
1356    fn as_any(&self) -> &dyn std::any::Any {
1357        self
1358    }
1359}
1360
1361#[cfg(test)]
1362mod test {
1363    use std::future::pending;
1364    use std::io::Cursor;
1365    use std::sync::Arc;
1366
1367    use arrow_ipc::reader::StreamReader;
1368    use arrow_schema::DataType;
1369    use axum::handler::Handler;
1370    use axum::http::StatusCode;
1371    use axum::routing::get;
1372    use common_query::{Output, OutputData};
1373    use common_recordbatch::RecordBatches;
1374    use datafusion_expr::LogicalPlan;
1375    use datatypes::prelude::*;
1376    use datatypes::schema::{ColumnSchema, Schema};
1377    use datatypes::vectors::{StringVector, UInt32Vector};
1378    use header::constants::GREPTIME_DB_HEADER_TIMEOUT;
1379    use query::parser::PromQuery;
1380    use query::query_engine::DescribeResult;
1381    use session::context::QueryContextRef;
1382    use sql::statements::statement::Statement;
1383    use tokio::sync::mpsc;
1384    use tokio::time::Instant;
1385
1386    use super::*;
1387    use crate::http::test_helpers::TestClient;
1388    use crate::prom_remote_write::validation::validate_label_name;
1389    use crate::query_handler::sql::SqlQueryHandler;
1390
1391    struct DummyInstance {
1392        _tx: mpsc::Sender<(String, Vec<u8>)>,
1393    }
1394
1395    #[async_trait]
1396    impl SqlQueryHandler for DummyInstance {
1397        async fn do_query(&self, _: &str, _: QueryContextRef) -> Vec<Result<Output>> {
1398            unimplemented!()
1399        }
1400
1401        async fn do_analyze_stream_query(&self, _: &str, _: QueryContextRef) -> Result<Output> {
1402            let stream = common_recordbatch::RecordBatches::empty().as_stream();
1403            Ok(Output::new(OutputData::Stream(stream), Default::default()))
1404        }
1405
1406        async fn do_promql_query(&self, _: &PromQuery, _: QueryContextRef) -> Vec<Result<Output>> {
1407            unimplemented!()
1408        }
1409
1410        async fn do_exec_plan(
1411            &self,
1412            _plan: LogicalPlan,
1413            _stmt: Option<Statement>,
1414            _query_ctx: QueryContextRef,
1415        ) -> Result<Output> {
1416            unimplemented!()
1417        }
1418
1419        async fn do_describe(
1420            &self,
1421            _stmt: sql::statements::statement::Statement,
1422            _query_ctx: QueryContextRef,
1423        ) -> Result<Option<DescribeResult>> {
1424            unimplemented!()
1425        }
1426
1427        async fn is_valid_schema(&self, _catalog: &str, _schema: &str) -> Result<bool> {
1428            Ok(true)
1429        }
1430    }
1431
1432    fn timeout() -> DynamicTimeoutLayer {
1433        DynamicTimeoutLayer::new(Duration::from_millis(10))
1434    }
1435
1436    async fn forever() {
1437        pending().await
1438    }
1439
1440    fn make_test_app(tx: mpsc::Sender<(String, Vec<u8>)>) -> Router {
1441        make_test_app_custom(tx, HttpOptions::default())
1442    }
1443
1444    fn make_test_app_custom(tx: mpsc::Sender<(String, Vec<u8>)>, options: HttpOptions) -> Router {
1445        let instance = Arc::new(DummyInstance { _tx: tx });
1446        let server = HttpServerBuilder::new(options)
1447            .with_sql_handler(instance.clone())
1448            .build();
1449        server.build(server.make_app()).unwrap().route(
1450            "/test/timeout",
1451            get(forever.layer(ServiceBuilder::new().layer(timeout()))),
1452        )
1453    }
1454
1455    #[tokio::test]
1456    pub async fn test_analyze_stream_route_config_gate() {
1457        let (tx, _rx) = mpsc::channel(100);
1458        let options = HttpOptions {
1459            experimental_enable_explain_analyze_stream: false,
1460            ..Default::default()
1461        };
1462        let app = make_test_app_custom(tx, options);
1463        let client = TestClient::new(app).await;
1464        let res = client
1465            .post("/v1/sql/analyze/stream?sql=EXPLAIN%20ANALYZE%20VERBOSE%20SELECT%201")
1466            .send()
1467            .await;
1468        assert_eq!(res.status(), StatusCode::NOT_FOUND);
1469
1470        let (tx, _rx) = mpsc::channel(100);
1471        let app = make_test_app_custom(tx, HttpOptions::default());
1472        let client = TestClient::new(app).await;
1473        let res = client
1474            .post("/v1/sql/analyze/stream?sql=EXPLAIN%20ANALYZE%20VERBOSE%20SELECT%201")
1475            .send()
1476            .await;
1477        assert_ne!(res.status(), StatusCode::NOT_FOUND);
1478    }
1479
1480    #[tokio::test]
1481    pub async fn test_cors() {
1482        // cors is on by default
1483        let (tx, _rx) = mpsc::channel(100);
1484        let app = make_test_app(tx);
1485        let client = TestClient::new(app).await;
1486
1487        let res = client.get("/health").send().await;
1488
1489        assert_eq!(res.status(), StatusCode::OK);
1490        assert_eq!(
1491            res.headers()
1492                .get(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
1493                .expect("expect cors header origin"),
1494            "*"
1495        );
1496
1497        let res = client.get("/v1/health").send().await;
1498
1499        assert_eq!(res.status(), StatusCode::OK);
1500        assert_eq!(
1501            res.headers()
1502                .get(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
1503                .expect("expect cors header origin"),
1504            "*"
1505        );
1506
1507        let res = client
1508            .options("/health")
1509            .header("Access-Control-Request-Headers", "x-greptime-auth")
1510            .header("Access-Control-Request-Method", "DELETE")
1511            .header("Origin", "https://example.com")
1512            .send()
1513            .await;
1514        assert_eq!(res.status(), StatusCode::OK);
1515        assert_eq!(
1516            res.headers()
1517                .get(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
1518                .expect("expect cors header origin"),
1519            "*"
1520        );
1521        assert_eq!(
1522            res.headers()
1523                .get(http::header::ACCESS_CONTROL_ALLOW_HEADERS)
1524                .expect("expect cors header headers"),
1525            "*"
1526        );
1527        assert_eq!(
1528            res.headers()
1529                .get(http::header::ACCESS_CONTROL_ALLOW_METHODS)
1530                .expect("expect cors header methods"),
1531            "GET,POST,PUT,DELETE,HEAD"
1532        );
1533    }
1534
1535    #[tokio::test]
1536    pub async fn test_cors_custom_origins() {
1537        // cors is on by default
1538        let (tx, _rx) = mpsc::channel(100);
1539        let origin = "https://example.com";
1540
1541        let options = HttpOptions {
1542            cors_allowed_origins: vec![origin.to_string()],
1543            ..Default::default()
1544        };
1545
1546        let app = make_test_app_custom(tx, options);
1547        let client = TestClient::new(app).await;
1548
1549        let res = client.get("/health").header("Origin", origin).send().await;
1550
1551        assert_eq!(res.status(), StatusCode::OK);
1552        assert_eq!(
1553            res.headers()
1554                .get(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
1555                .expect("expect cors header origin"),
1556            origin
1557        );
1558
1559        let res = client
1560            .get("/health")
1561            .header("Origin", "https://notallowed.com")
1562            .send()
1563            .await;
1564
1565        assert_eq!(res.status(), StatusCode::OK);
1566        assert!(
1567            !res.headers()
1568                .contains_key(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
1569        );
1570    }
1571
1572    #[tokio::test]
1573    pub async fn test_cors_disabled() {
1574        // cors is on by default
1575        let (tx, _rx) = mpsc::channel(100);
1576
1577        let options = HttpOptions {
1578            enable_cors: false,
1579            ..Default::default()
1580        };
1581
1582        let app = make_test_app_custom(tx, options);
1583        let client = TestClient::new(app).await;
1584
1585        let res = client.get("/health").send().await;
1586
1587        assert_eq!(res.status(), StatusCode::OK);
1588        assert!(
1589            !res.headers()
1590                .contains_key(http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
1591        );
1592    }
1593
1594    #[test]
1595    fn test_http_options_default() {
1596        let default = HttpOptions::default();
1597        assert_eq!("127.0.0.1:4000".to_string(), default.addr);
1598        assert_eq!(Duration::from_secs(0), default.timeout)
1599    }
1600
1601    #[tokio::test]
1602    async fn test_http_server_request_timeout() {
1603        common_telemetry::init_default_ut_logging();
1604
1605        let (tx, _rx) = mpsc::channel(100);
1606        let app = make_test_app(tx);
1607        let client = TestClient::new(app).await;
1608        let res = client.get("/test/timeout").send().await;
1609        assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
1610
1611        let now = Instant::now();
1612        let res = client
1613            .get("/test/timeout")
1614            .header(GREPTIME_DB_HEADER_TIMEOUT, "20ms")
1615            .send()
1616            .await;
1617        assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
1618        let elapsed = now.elapsed();
1619        assert!(elapsed > Duration::from_millis(15));
1620
1621        tokio::time::timeout(
1622            Duration::from_millis(15),
1623            client
1624                .get("/test/timeout")
1625                .header(GREPTIME_DB_HEADER_TIMEOUT, "0s")
1626                .send(),
1627        )
1628        .await
1629        .unwrap_err();
1630
1631        tokio::time::timeout(
1632            Duration::from_millis(15),
1633            client
1634                .get("/test/timeout")
1635                .header(
1636                    GREPTIME_DB_HEADER_TIMEOUT,
1637                    humantime::format_duration(Duration::default()).to_string(),
1638                )
1639                .send(),
1640        )
1641        .await
1642        .unwrap_err();
1643    }
1644
1645    #[tokio::test]
1646    async fn test_schema_for_empty_response() {
1647        let column_schemas = vec![
1648            ColumnSchema::new("numbers", ConcreteDataType::uint32_datatype(), false),
1649            ColumnSchema::new("strings", ConcreteDataType::string_datatype(), true),
1650        ];
1651        let schema = Arc::new(Schema::new(column_schemas));
1652
1653        let recordbatches = RecordBatches::try_new(schema.clone(), vec![]).unwrap();
1654        let outputs = vec![Ok(Output::new_with_record_batches(recordbatches))];
1655
1656        let json_resp = GreptimedbV1Response::from_output(outputs).await;
1657        if let HttpResponse::GreptimedbV1(json_resp) = json_resp {
1658            let json_output = &json_resp.output[0];
1659            if let GreptimeQueryOutput::Records(r) = json_output {
1660                assert_eq!(r.num_rows(), 0);
1661                assert_eq!(r.num_cols(), 2);
1662                assert_eq!(r.schema.column_schemas[0].name, "numbers");
1663                assert_eq!(r.schema.column_schemas[0].data_type, "UInt32");
1664            } else {
1665                panic!("invalid output type");
1666            }
1667        } else {
1668            panic!("invalid format")
1669        }
1670    }
1671
1672    #[tokio::test]
1673    async fn test_recordbatches_conversion() {
1674        let column_schemas = vec![
1675            ColumnSchema::new("numbers", ConcreteDataType::uint32_datatype(), false),
1676            ColumnSchema::new("strings", ConcreteDataType::string_datatype(), true),
1677        ];
1678        let schema = Arc::new(Schema::new(column_schemas));
1679        let columns: Vec<VectorRef> = vec![
1680            Arc::new(UInt32Vector::from_slice(vec![1, 2, 3, 4])),
1681            Arc::new(StringVector::from(vec![
1682                None,
1683                Some("hello"),
1684                Some("greptime"),
1685                None,
1686            ])),
1687        ];
1688        let recordbatch = RecordBatch::new(schema.clone(), columns).unwrap();
1689
1690        for format in [
1691            ResponseFormat::GreptimedbV1,
1692            ResponseFormat::InfluxdbV1,
1693            ResponseFormat::Csv(true, true),
1694            ResponseFormat::Table,
1695            ResponseFormat::Arrow,
1696            ResponseFormat::Json,
1697            ResponseFormat::Null,
1698        ] {
1699            let recordbatches =
1700                RecordBatches::try_new(schema.clone(), vec![recordbatch.clone()]).unwrap();
1701            let outputs = vec![Ok(Output::new_with_record_batches(recordbatches))];
1702            let json_resp = match format {
1703                ResponseFormat::Arrow => ArrowResponse::from_output(outputs, None).await,
1704                ResponseFormat::Csv(with_names, with_types) => {
1705                    CsvResponse::from_output(outputs, with_names, with_types).await
1706                }
1707                ResponseFormat::Table => TableResponse::from_output(outputs).await,
1708                ResponseFormat::GreptimedbV1 => GreptimedbV1Response::from_output(outputs).await,
1709                ResponseFormat::InfluxdbV1 => InfluxdbV1Response::from_output(outputs, None).await,
1710                ResponseFormat::Json => JsonResponse::from_output(outputs).await,
1711                ResponseFormat::Null => NullResponse::from_output(outputs).await,
1712            };
1713
1714            match json_resp {
1715                HttpResponse::GreptimedbV1(resp) => {
1716                    let json_output = &resp.output[0];
1717                    if let GreptimeQueryOutput::Records(r) = json_output {
1718                        assert_eq!(r.num_rows(), 4);
1719                        assert_eq!(r.num_cols(), 2);
1720                        assert_eq!(r.schema.column_schemas[0].name, "numbers");
1721                        assert_eq!(r.schema.column_schemas[0].data_type, "UInt32");
1722                        assert_eq!(r.rows[0][0], serde_json::Value::from(1));
1723                        assert_eq!(r.rows[0][1], serde_json::Value::Null);
1724                    } else {
1725                        panic!("invalid output type");
1726                    }
1727                }
1728                HttpResponse::InfluxdbV1(resp) => {
1729                    let json_output = &resp.results()[0];
1730                    assert_eq!(json_output.num_rows(), 4);
1731                    assert_eq!(json_output.num_cols(), 2);
1732                    assert_eq!(json_output.series[0].columns.clone()[0], "numbers");
1733                    assert_eq!(
1734                        json_output.series[0].values[0][0],
1735                        serde_json::Value::from(1)
1736                    );
1737                    assert_eq!(json_output.series[0].values[0][1], serde_json::Value::Null);
1738                }
1739                HttpResponse::Csv(resp) => {
1740                    let output = &resp.output()[0];
1741                    if let GreptimeQueryOutput::Records(r) = output {
1742                        assert_eq!(r.num_rows(), 4);
1743                        assert_eq!(r.num_cols(), 2);
1744                        assert_eq!(r.schema.column_schemas[0].name, "numbers");
1745                        assert_eq!(r.schema.column_schemas[0].data_type, "UInt32");
1746                        assert_eq!(r.rows[0][0], serde_json::Value::from(1));
1747                        assert_eq!(r.rows[0][1], serde_json::Value::Null);
1748                    } else {
1749                        panic!("invalid output type");
1750                    }
1751                }
1752
1753                HttpResponse::Table(resp) => {
1754                    let output = &resp.output()[0];
1755                    if let GreptimeQueryOutput::Records(r) = output {
1756                        assert_eq!(r.num_rows(), 4);
1757                        assert_eq!(r.num_cols(), 2);
1758                        assert_eq!(r.schema.column_schemas[0].name, "numbers");
1759                        assert_eq!(r.schema.column_schemas[0].data_type, "UInt32");
1760                        assert_eq!(r.rows[0][0], serde_json::Value::from(1));
1761                        assert_eq!(r.rows[0][1], serde_json::Value::Null);
1762                    } else {
1763                        panic!("invalid output type");
1764                    }
1765                }
1766
1767                HttpResponse::Arrow(resp) => {
1768                    let output = resp.data;
1769                    let mut reader = StreamReader::try_new(Cursor::new(output), None)
1770                        .expect("Arrow reader error");
1771                    let schema = reader.schema();
1772                    assert_eq!(schema.fields[0].name(), "numbers");
1773                    assert_eq!(schema.fields[0].data_type(), &DataType::UInt32);
1774                    assert_eq!(schema.fields[1].name(), "strings");
1775                    assert_eq!(schema.fields[1].data_type(), &DataType::Utf8);
1776
1777                    let rb = reader.next().unwrap().expect("read record batch failed");
1778                    assert_eq!(rb.num_columns(), 2);
1779                    assert_eq!(rb.num_rows(), 4);
1780                }
1781
1782                HttpResponse::Json(resp) => {
1783                    let output = &resp.output()[0];
1784                    if let GreptimeQueryOutput::Records(r) = output {
1785                        assert_eq!(r.num_rows(), 4);
1786                        assert_eq!(r.num_cols(), 2);
1787                        assert_eq!(r.schema.column_schemas[0].name, "numbers");
1788                        assert_eq!(r.schema.column_schemas[0].data_type, "UInt32");
1789                        assert_eq!(r.rows[0][0], serde_json::Value::from(1));
1790                        assert_eq!(r.rows[0][1], serde_json::Value::Null);
1791                    } else {
1792                        panic!("invalid output type");
1793                    }
1794                }
1795
1796                HttpResponse::Null(resp) => {
1797                    assert_eq!(resp.rows(), 4);
1798                }
1799
1800                HttpResponse::Error(err) => unreachable!("{err:?}"),
1801            }
1802        }
1803    }
1804
1805    #[test]
1806    fn test_response_format_misc() {
1807        assert_eq!(ResponseFormat::default(), ResponseFormat::GreptimedbV1);
1808        assert_eq!(ResponseFormat::parse("arrow"), Some(ResponseFormat::Arrow));
1809        assert_eq!(
1810            ResponseFormat::parse("csv"),
1811            Some(ResponseFormat::Csv(false, false))
1812        );
1813        assert_eq!(
1814            ResponseFormat::parse("csvwithnames"),
1815            Some(ResponseFormat::Csv(true, false))
1816        );
1817        assert_eq!(
1818            ResponseFormat::parse("csvwithnamesandtypes"),
1819            Some(ResponseFormat::Csv(true, true))
1820        );
1821        assert_eq!(ResponseFormat::parse("table"), Some(ResponseFormat::Table));
1822        assert_eq!(
1823            ResponseFormat::parse("greptimedb_v1"),
1824            Some(ResponseFormat::GreptimedbV1)
1825        );
1826        assert_eq!(
1827            ResponseFormat::parse("influxdb_v1"),
1828            Some(ResponseFormat::InfluxdbV1)
1829        );
1830        assert_eq!(ResponseFormat::parse("json"), Some(ResponseFormat::Json));
1831        assert_eq!(ResponseFormat::parse("null"), Some(ResponseFormat::Null));
1832
1833        // invalid formats
1834        assert_eq!(ResponseFormat::parse("invalid"), None);
1835        assert_eq!(ResponseFormat::parse(""), None);
1836        assert_eq!(ResponseFormat::parse("CSV"), None); // Case sensitive
1837
1838        // as str
1839        assert_eq!(ResponseFormat::Arrow.as_str(), "arrow");
1840        assert_eq!(ResponseFormat::Csv(false, false).as_str(), "csv");
1841        assert_eq!(ResponseFormat::Csv(true, true).as_str(), "csv");
1842        assert_eq!(ResponseFormat::Table.as_str(), "table");
1843        assert_eq!(ResponseFormat::GreptimedbV1.as_str(), "greptimedb_v1");
1844        assert_eq!(ResponseFormat::InfluxdbV1.as_str(), "influxdb_v1");
1845        assert_eq!(ResponseFormat::Json.as_str(), "json");
1846        assert_eq!(ResponseFormat::Null.as_str(), "null");
1847        assert_eq!(ResponseFormat::default().as_str(), "greptimedb_v1");
1848    }
1849
1850    #[test]
1851    fn test_decode_label_name_strict() {
1852        let strict = PromValidationMode::Strict;
1853
1854        // Valid Prometheus label names
1855        assert!(strict.decode_label_name(b"__name__").is_ok());
1856        assert!(strict.decode_label_name(b"job").is_ok());
1857        assert!(strict.decode_label_name(b"instance").is_ok());
1858        assert!(strict.decode_label_name(b"_private").is_ok());
1859        assert!(strict.decode_label_name(b"label_with_underscores").is_ok());
1860        assert!(strict.decode_label_name(b"abc123").is_ok());
1861        assert!(strict.decode_label_name(b"A").is_ok());
1862        assert!(strict.decode_label_name(b"_").is_ok());
1863
1864        // Invalid: starts with digit
1865        assert!(strict.decode_label_name(b"0abc").is_err());
1866        assert!(strict.decode_label_name(b"123").is_err());
1867
1868        // Invalid: contains special characters
1869        assert!(strict.decode_label_name(b"label-name").is_err());
1870        assert!(strict.decode_label_name(b"label.name").is_err());
1871        assert!(strict.decode_label_name(b"label name").is_err());
1872        assert!(strict.decode_label_name(b"label/name").is_err());
1873
1874        // Invalid: empty
1875        assert!(strict.decode_label_name(b"").is_err());
1876
1877        // Invalid: non-ASCII UTF-8
1878        assert!(strict.decode_label_name("ラベル".as_bytes()).is_err());
1879
1880        // Invalid UTF-8 bytes should fail
1881        assert!(strict.decode_label_name(&[0xff, 0xfe]).is_err());
1882    }
1883
1884    #[test]
1885    fn test_decode_label_name_lossy() {
1886        let lossy = PromValidationMode::Lossy;
1887
1888        // Label name validation is always enforced.
1889        assert!(lossy.decode_label_name(b"__name__").is_ok());
1890        assert!(lossy.decode_label_name(b"label-name").is_err());
1891        assert!(lossy.decode_label_name(b"0abc").is_err());
1892
1893        // Invalid UTF-8 bytes fail the label-name byte check.
1894        assert!(lossy.decode_label_name(&[0xff, 0xfe]).is_err());
1895    }
1896
1897    #[test]
1898    fn test_decode_label_name_unchecked() {
1899        let unchecked = PromValidationMode::Unchecked;
1900
1901        // Label name validation is always enforced.
1902        assert!(unchecked.decode_label_name(b"__name__").is_ok());
1903        assert!(unchecked.decode_label_name(b"label-name").is_err());
1904        assert!(unchecked.decode_label_name(b"0abc").is_err());
1905    }
1906
1907    #[test]
1908    fn test_is_valid_prom_label_name_bytes() {
1909        assert!(validate_label_name(b"__name__"));
1910        assert!(validate_label_name(b"job"));
1911        assert!(validate_label_name(b"_"));
1912        assert!(validate_label_name(b"A"));
1913        assert!(validate_label_name(b"abc123"));
1914        assert!(validate_label_name(b"_leading_underscore"));
1915
1916        assert!(!validate_label_name(b""));
1917        assert!(!validate_label_name(b"0starts_with_digit"));
1918        assert!(!validate_label_name(b"has-dash"));
1919        assert!(!validate_label_name(b"has.dot"));
1920        assert!(!validate_label_name(b"has space"));
1921        assert!(!validate_label_name(&[0xff, 0xfe]));
1922    }
1923}