I want to PUT json data to a REST service with TIdHTTP.
It works, as long as I don't have scandinavian letter in the json-data (ÅÄÖ). Then the server rejects the message. I can send the same data OK with Postman, so it is not a server issue.
My code:
String JsonData = "{...}";
TStringStream *JsonStream = new TStringStream(JsonData);
IdHTTP1->Request->CustomHeaders->AddValue("user", AUser);
IdHTTP1->Request->CustomHeaders->AddValue("password", APassword);
IdHTTP1->Request->ContentType = "application/json";
IdHTTP1->Request->CharSet = "utf-8";
IdHTTP1->Put("https://restserver", JsonStream);
delete JsonStream;
I've found examples in Delphi, where you create the TStringStream with an encoding flag:
AStream := TStringStream.Create(SomeData, TEncoding.UTF8);
But I can not see how an eqvuivalent works in c++.
This is an multi device application written with C++Builder v10.3
The TEncoding class is declared in the <System.SysUtils.hpp> header, and has a static UTF8 property (an example of its use is in Embarcadero's DocWiki). In your case, the construction of the TStringStream should look like this:
TStringStream *JsonStream = new TStringStream(JsonData, TEncoding::UTF8, false);
Related
Using Embarcadero C++ Builder 10.3.
I have a DynamicArray<uint8_t> myData object. I want to send/write its raw binary content (bytes) to a server using the TIdTcpClient component. I'm going about it like this:
TIdTcpClient tcpClient1;
// Bla Bla Bla
tcpClient1->IOHandler->Write(rawData);
Where rawData should be of type TIdBytes or TIdStream
So basically, it boils down to the following: How to convert myData object to a rawData type of either TIdBytes or TIdStream?
First off, TIdStream has not been part of Indy in a VERY VERY LONG time, which makes me wonder if you are using a very old version of Indy, not the one that shipped with C++Builder 10.3. Indy has supported the RTL's standard TStream class for a very long time.
That being said...
TIdBytes is an alias for System::DynamicArray<System::Byte>, where System::Byte is an alias for unsigned char, which is the same size and sign-ness as uint8_t (depending on compiler, uint8_t might even just be an alias for unsigned char).
So, the simplest solution, without having to make a separate copy of your data, is to simply type-cast it, eg:
tcpClient1->IOHandler->Write(reinterpret_cast<TIdBytes&>(myData));
This is technically undefined behavior, since DynamicArray<uint8_t> and DynamicArray<Byte> are unrelated types (unless uint8_t and Byte are both aliases for unsigned char), but it will work in your case since it is the same underlying code behind both arrays, and uint8_t and Byte have the same underlying memory layout.
Alternatively, the next simplest solution, without copying data or invoking undefined behavior, is to use Indy's TIdReadOnlyMemoryBufferStream class in IdGlobal.hpp, eg:
TIdReadOnlyMemoryBufferStream *ms = new TIdReadOnlyMemoryBufferStream(&myData[0], myData.Length);
try {
tcpClient1->IOHandler->Write(ms);
}
__finally {
delete ms;
}
Or:
{
auto ms = std::make_unique<TIdReadOnlyMemoryBufferStream>(&myData[0], myData.Length);
tcpClient1->IOHandler->Write(ms.get());
}
Otherwise, the final solution is to just copy the data into a TIdBytes, eg:
{
TIdBytes bytes;
bytes.Length = myData.Length;
memcpy(&bytes[0], &myData[0], myData.Length);
or:
std::copy(myData.begin(), myData.end(), bytes.begin());
tcpClient1->IOHandler->Write(bytes);
}
I am using the code below in C++Builder XE4 VCL 32bit. I am using the Indy components, version 10.6.0.497.
I have been using IdHTTP->Get() with HTTP addresses that have now changed to HTTPS. I believe I need to create a TIdSSLIOHandlerSocketOpenSSL component and add it to TIdHTTP as its IOHandler.
When I try to do this, the code below gives the error:
E2451 Undefined symbol 'TIdSSLIOHandlerSocketOpenSSL'
The error is on the code, std::auto_ptr<TIdSSLIOHandlerSocketOpenSSL>.
I am not sure why TIdSSLIOHandlerSocketOpenSSL is undefined, because I have Indy installed and can use TIdSSLIOHandlerSocketOpenSSL as a traditional component from the component palette.
Can anyone show me how I can set this code up to use HTTPS addresses?
std::auto_ptr<TIdSSLIOHandlerSocketOpenSSL> Local_IOHandler( new TIdSSLIOHandlerSocketOpenSSL( NULL ) );
//error: E2451 Undefined symbol 'TIdSSLIOHandlerSocketOpenSSL'
//error: E2299 Cannot generate template specialization from 'std::auto_ptr<_Ty>'
std::auto_ptr<TIdHTTP> Local_IdHTTP( new TIdHTTP( NULL ) );
Local_IdHTTP->Name="MyLocalHTTP";
Local_IdHTTP->HandleRedirects=true;
Local_IdHTTP->IOHandler=Local_IOHandler;
TStringStream *jsonToSend = new TStringStream;
UnicodeString GetURL = "https://chartapi.finance.yahoo.com/instrument/1.0/CLZ17.NYM/chartdata;type=quote;range=1d/csv/";
jsonToSend->Clear();
try
{
Local_IdHTTP->Get(GetURL, jsonToSend);
}
catch (const Exception &E)
{
ShowMessage( E.Message );
//error: IOHandler value is not valid
}
When I try to do this the code below gives the error E2451 Undefined symbol 'TIdSSLIOHandlerSocketOpenSSL'
Add #include <IdSSLOpenSSL.hpp> to your code.
I am not sure why 'TIdSSLIOHandlerSocketOpenSSL' is Undefined because I have Indy installed and can use 'TIdSSLIOHandlerSocketOpenSSL' as a traditional component from the compoenent pallet?
Dropping a component onto your Form at design-time auto-generates any necessary #include statements for you. TIdSSLIOHandlerSocketOpenSSL is no different.
That being said, once you get that fixed, you cannot assign a std::auto_ptr itself to the IOHandler. You need to use its get() method to get the object pointer:
Local_IdHTTP->IOHandler = Local_IOHandler.get();
And you should consider using std::auto_ptr for your TStringStream as well:
std::auto_ptr<TStringStream> json( new TStringStream );
Local_IdHTTP->Get(GetURL, json.get());
// use json as needed...
Though in this situation, I would suggest using the overloaded version of TIdHTTP::Get() that returns a String instead, there is no benefit to using a TStringStream:
String json = Local_IdHTTP->Get(GetURL);
// use json as needed...
String content = "Jane";
String container = 'A.Sven,G.Jane,Jack'; // This is the string which i need to be searched with string content
boolean containerContainsContent = StringUtils.containsIgnoreCase(container, content); // I used to write like this in java
I am new to Delphi. Is there a contains command in Delphi or any other command which performs the same operation?
You can use the functions in StrUtils in Delphi
uses
StrUtils;
..
if ContainsText('A.Sven,G.Jane,Jack', 'Jane') then
...
ContainsText returns true if the subtext is found, without case-sensitivity, in the given text
In StrUtils you'll also find handy functions like StartsText, EndsText and ReplaceText
You might also find helpful the Contains Function in System.SysUtils as below.
uses
Sysytem.SysUtils;
....
txt := 'This is a string variable';
if txt.contains('str') then
....
I'm having a problem with UTF8 encoding in my asp.net mvc 2 application in C#. I'm trying let user download a simple text file from a string. I am trying to get bytes array with the following line:
var x = Encoding.UTF8.GetBytes(csvString);
but when I return it for download using:
return File(x, ..., ...);
I get a file which is without BOM so I don't get Croatian characters shown up correctly. This is because my bytes array does not include BOM after encoding. I triend inserting those bytes manually and then it shows up correctly, but that's not the best way to do it.
I also tried creating UTF8Encoding class instance and passing a boolean value (true) to its constructor to include BOM, but it doesn't work either.
Anyone has a solution? Thanks!
Try like this:
public ActionResult Download()
{
var data = Encoding.UTF8.GetBytes("some data");
var result = Encoding.UTF8.GetPreamble().Concat(data).ToArray();
return File(result, "application/csv", "foo.csv");
}
The reason is that the UTF8Encoding constructor that takes a boolean parameter doesn't do what you would expect:
byte[] bytes = new UTF8Encoding(true).GetBytes("a");
The resulting array would contain a single byte with the value of 97. There's no BOM because UTF8 doesn't require a BOM.
I created a simple extension to convert any string in any encoding to its representation of byte array when it is written to a file or stream:
public static class StreamExtensions
{
public static byte[] ToBytes(this string value, Encoding encoding)
{
using (var stream = new MemoryStream())
using (var sw = new StreamWriter(stream, encoding))
{
sw.Write(value);
sw.Flush();
return stream.ToArray();
}
}
}
Usage:
stringValue.ToBytes(Encoding.UTF8)
This will work also for other encodings like UTF-16 which requires the BOM.
UTF-8 does not require a BOM, because it is a sequence of 1-byte words. UTF-8 = UTF-8BE = UTF-8LE.
In contrast, UTF-16 requires a BOM at the beginning of the stream to identify whether the remainder of the stream is UTF-16BE or UTF-16LE, because UTF-16 is a sequence of 2-byte words and the BOM identifies whether the bytes in the words are BE or LE.
The problem does not lie with the Encoding.UTF8 class. The problem lies with whatever program you are using to view the files.
Remember that .NET strings are all unicode while there stay in memory, so if you can see your csvString correctly with the debugger the problem is writing the file.
In my opinion you should return a FileResult with the same encoding that the files. Try setting the returning File encoding,
I have a site where I allow members to upload photos. In the MVC Controller I take the FormCollection as the parameter to the Action. I then read the first file as type HttpPostedFileBase. I use this to generate thumbnails. This all works fine.
In addition to allowing members to upload their own photos, I would like to use the System.Net.WebClient to import photos myself.
I am trying to generalize the method that processes the uploaded photo (file) so that it can take a general Stream object instead of the specific HttpPostedFileBase.
I am trying to base everything off of Stream since the HttpPostedFileBase has an InputStream property that contains the stream of the file and the WebClient has an OpenRead method that returns Stream.
However, by going with Stream over HttpPostedFileBase, it looks like I am loosing ContentType and ContentLength properties which I use for validating the file.
Not having worked with binary stream before, is there a way to get the ContentType and ContentLength from a Stream? Or is there a way to create a HttpPostedFileBase object using the Stream?
You're right to look at it from a raw stream perspective because then you can create one method that handles streams and therefore many scenarios from which they come.
In the file upload scenario, the stream you're acquiring is on a separate property from the content-type. Sometimes magic numbers (also a great source here) can be used to detect the data type by the stream header bytes but this might be overkill since the data is already available to you through other means (i.e. the Content-Type header, or the .ext file extension, etc).
You can measure the byte length of the stream just by virtue of reading it so you don't really need the Content-Length header: the browser just finds it useful to know what size of file to expect in advance.
If your WebClient is accessing a resource URI on the Internet, it will know the file extension like http://www.example.com/image.gif and that can be a good file type identifier.
Since the file info is already available to you, why not open up one more argument on your custom processing method to accept a content type string identifier like:
public static class Custom {
// Works with a stream from any source and a content type string indentifier.
static public void SavePicture(Stream inStream, string contentIdentifer) {
// Parse and recognize contentIdentifer to know the kind of file.
// Read the bytes of the file in the stream (while counting them).
// Write the bytes to wherever the destination is (e.g. disk)
// Example:
long totalBytesSeen = 0L;
byte[] bytes = new byte[1024]; //1K buffer to store bytes.
// Read one chunk of bytes at a time.
do
{
int num = inStream.Read(bytes, 0, 1024); // read up to 1024 bytes
// No bytes read means end of file.
if (num == 0)
break; // good bye
totalBytesSeen += num; //Actual length is accumulating.
/* Can check for "magic number" here, while reading this stream
* in the case the file extension or content-type cannot be trusted.
*/
/* Write logic here to write the byte buffer to
* disk or do what you want with them.
*/
} while (true);
}
}
Some useful filename parsing features are in the IO namespace:
using System.IO;
Use your custom method in the scenarios you mentioned like so:
From an HttpPostedFileBase instance named myPostedFile
Custom.SavePicture(myPostedFile.InputStream, myPostedFile.ContentType);
When using a WebClient instance named webClient1:
var imageFilename = "pic.gif";
var stream = webClient1.DownloadFile("http://www.example.com/images/", imageFilename)
//...
Custom.SavePicture(stream, Path.GetExtension(imageFilename));
Or even when processing a file from disk:
Custom.SavePicture(File.Open(pathToFile), Path.GetExtension(pathToFile));
Call the same custom method for any stream with a content identifer that you can parse and recognize.