Skip to content

Commit

Permalink
Some improvements to multipart parser (#2007)
Browse files Browse the repository at this point in the history
This PR addresses some issues with the current multipart parser implementation.
- Allow part headers to span multiple TCP packets (similar to how HTTP headers are handled). It is very unlikely for this issue to occur for requests with only one part, since all the headers are probably part of the first TCP packet. However, requests with multiple parts may fail randomly if a part header just happens to span across a TCP packet boundary. 
- Allow construction of the ``MultipartParser`` instance to fail, e.g. when the 'boundary' part of the Content-Type header is missing.
- Make parser state (``multipart_parser_t``) a member of ``MultipartParser`` to avoid additional dynamic memory allocation.
- Allow (and ignore) preamble data. Although preamble data is rarely used in practice, it has been [observed](civetweb/civetweb#470) that some clients add an additional newline before the message body, which, technically, qualifies as preamble data.

[scan:coverity]
  • Loading branch information
aemseemann authored and slaff committed Jan 5, 2020
1 parent 41d03e8 commit ca120a3
Show file tree
Hide file tree
Showing 19 changed files with 471 additions and 219 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
url = https://github.com/jacketizer/libyuarel.git
ignore = dirty
[submodule "multipart-parser"]
path = Sming/Components/MultipartParser/multipart-parser
path = Sming/Libraries/MultipartParser/multipart-parser
url = https://github.com/iafonov/multipart-parser-c.git
ignore = dirty
[submodule "FlashString"]
Expand Down
4 changes: 0 additions & 4 deletions Sming/Components/MultipartParser/README.rst

This file was deleted.

139 changes: 0 additions & 139 deletions Sming/Components/MultipartParser/multipart-parser.patch

This file was deleted.

7 changes: 0 additions & 7 deletions Sming/Core/Network/HttpServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@
#include "TcpClient.h"
#include "WString.h"

#ifdef ENABLE_HTTP_SERVER_MULTIPART
#include <MultipartParser/MultipartParser.h>
#endif

void HttpServer::configure(const HttpServerSettings& settings)
{
this->settings = settings;
Expand All @@ -27,9 +23,6 @@ void HttpServer::configure(const HttpServerSettings& settings)

if(settings.useDefaultBodyParsers) {
setBodyParser(MIME_FORM_URL_ENCODED, formUrlParser);
#ifdef ENABLE_HTTP_SERVER_MULTIPART
setBodyParser(MIME_FORM_MULTIPART, formMultipartParser);
#endif
}

setKeepAlive(settings.keepAliveSeconds);
Expand Down
74 changes: 74 additions & 0 deletions Sming/Libraries/MultipartParser/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
Multipart Parser
================

Component to manage processing of multipart form data according to
`RFC7578 <https://tools.ietf.org/html/rfc7578>`_, mostly used to support file
uploads via HTTP/POST.

Usage
-----

While setting up your web server, register the body parser provided by the
library:

.. code-block:: c++

#include <MultipartParser.h>

HttpServer server;
...

server.setBodyParser(MIME_FORM_MULTIPART, formMultipartParser);

Now add a :cpp:class:`HttpMultipartResource` for the path to receive the multipart data:

.. code-block:: c++

void fileUploadMapper(HttpFiles& files)
{
files["file"] = <writable_stream_to_process_file>;
}

int onUpload(HttpServerConnection& connection, HttpRequest& request, HttpResponse& response)
{
// `file` points to the stream from `fileUploadMapper`.
auto* file = request.files["file"];

// TODO: use methods of `file` to check if data was processed successfully

// TODO: setup HTTP response

return 0;
}

...

server.paths.set("/upload", new HttpMultipartResource(fileUploadMapper, onUpload));


See :sample:`HttpServer_FirmwareUpload` for further details.

Upgrade Notes
-------------

The functionality provided by this lirbary was previously controlled by the config option
`ENABLE_HTTP_SERVER_MULTIPART`.

To upgrade, you have to replace::

ENABLE_HTTP_SERVER_MULTIPART := 1

by::
ARDUINO_LIBRARIES += MultipartParser

in your `component.mk`. In addition, body parser registration must now be done explicitly by
application (see above).

API Documentation
-----------------

.. toctree::
:maxdepth: 1

api
5 changes: 5 additions & 0 deletions Sming/Libraries/MultipartParser/api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
MultipartParser API
===================

.. doxygenfunction:: formMultipartParser
.. doxygenclass:: HttpMultipartResource
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
COMPONENT_SRCDIRS := src
COMPONENT_INCDIRS := src
COMPONENT_DOXYGEN_INPUT := src

COMPONENT_SUBMODULES := multipart-parser
COMPONENT_SRCFILES := multipart-parser/multipart_parser.c
Loading

0 comments on commit ca120a3

Please sign in to comment.