Simple-Web-Server
Simple-Web-Server copied to clipboard
Does it support upload/download file?
Does it support upload/download file?
The default resource example shows one way to downloads files. For upload, you'd have to create a post resource that handles this. This library is quite low level in order to keep it simple and make it easy for developers to change it or improve it according to their need.
Thanks for your reply, but we are not familiar with web server programming, it's possible require you add "upload file" feature then we can pay for it or donate for this project.
We just need the upload file example or a low level handler for it :)
BR,
It is not that hard actually, just read a set number of bytes from the request->content stream and store it in a file using write with the byte buffer received from the request->content stream. In a way, the reverse of the default_resource example. I do not have time to make this example sorry!
But when I think about it, I would not use this library to upload large files, since the request->content stream would have the entire file stored in memory.
Thanks!
We should actually add a max Content-Length variable, and not accept larger posts than that variable.
I added a new file to support upload file, and add a max Content-Length variable: if (content_length > max_content_length) {//not accept larger posts than max_content_length if (timeout_content > 0) timer->cancel(); find_resource(socket, request); return; } But when the content_length > max_content_length, will return a error page: The connection was reset The connection to the server was reset while the page was loading.
The site could be temporarily unavailable or too busy. Try again in a few moments.
If you are unable to load any pages, check your computer's network connection.
If your computer or network is protected by a firewall or proxy, make sure that Firefox is permitted to access the Web.
How to process when content_length > max_content_length>? I has send a Pull requests about upload file.
Does the server support handling chunked transfer?
@Lucas-W No chunked transfer would have to be implemented by you on top of Simple-Web-Server. See the default_resource example on how to send a file piece by piece. One could extend this example to include chunked transfer.
I write the upload method like this:
server.resource["^/upload"]["POST"] = [](shared_ptrHttpServer::Response response, shared_ptrHttpServer::Requestrequest) {
//auto ifs = make_shared
*response << "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin:*\r\nContent-Type:application/x-jpg" << "\r\n\r\n";
};
but,the save file is not right ,who can solve this problem
I would just suggest to be carefull when using "Access-Control-Allow-Origin:*". There's no point of using it here, this suggest you've generalised its usage and this sound like a bad idea.
I have the some problem too. When I try to post a file and the request->content.rdbuf() is mixed with form content. Like
-----------------------------1780600374882607152068485472 Content-Disposition: form-data; name="upload"; filename="u=3770957164,2342922209&fm=27&gp=0.jpg" Content-Type: image/jpeg
@yangruixuan This is due to the form
attribute enctype="multipart/form-data"
(you can read more about this in https://tools.ietf.org/html/rfc7578). You would have to decode this yourself at the moment. Not sure if we should support this encoding, that is, if it is part of the scope of this project, but I'll give it some more thought.
Accepting posted file(s) from a web browser was a bit more complex than I initially thought. This is due to the strange multipart/form-data
that needs to be supported. Why this standard does not include length of file is strange and adds to the complexity, but anyway, here is an example supporting both text/binary files in a decent way using the latest master (please test before production use):
#include "server_http.hpp"
typedef SimpleWeb::Server<SimpleWeb::HTTP> HttpServer;
int main() {
HttpServer server;
server.config.port = 8080;
server.default_resource["GET"] = [](std::shared_ptr<HttpServer::Response> response, std::shared_ptr<HttpServer::Request> /*request*/) {
response->write(R"(<html>
<body>
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" multiple>
<input type="submit">
</form>
</body>
</html>
)");
};
server.resource["/upload"]["POST"] = [](std::shared_ptr<HttpServer::Response> response, std::shared_ptr<HttpServer::Request> request) {
std::string buffer;
buffer.resize(131072);
std::string boundary;
if(!getline(request->content, boundary)) {
response->write(SimpleWeb::StatusCode::client_error_bad_request);
return;
}
// go through all content parts
while(true) {
std::stringstream file; // std::stringstream is used as example output type
std::string filename;
auto header = SimpleWeb::HttpHeader::parse(request->content);
auto header_it = header.find("Content-Disposition");
if(header_it != header.end()) {
auto content_disposition_attributes = SimpleWeb::HttpHeader::FieldValue::SemicolonSeparatedAttributes::parse(header_it->second);
auto filename_it = content_disposition_attributes.find("filename");
if(filename_it != content_disposition_attributes.end()) {
filename = filename_it->second;
bool add_newline_next = false; // there is an extra newline before content boundary, this avoids adding this extra newline to file
// store file content in variable file
while(true) {
request->content.getline(&buffer[0], static_cast<std::streamsize>(buffer.size()));
if(request->content.eof()) {
response->write(SimpleWeb::StatusCode::client_error_bad_request);
return;
}
auto size = request->content.gcount();
if(size >= 2 && (static_cast<size_t>(size - 1) == boundary.size() || static_cast<size_t>(size - 1) == boundary.size() + 2) && // last boundary ends with: --
std::strncmp(buffer.c_str(), boundary.c_str(), boundary.size() - 1 /*ignore \r*/) == 0 &&
buffer[static_cast<size_t>(size) - 2] == '\r') // buffer must also include \r at end
break;
if(add_newline_next) {
file.put('\n');
add_newline_next = false;
}
if(!request->content.fail()) { // got line or section that ended with newline
file.write(buffer.c_str(), size - 1); // size includes newline character, but buffer does not
add_newline_next = true;
}
else
file.write(buffer.c_str(), size);
request->content.clear(); // clear stream state
}
std::cout << "filename: " << filename << std::endl
<< "file content:" << std::endl
<< file.str() << std::endl;
}
}
else { // no more parts
response->write(); // Write empty success response
return;
}
}
};
server.start();
}
edit: HttpHeader::FieldValue::SemicolonSeparated renamed to HttpHeader::FieldValue::SemicolonSeparatedAttributes, and the returned attribute values from parse
are now also percent-decoded
Great job! Thanks!