I mainly focused on generating a multipart message this week.
I was using
curl to send a multipart formpost previously. For example,
curl -kv -F 'lang=vlog' -F '[email protected]' http://127.0.0.4:8080/api/v19/workspace.elaborate was used to transfer data to a server. The request body was shown below. (Note: A boundary was a string of random numbers.)
--MIME_boundary_2CA6E12165908974 Content-Disposition: form-data; name="lang" vlog --MIME_boundary_2CA6E12165908974 Content-Disposition: form-data; name="..."; filename="source.v" Content-Type: text/plain (contents of the file) --MIME_boundary_2CA6E12165908974--
Instead of using curl to transfer a multipart message, I had to use
Poco::Net::HTMLForm class. There was another class to create a multipart message, e.g.
Wt::Http::Request class was unable to interpret the message written by this particular class. As a result,
Poco::Net::HTMLform class came in handy. In addition,
Poco::Net::FilePartSource class was also instantiated to attach a file to the message. The code was demonstrated below to send an HTML form.
Poco::Net::HTMLForm pocoForm; pocoForm.setEncoding(Poco::Net::HTMLForm::ENCODING_MULTIPART); pocoForm.add("param","value"); pocoForm.addPart("...",new Poco::Net::FilePartSource(Poco::Path("...","system.v").toString(), "text/plain"));
Furthermore, I had to set up a HTTP client session to send a request body with Poco library. There were several steps to follow to set up the Poco HTTP client session. Firstly, I had to instantiate a
Poco::Net::HTTPClientSession class with the given host and port. After that, a
Poco::Net::HTTPRequest class should be instantiated.
sendRequest() could be called at this point of time and it would return an output stream, which was to write the request body. The request was valid until
receiveResponse() was called. The code to set up a HTTP client session was demonstrated below.
Poco::Net::HTTPClientSession httpSession("...", "..."); Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "...", Poco::Net::HTTPMessage::HTTP_1_0); pocoForm.prepareSubmit(request); pocoForm.write(httpSession.sendRequest(request)); request.setContentLength(pocoForm.calculateContentLength()); request.setContentType("multipart/form-data; boundary=" + pocoForm.boundary()); Poco::Net::HTTPResponse response; std::istream &stream = httpSession.receiveResponse(response);
Note that I had to pass
HTTP_1_0 as an argument the
HTTPRequest class. The reason was that if I passed
HTTP_1_1 as an argument, it might mess up the multipart message as an additional 0 was introduced after the boundary. In this case
Wt::Http::Request would throw an error message, e.g.
WebController: could not parse request: CgiParser: reached end of input while seeking end of headers or content. Format of CGI input is wrong. The incorrect multipart message was illustrated below.
--MIME_boundary_2CA6E12165908974 Content-Disposition: form-data; name="lang" vlog --MIME_boundary_2CA6E12165908974 Content-Disposition: form-data; name="..."; filename="source.v" Content-Type: text/plain (contents of the file) --MIME_boundary_2CA6E12165908974-- 0
I was unable to resolve this issue for quite a while and I only managed to discover the root cause after I used
netcat to do reading to the network connection. A simple nc command was shown below to capture the packet.
nc -l 8080 > out
All in all, I was pleased to work for AESTE as an apprentice and I learned a lot from Dr Shawn. I would also continue to work on my weaknesses in order to become a better software developer.