If found that if I send file via html post form it doesn’t send whole file but only part if the file size is bigger than about 2.5K.
What the max post size for http post request data? Is it configurable?
I don’t see any settings regarding it in the httpd.h
Hi @Tuxford ,
Do you mind sharing the example from the standard SDK that you are running?
And please provide your sdk version as well.
Thanks
Hi @dakamaster
There is a callback that provides a form:
void uploadPageCB(struct httpd_conn *conn)
{
if (httpd_request_is_method(conn, "GET")) {
char *body = "<HTML><BODY>"
"<FORM action=\"/upload.action\" enctype=\"multipart/form-data\" "
"method=\"post\">"
"Directory: <input type=\"text\" name=\"dir\"><br>"
"File: <INPUT type=\"file\" name=\"text1\" size=\"50\" "
"maxlength=\"50\"><BR>"
"<INPUT type=\"submit\" value=\"POST\"><BR>"
"</FORM>"
"</BODY></HTML>";
// write HTTP response
httpd_response_write_header_start(conn, "200 OK", "text/html", strlen(body));
httpd_response_write_header(conn, "Connection", "close");
httpd_response_write_header_finish(conn);
httpd_response_write_data(conn, (uint8_t *)body, strlen(body));
} else {
// HTTP/1.1 405 Method Not Allowed
httpd_response_method_not_allowed(conn, NULL);
}
httpd_conn_close(conn);
}
And this is form content handler callback. It’s quite big before there is no methods for post form data fetching especially files.
void uploadReqCB(struct httpd_conn *conn)
{
if (httpd_request_is_method(conn, "POST")) {
size_t content_len = conn->request.content_len;
uint8_t *body = new uint8_t[content_len + 1];
bool success = true;
if (body) {
// read HTTP body
memset(body, 0, content_len + 1);
char *contentType = NULL;
httpd_request_get_header_field(conn, "Content-Type", &contentType);
httpd_request_read_data(conn, body, content_len);
const std::string boundary = getToken(contentType, "boundary");
httpd_free((char *)contentType);
if (boundary.empty() == true) {
printf("ERROR: No boundary found\n");
success = false;
}
std::string bodyCp((char *)body);
const char *delim = "\r\n";
std::string::size_type pos = bodyCp.find("\r\n", 0);
const std::string bodyBoundary = bodyCp.substr(0, pos);
if (bodyBoundary.empty() == false) {
if (bodyBoundary.find(boundary, 0) == std::string::npos) {
printf("ERROR: Boundary not found\n");
success = false;
}
} else {
printf("ERROR: Wrong body found\n");
success = false;
}
std::string::size_type cddBegin = bodyBoundary.length() + strlen(delim);
std::string::size_type cddEnd = bodyCp.find(bodyBoundary, cddBegin);
const std::string contentDispDir = bodyCp.substr(cddBegin, cddEnd - cddBegin);
const std::string dirName = getValueFromDisposition(contentDispDir);
std::string::size_type cdfBegin = cddEnd + bodyBoundary.length() + strlen(delim);
std::string::size_type cdfEnd = bodyCp.find_first_of(delim, cdfBegin);
std::string contentDispFile = bodyCp.substr(cdfBegin, cdfEnd - cdfBegin);
if (contentDispFile.empty() == true) {
printf("ERROR: Wrong body found\n");
success = false;
}
std::string fileName = getAttrValueFromDisposition(contentDispFile, "filename");
std::string::size_type ctBegin = cdfEnd + strlen(delim);
std::string::size_type ctEnd = bodyCp.find_first_of(delim, cdfEnd + strlen(delim));
std::string ct = bodyCp.substr(ctBegin, ctEnd - ctBegin);
if (ct.empty() == true) {
printf("ERROR: Wrong body found\n");
success = false;
}
const std::string drive = "0:/";
std::string path = drive + dirName + "/" + fileName;
char *contentTypeStart = strstr((char *)body, ct.c_str());
char *dataFileStart = contentTypeStart + ct.length() + 4;
if (contentTypeStart != NULL) {
const char *dataFileEnd = strstr(dataFileStart, boundary.c_str());
printf("#### %s \n ####", (char *)body);
printf("D+++++: %s ----- %s\n", dataFileStart, boundary.c_str());
if (dataFileEnd != NULL) {
UINT fileLen = (UINT)(dataFileEnd - dataFileStart - 4);
dataFileStart[fileLen] = 0;
File::remove(path);
std::shared_ptr<File> fl(new File(path, OpenMode::Write));
ASSERT((fl != nullptr), "File allocation failure");
size_t written = fl->write((uint8_t *)dataFileStart, fileLen);
success = (written == fileLen);
} else {
printf("ERROR: no boundary at the end\n");
success = false;
}
} else {
printf("ERROR: can't find the beginning of the file");
success = false;
}
// write HTTP response
if (success == true) {
const char *message = "File uploaded";
httpd_response_write_header_start(conn, "200 OK", "text/plain", 0);
httpd_response_write_header(conn, "Connection", "close");
httpd_response_write_header_finish(conn);
httpd_response_write_data(conn, (uint8_t *)message, strlen(message));
} else {
const char *message = "File not uploaded";
httpd_response_write_header_start(conn, "200 OK", "text/plain", 0);
httpd_response_write_header(conn, "Connection", "close");
httpd_response_write_header_finish(conn);
httpd_response_write_data(conn, (uint8_t *)message, strlen(message));
}
free(body);
} else {
// HTTP/1.1 500 Internal Server Error
httpd_response_internal_server_error(conn, NULL);
}
} else {
// HTTP/1.1 405 Method Not Allowed
httpd_response_method_not_allowed(conn, NULL);
}
httpd_conn_close(conn);
}
I use this sdk: GitHub - ambiot/ambd_sdk: Release SDK for AmebaD
Branch dev.
Hi @Tuxford,
Upon testing in the 6.2 standard sdk (ambd_sdk) httpd example, there is no issue with HTTP Post of data size larger than 2.5kB, please refer to the screenshot below:
The lines I have modified are:
"Text1: <INPUT type=\"text\" name=\"text1\" size=\"2500\" maxlength=\"2500\"><BR>" \
"Text2: <INPUT type=\"text\" name=\"text2\" size=\"2500\" maxlength=\"2500\"><BR>" \
Besides, I have pasted your code in example_httpd.c
but it failed to compile.
Hi @dakamaster
Everything is fine until I stated using input type “file”. Problem with this type.
Regarding next lines
File::remove(path);
std::shared_ptr<File> fl(new File(path, OpenMode::Write));
ASSERT((fl != nullptr), "File allocation failure");
size_t written = fl->write((uint8_t *)dataFileStart, fileLen);
You can drop it. It implements saving data to disk. For our case it doesn’t have any impact.
I din’t try to upload binary files. I use only text ones.
Hi @Tuxford,
It’s hard for me to reproduce your error since our standard SDK is in the c environment and some of your APIs like getToken
are missing.
Could you please provide a chunk of code that is able to run the functions that you want to achieve?
Meanwhile, do you mind changing the below settings in your own environment to see whether it helps?
-
Increase the size and maxlength of the input file textbox:
File: <INPUT type= "file" name="text1" size= "50" maxlength= "50">
For example: (5000000 bytes = 5 megabytes)<form action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="fileInput" maxlength="5000000"> <input type="submit" value="Upload File"> </form>
-
Modifying macros such as:
HTTPD_LOCAL_LARGE_BUF_LEN
or
httpd_tmp_buf_size
-
Increase the 3rd parameter
strlen(body)
in
httpd_response_write_data(conn, (uint8_t *)body, strlen(body));
Thanks
Hi @dakamaster
Sorry I forgot to give this function and others:
static std::string getToken(const std::string &contentType, const std::string &key)
{
std::string ct = contentType;
const std::string delim = ";= \r\n";
std::string::size_type prevPos = contentType.find_first_not_of(delim);
std::string::size_type pos = contentType.find_first_of(delim, 0);
std::string tok = contentType.substr(prevPos, pos - prevPos);
while (pos != std::string::npos) {
if (tok == key) {
prevPos = contentType.find_first_not_of(delim, pos);
pos = contentType.find_first_of(delim, prevPos);
tok = contentType.substr(prevPos, pos - prevPos);
return tok;
}
prevPos = contentType.find_first_not_of(delim, pos);
pos = contentType.find_first_of(delim, prevPos);
tok = contentType.substr(prevPos, pos - prevPos);
}
return std::string();
}
static std::string getAttrValueFromDisposition(const std::string &contentDsip, const std::string &key)
{
auto AttrValueKeyPos = contentDsip.find(key, 0);
if (AttrValueKeyPos != std::string::npos) {
auto attrBegin = contentDsip.find_first_not_of(" =\"", AttrValueKeyPos + key.length());
auto attrEnd = contentDsip.find_first_of("\"", attrBegin);
auto attrValue = contentDsip.substr(attrBegin, attrEnd - attrBegin);
return attrValue;
}
return std::string();
}
static std::string getValueFromDisposition(const std::string &contentDisp)
{
const char *delim = "\r\n";
std::string value = "&";
auto valBegin = contentDisp.find_first_of(delim, 0);
if (valBegin == std::string::npos) {
return value;
}
valBegin += 2 * strlen(delim);
auto valEnd = contentDisp.find_first_of(delim, valBegin);
if (valEnd == std::string::npos) {
return value;
}
value = contentDisp.substr(valBegin, valEnd - valBegin);
return value;
}
I tried first step and it doesn’t help.
About HTTPD_LOCAL_LARGE_BUF_LEN or httpd_tmp_buf_size
I can’t find those marco.
And about increasing size of data. It gives form without any problems.
<HTML><BODY><FORM action="[/upload.action](view-source:http://192.168.0.100/upload.action)" enctype="multipart/form-data" method="post">Directory: <input type="text" name="dir"><br>File: <INPUT type="file" name="text1" size="50" maxlength="50"><BR><INPUT type="submit" value="POST"><BR></FORM></BODY></HTML>
Yes, I have double-checked that these macros are not being provided in the released ambd_sdk
. You can access these macros only after signing the NDA. A guide for signing NDA from here.
The reason for modifying the maxlength
in your HTML
code is trying to see whether this attribute limits the upload size of your file. As a reference, the html_input_file code from W3School didn’t seem to specify the max length attribute.