├── UDHttp ├── library.properties ├── keywords.txt ├── src │ ├── UDHttp.h │ └── UDHttp.cpp └── examples │ └── esp32udhttp │ └── esp32udhttp.ino ├── README.md └── upload.php /UDHttp/library.properties: -------------------------------------------------------------------------------- 1 | name=UDHttp 2 | version=1.0.0 3 | author=iotsharing.com 4 | maintainer=https://github.com/nhatuan84 5 | sentence=ESP32 upload and download file 6 | paragraph=ESP32 upload and download file 7 | category=Communication 8 | url=iotsharing.com 9 | architectures=esp32 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp-upload-download-file-http 2 | This library supports upload multipart and download file via http 3 | Full demo at iotsharing.com 4 | 5 | Demo 39: ESP32/8266 multipart upload a file and download a file via HTTP 6 | 7 | http://www.iotsharing.com/2018/01/esp32-multipart-upload-file-and-download-via-http.html 8 | -------------------------------------------------------------------------------- /upload.php: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /UDHttp/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map UDHttp 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | UDHttp KEYWORD1 UDHttp 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | upload KEYWORD2 15 | download KEYWORD2 16 | ####################################### 17 | # Constants (LITERAL1) 18 | ####################################### 19 | -------------------------------------------------------------------------------- /UDHttp/src/UDHttp.h: -------------------------------------------------------------------------------- 1 | /* 2 | Tuan Nguyen (http://www.iotsharing.com) or (nha.tuan84@gmail.com) 3 | */ 4 | 5 | #ifndef UDHTTP_H 6 | #define UDHTTP_H 7 | 8 | #include 9 | #include 10 | 11 | #define HEADER_SIZE 500 12 | #define CHUNK_SIZE 100 13 | #define HOST_LEN 200 14 | //callback that will be invoked whenever data is available 15 | typedef int (*DataCb)(uint8_t *buffer, int len); 16 | typedef void (*ProgressCb)(int percent); 17 | 18 | class UDHttp 19 | { 20 | private: 21 | void sendChunk(Client *client, uint8_t *buf, int len); 22 | int simpleUrlParser(char *url, char *host, int &port); 23 | public: 24 | UDHttp(); 25 | ~UDHttp(); 26 | int upload(char *uploadUrlHandler, char *fileName, int sizeOfFile, DataCb dataCb, ProgressCb progressCb, DataCb responseCb); 27 | int download(char *downloadUrl, char *downloadFile, DataCb dataCb, ProgressCb progressCb); 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /UDHttp/examples/esp32udhttp/esp32udhttp.ino: -------------------------------------------------------------------------------- 1 | #include "UDHttp.h" 2 | #include "mySD.h" 3 | 4 | 5 | const char* ssid = "dd-wrt"; 6 | const char* password = "0000000000"; 7 | 8 | File root; 9 | //these callbacks will be invoked to read and write data to sdcard 10 | //and process response 11 | //and showing progress 12 | int responsef(uint8_t *buffer, int len){ 13 | Serial.printf("%s\n", buffer); 14 | return 0; 15 | } 16 | 17 | int rdataf(uint8_t *buffer, int len){ 18 | //read file to upload 19 | if (root.available()) { 20 | return root.read(buffer, len); 21 | } 22 | return 0; 23 | } 24 | 25 | int wdataf(uint8_t *buffer, int len){ 26 | //write downloaded data to file 27 | return root.write(buffer, len); 28 | } 29 | 30 | void progressf(int percent){ 31 | Serial.printf("%d\n", percent); 32 | } 33 | 34 | void setup() { 35 | // put your setup code here, to run once: 36 | Serial.begin(115200); 37 | 38 | WiFi.begin(ssid, password); 39 | 40 | while (WiFi.status() != WL_CONNECTED) { 41 | delay(500); 42 | Serial.print("."); 43 | } 44 | 45 | Serial.println(""); 46 | Serial.println("WiFi connected"); 47 | Serial.println("IP address: "); 48 | Serial.println(WiFi.localIP()); 49 | 50 | Serial.print("Initializing SD card..."); 51 | if (!SD.begin(32, 14, 12, 27)) { 52 | Serial.println("initialization failed!"); 53 | return; 54 | } 55 | Serial.println("initialization done."); 56 | 57 | while(1){ 58 | SD.remove("test.mp3"); 59 | UDHttp udh; 60 | //open file on sdcard to write 61 | root = SD.open("test.mp3", FILE_WRITE); 62 | if (!root) { 63 | Serial.println("can not open file!"); 64 | return; 65 | } 66 | //download the file from url 67 | int r = udh.download("http://192.168.1.3/audio.mp3", "audio.mp3", wdataf, progressf); 68 | if(r == -1) 69 | { 70 | Serial.println("error"); 71 | } 72 | else 73 | { 74 | root.close(); 75 | break; 76 | } 77 | root.close(); 78 | Serial.printf("try downloading again\n"); 79 | delay(1000); 80 | } 81 | Serial.printf("done downloading\n"); 82 | { 83 | UDHttp udh; 84 | //open file on sdcard to read 85 | root = SD.open("test.pdf"); 86 | if (!root) { 87 | Serial.println("can not open file!"); 88 | return; 89 | } 90 | //upload downloaded file to local server 91 | udh.upload("http://192.168.1.107:80/upload/upload.php", "test.pdf", root.size(), rdataf, progressf, responsef); 92 | root.close(); 93 | Serial.printf("done uploading\n"); 94 | } 95 | } 96 | 97 | void loop() { 98 | // put your main code here, to run repeatedly: 99 | 100 | } 101 | -------------------------------------------------------------------------------- /UDHttp/src/UDHttp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Tuan Nguyen (http://www.iotsharing.com) or (nha.tuan84@gmail.com) 3 | */ 4 | 5 | #include "UDHttp.h" 6 | #include 7 | #include 8 | 9 | #define HEADER "POST %s HTTP/1.1\r\n" \ 10 | "Host: %s:%d\r\n"\ 11 | "Connection: keep-alive\r\n"\ 12 | "Accept: */*\r\n"\ 13 | "Content-Length: %d\r\n"\ 14 | "Expect: \r\n"\ 15 | "Content-Type: multipart/form-data; boundary=------------------------%s\r\n\r\n" 16 | #define OPEN "--------------------------%s\r\n"\ 17 | "Content-Disposition: form-data; name='data'; filename='%s'\r\n"\ 18 | "Content-Type: application/octet-stream\r\n\r\n" 19 | #define CLOSE "\r\n--------------------------%s--\r\n" 20 | 21 | #define GETR "GET %s HTTP/1.1\r\nHost: %s:%d\r\nAccept: */*\r\n\r\n" 22 | 23 | UDHttp::UDHttp(){ 24 | } 25 | 26 | UDHttp::~UDHttp(){ 27 | } 28 | //simple url parser 29 | int UDHttp::simpleUrlParser(char *url, char *host, int &port){ 30 | char *tmp = strstr(url, "http://"); 31 | port = 80; 32 | char cport[6]; 33 | char *tmp2; 34 | char *tmp3; 35 | if(tmp != NULL && host != NULL){ 36 | tmp2 = tmp + strlen("http://"); 37 | tmp = strchr(tmp2, '/'); 38 | if(tmp != NULL){ 39 | tmp3 = strchr(tmp2, ':'); 40 | if(tmp3 == NULL) { 41 | int len = tmp - tmp2; 42 | if(len < HOST_LEN){ 43 | memcpy(host, tmp2, len); 44 | return 0; 45 | } 46 | printf("increase HOST_LEN\n"); 47 | } else { 48 | int len = tmp3 - tmp2; 49 | if(len < HOST_LEN){ 50 | memcpy(host, tmp2, len); 51 | memset(cport, 0, 6); 52 | memcpy(cport, tmp3+1, tmp- (tmp3+1)); 53 | port = atoi(cport); 54 | return 0; 55 | } 56 | printf("increase HOST_LEN\n"); 57 | } 58 | } 59 | } 60 | return -1; 61 | } 62 | 63 | void UDHttp::sendChunk(Client *client, uint8_t *buf, int len){ 64 | int idx = 0; 65 | size_t result; 66 | while(len > 0){ 67 | if(len < CHUNK_SIZE){ 68 | result = client->write(&buf[idx], len); 69 | len -= result; 70 | idx += result; 71 | } else { 72 | result = client->write(&buf[idx], CHUNK_SIZE); 73 | len -= result; 74 | idx += result; 75 | } 76 | } 77 | } 78 | 79 | int UDHttp::upload(char *uploadUrlHandler, char *fileName, int sizeOfFile, DataCb dataCb, ProgressCb progressCb, DataCb responseCb){ 80 | char buf[HEADER_SIZE]; 81 | char host[HOST_LEN]; 82 | int port = 80; 83 | int contentLen; 84 | WiFiClient client; 85 | int result; 86 | int sent = 0; 87 | 88 | if(dataCb == NULL ){ 89 | printf("DataCb or ProgressCb is NULL!\n"); 90 | return -1; 91 | } 92 | //gen key from file name using b64 93 | //String key = base64::encode(String(fileName)); //it make app crash -> fix later 94 | char *key = "aHR0cDovL3d3dy5pb3RzaGFyaW5nLmNvbQ=="; 95 | //very simple url parser 96 | 97 | if((strlen(OPEN) + strlen(key) + strlen(fileName)) > HEADER_SIZE){ 98 | printf("Increase HEADER_SIZE\n"); 99 | return -1; 100 | } 101 | if((strlen(CLOSE) + strlen(key)) > HEADER_SIZE){ 102 | printf("Increase HEADER_SIZE\n"); 103 | return -1; 104 | } 105 | if((strlen(HEADER) + strlen(host) + strlen(key) + 20) > HEADER_SIZE){ 106 | printf("Increase HEADER_SIZE\n"); 107 | return -1; 108 | } 109 | memset(host, 0, HOST_LEN); 110 | if(simpleUrlParser(uploadUrlHandler, host, port) == -1){ 111 | printf("url is wrong\n"); 112 | return -1; 113 | } 114 | //calculate open 115 | memset(buf, 0, HEADER_SIZE); 116 | snprintf(buf, HEADER_SIZE, OPEN, key, fileName); 117 | contentLen = strlen(buf); 118 | //calculate close 119 | memset(buf, 0, HEADER_SIZE); 120 | snprintf(buf, HEADER_SIZE, CLOSE, key); 121 | // content-length 122 | contentLen = contentLen + strlen(buf) + sizeOfFile; 123 | //fill header 124 | memset(buf, 0, HEADER_SIZE); 125 | snprintf(buf, HEADER_SIZE, HEADER, uploadUrlHandler, host, port, contentLen, key); 126 | 127 | if (!client.connect(host, port)) { 128 | printf("Connection failed\n"); 129 | return -1; 130 | } 131 | //send header 132 | sendChunk(&client, (uint8_t *)buf, strlen(buf)); 133 | memset(buf, 0, HEADER_SIZE); 134 | //send open 135 | snprintf(buf, HEADER_SIZE, OPEN, key, fileName); 136 | sendChunk(&client, (uint8_t *)buf, strlen(buf)); 137 | //send data 138 | do{ 139 | result = dataCb((uint8_t *)buf, CHUNK_SIZE); 140 | sendChunk(&client, (uint8_t *)buf, result); 141 | if(progressCb != NULL){ 142 | sent += result; 143 | progressCb(sent*100/sizeOfFile); 144 | } 145 | }while(result >0); 146 | memset(buf, 0, HEADER_SIZE); 147 | snprintf(buf, HEADER_SIZE, CLOSE, key); 148 | sendChunk(&client, (uint8_t *)buf, strlen(buf)); 149 | memset(buf, 0, CHUNK_SIZE); 150 | //process response 151 | while (client.available() > 0){ 152 | int result = client.read((uint8_t *)buf, CHUNK_SIZE); 153 | if(responseCb != NULL && result != -1){ 154 | responseCb((uint8_t *)buf, result); 155 | } 156 | } 157 | return 0; 158 | } 159 | 160 | int UDHttp::download(char *downloadUrl, char *downloadFile, DataCb dataCb, ProgressCb progressCb){ 161 | char buf[HEADER_SIZE]; 162 | char host[HOST_LEN]; 163 | int port = 80; 164 | WiFiClient client; 165 | char num[10]; 166 | unsigned int bytes; 167 | unsigned int received = 0; 168 | char *tmp = NULL; 169 | char *data; 170 | unsigned int total; 171 | unsigned int len = strlen("\r\n\r\n"); 172 | 173 | if(dataCb == NULL){ 174 | printf("DataCb is NULL!\n"); 175 | return -1; 176 | } 177 | if((strlen(GETR) + strlen(downloadUrl)) > HEADER_SIZE){ 178 | printf("Increase HEADER_SIZE\n"); 179 | return -1; 180 | } 181 | memset(buf, 0, HEADER_SIZE); 182 | snprintf(buf, HEADER_SIZE, GETR, downloadFile, host, port); 183 | //parse url 184 | memset(host, 0, HOST_LEN); 185 | if(simpleUrlParser(downloadUrl, host, port) == -1){ 186 | printf("url is wrong\n"); 187 | return -1; 188 | } 189 | if (!client.connect(host, port)) { 190 | printf("Connection failed\n"); 191 | return -1; 192 | } 193 | 194 | sendChunk(&client, (uint8_t *)buf, strlen(buf)); 195 | memset(buf, 0, HEADER_SIZE); 196 | //read response 197 | do { 198 | if(client.available()){ 199 | bytes = client.read((uint8_t *)&buf[received], HEADER_SIZE); 200 | if(bytes != -1){ 201 | received += bytes; 202 | tmp = strstr(buf, "\r\n\r\n"); 203 | } 204 | } 205 | } while (tmp == NULL); 206 | //parse header 207 | data = tmp; 208 | tmp = strstr(buf, "200"); 209 | if(tmp == NULL) 210 | { 211 | return -1; 212 | } 213 | tmp = strstr(buf, "Content-Length: "); 214 | if(tmp == NULL) 215 | { 216 | return -1; 217 | } 218 | char *tmp2 = strstr(tmp, "\r\n"); 219 | memset(num, 0, 10); 220 | int clen = strlen("Content-Length: "); 221 | memcpy(num, tmp+clen, tmp2-tmp-clen); 222 | total = atoi(num); 223 | //start downloading 224 | clen = total; 225 | if(received > (data+len+1-buf)){ 226 | dataCb((uint8_t *)(data+len), received - (data+len-buf)); 227 | total = total - (received - (data+len-buf)); 228 | if(progressCb != NULL){ 229 | progressCb(100*(received - (data+len-buf))/clen); 230 | } 231 | } 232 | if(total == 0) return 0; 233 | clen = total; 234 | received = 0; 235 | do { 236 | bytes = client.read((uint8_t *)buf, HEADER_SIZE); 237 | if(bytes != -1){ 238 | received += bytes; 239 | dataCb((uint8_t *)buf, bytes); 240 | total = total - bytes; 241 | if(progressCb != NULL){ 242 | progressCb(100*received/clen); 243 | } 244 | } 245 | } while (total > 0); 246 | return 0; 247 | } 248 | --------------------------------------------------------------------------------