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