@@ -6,6 +6,7 @@ extern crate lazy_static;
6
6
mod types;
7
7
8
8
use crate :: types:: libsql_config;
9
+ use http:: Uri ;
9
10
use libsql:: { errors, Builder , LoadExtensionGuard } ;
10
11
use tokio:: runtime:: Runtime ;
11
12
use types:: {
@@ -122,6 +123,102 @@ pub unsafe extern "C" fn libsql_open_sync_with_webpki(
122
123
libsql_open_sync_with_config ( config, out_db, out_err_msg)
123
124
}
124
125
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
+
125
222
#[ no_mangle]
126
223
pub unsafe extern "C" fn libsql_open_sync_with_config (
127
224
config : libsql_config ,
@@ -152,41 +249,38 @@ pub unsafe extern "C" fn libsql_open_sync_with_config(
152
249
return 3 ;
153
250
}
154
251
} ;
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 ,
157
254
Err ( e) => {
158
255
set_err_msg ( format ! ( "Wrong primary URL: {e}" ) , out_err_msg) ;
159
256
return 100 ;
160
257
}
161
258
} ;
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 ;
176
275
}
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 ;
190
284
}
191
285
}
192
286
}
0 commit comments