1
1
#include " node_sqlite.h"
2
2
#include < path.h>
3
- #include " ada.h"
4
3
#include " base_object-inl.h"
5
4
#include " debug_utils-inl.h"
6
5
#include " env-inl.h"
@@ -184,7 +183,7 @@ class BackupJob : public ThreadPoolWork {
184
183
HandleScope handle_scope (isolate);
185
184
backup_status_ = sqlite3_open_v2 (destination_name_.c_str (),
186
185
&dest_,
187
- SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
186
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI ,
188
187
nullptr );
189
188
Local<Promise::Resolver> resolver =
190
189
Local<Promise::Resolver>::New (env ()->isolate (), resolver_);
@@ -504,11 +503,14 @@ bool DatabaseSync::Open() {
504
503
}
505
504
506
505
// TODO(cjihrig): Support additional flags.
506
+ int default_flags = SQLITE_OPEN_URI;
507
507
int flags = open_config_.get_read_only ()
508
508
? SQLITE_OPEN_READONLY
509
509
: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
510
- int r = sqlite3_open_v2 (
511
- open_config_.location ().c_str (), &connection_, flags, nullptr );
510
+ int r = sqlite3_open_v2 (open_config_.location ().c_str (),
511
+ &connection_,
512
+ flags | default_flags,
513
+ nullptr );
512
514
CHECK_ERROR_OR_THROW (env ()->isolate (), this , r, SQLITE_OK, false );
513
515
514
516
r = sqlite3_db_config (connection_,
@@ -586,8 +588,84 @@ bool DatabaseSync::ShouldIgnoreSQLiteError() {
586
588
return ignore_next_sqlite_error_;
587
589
}
588
590
589
- bool IsURL (Local<Value> value) {
590
- return false ;
591
+ bool IsURL (Environment* env, Local<Value> path) {
592
+ Local<Object> url;
593
+ if (!path->ToObject (env->context ()).ToLocal (&url)) {
594
+ return false ;
595
+ }
596
+
597
+ Local<Value> href;
598
+ if (!url->Get (env->context (), FIXED_ONE_BYTE_STRING (env->isolate (), " href" ))
599
+ .ToLocal (&href)) {
600
+ return false ;
601
+ }
602
+
603
+ if (!href->IsString ()) {
604
+ return false ;
605
+ }
606
+
607
+ return true ;
608
+ }
609
+
610
+ Local<String> BufferToString (Environment* env, Local<Uint8Array> buffer) {
611
+ size_t byteOffset = buffer->ByteOffset ();
612
+ size_t byteLength = buffer->ByteLength ();
613
+ if (byteLength == 0 ) {
614
+ THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
615
+ " The \" path\" argument must not be empty." );
616
+ return Local<String>();
617
+ }
618
+
619
+ auto data =
620
+ static_cast <const uint8_t *>(buffer->Buffer ()->Data ()) + byteOffset;
621
+ if (std::find (data, data + byteLength, 0 ) != data + byteLength) {
622
+ THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
623
+ " The \" path\" argument must not contain null "
624
+ " bytes." );
625
+ return Local<String>();
626
+ }
627
+
628
+ auto path = std::string (reinterpret_cast <const char *>(data), byteLength);
629
+ return String::NewFromUtf8 (
630
+ env->isolate (), path.c_str (), NewStringType::kNormal )
631
+ .ToLocalChecked ();
632
+ }
633
+
634
+ Local<String> ToPathIfURL (Environment* env, Local<Value> path) {
635
+ if (!IsURL (env, path)) {
636
+ if (path->IsString ()) {
637
+ return path.As <String>();
638
+ }
639
+
640
+ return BufferToString (env, path.As <Uint8Array>());
641
+ }
642
+
643
+ Local<Object> url = path.As <Object>();
644
+ Local<Value> href;
645
+ Local<Value> protocol;
646
+ if (!url->Get (env->context (), FIXED_ONE_BYTE_STRING (env->isolate (), " href" ))
647
+ .ToLocal (&href)) {
648
+ return Local<String>();
649
+ }
650
+
651
+ if (!url->Get (env->context (),
652
+ FIXED_ONE_BYTE_STRING (env->isolate (), " protocol" ))
653
+ .ToLocal (&protocol)) {
654
+ return Local<String>();
655
+ }
656
+
657
+ if (!href->IsString () || !protocol->IsString ()) {
658
+ return Local<String>();
659
+ }
660
+
661
+ std::string protocol_v =
662
+ Utf8Value (env->isolate (), protocol.As <String>()).ToString ();
663
+ if (protocol_v != " file:" ) {
664
+ THROW_ERR_INVALID_URL_SCHEME (env->isolate ());
665
+ return Local<String>();
666
+ }
667
+
668
+ return href.As <String>();
591
669
}
592
670
593
671
void DatabaseSync::New (const FunctionCallbackInfo<Value>& args) {
@@ -598,47 +676,20 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
598
676
return ;
599
677
}
600
678
601
- Local<Value> path = args[0 ]; // if object, it's a URL, so path will be the
602
- // "href" property then i can check the scheme
603
- // and if it's not file, throw an error
604
- if (!path->IsString () && !path->IsUint8Array () && !IsURL (path)) {
679
+ Local<Value> path = args[0 ];
680
+ if (!path->IsString () && !path->IsUint8Array () && !IsURL (env, path)) {
605
681
THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
606
- " The \" path \" argument must be a string, "
682
+ " The \" location \" argument must be a string, "
607
683
" Uint8Array, or URL without null bytes." );
608
684
return ;
609
685
}
610
686
611
- std::string location;
612
- if (path->IsUint8Array ()) {
613
- Local<Uint8Array> buffer = path.As <Uint8Array>();
614
- size_t byteOffset = buffer->ByteOffset ();
615
- size_t byteLength = buffer->ByteLength ();
616
- if (byteLength == 0 ) {
617
- THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
618
- " The \" path\" argument must not be empty." );
619
- return ;
620
- }
621
-
622
- auto data =
623
- static_cast <const uint8_t *>(buffer->Buffer ()->Data ()) + byteOffset;
624
- if (std::find (data, data + byteLength, 0 ) != data + byteLength) {
625
- THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
626
- " The \" path\" argument must not contain null "
627
- " bytes." );
628
- return ;
629
- }
630
-
631
- location = std::string (reinterpret_cast <const char *>(data), byteLength);
632
- } else {
633
- location = Utf8Value (env->isolate (), args[0 ].As <String>()).ToString ();
687
+ Local<String> path_str = ToPathIfURL (env, path);
688
+ if (path_str.IsEmpty ()) {
689
+ return ;
634
690
}
635
691
636
- // TODO: uncomment this we still need to handle URLs
637
- /* auto parsed_url = ada::parse<ada::url_aggregator>(location, nullptr); */
638
- /* if (parsed_url && parsed_url->type != ada::scheme::FILE) { */
639
- /* THROW_ERR_INVALID_URL_SCHEME(env->isolate()); */
640
- /* } */
641
-
692
+ std::string location = Utf8Value (env->isolate (), path_str).ToString ();
642
693
DatabaseOpenConfiguration open_config (std::move (location));
643
694
bool open = true ;
644
695
bool allow_load_extension = false ;
@@ -1020,17 +1071,23 @@ void Backup(const FunctionCallbackInfo<Value>& args) {
1020
1071
DatabaseSync* db;
1021
1072
ASSIGN_OR_RETURN_UNWRAP (&db, args[0 ].As <Object>());
1022
1073
THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
1023
- if (!args[1 ]->IsString ()) {
1024
- THROW_ERR_INVALID_ARG_TYPE (
1025
- env->isolate (), " The \" destination\" argument must be a string." );
1074
+ Local<Value> path = args[1 ];
1075
+ if (!path->IsString () && !path->IsUint8Array () && !IsURL (env, path)) {
1076
+ THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
1077
+ " The \" destination\" argument must be a string, "
1078
+ " Uint8Array, or URL without null bytes." );
1079
+ return ;
1080
+ }
1081
+
1082
+ Local<String> path_str = ToPathIfURL (env, path);
1083
+ if (path_str.IsEmpty ()) {
1026
1084
return ;
1027
1085
}
1028
1086
1029
1087
int rate = 100 ;
1030
1088
std::string source_db = " main" ;
1031
1089
std::string dest_db = " main" ;
1032
-
1033
- Utf8Value dest_path (env->isolate (), args[1 ].As <String>());
1090
+ Utf8Value dest_path (env->isolate (), path_str);
1034
1091
Local<Function> progressFunc = Local<Function>();
1035
1092
1036
1093
if (args.Length () > 2 ) {
0 commit comments