css and other in gnu microhttpd - c++

i work on a soft using the gnu microhttpd library and it's working fine.
Anyway to made my html output human-friendly, i want to use css and so one.
sound like a made an error but i don't see :
so, if someone could help.
string sPage;
sPage = "<html><head><link rel = \"stylesheet\" type = \"text/css\" href = \"./template.css\" /></head><body style=\"background-color:red>Link to this folder<div class=\"flex-container\"><div>Le processus " + Process
+ " n\'est pas actif, impossible de se connecter</div></div><IMG src=\"../images/TrafficLights.png\"></body></html>";
struct MHD_Response *response;
int ret;
//response = MHD_create_response_from_buffer (strlen (page),(void*) page, MHD_RESPMEM_PERSISTENT);
response = MHD_create_response_from_buffer (strlen (sPage.c_str()),(void*) sPage.c_str(), MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
return ret;

From the documentation of MHD_queue_response:
[mode] memory management options for buffer; use MHD_RESPMEM_PERSISTENT if the buffer is static/global memory, use MHD_RESPMEM_MUST_FREE if the buffer is heap-allocated and should be freed by MHD and MHD_RESPMEM_MUST_COPY if the buffer is in transient memory (i.e. on the stack) and must be copied by MHD;
So either define sPage with its full contents somewhere statically, or keep your stack allocated sPage but set the mode to MHD_RESPMEM_MUST_COPY.

Related

Arduino can NOT send JSON

I want so send data via a JSON object. All 7 variables you can see in the code should be well defined.
I get the following "error message"/incomplete JSON from Arduino monitor:
{"topic":"Statistics","DrillDuration":"1000","SpeedToDrill":"20","SpeedWithObjectBefore":"100","SpeedWithObjectAfter":"100⸮⸮
Any idea? Is the package for my JSON too small?
I tested my function on a separate Arduino, where I cut my hole program. There it runs without any problems. This function "sendSummary" runs at the end of a bigger code, maybe this could lead to some issues?
Thanks a lot for your help!
void sendSummary()
{
const size_t capacity = JSON_OBJECT_SIZE(14);
DynamicJsonDocument doc(capacity);
doc["topic"] = "Statistics";
doc["DrillDuration"] = DrillDuration;
doc["SpeedToDrill"] = SpeedToDrill;
doc["SpeedWithObjectBefore"] = SpeedWithObjectBefore;
doc["SpeedWithObjectAfter"] = SpeedWithObjectAfter;
doc["SpeedWithoutObject"] = SpeedWithoutObject;
doc["DrillSpeed"] = DrillSpeedVar;
serializeJson(doc, Serial);
Serial.write("\n");
}

Some Problems of Indy 10 IdHTTP Implementation

In regard to Indy 10 of IdHTTP, many things have been running perfectly, but there are a few things that don't work so well here. That is why, once again, I need your help.
Download button has been running perfectly. I'm using the following code :
void __fastcall TForm1::DownloadClick(TObject *Sender)
{
MyFile = SaveDialog->FileName;
TFileStream* Fist = new TFileStream(MyFile, fmCreate | fmShareDenyNone);
Download->Enabled = false;
Urlz = Edit1->Text;
Url->Caption = Urlz;
try
{
IdHTTP->Get(Edit1->Text, Fist);
IdHTTP->Connected();
IdHTTP->Response->ResponseCode = 200;
IdHTTP->ReadTimeout = 70000;
IdHTTP->ConnectTimeout = 70000;
IdHTTP->ReuseSocket;
Fist->Position = 0;
}
__finally
{
delete Fist;
Form1->Updated();
}
}
However, a "Cancel Resume" button is still can't resume interrupted downloads. Meant, it is always sending back the entire file every time I call Get() though I've used IdHTTP->Request->Ranges property.
I use the following code:
void __fastcall TForm1::CancelResumeClick(TObject *Sender)
{
MyFile = SaveDialog->FileName;;
TFileStream* TFist = new TFileStream(MyFile, fmCreate | fmShareDenyNone);
if (IdHTTP->Connected() == true)
{
IdHTTP->Disconnect();
CancelResume->Caption = "RESUME";
IdHTTP->Response->AcceptRanges = "Bytes";
}
else
{
try {
CancelResume->Caption = "CANCEL";
// IdHTTP->Request->Ranges == "0-100";
// IdHTTP->Request->Range = Format("bytes=%d-",ARRAYOFCONST((TFist->Position)));
IdHTTP->Request->Ranges->Add()->StartPos = TFist->Position;
IdHTTP->Get(Edit1->Text, TFist);
IdHTTP->Request->Referer = Edit1->Text;
IdHTTP->ConnectTimeout = 70000;
IdHTTP->ReadTimeout = 70000;
}
__finally {
delete TFist;
}
}
Meanwhile, by using the FormatBytes function, found here, has been able to shows only the size of download files. But still unable to determine the speed of download or transfer speed.
I'm using the following code:
void __fastcall TForm1::IdHTTPWork(TObject *ASender, TWorkMode AWorkMode, __int64 AWorkCount)
{
__int64 Romeo = 0;
Romeo = IdHTTP->Response->ContentStream->Position;
// Romeo = AWorkCount;
Download->Caption = FormatBytes(Romeo) + " (" + IntToStr(Romeo) + " Bytes)";
ForSpeed->Caption = FormatBytes(Romeo);
ProgressBar->Position = AWorkCount;
ProgressBar->Update();
Form1->Updated();
}
Please advise and give an example. Any help would sure be appreciated!
In your DownloadClick() method:
Calling Connected() is useless, since you don't do anything with the result. Nor is there any guarantee that the connection will remain connected, as the server could send a Connection: close response header. I don't see anything in your code that is asking for HTTP keep-alives. Let TIdHTTP manage the connection for you.
You are forcing the Response->ResponseCode to 200. Don't do that. Respect the response code that the server actually sent. The fact that no exception was raised means the response was successful whether it is 200 or 206.
You are reading the ReuseSocket property value and ignoring it.
There is no need to reset the Fist->Position property to 0 before closing the file.
Now, with that said, your CancelResumeClick() method has many issues.
You are using the fmCreate flag when opening the file. If the file already exists, you will overwrite it from scratch, thus TFist->Position will ALWAYS be 0. Use fmOpenReadWrite instead so an existing file will open as-is. And then you have to seek to the end of the file to provide the correct Position to the Ranges header.
You are relying on the socket's Connected() state to make decisions. DO NOT do that. The connection may be gone after the previous response, or may have timed out and been closed before the new request is made. The file can still be resumed either way. HTTP is stateless. It does not matter if the socket remains open between requests, or is closed in between. Every request is self-contained. Use information provided in the previous response to govern the next request. Not the socket state.
You are modifying the value of the Response->AcceptRanges property, instead of using the value provided by the previous response. The server tells you if the file supports resuming, so you have to remember that value, or query it before then attempting to resumed download.
When you actually call Get(), the server may or may not respect the requested Range, depending on whether the requested file supports byte ranges or not. If the server responds with a response code of 206, the requested range is accepted, and the server sends ONLY the requested bytes, so you need to APPEND them to your existing file. However, if the server response with a response code of 200, the server is sending the entire file from scratch, so you need to REPLACE your existing file with the new bytes. You are not taking that into account.
In your IdHTTPWork() method, in order to calculate the download/transfer speed, you have to keep track of how many bytes are actually being transferred in between each event firing. When the event is fired, save the current AWorkCount and tick count, and then the next time the event is fired, you can compare the new AWorkCount and current ticks to know how much time has elapsed and how many bytes were transferred. From those value, you can calculate the speed, and even the estimated time remaining.
As for your progress bar, you can't use AWorkCount alone to calculate a new position. That only works if you set the progress bar's Max to AWorkCountMax in the OnWorkBegin event, and that value is not always know before a download begins. You need to take into account the size of the file being downloaded, whether it is being downloaded fresh or being resumed, how many bytes are being requested during a resume, etc. So there is lot more work involved in displaying a progress bar for a HTTP download.
Now, to answer your two questions:
How to retrieve and save the download file to a disk by using its original name?
It is provided by the server in the filename parameter of the Content-Disposition header, and/or in the name parameter of the Content-Type header. If neither value is provided by the server, you can use the filename that is in the URL you are requesting. TIdHTTP has a URL property that provides the parsed version of the last requested URL.
However, since you are creating the file locally before sending your download request, you will have to create a local file using a temp filename, and then rename the local file after the download is complete. Otherwise, use TIdHTTP.Head() to determine the real filename (you can also use it to determine if resuming is supported) before creating the local file with that filename, then use TIdHTTP.Get() to download to that local file. Otherwise, download the file to memory using TMemoryStream instead of TFileStream, and then save with the desired filename when complete.
when I click http://get.videolan.org/vlc/2.2.1/win32/vlc-2.2.1-win32.exe then the server will process requests to its actual url. http://mirror.vodien.com/videolan/vlc/2.2.1/win32/vlc-2.2.1-win32.exe. The problem is that IdHTTP will not automatically grab through it.
That is because VideoLan is not using an HTTP redirect to send clients to the real URL (TIdHTTP supports HTTP redirects). VideoLan is using an HTML redirect instead (TIdHTTP does not support HTML redirects). When a webbrowser downloads the first URL, a 5 second countdown timer is displayed before the real download then begins. As such, you will have to manually detect that the server is sending you an HTML page instead of the real file (look at the TIdHTTP.Response.ContentType property for that), parse the HTML to determine the real URL, and then download it. This also means that you cannot download the first URL directly into your target local file, otherwise you will corrupt it, especially during a resume. You have to cache the server's response first, either to a temp file or to memory, so you can analyze it before deciding how to act on it. It also means you have to remember the real URL for resuming, you cannot resume the download using the original countdown URL.
Try something more like the following instead. It does not take into account for everything mentioned above (particularly speed/progress tracking, HTML redirects, etc), but should get you a little closer:
void __fastcall TForm1::DownloadClick(TObject *Sender)
{
Urlz = Edit1->Text;
Url->Caption = Urlz;
IdHTTP->Head(Urlz);
String FileName = IdHTTP->Response->RawHeaders->Params["Content-Disposition"]["filename"];
if (FileName.IsEmpty())
{
FileName = IdHTTP->Response->RawHeaders->Params["Content-Type"]["name"];
if (FileName.IsEmpty())
FileName = IdHTTP->URL->Document;
}
SaveDialog->FileName = FileName;
if (!SaveDialog->Execute()) return;
MyFile = SaveDialog->FileName;
TFileStream* Fist = new TFileStream(MyFile, fmCreate | fmShareDenyWrite);
try
{
try
{
Download->Enabled = false;
Resume->Enabled = false;
IdHTTP->Request->Clear();
//...
IdHTTP->ReadTimeout = 70000;
IdHTTP->ConnectTimeout = 70000;
IdHTTP->Get(Urlz, Fist);
}
__finally
{
delete Fist;
Download->Enabled = true;
Updated();
}
}
catch (const EIdHTTPProtocolException &)
{
DeleteFile(MyFile);
throw;
}
}
void __fastcall TForm1::ResumeClick(TObject *Sender)
{
TFileStream* Fist = new TFileStream(MyFile, fmOpenReadWrite | fmShareDenyWrite);
try
{
Download->Enabled = false;
Resume->Enabled = false;
IdHTTP->Request->Clear();
//...
Fist->Seek(0, soEnd);
IdHTTP->Request->Ranges->Add()->StartPos = Fist->Position;
IdHTTP->Request->Referer = Edit1->Text;
IdHTTP->ConnectTimeout = 70000;
IdHTTP->ReadTimeout = 70000;
IdHTTP->Get(Urlz, Fist);
}
__finally
{
delete Fist;
Download->Enabled = true;
Updated();
}
}
void __fastcall TForm1::IdHTTPHeadersAvailable(TObject*Sender, TIdHeaderList *AHeaders, bool &VContinue)
{
Resume->Enabled = ( ((IdHTTP->Response->ResponseCode == 200) || (IdHTTP->Response->ResponseCode == 206)) && TextIsSame(AHeaders->Values["Accept-Ranges"], "bytes") );
if ((IdHTTP->Response->ContentStream) && (IdHTTP->Request->Ranges->Count > 0) && (IdHTTP->Response->ResponseCode == 200))
IdHTTP->Response->ContentStream->Size = 0;
}
#Romeo:
Also, you can try a following function to determine the real download filename.
I've translated this to C++ based on the RRUZ'function. So far so good, I'm using it on my simple IdHTTP download program, too.
But, this translation result is of course still need value improvement input from Remy Lebeau, RRUZ, or any other master here.
String __fastcall GetRemoteFileName(const String URI)
{
String result;
try
{
TIdHTTP* HTTP = new TIdHTTP(NULL);
try
{
HTTP->Head(URI);
result = HTTP->Response->RawHeaders->Params["Content-Disposition"]["filename"];
if (result.IsEmpty())
{
result = HTTP->Response->RawHeaders->Params["Content-Type"]["name"];
if (result.IsEmpty())
result = HTTP->URL->Document;
}
}
__finally
{
delete HTTP;
}
}
catch(const Exception &ex)
{
ShowMessage(const_cast<Exception&>(ex).ToString());
}
return result;
}

iOS How to Store C++ Object into a NSArray used as a tableview's datasource

Recently, I encountered a problem: in my tableview, I retrieve data from web request, after received response from the network, I need to decode the data and store the data in a C++ object.
However, the tableview datasource, NSArray cannot store C++ object.
I have tried some solutions, like using CFMutableArrayRef or save the C++ object pointer in a NSValue and then put the NSValue into the NSArray. But when I called [tableview reloadData],the data in the CFMutableArray or the NSValue don't have the right data.
Could anybody help me with this problem? Thanks!
Here are some code:
std::list<ImageTextContent> msgs = body->getMsgs();
std::list<ImageTextContent>::iterator itmsgs0;
for(itmsgs0 = msgs.begin();itmsgs0 != msgs.end();itmsgs0++)
{
ImageTextContent *tmpmsgs = &(*itmsgs0);
CFArrayAppendValue(_dataSourceRef, tmpmsgs);
}
and
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ImageTextContent *itc = (ImageTextContent *)CFArrayGetValueAtIndex(_dataSourceRef, 0);
NSString *title = [NSString stringWithCString:(itc->getSubmitTime()).c_str() encoding:NSUTF8StringEncoding];
cell.contentLabel.text = title;
....
}
in cellForRowAtIndexPath method I can't get the right data, why?
The pointers in your _dataSourceRef array become invalid as soon as the lifetime of msgs ends.
Dereferencing any of them is undefined at that point and anything can happen.
(Very common is that the data has been overwritten and you just find some random stuff there.)
Either make getMsgs return a list of pointers, or dynamically allocate a copy the data when you populate the array, like this:
for(itmsgs0 = msgs.begin();itmsgs0 != msgs.end();itmsgs0++)
{
CFArrayAppendValue(_dataSourceRef, new ImageTextContent(*itmsgs0));
}

Using UpdateResource with StringTables in C++

I need to edit the resources of a file in C++ using UpdateResource(), however I am unsure on how to go about getting the data for the 5th parameter (lpData).
I have no idea about how to create the data that needs to be provided for the function and the structure of the data, Can anybody provide guidance on how to go about getting/creating the data?
Simply you can use:
wchar_t wszMyText[] = L"Some text";
HANDLE hUpdate = BeginUpdateResourceW( L"/path/to/file", FALSE );
// test return value.
BOOL res = UpdateResourceW( hUpdate, RT_STRING, L"MyResource", wszMyText,
sizeof(wszMyText) - sizeof(wchar_t);
// check return value
EndUpdateResource( hUpdate, FALSE );

how to get log in ISA server 2006 C++ SDK without memory leak

i wrote a method that get the all session log info with isa server 2006 SDK
the main code is below and i have to use this code in do-while() to get all sessions information but this line make leak memory .
at the end i released the pointer of FPCLib::IFPCLogEntryptr but mem leak is still exist .
:(
could you please help me this problem .
FPCLib::IFPCLogEntryptr = FPCLib::IFPCLogContentPtr::Item(index)
.
. // reading informationsuch as ip, url , byte send , ....
.
FPCLib::IFPCLogEntryptr.release();
hr = LOGFilter.CreateInstance("FPC.FPCFilterExpressions");
hr = LOGFilter->put_FilterType(FPCLib::FpcFilterType::fpcNoFilterType);
FPClogviewer = FPCArray->LogViewer;
LOGContent = FPClogviewer->GetLogContentOnline();
LOGContent->ExecuteQuery(LOGFilter,EXECUTEROWCOUNT);
FPCLib::IFPCLogEntryPtr FPCLogEntry;
_bstr_t ClientIP;
int index= 0;
do
{
index ++ ;
FPCLogEntry = LOGContent->Item(_variant_t(index));
ClientIP = FPCLogEntry->ClientIP;
FPCLogEntry.Release();
}
while (1)
the point is this line
LOGContent->ExecuteQuery(LOGFilter,EXECUTEROWCOUNT);
the fist step change the do while to for
second- EXECUTEROWCOUN must be not larg number such as 1000000000
after 'for' you have to use LOGContent->EndQuery()
if you need still LOGGING start function again