Skip to content

Commit ff06574

Browse files
authored
Merge pull request #1853 from tursodatabase/remove_offline_query_param
Remove query parameter from embedded replica url
2 parents 76f1788 + 7749b38 commit ff06574

File tree

3 files changed

+125
-29
lines changed

3 files changed

+125
-29
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindings/c/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ hyper-rustls = { version = "0.25", features = ["webpki-roots"]}
1818
tracing = "0.1.40"
1919
tracing-subscriber = "0.3.18"
2020
http = "1.1.0"
21+
anyhow = "1.0.86"
2122

2223
[target.'cfg(not(any(target_os = "ios", target_os = "android")))'.dependencies]
2324
libsql = { path = "../../libsql", features = ["encryption"] }

bindings/c/src/lib.rs

Lines changed: 123 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ extern crate lazy_static;
66
mod types;
77

88
use crate::types::libsql_config;
9+
use http::Uri;
910
use libsql::{errors, Builder, LoadExtensionGuard};
1011
use tokio::runtime::Runtime;
1112
use types::{
@@ -122,6 +123,102 @@ pub unsafe extern "C" fn libsql_open_sync_with_webpki(
122123
libsql_open_sync_with_config(config, out_db, out_err_msg)
123124
}
124125

126+
/// Returns a new URI with the offline query parameter removed or None if the URI does not contain the offline query parameter.
127+
fn maybe_remove_offline_query_param(url: &str) -> anyhow::Result<Option<String>> {
128+
let uri: Uri = url.try_into()?;
129+
let Some(query) = uri.query() else {
130+
return Ok(None);
131+
};
132+
let query = query.to_owned();
133+
let query_segments = query.split('&').collect::<Vec<&str>>();
134+
let segments_count = query_segments.len();
135+
let query_segments = query_segments
136+
.into_iter()
137+
.filter(|s| s != &"offline" && !s.starts_with("offline="))
138+
.collect::<Vec<&str>>();
139+
if segments_count == query_segments.len() {
140+
return Ok(None);
141+
}
142+
let query = query_segments.join("&");
143+
let Some(query_idx) = url.find('?') else {
144+
return Ok(None);
145+
};
146+
if query.is_empty() {
147+
return Ok(Some(url[..query_idx].to_owned()));
148+
}
149+
150+
Ok(Some(url[..query_idx].to_owned() + "?" + &query))
151+
}
152+
153+
#[cfg(test)]
154+
mod test {
155+
use super::*;
156+
157+
#[test]
158+
fn test_remove_offline_query_param() {
159+
let uri = "http://example.com";
160+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
161+
assert_eq!(new_uri, None);
162+
163+
let uri = "http://example.com?";
164+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
165+
assert_eq!(new_uri, None);
166+
167+
let uri = "http://example.com?foo=bar";
168+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
169+
assert_eq!(new_uri, None);
170+
171+
let uri = "http://example.com?offline";
172+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
173+
assert_eq!(new_uri.as_deref(), Some("http://example.com"));
174+
175+
let uri = "http://example.com?offline=bar";
176+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
177+
assert_eq!(new_uri.as_deref(), Some("http://example.com"));
178+
179+
let uri = "http://example.com?offline&foo=bar";
180+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
181+
assert_eq!(new_uri.as_deref(), Some("http://example.com?foo=bar"));
182+
183+
let uri = "http://example.com?offline=true&foo=bar";
184+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
185+
assert_eq!(new_uri.as_deref(), Some("http://example.com?foo=bar"));
186+
187+
let uri = "http://example.com?foo=bar&offline";
188+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
189+
assert_eq!(new_uri.as_deref(), Some("http://example.com?foo=bar"));
190+
191+
let uri = "http://example.com?foo=bar&offline=true";
192+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
193+
assert_eq!(new_uri.as_deref(), Some("http://example.com?foo=bar"));
194+
195+
let uri = "http://example.com?foo=bar&offline&foo2=bar2";
196+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
197+
assert_eq!(
198+
new_uri.as_deref(),
199+
Some("http://example.com?foo=bar&foo2=bar2")
200+
);
201+
202+
let uri = "http://example.com?foo=bar&offline=true&foo2=bar2";
203+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
204+
assert_eq!(
205+
new_uri.as_deref(),
206+
Some("http://example.com?foo=bar&foo2=bar2")
207+
);
208+
209+
let uri = "http://example.com?offline&foo=bar&offline";
210+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
211+
assert_eq!(new_uri.as_deref(), Some("http://example.com?foo=bar"));
212+
213+
let uri = "http://example.com?offline&foo=bar&offline&foo2=bar2";
214+
let new_uri = maybe_remove_offline_query_param(uri).unwrap();
215+
assert_eq!(
216+
new_uri.as_deref(),
217+
Some("http://example.com?foo=bar&foo2=bar2")
218+
);
219+
}
220+
}
221+
125222
#[no_mangle]
126223
pub unsafe extern "C" fn libsql_open_sync_with_config(
127224
config: libsql_config,
@@ -152,41 +249,38 @@ pub unsafe extern "C" fn libsql_open_sync_with_config(
152249
return 3;
153250
}
154251
};
155-
let uri: http::Uri = match primary_url.try_into() {
156-
Ok(uri) => uri,
252+
let primary_url_with_offline_removed = match maybe_remove_offline_query_param(&primary_url) {
253+
Ok(url) => url,
157254
Err(e) => {
158255
set_err_msg(format!("Wrong primary URL: {e}"), out_err_msg);
159256
return 100;
160257
}
161258
};
162-
if let Some(query) = uri.query() {
163-
if query.contains("offline") {
164-
let mut builder = Builder::new_synced_database(
165-
db_path,
166-
primary_url.to_owned(),
167-
auth_token.to_owned(),
168-
);
169-
if config.with_webpki != 0 {
170-
let https = hyper_rustls::HttpsConnectorBuilder::new()
171-
.with_webpki_roots()
172-
.https_or_http()
173-
.enable_http1()
174-
.build();
175-
builder = builder.connector(https);
259+
if let Some(primary_url) = primary_url_with_offline_removed {
260+
let mut builder =
261+
Builder::new_synced_database(db_path, primary_url.to_owned(), auth_token.to_owned());
262+
if config.with_webpki != 0 {
263+
let https = hyper_rustls::HttpsConnectorBuilder::new()
264+
.with_webpki_roots()
265+
.https_or_http()
266+
.enable_http1()
267+
.build();
268+
builder = builder.connector(https);
269+
}
270+
match RT.block_on(builder.build()) {
271+
Ok(db) => {
272+
let db = Box::leak(Box::new(libsql_database { db }));
273+
*out_db = libsql_database_t::from(db);
274+
return 0;
176275
}
177-
match RT.block_on(builder.build()) {
178-
Ok(db) => {
179-
let db = Box::leak(Box::new(libsql_database { db }));
180-
*out_db = libsql_database_t::from(db);
181-
return 0;
182-
}
183-
Err(e) => {
184-
set_err_msg(
185-
format!("Error opening offline db path {db_path}, primary url {primary_url}: {e}"),
186-
out_err_msg,
187-
);
188-
return 101;
189-
}
276+
Err(e) => {
277+
set_err_msg(
278+
format!(
279+
"Error opening offline db path {db_path}, primary url {primary_url}: {e}"
280+
),
281+
out_err_msg,
282+
);
283+
return 101;
190284
}
191285
}
192286
}

0 commit comments

Comments
 (0)