fix: tiles attribute in tilejson with x-rewrite-url (#266)

This commit is contained in:
Stepan Kuzmin 2021-10-15 18:19:36 +03:00 committed by GitHub
parent 194a83e63f
commit f2d56c2f7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 51 deletions

View File

@ -615,7 +615,7 @@ If you are running martin behind Nginx proxy, you may want to rewrite the reques
```nginx
location ~ /tiles/(?<fwd_path>.*) {
proxy_set_header X-Rewrite-URL $request_uri;
proxy_set_header X-Rewrite-URL $uri;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
@ -640,7 +640,7 @@ http {
server {
...
location ~ /tiles/(?<fwd_path>.*) {
proxy_set_header X-Rewrite-URL $request_uri;
proxy_set_header X-Rewrite-URL $uri;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;

View File

@ -56,7 +56,7 @@ http {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Rewrite-URL $request_uri;
proxy_set_header X-Rewrite-URL $uri;
proxy_redirect off;
proxy_connect_timeout 15m;

View File

@ -1,4 +1,3 @@
use serde::Deserialize;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Deref;
@ -6,9 +5,11 @@ use std::rc::Rc;
use actix::{Actor, Addr, SyncArbiter, SystemRunner};
use actix_cors::Cors;
use actix_web::http::Uri;
use actix_web::{
error, http, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result,
error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result,
};
use serde::Deserialize;
use crate::composite_source::CompositeSource;
use crate::config::Config;
@ -19,6 +20,7 @@ use crate::function_source::FunctionSources;
use crate::messages;
use crate::source::{Source, Xyz};
use crate::table_source::{TableSource, TableSources};
use crate::utils::parse_x_rewrite_url;
use crate::worker_actor::WorkerActor;
pub struct AppState {
@ -126,30 +128,28 @@ async fn get_composite_source(
let tiles_path = req
.headers()
.get("x-rewrite-url")
.map_or(Ok(req.path().trim_end_matches(".json")), |header| {
let header_str = header.to_str()?;
Ok(header_str.trim_end_matches(".json"))
})
.map_err(|e: http::header::ToStrError| {
error::ErrorBadRequest(format!("Can't build TileJSON: {}", e))
})?;
let (sep, query) = if req.query_string().is_empty() {
("", "")
} else {
("?", req.query_string())
};
.and_then(parse_x_rewrite_url)
.unwrap_or_else(|| req.path().trim_end_matches(".json").to_owned());
let connection_info = req.connection_info();
let tiles_url = format!(
"{}://{}{}/{{z}}/{{x}}/{{y}}.pbf{}{}",
connection_info.scheme(),
connection_info.host(),
tiles_path,
sep,
query
);
let path_and_query = if req.query_string().is_empty() {
format!("{}/{{z}}/{{x}}/{{y}}.pbf", tiles_path)
} else {
format!(
"{}/{{z}}/{{x}}/{{y}}.pbf?{}",
tiles_path,
req.query_string()
)
};
let tiles_url = Uri::builder()
.scheme(connection_info.scheme())
.authority(connection_info.host())
.path_and_query(path_and_query)
.build()
.map(|tiles_url| tiles_url.to_string())
.map_err(|e| error::ErrorBadRequest(format!("Can't build tiles URL: {}", e)))?;
tilejson.tiles = vec![tiles_url];
Ok(HttpResponse::Ok().json(tilejson))
@ -266,30 +266,28 @@ async fn get_function_source(
let tiles_path = req
.headers()
.get("x-rewrite-url")
.map_or(Ok(req.path().trim_end_matches(".json")), |header| {
let header_str = header.to_str()?;
Ok(header_str.trim_end_matches(".json"))
})
.map_err(|e: http::header::ToStrError| {
error::ErrorBadRequest(format!("Can't build TileJSON: {}", e))
})?;
let (sep, query) = if req.query_string().is_empty() {
("", "")
} else {
("?", req.query_string())
};
.and_then(parse_x_rewrite_url)
.unwrap_or_else(|| req.path().trim_end_matches(".json").to_owned());
let connection_info = req.connection_info();
let tiles_url = format!(
"{}://{}{}/{{z}}/{{x}}/{{y}}.pbf{}{}",
connection_info.scheme(),
connection_info.host(),
tiles_path,
sep,
query
);
let path_and_query = if req.query_string().is_empty() {
format!("{}/{{z}}/{{x}}/{{y}}.pbf", tiles_path)
} else {
format!(
"{}/{{z}}/{{x}}/{{y}}.pbf?{}",
tiles_path,
req.query_string()
)
};
let tiles_url = Uri::builder()
.scheme(connection_info.scheme())
.authority(connection_info.host())
.path_and_query(path_and_query)
.build()
.map(|tiles_url| tiles_url.to_string())
.map_err(|e| error::ErrorBadRequest(format!("Can't build tiles URL: {}", e)))?;
tilejson.tiles = vec![tiles_url];
Ok(HttpResponse::Ok().json(tilejson))

View File

@ -1,6 +1,7 @@
use std::collections::HashMap;
use crate::source::{Query, Xyz};
use actix_web::http;
use postgis::{ewkb, LineString, Point, Polygon};
use postgres::types::Json;
use serde_json::Value;
@ -92,3 +93,11 @@ pub fn polygon_to_bbox(polygon: ewkb::Polygon) -> Option<Vec<f32>> {
}
})
}
pub fn parse_x_rewrite_url(header: &http::HeaderValue) -> Option<String> {
header
.to_str()
.ok()
.and_then(|header| header.parse::<http::Uri>().ok())
.map(|uri| uri.path().trim_end_matches(".json").to_owned())
}

View File

@ -82,17 +82,19 @@ async fn test_get_table_source_ok() {
assert_eq!(response.status(), http::StatusCode::NOT_FOUND);
let req = test::TestRequest::get()
.uri("/public.table_source.json")
.uri("/public.table_source.json?token=martin")
.header(
"x-rewrite-url",
"/tiles/public.table_source.json?token=martin",
)
.to_request();
let result: TileJSON = test::read_response_json(&mut app, req).await;
println!("{:?}", result);
assert_eq!(result.name, Some(String::from("public.table_source")));
assert_eq!(
result.tiles,
vec!["http://localhost:8080/public.table_source/{z}/{x}/{y}.pbf"]
vec!["http://localhost:8080/tiles/public.table_source/{z}/{x}/{y}.pbf?token=martin"]
);
assert_eq!(result.minzoom, Some(0));
assert_eq!(result.maxzoom, Some(30));
@ -504,6 +506,21 @@ async fn test_get_function_source_ok() {
let response = test::call_service(&mut app, req).await;
assert!(response.status().is_success());
let req = test::TestRequest::get()
.uri("/rpc/public.function_source.json?token=martin")
.header(
"x-rewrite-url",
"/tiles/rpc/public.function_source.json?token=martin",
)
.to_request();
let result: TileJSON = test::read_response_json(&mut app, req).await;
assert_eq!(
result.tiles,
vec!["http://localhost:8080/tiles/rpc/public.function_source/{z}/{x}/{y}.pbf?token=martin"]
);
}
#[actix_rt::test]