@@ -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" ,
@@ -987,6 +997,28 @@ static uint8_t _hex2nibble(char h) {
987
997
return h - 'a' + 0xa ;
988
998
}
989
999
1000
+ // Decode percent encoding in place. Only do this once on a string!
1001
+ static void _decode_percents (char * str ) {
1002
+ size_t o = 0 ;
1003
+ size_t i = 0 ;
1004
+ size_t startlen = strlen (str );
1005
+ while (i < startlen ) {
1006
+ if (str [i ] == '%' ) {
1007
+ str [o ] = _hex2nibble (str [i + 1 ]) << 4 | _hex2nibble (str [i + 2 ]);
1008
+ i += 3 ;
1009
+ } else {
1010
+ if (i != o ) {
1011
+ str [o ] = str [i ];
1012
+ }
1013
+ i += 1 ;
1014
+ }
1015
+ o += 1 ;
1016
+ }
1017
+ if (o < i ) {
1018
+ str [o ] = '\0' ;
1019
+ }
1020
+ }
1021
+
990
1022
static bool _reply (socketpool_socket_obj_t * socket , _request * request ) {
991
1023
if (request -> redirect ) {
992
1024
_reply_redirect (socket , request , request -> path );
@@ -1007,23 +1039,8 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
1007
1039
// Decode any percent encoded bytes so that we're left with UTF-8.
1008
1040
// We only do this on /fs/ paths and after redirect so that any
1009
1041
// path echoing we do stays encoded.
1010
- size_t o = 0 ;
1011
- size_t i = 0 ;
1012
- while (i < strlen (request -> path )) {
1013
- if (request -> path [i ] == '%' ) {
1014
- request -> path [o ] = _hex2nibble (request -> path [i + 1 ]) << 4 | _hex2nibble (request -> path [i + 2 ]);
1015
- i += 3 ;
1016
- } else {
1017
- if (i != o ) {
1018
- request -> path [o ] = request -> path [i ];
1019
- }
1020
- i += 1 ;
1021
- }
1022
- o += 1 ;
1023
- }
1024
- if (o < i ) {
1025
- request -> path [o ] = '\0' ;
1026
- }
1042
+ _decode_percents (request -> path );
1043
+
1027
1044
char * path = request -> path + 3 ;
1028
1045
size_t pathlen = strlen (path );
1029
1046
FATFS * fs = filesystem_circuitpy ();
@@ -1067,6 +1084,34 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
1067
1084
_reply_no_content (socket , request );
1068
1085
return true;
1069
1086
}
1087
+ } else if (strcasecmp (request -> method , "MOVE" ) == 0 ) {
1088
+ if (_usb_active ()) {
1089
+ _reply_conflict (socket , request );
1090
+ return false;
1091
+ }
1092
+
1093
+ _decode_percents (request -> destination );
1094
+ char * destination = request -> destination + 3 ;
1095
+ size_t destinationlen = strlen (destination );
1096
+ if (destination [destinationlen - 1 ] == '/' && destinationlen > 1 ) {
1097
+ destination [destinationlen - 1 ] = '\0' ;
1098
+ }
1099
+
1100
+ FRESULT result = f_rename (fs , path , destination );
1101
+ #if CIRCUITPY_USB_MSC
1102
+ usb_msc_unlock ();
1103
+ #endif
1104
+ if (result == FR_EXIST ) { // File exists and won't be overwritten.
1105
+ _reply_precondition_failed (socket , request );
1106
+ } else if (result == FR_NO_PATH || result == FR_NO_FILE ) { // Missing higher directories or target file.
1107
+ _reply_missing (socket , request );
1108
+ } else if (result != FR_OK ) {
1109
+ ESP_LOGE (TAG , "move error %d %s" , result , path );
1110
+ _reply_server_error (socket , request );
1111
+ } else {
1112
+ _reply_created (socket , request );
1113
+ return true;
1114
+ }
1070
1115
} else if (directory ) {
1071
1116
if (strcasecmp (request -> method , "GET" ) == 0 ) {
1072
1117
FF_DIR dir ;
@@ -1321,6 +1366,8 @@ static void _process_request(socketpool_socket_obj_t *socket, _request *request)
1321
1366
} else if (strcasecmp (request -> header_key , "Sec-WebSocket-Key" ) == 0 &&
1322
1367
strlen (request -> header_value ) == 24 ) {
1323
1368
strcpy (request -> websocket_key , request -> header_value );
1369
+ } else if (strcasecmp (request -> header_key , "X-Destination" ) == 0 ) {
1370
+ strcpy (request -> destination , request -> header_value );
1324
1371
}
1325
1372
ESP_LOGI (TAG , "Header %s %s" , request -> header_key , request -> header_value );
1326
1373
} else if (request -> offset > sizeof (request -> header_value ) - 1 ) {
0 commit comments