@@ -78,8 +78,9 @@ typedef struct {
78
78
enum request_state state ;
79
79
char method [8 ];
80
80
char path [256 ];
81
+ char destination [256 ];
81
82
char header_key [64 ];
82
- char header_value [64 ];
83
+ char header_value [256 ];
83
84
// We store the origin so we can reply back with it.
84
85
char origin [64 ];
85
86
size_t content_length ;
@@ -553,6 +554,15 @@ static void _reply_conflict(socketpool_socket_obj_t *socket, _request *request)
553
554
_send_str (socket , "\r\nUSB storage active." );
554
555
}
555
556
557
+
558
+ static void _reply_precondition_failed (socketpool_socket_obj_t * socket , _request * request ) {
559
+ _send_strs (socket ,
560
+ "HTTP/1.1 412 Precondition Failed\r\n" ,
561
+ "Content-Length: 0\r\n" , NULL );
562
+ _cors_header (socket , request );
563
+ _send_str (socket , "\r\n" );
564
+ }
565
+
556
566
static void _reply_payload_too_large (socketpool_socket_obj_t * socket , _request * request ) {
557
567
_send_strs (socket ,
558
568
"HTTP/1.1 413 Payload Too Large\r\n" ,
@@ -986,6 +996,28 @@ static uint8_t _hex2nibble(char h) {
986
996
return h - 'a' + 0xa ;
987
997
}
988
998
999
+ // Decode percent encoding in place. Only do this once on a string!
1000
+ static void _decode_percents (char * str ) {
1001
+ size_t o = 0 ;
1002
+ size_t i = 0 ;
1003
+ size_t startlen = strlen (str );
1004
+ while (i < startlen ) {
1005
+ if (str [i ] == '%' ) {
1006
+ str [o ] = _hex2nibble (str [i + 1 ]) << 4 | _hex2nibble (str [i + 2 ]);
1007
+ i += 3 ;
1008
+ } else {
1009
+ if (i != o ) {
1010
+ str [o ] = str [i ];
1011
+ }
1012
+ i += 1 ;
1013
+ }
1014
+ o += 1 ;
1015
+ }
1016
+ if (o < i ) {
1017
+ str [o ] = '\0' ;
1018
+ }
1019
+ }
1020
+
989
1021
static bool _reply (socketpool_socket_obj_t * socket , _request * request ) {
990
1022
if (request -> redirect ) {
991
1023
_reply_redirect (socket , request , request -> path );
@@ -1006,23 +1038,8 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
1006
1038
// Decode any percent encoded bytes so that we're left with UTF-8.
1007
1039
// We only do this on /fs/ paths and after redirect so that any
1008
1040
// path echoing we do stays encoded.
1009
- size_t o = 0 ;
1010
- size_t i = 0 ;
1011
- while (i < strlen (request -> path )) {
1012
- if (request -> path [i ] == '%' ) {
1013
- request -> path [o ] = _hex2nibble (request -> path [i + 1 ]) << 4 | _hex2nibble (request -> path [i + 2 ]);
1014
- i += 3 ;
1015
- } else {
1016
- if (i != o ) {
1017
- request -> path [o ] = request -> path [i ];
1018
- }
1019
- i += 1 ;
1020
- }
1021
- o += 1 ;
1022
- }
1023
- if (o < i ) {
1024
- request -> path [o ] = '\0' ;
1025
- }
1041
+ _decode_percents (request -> path );
1042
+
1026
1043
char * path = request -> path + 3 ;
1027
1044
size_t pathlen = strlen (path );
1028
1045
FATFS * fs = filesystem_circuitpy ();
@@ -1066,6 +1083,34 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
1066
1083
_reply_no_content (socket , request );
1067
1084
return true;
1068
1085
}
1086
+ } else if (strcasecmp (request -> method , "MOVE" ) == 0 ) {
1087
+ if (_usb_active ()) {
1088
+ _reply_conflict (socket , request );
1089
+ return false;
1090
+ }
1091
+
1092
+ _decode_percents (request -> destination );
1093
+ char * destination = request -> destination + 3 ;
1094
+ size_t destinationlen = strlen (destination );
1095
+ if (destination [destinationlen - 1 ] == '/' && destinationlen > 1 ) {
1096
+ destination [destinationlen - 1 ] = '\0' ;
1097
+ }
1098
+
1099
+ FRESULT result = f_rename (fs , path , destination );
1100
+ #if CIRCUITPY_USB_MSC
1101
+ usb_msc_unlock ();
1102
+ #endif
1103
+ if (result == FR_EXIST ) { // File exists and won't be overwritten.
1104
+ _reply_precondition_failed (socket , request );
1105
+ } else if (result == FR_NO_PATH || result == FR_NO_FILE ) { // Missing higher directories or target file.
1106
+ _reply_missing (socket , request );
1107
+ } else if (result != FR_OK ) {
1108
+ ESP_LOGE (TAG , "move error %d %s" , result , path );
1109
+ _reply_server_error (socket , request );
1110
+ } else {
1111
+ _reply_created (socket , request );
1112
+ return true;
1113
+ }
1069
1114
} else if (directory ) {
1070
1115
if (strcasecmp (request -> method , "GET" ) == 0 ) {
1071
1116
FF_DIR dir ;
@@ -1318,6 +1363,8 @@ static void _process_request(socketpool_socket_obj_t *socket, _request *request)
1318
1363
} else if (strcasecmp (request -> header_key , "Sec-WebSocket-Key" ) == 0 &&
1319
1364
strlen (request -> header_value ) == 24 ) {
1320
1365
strcpy (request -> websocket_key , request -> header_value );
1366
+ } else if (strcasecmp (request -> header_key , "X-Destination" ) == 0 ) {
1367
+ strcpy (request -> destination , request -> header_value );
1321
1368
}
1322
1369
ESP_LOGI (TAG , "Header %s %s" , request -> header_key , request -> header_value );
1323
1370
} else if (request -> offset > sizeof (request -> header_value ) - 1 ) {
0 commit comments