Downloading file as a result of POST request (IdHTTP) - c++builder

I know there's IdHTTP->Get to download data to filestream.
But I need to do that after post request
TFileStream* fs = new TFileStream(fileName, fmCreate|fmOpenWrite);
TStringList * S=new TStringList();
S->Clear();
S->Add("info=" + kindainfo);
fs = IdHTTP1->Post(URL, S);
That's what I need to get.. because I don't think file will be fine with AnsiString

Found answer
IdHTTP1->Post(URL, S, fs);

Related

boost::beast::http::request Sending a file as multipart/form-data

Just getting in to this using http_client_sync.cpp. I added a little bit of code to use the
http::file_body type.
I can't seem to figure out how to get the multipart boundaries inserted. Is there something in particular I need to do to make that happen? When I look at the POST in wireshark, the entire multipart/form data is in one big part. Relevant (I hope) snippet below. Modified from oroginal http_client_sync.cpp.
// Set up an HTTP POST request message
http::request<http::file_body> req{http::verb::post, target, version};
// use the full host:port here
req.set(http::field::host, fullhost.c_str());
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.set(http::field::accept,"*/*");
req.set(http::field::content_length,contentLen);
req.set(http::field::content_type,"multipart/form-data; boundary=fd1c38d86c0a42ac933e7319e51882fd");
req.body() = std::move(body);
http::request_serializer<http::file_body, http::fields> sr{req};
// Send the HTTP request to the remote host
http::write(socket, sr);
I did also try this, but the result was the same
size_t len = http::write_header(socket, sr);
while(len!=0)
{
len = http::write_some(socket, sr);
}
The server I'm talking to is expecting multiple parts.
Many Thanks
Ok it turns out this is possible, and cured my issue. Probably not the "right" way to do it, but it works.
size_t len = http::write_header(socket, sr);
// where multipart header is a string containing the first boundary
// and the content disposition
boost::asio::write(socket,boost::asio::buffer( multipartHeader));
while(len!=0)
{
len = http::write_some(socket, sr);
}
// where multipart trailer is a string containing the final boundary
boost::asio::write(socket,boost::asio::buffer( multipartTrailer));
Happy to hear better solutions.

Export SSRS report directly without rendering it on ReportViewer

I have a set of RDL reports hosted on the report server instance. Some of the report renders more than 100,000 records on the ReportViewer. So that it takes quite long time to render it on the Viewer. So, we decided to go with Export the content directly from the server based on the user input parameters for the report as well as export file format.
Main thing here, I do not want the user to wait until the export file available for download. Rather, User can submit the action and can proceed to do other works. In the background, the program has to export the file to some physical location. When the download will be available, the user will be informed with some notification about the exported file.
I found the way in this Link. I need to know what are the ways to achieve the above mentioned functionality as well as how to pass the input parameters for the report. Pl suggest me.
Note: I was using XML as datasource for the rdl reports.
EDIT
I found something useful and did the coding like the below,
string path = ServerURL +"?" + _reportFolder + "ReportName&rs:Command=Render&rs:Format=PDF";
WebRequest req = WebRequest.Create(path);
string reportParametersQT = String.Empty;
req.Credentials = CredentialCache.DefaultNetworkCredentials;
WebResponse response = req.GetResponse();
Stream stream = response.GetResponseStream();
//screen.Response.Clear();
string enCodeFileName = HttpUtility.UrlEncode("fileName.pdf", System.Text.Encoding.UTF8);
// The word attachment in Addheader is used to directly show the save dialog box in browser
Response.AddHeader("content-disposition", "attachment; filename=" + enCodeFileName);
Response.BufferOutput = false; // to prevent buffering
Response.ContentType = response.ContentType;
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
Response.OutputStream.Write(buffer, 0, bytesRead);
}
Response.End();
I am able to download the exported file. But need to save the file in physical location instead of downloading. I dont know how to do that.
Both of these are very easy to do. You essentially just pass the parameters in the URL that you're calling, for example for a parameter called "LearnerList" you add &LearnerList=12345 to the URL. For exporting, add an additional paramter for Format=PDF (or whatever you want the file as) to get the report to export as a PDF instead of generating in Report Viewer.
Here's an example URL:
https://reporting.MySite.net/ReportServer/Pages/ReportViewer.aspx?/Users+Folders/User/My+Reports/Learner+Details&rs:Format=PDF&LearnerList=202307
Read these two pages, and you should be golden:
https://msdn.microsoft.com/en-us/library/ms155391.aspx
https://msdn.microsoft.com/en-us/library/ms154040.aspx

Serving files with IdHTTPServer when the files are being written

I'm working with a TIdHTTPServer to serve files to clients, using the ResponseInfo->ServeFile function. This works fine for files that are "static": not being written by some other process. As far as I can see from the code, the ServeFile function internally uses a TIdReadFileExclusiveStream, which disallows me from reading a file being written, but I need to be able to send also files that are being written by some other process.
So, I moved to create a FileStream myself and use the ContentStream property to return it to the client, but I get a 0 bytes file in the client (for any file, being written or not), and I can't see what I'm missing or doing wrong. Here is the code I'm using on the OnCommandGet event handler:
AResponseInfo->ContentStream = new TFileStream(path, fmOpenRead | fmShareDenyNone);
AResponseInfo->ContentStream->Position = 0;
AResponseInfo->ContentLength = AResponseInfo->ContentStream->Size;
AResponseInfo->ResponseNo = 200;
AResponseInfo->WriteHeader();
AResponseInfo->WriteContent();
The ContentLength property at this point has a valid value (i.e., the file size when calling ContentStream->Size), and that's what I would like to send to the client, even if the file changes in between.
I have tried removing the WriteContent() function, the WriteHeader(), but the results are the same. I searched for some examples but the few I found are more or less the same than this code, so I don't know what's wrong. Most examples don't include the WriteContent() call, that's why I have tried removing them, but there doesn't seem to be any difference.
As a side note: the files being written take 24 hours to finish writing, but that's to be expected from the client side: I just need the bytes already written at the time of the request (even somewhat less is valid). The files will never get deleted: they will just keep getting bigger.
Any ideas?
Update
Using Fiddler, I get some warnings on protocol violations, that would be related to this. I get, for instance:
Content-Length mismatch: Response Header indicated 111,628,288 bytes, but server sent 41 bytes
The content length is correct, it's the file size, but I don't know what I'm doing wrong that makes the app sent just 41 bytes.
WriteHeader() and WriteContent() expect the ContentStream to be complete and unchanging at the time they are called. WriteHeader() creates a Content-Length header using the current ContentStream->Size value if the AResponseInfo->ContentLength property is -1 (you are actually setting the value yourself), and WriteContent() sends only as many bytes as the current ContentStream->Size value says. So your client is receiving 0 bytes because the file Size is still 0 at the time you are calling WriteHeader() and WriteContent().
Neither ServeFile() nor ContentStream are suitable for your needs. Since the file is being written live, you do not know the final file size when the HTTP headers are created and sent to the client. So you must use HTTP 1.1's chunked transfer coding to send the file data. That will allow you to send the file data in chunks as the file is being written, and then signal the client when the file is finished.
However, TIdHTTPServer does not natively support sending chunked responses, so you will have to implement it manually, eg:
TFileStream *fs = new TFileStream(path, fmOpenRead | fmShareDenyNone);
try
{
AResponseInfo->ResponseNo = 200;
AResponseInfo->TransferEncoding = "chunked";
AResponseInfo->WriteHeader();
TIdBytes buffer;
buffer.Length = 1024;
do
{
int NumRead = fs->Read(&buffer[0], 1024);
if (NumRead == -1) RaiseLastOSError();
if (NumRead == 0)
{
// check for EOF, unless you have another way to detect it...
Sleep(1000);
NumRead = fs->Read(&buffer[0], 1024);
if (NumRead <= 0) break;
}
// send the current chunk
AContext->Connection->IOHandler->WriteLn(IntToHex(NumRead));
AContext->Connection->IOHandler->Write(buffer, NumRead);
AContext->Connection->IOHandler->WriteLn();
}
while (true);
// send the last chunk to signal EOF
AContext->Connection->IOHandler->WriteLn("0");
// send any trailer headers you need, if any...
// finish the transfer encoding
AContext->Connection->IOHandler->WriteLn();
}
__finally
{
delete fs;
}
The final working code is:
std::unique_ptr< TFileStream >fs(new TFileStream(path, fmOpenRead | fmShareDenyNone));
fs->Position = 0;
__int64 size = fs->Size;
AResponseInfo->ContentLength = size;
AResponseInfo->ResponseNo = 200;
AResponseInfo->WriteHeader();
AContext->Connection->IOHandler->Write(fs.get(), size);
This allows the client to receive up to size bytes of the original file, even if the file is being written to at the same time.
For some reason passing the ContentStream did not return any content to the client, but doing the IOHandler->Write directly (which is what the ServeFile ends doing internally) works fine.

Save SpreadsheetDocument in the DB

I have a valid SpreadsheetDocument object created from the stream. I can manipulate it (f.e. add new row). After my changes I need to save this changed document in SQL Server as varbinary and later read it for SQL Server to manipulate further.
Could you provide some example how to achieve it?
I know how to put/read data from SQL Server. What I'm looking for is the way somehow to convert SpreadsheetDocument to byte array and to create back SpreadsheetDocument from byte array for SQL Server.
I'm using Open XML SDK 2.0
Thanks a lot,
Alexander
Not quite the same but I needed to load an Excel template into memory, modify it and send it over HTTP using IIS. I did it by loading the data into a memory stream, then doing the modifications (that seems to be the way Microsoft recomend here:
http://msdn.microsoft.com/en-us/library/ee945362%28v=office.11%29.aspx
This might help you:
MemoryStream ms = new MemoryStream();
byte [] byteArray = System.IO.File.ReadAllBytes("document.xslm");
ms.Write(byteArray, 0, byteArray.Length);
ms.Position = 0;
using (SpreadsheetDocument doc = SpreadsheetDocument.Open(ms, true))
{
<Do stuff>
}
return File(ms.ToArray(), "application/vnd.ms-excel.sheet.macroEnabled.12", "output.xlsm");
Obviously the last line is what I needed to do, you're going to need to save the stream to the database.

Upload images to Imgur from Mathematica

Here's a challenge to all mathematica tag followers. Let's make it a lot more convenient to insert images into SO post from Mathematica by creating an imgur uploader.
How can we create a function imgur[g_] that will rasterize its argument (making sure that the final size is not wider than the width of StackOverflow posts), convert it to PNG, upload it to imgur, and return a ready to be pasted MarkDown line such as ![Mathematica graphic](http://i.imgur.com/ZENa4.jpg) ?
Useful references:
Imgur API
Example of using POST request from Mathematica on WRI blog (posting to Twitter) by ragfield
Example of using POST requests from Mathematica on SO (uploading to ifile.it)
I failed to adapt this latter method to uploading an image without exporting it to a file first.
Warning, use with care! StackOverflow uses a separate imgur installation that keep images indefinitely. If you use the main imgur, the images will disappear after 6 months if no one views them. Unfortunately as of 2011 November there seems to be no official way to upload images to StackOverflow programmatically.
Update: See below a solution for uploading to StackOverflow directly.
A little bird just informed me of a Mathematica solution to this question (the underlying implementation still uses JLink, but this answer hides all the java related code):
imgur[expr_] := Module[
{url, key, image, data, xml, imgurUrl},
url = "http://api.imgur.com/2/upload";
key = "c07bc3fb59ef878d5e23a0c4972fbb29";
image = Fold[ExportString, expr, {"PNG", "Base64"}];
xml = Import[url,
"XML", "RequestMethod" -> "POST",
"RequestParameters" -> {"key" -> key, "image" -> image}];
imgurUrl = Cases[xml, XMLElement["original", {}, {string_}] :> string,
Infinity][[1]];
"![Mathematica graphic](" <> imgurUrl <> ")"
]
This is V8 only and the XML import options "RequestMethod" and "RequestParameters" are undocumented and experimental (and therefore subject to change).
Note: Get an ready-made palette with this functionality here.
Arnoud's solution got me excited and impatient, so here's an improvement to it. I couldn't have done this without studying his code. This version seems to be somewhat more reliable and less prone to timeout errors, but to be honest, I know no Java at all, so any improvements are welcome.
Most importantly: this version uploads to stack.imgur.com directly, so it's safe to use here on StackOverflow, without having to worry that uploaded images will disappear after a while.
I provide three functions:
stackImage uploads the expression, exported as PNG, and returns the URL
stackMarkdown returns the markdown, ready to be copied
stackCopyMarkdown copies the markdown to the clipboard
Next step: create a palette button that does this automatically for the selected graphic in the notebook. Improvements to the code are very welcome.
Needs["JLink`"]
stackImage::httperr = "Server returned respose code: `1`";
stackImage::err = "Server returner error: `1`";
stackImage[g_] :=
Module[
{getVal, url, client, method, data, partSource, part, entity, code,
response, error, result},
(* this function attempts to parse the response fro the SO server *)
getVal[res_, key_String] :=
With[{k = "var " <> key <> " = "},
StringTrim[
First#StringCases[First#Select[res, StringMatchQ[#, k ~~ ___] &],
k ~~ v___ ~~ ";" :> v],
"'"]
];
data = ExportString[g, "PNG"];
JavaBlock[
url = "https://stackoverflow.com/upload/image";
client = JavaNew["org.apache.commons.httpclient.HttpClient"];
method = JavaNew["org.apache.commons.httpclient.methods.PostMethod", url];
partSource = JavaNew["org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource", "mmagraphics.png", MakeJavaObject[data]#toCharArray[]];
part = JavaNew["org.apache.commons.httpclient.methods.multipart.FilePart", "name", partSource];
part#setContentType["image/png"];
entity = JavaNew["org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity", {part}, method#getParams[]];
method#setRequestEntity[entity];
code = client#executeMethod[method];
response = method#getResponseBodyAsString[];
]
If[code =!= 200, Message[stackImage::httperr, code]; Return[$Failed]];
response = StringTrim /# StringSplit[response, "\n"];
error = getVal[response, "error"];
result = getVal[response, "result"];
If[StringMatchQ[result, "http*"],
result,
Message[stackImage::err, error]; $Failed]
]
stackMarkdown[g_] := "![Mathematica graphics](" <> stackImage[g] <> ")"
stackCopyMarkdown[g_] := Module[{nb, markdown},
markdown = Check[stackMarkdown[g], $Failed];
If[markdown =!= $Failed,
nb = NotebookCreate[Visible -> False];
NotebookWrite[nb, Cell[markdown, "Text"]];
SelectionMove[nb, All, Notebook];
FrontEndTokenExecute[nb, "Copy"];
NotebookClose[nb];
]
]
Update:
Here's a button that will show a preview of the selection and will offer uploading (or cancelling). It requires the previous functions to be defined.
Button["Upload to SO",
Module[{cell = NotebookRead#InputNotebook[], img},
If[cell =!= {}, img = Rasterize[cell];
MessageDialog[
Column[{"Upload image to StackExchange sites?",
img}], {"Upload and copy MarkDown" :> stackCopyMarkdown[img],
"Cancel" :> Null}, WindowTitle -> "Upload to StackExchange"]]]]
Unfortunately I can't put the button in a palette (CreatePalette) because the palette dimensions will influence the rasterization. Solutions to this problem are welcome.
Update 2:
Based on the answer to this question, here's a working Windows-only palette button:
button = Button["Upload to SO",
Module[{sel},
FrontEndExecute[
FrontEndToken[FrontEnd`SelectedNotebook[], "CopySpecial", "MGF"]];
sel = Cases[NotebookGet#ClipboardNotebook[],
RasterBox[data_, ___] :>
Image[data, "Byte", ColorSpace -> "RGB", Magnification -> 1],
Infinity];
If[sel =!= {},
With[{img = First[sel]},
MessageDialog[
Column[{"Upload image to StackExchange sites?",
img}], {"Upload and copy MarkDown" :> stackCopyMarkdown[img],
"Cancel" :> Null}, WindowTitle -> "Upload to StackExchange"]
]
]
]
]
CreatePalette[button]
Warning: it destroys the clipboard contents even if you click cancel in the preview box.
Note: This is using the anonymous imgur uploader with my anonymous key. The imgur site restricts uploads to 50 uploads/hour which should be fine normally, but this may cause a problem if a lot of people try this simultaneously. So please get your own anonymous key here:
http://imgur.com/register/api_anon
And then replace the key in the code below with your own key (thanks!).
The trickiest part to code was the conversion from a Mathematica expression to PNG image to Base64 encoding to URL encoding. There are about a 1,000 ways to do it wrong and I think I managed to try them all.
The code breaks down into a few pieces:
Construct the POST url
Make the HTTP connection
Send the POST url
Read back the result, which is XML
Extract the imgur url from the XML
Format the imgur url as markdown (or as a Mathematica Hyperlink function).
Here is the code:
imgur[expr_] :=
Module[{url, key, image, data, jUrl, jConn, jWriter, jInput, buffer,
byte, xml, imgurUrl},
Needs["JLink`"];
JLink`JavaBlock[
JLink`LoadJavaClass["java.net.URLEncoder"];
url = "http://api.imgur.com/2/upload";
key = "c07bc3fb59ef878d5e23a0c4972fbb29";
image = ExportString[ExportString[expr, "PNG"], "Base64"];
data =
URLEncoder`encode["key" , "UTF-8"] <> "=" <>
URLEncoder`encode[ key , "UTF-8"] <> "&" <>
URLEncoder`encode["image" , "UTF-8"] <> "=" <>
URLEncoder`encode[ image , "UTF-8"] ;
jUrl = JLink`JavaNew["java.net.URL", url];
jConn = jUrl#openConnection[];
jConn#setDoOutput[True];
jWriter =
JLink`JavaNew["java.io.OutputStreamWriter",
jConn#getOutputStream[]];
jWriter#write[data];
jWriter#flush[];
jInput = jConn#getInputStream[];
buffer = {};
While[(byte = jInput#read[]; byte >= 0), AppendTo[buffer, byte]];
];
xml = ImportString[FromCharacterCode[buffer], "XML"];
imgurUrl =
Cases[xml,
XMLElement["original", {}, {string_}] :>
string, \[Infinity]][[1]];
"![Mathematica graphic](" <> imgurUrl <> ")"
]
Testing:
In[]:= g = Graphics[{Blue, Disk[]}, PlotRange -> 1.2, ImageSize -> Small];
pic = Overlay[{Blur[Binarize#g, 10], g}];
imgur[pic]
Out[]= ![Mathematica graphic](http://i.imgur.com/eGOlL.png)
And the actual image:

Resources