130 lines
3.5 KiB
C++
130 lines
3.5 KiB
C++
#include "PsychicUploadHandler.h"
|
|
|
|
PsychicUploadHandler::PsychicUploadHandler() : PsychicWebHandler(), _uploadCallback(nullptr)
|
|
{
|
|
}
|
|
PsychicUploadHandler::~PsychicUploadHandler() {}
|
|
|
|
bool PsychicUploadHandler::canHandle(PsychicRequest* request)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
esp_err_t PsychicUploadHandler::handleRequest(PsychicRequest* request, PsychicResponse* response)
|
|
{
|
|
esp_err_t err = ESP_OK;
|
|
|
|
/* File cannot be larger than a limit */
|
|
if (request->contentLength() > request->server()->maxUploadSize)
|
|
{
|
|
ESP_LOGE(PH_TAG, "File too large : %d bytes", request->contentLength());
|
|
|
|
/* Respond with 400 Bad Request */
|
|
char error[50];
|
|
sprintf(error, "File size must be less than %lu bytes!", request->server()->maxUploadSize);
|
|
return httpd_resp_send_err(request->request(), HTTPD_400_BAD_REQUEST, error);
|
|
}
|
|
|
|
// TODO: support for the 100 header. not sure if we can do it.
|
|
// if (request->header("Expect").equals("100-continue"))
|
|
// {
|
|
// char response[] = "100 Continue";
|
|
// httpd_socket_send(self->server, httpd_req_to_sockfd(req), response, strlen(response), 0);
|
|
// }
|
|
|
|
// 2 types of upload requests
|
|
if (request->isMultipart())
|
|
err = _multipartUploadHandler(request);
|
|
else
|
|
err = _basicUploadHandler(request);
|
|
|
|
// we can also call onRequest for some final processing and response
|
|
if (err == ESP_OK)
|
|
{
|
|
if (_requestCallback != NULL)
|
|
err = _requestCallback(request, response);
|
|
else
|
|
err = response->send("Upload Successful.");
|
|
}
|
|
else if (err == ESP_ERR_HTTPD_INVALID_REQ)
|
|
response->send(400, "text/html", "No multipart boundary found.");
|
|
else
|
|
response->send(500, "text/html", "Error processing upload.");
|
|
|
|
return err;
|
|
}
|
|
|
|
esp_err_t PsychicUploadHandler::_basicUploadHandler(PsychicRequest* request)
|
|
{
|
|
esp_err_t err = ESP_OK;
|
|
|
|
String filename = request->getFilename();
|
|
|
|
/* Retrieve the pointer to scratch buffer for temporary storage */
|
|
char* buf = (char*)malloc(FILE_CHUNK_SIZE);
|
|
int received;
|
|
unsigned long index = 0;
|
|
|
|
/* Content length of the request gives the size of the file being uploaded */
|
|
int remaining = request->contentLength();
|
|
|
|
while (remaining > 0)
|
|
{
|
|
#ifdef ENABLE_ASYNC
|
|
httpd_sess_update_lru_counter(request->server()->server, request->client()->socket());
|
|
#endif
|
|
|
|
// ESP_LOGD(PH_TAG, "Remaining size : %d", remaining);
|
|
|
|
/* Receive the file part by part into a buffer */
|
|
if ((received = httpd_req_recv(request->request(), buf, min(remaining, FILE_CHUNK_SIZE))) <= 0)
|
|
{
|
|
/* Retry if timeout occurred */
|
|
if (received == HTTPD_SOCK_ERR_TIMEOUT)
|
|
continue;
|
|
// bail if we got an error
|
|
else if (received == HTTPD_SOCK_ERR_FAIL)
|
|
{
|
|
ESP_LOGE(PH_TAG, "Socket error");
|
|
err = ESP_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// call our upload callback here.
|
|
if (_uploadCallback != NULL)
|
|
{
|
|
err = _uploadCallback(request, filename, index, (uint8_t*)buf, received, (remaining - received == 0));
|
|
if (err != ESP_OK)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ESP_LOGE(PH_TAG, "No upload callback specified!");
|
|
err = ESP_FAIL;
|
|
break;
|
|
}
|
|
|
|
/* Keep track of remaining size of the file left to be uploaded */
|
|
remaining -= received;
|
|
index += received;
|
|
}
|
|
|
|
// dont forget to free our buffer
|
|
free(buf);
|
|
|
|
return err;
|
|
}
|
|
|
|
esp_err_t PsychicUploadHandler::_multipartUploadHandler(PsychicRequest* request)
|
|
{
|
|
MultipartProcessor mpp(request, _uploadCallback);
|
|
return mpp.process();
|
|
}
|
|
|
|
PsychicUploadHandler* PsychicUploadHandler::onUpload(PsychicUploadCallback fn)
|
|
{
|
|
_uploadCallback = fn;
|
|
return this;
|
|
}
|