@@ -6,6 +6,7 @@ extern crate lazy_static;
66mod types;
77
88use crate :: types:: libsql_config;
9+ use http:: Uri ;
910use libsql:: { errors, Builder , LoadExtensionGuard } ;
1011use tokio:: runtime:: Runtime ;
1112use 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]
126223pub 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