Use cpprest (Casablanca) to return PDF response - c++

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) {});
});
}

Related

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);

How do I get the Content-Encoding in a POCO::Net::HTTPResponse object?

I'm fetching a server page using Poco::Net::HTTPClientSession with an appropriate Poco::Net::HTTPRequest, which works fine. Now I get a response back, and sometimes the returned page will be gzipped.
I need to find out when that is the case, so that I may deflate if necessary. The HTTP header that should indicate this, is Content-Encoding: gzip; but there's no getContentEncoding() method in Poco::Net::HTTPResponse.
Here's a non-working snippet (because there's no resp.getContentEncoding()):
// resp is the Poco::Net::HTTPResponse object,
// sess is the Poco::Net::HTTPClientSession
std::istream &in = sess.receiveResponse(resp);
// Get the server-returned body as a string (potentially deflate)
std::ostringstream serveroutput;
if (resp.getContentEncoding() == "gzip") {
Poco::InflatingInputStream
inflater(in, Poco::InflatingStreamBuf::STREAM_GZIP);
Poco::StreamCopier::copyStream(inflater, serveroutput);
} else
Poco::StreamCopier::copyStream(in, serveroutput);
// Now we can get at the body as a string
std::string txt = serveroutput.str();
Does anyone know how to get at the raw headers, so that I can inspect the header Content-Encoding myself, or of another useful method to determine whether a server response is gzipped?
if the server set the Content-Encoding header
you could get the encoding value like the following.
resp.get("Content-Encoding")

POCO C++ simple form submit sample not working

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.

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