POCO C++ simple form submit sample not working - c++

I tried submitting this simple form given in the presentation of POCO library but the server receives no get or post requests.
HTTPClientSession s("localhost");
HTTPRequest request(HTTPRequest::HTTP_POST, "/fileupload/upload_file.php");
HTMLForm form;
form.add("entry1", "value1");
form.prepareSubmit(request);
s.sendRequest(request);
Poco::Net::HTTPResponse res;
std::istream &is = s.receiveResponse(res);
Poco::StreamCopier::copyStream(is, std::cout);

Finally got the answer after trying for a bit. I was missing a form.write statement after prepareSubmit statement. My final code goes like this which sends post requests as well as file upload requests.
HTTPRequest request(HTTPRequest::HTTP_POST, "/fileupload/upload_file.php", HTTPMessage::HTTP_1_1);
HTMLForm form;
form.setEncoding(HTMLForm::ENCODING_MULTIPART);
form.set("entry1", "value1");
form.set("entry2", "value2");
form.addPart("file", new FilePartSource("/home/abc/Pictures/sample.png"));
form.prepareSubmit(request);
HTTPClientSession *httpSession = new HTTPClientSession("localhost");
httpSession->setTimeout(Poco::Timespan(20, 0));
form.write(httpSession->sendRequest(request));
Poco::Net::HTTPResponse res;
std::istream &is = httpSession->receiveResponse(res);
Poco::StreamCopier::copyStream(is, std::cout);
The corresponding upload server is using standard PHP code for uploading HTML form files.

Related

Why Sending multi-part form data using SSL & POCO returns status 411?

I have written an interface to use the JIRA Service Desk API. One of the REST API calls I have implemented does a HTTP POST of multipart/form-data. This works fine when i use HTTP, however when I use HTTPS i get a 411 Length Required response.
The REST API call command works fine over HTTPS when I use curl or postman.
Is there something I am missing when HTTPS is used?
my form post code is as follows:
// generic form send
RESTClient::Error RESTClient::HTTPFormSend(
const std::string & method,
const std::string & command,
const Params & headerParams,
Poco::Net::HTMLForm & form,
HTTPRequestSetup requestFunc
)
{
Error ret = Error::None;
try
{
Poco::Net::HTTPRequest request;
Poco::SharedPtr<Poco::Net::HTTPClientSession> pSession(PrepareSession(method, command, headerParams, request));
Poco::Net::HTTPResponse httpResponse;
// authenticate
m_credentials.authenticate(request);
// custom request setup
if (requestFunc)
requestFunc(request);
if (!DoFormRequest(pSession, request, httpResponse, form))
{
m_credentials.authenticate(request);
if (!DoFormRequest(pSession, request, httpResponse, form))
{
m_logger.error("Invalid username or password");
}
}
}
catch (const Poco::Exception &ex)
{
m_logger.error(ex.displayText());
ret = Error::Internal;
}
return ret;
}
// send form
bool RESTClient::DoFormRequest(
Poco::Net::HTTPClientSession *pSession,
Poco::Net::HTTPRequest & request,
Poco::Net::HTTPResponse & response,
Poco::Net::HTMLForm &form
)
{
Poco::LogStream logStream(m_logger);
form.prepareSubmit(request);
pSession->setTimeout(Poco::Timespan(20, 0));
form.write(pSession->sendRequest(request));
return ProcessResponse(pSession, response);
}
Poco::Net::HTMLForm::prepareSubmit() will normally use Chunked Transfer-Encoding when submitting multipart forms, so no Content-Length header will be set. As a workaround, you could try to set the HTTP Version of the request to 1.0 before calling prepareSubmit(). This will force prepareSubmit() to calculate the length and set the Content-Length header, instead of using Chunked Transfer Encoding. After calling prepareSubmit(), you can reset the HTTP version to 1.1.
request.setVersion(Poco::Net::HTTPMessage::HTTP_1_0);
form.prepareSubmit(request);
request.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);

Use cpprest (Casablanca) to return PDF response

I am using cpprest in a server on Ubuntu Linux. So far I am able to process requests, and reply with JSON responses.
One of the requests that I accept needs to respond with a PDF file. I see that the http_request class has a reply() method that accepts an asynchronous stream. For the life of me, I can't figure out how to associate this stream with my PDF file on disk.
utility::string_t pdfFilename = getPdfFilename();
concurrency::streams::istream stream; // how do associate my pdfFilename?
request.reply(web::http::status_codes::OK, stream, "application/pdf");
I hope you already figured it out. Here's how I reply with local pdf files
void replyPdf(web::http::http_request message, string_t file_name)
{
concurrency::streams::fstream::open_istream(file_name, std::ios::in)
.then([=](concurrency::streams::istream is)
{
web::http::http_response response(web::http::status_codes::OK);
response.headers().add(L"Content-Disposition", U("inline; filename = \"") + file_name + U("\""));
response.set_body(std::move(is), U("application/pdf"));
message.reply(response).then([](pplx::task<void> t) {});
});
}

Displaying file: MessageBodyReader not found for media type=application/octet-stream

My requirement is that I should display a file using RESTFul services. Here how I proceeded:
Server:
#GET
#Path("/{name}")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile {
...
return Response.ok(inputStream).header("Content-Disposition", "attachment; filename=" + fileName).build();
Client:
final WebTarget target = createRestClient("path/" + fileName, new HashMap<String, Object>());
return target.request(MediaType.APPLICATION_OCTET_STREAM).get().readEntity(Part.class);
When I run it, I've got this error:
MessageBodyReader not found for media type=application/octet-stream, type=interface javax.servlet.http.Part, genericType=interface javax.servlet.http.Part.
Do you have any idea where did this come from?
Thanks.
javax.servlet.http.Part should be used to obtain upload multipart data, and is created by the servlet container, which you obtain from a HttpServletRequest. It should not be used in this way. Beside the data is not even multipart.
Instead, you can simply get the InputStream from the from the Response and the Content-Dispostion get explicitly from the header. Something like
Response response = target.request()
.accept(MediaType.APPLICATION_OCTET_STREAM)
.get();
// get InputStream
InputStream is = response.readEntity(InputStream.class);
// get Content-Disposition header
String contentDisposition = (String)response
.getHeaderString(HttpHeaders.CONTENT_DISPOSITION);
// get filename
contentDisposition = contentDisposition
.substring(contentDisposition.indexOf("filename=") + "filename".length() + 1);
System.out.println(contentDisposition);

POCO : How to upload image to webser using poco in c++

I am trying to upload an image to remote web server. I have used HTMLForm and FilePartSource. I am able to successfully upload image to local sever (i.e. loclhost) but when i try to upload it in remote server, the response received from remote web server is "411 Length Required ".
I tried to set request.setContentLength(sizeofimagefile) but still same issue.
Can anyone guide me on what is the issue or .
Here is my code.
HTMLForm htmlform;
htmlform.set("aaaaaa", "bbbbbbb");
htmlform.set("cccccc", "ddddddd");
htmlform.setEncoding(HTMLForm::ENCODING_MULTIPART);
PartSource * pFileSrc = new FilePartSource("filename", "application/octet-stream");
std::istream& mystream = pFileSrc->stream();
mystream.seekg(0, std::ios::end);
int uiLength = mystream.tellg();
htmlform.addPart("file", pFileSrc);
URI uri("yyy");
HTTPClientSession session(uri.getHost(), uri.getPort());
HTTPRequest post_req(Poco::Net::HTTPRequest::HTTP_POST,"xxx",HTTPMessage::HTTP_1_1);
post_req.setKeepAlive(true);
htmlform.prepareSubmit(post_req);
std::ostream& oustr = session.sendRequest(post_req);
htmlform.write(oustr);
HTTPResponse res;
std::istream& rs = session.receiveResponse(res);
std::cerr << rs.rdbuf();
Thanks in advance
std::ostream& oustr = session.sendRequest(post_req);
htmlform.write(oustr);
Your code is not able to assign form data into the request object. So when you call session.sendRequest, an empty request is sent to the server. To do a proper conversion of HTMLForm to HTTPRequest, you must write like this -
htmlform.write(session.sendRequest(post_req));
The image upload code which is working for me is -
HTTPRequest request(HTTPRequest::HTTP_POST, "/fileupload/upload_file.php", HTTPMessage::HTTP_1_1);
HTMLForm form;
form.setEncoding(HTMLForm::ENCODING_MULTIPART);
form.set("entry1", "value1");
form.set("entry2", "value2");
form.addPart("file", new FilePartSource("/home/abc/Pictures/sample.png"));
form.prepareSubmit(request);
HTTPClientSession *httpSession = new HTTPClientSession("localhost");
httpSession->setTimeout(Poco::Timespan(20, 0));
form.write(httpSession->sendRequest(request));
Poco::Net::HTTPResponse res;
std::istream &is = httpSession->receiveResponse(res);
Poco::StreamCopier::copyStream(is, std::cout);
The corresponding upload server is using standard PHP code for uploading HTML form files.
If you can upload a file to your local server but can't with your remote server, first you should check if your remote Apache/PHP has an upload limit. Try a phpinfo() in your remote server.
http://www.cyberciti.biz/faq/linux-unix-apache-increase-php-upload-limit/
If not, you should revise your code...
From Poco documentation, at URL:
http://www.appinf.com/docs/poco/Poco.Net.HTMLForm.html
HTMLForm:
HTMLForm( const HTTPRequest & request, std::istream &
requestBody);
Creates a HTMLForm from the given HTTP request. Uploaded files are
silently discarded.
And with this constructor:
HTMLForm:
HTMLForm( const HTTPRequest & request, std::istream & requestBody, PartHandler & handler);
Creates a HTMLForm from the given HTTP request. Uploaded files are passed to the given PartHandler.
In your example, What constructor are you applying?
On the other hand,
addPart:
void addPart(
const std::string & name,
PartSource * pSource ); Adds an part/attachment (file upload) to the form. The form takes ownership of the PartSource and deletes it
when it is no longer needed. The part will only be sent if the
encoding set for the form is "multipart/form-data"
Try to use "multipart/form-data" with addPart and the second constructor for HTMLForm.
If it doesn't work, try to use a network sniffer like Wireshark to check what are you sendding.
Check if Content-Length header of your Request, have the sizeof(your image) + sizeof("aaaaaa" and "cccccc" params). Or try to send your form with GET method instead of POST.
Let me know if it works.
Regards

Can System.Net.WebClient be used in a console app to stream what my HttpHandler can do with Httpcontext.Response.OutputStream.Write?

I'm trying to do something in a console app for a test (based on some code in an HttpHandler in a web app).
Given something like this below which works for my HttpHandler which has HttpContext passed to it:
context.Response.AppendHeader("Content-Length", docContent.Length.ToString());
context.Response.AppendHeader("content-disposition", "attachment; filename=\"" + fileName + "\"");
context.Response.ContentType = MIMEType.MimeType(fileType);
context.Response.OutputStream.Write(docContent, 0, docContent.Length);
context.Response.OutputStream.Flush();
I have part of it, I think and then I get stuck:
WebClient client = new WebClient ();
client.Headers.Add("Content-Length", docContent.Length.ToString());
client.Headers.Add("content-disposition", "attachment; filename=\"" + fileName + "\"");
string ContentType = MIMEType.MimeType(fileType);
// ??
// how to build the response as an output stream from my byte array which has the data ?
MemoryStream(byte[]) can create a Stream from a byte[].
But a problem is WebClient is designed to issue HTTP requests only. If your goal is to test the server by downloading an attachment, then you'll need different headers.
If indeed you're trying to download a file, then try using WebClient.DownloadFile