Delphi Devart SecureBridge POST Request - delphi

I am using the trial version of DevArt's SecureBridge product. I am trying to process POST, but somehow I could not print the request data.
XML:
<test>
<a>test1</a>
<b>test2</b>
</test>
Delphi:
ScHttpWebRequest1.Method := rmPOST;
ScHttpWebRequest1.ContentType := 'text/xml';
ScHttpWebRequest1.RequestUri := 'https://test.com/api';
ScHttpWebRequest1.KeepAlive := True;
ScHttpWebRequest1.ContentLength := Length(XML);
ScHttpWebRequest1.WriteBuffer(pAnsiChar(XML), 0, Length(XML)); ///I think I'm making a mistake here.
ShowMessage(ScHttpWebRequest1.GetResponse.ReadAsString);
I have reviewed the documents, but there is a feature called RequestStream. This feature was not available in the version I downloaded. I think WriteBuffer is used instead or different. all I want to do is request a POST with XML content on the relevant site. How can I do it?
Thanks.

Here's a chunk of code that has worked for me:
var
Response: TScHttpWebResponse;
ResponseStr: string;
buf: TBytes;
begin
ScHttpWebRequest1.Method := rmPOST;
ScHttpWebRequest1.ContentType := 'text/xml';
ScHttpWebRequest1.RequestUri := 'https://test.com/api';
ScHttpWebRequest1.KeepAlive := True;
buf := TEncoding.UTF8.GetBytes(xml);
ScHttpWebRequest1.ContentLength := Length(buf);
ScHttpWebRequest1.WriteBuffer(buf);
Response:=ScHttpWebRequest1.GetResponse;
ResponseStr:=Response.ReadAsString;
end;

Based on Devart forums information you can post/put stream or strings parameters as below:
var
Request: TScHttpWebRequest;
Response: TScHttpWebResponse;
ResponseStr: string;
Stream: TFileStream;
begin
Request := TScHttpWebRequest.Create(URL);
Stream := TFileStream.Create(FileName, fmOpenRead);
try
Request.Method := rmPut;
Request.ContentType := 'application/pdf';
Request.TransferEncoding := 'binary';
Request.Headers.Add('Content-Disposition', 'form-data; name="FormFile"; filename="Document1.pdf"');
Request.ContentLength := Stream.Size;
Request.SendChunked := True;
Request.RequestStream := Stream;
Response := Request.GetResponse;
ResponseStr := Response.ReadAsString;
Response.Free;
finally
Stream.Free;
Request.Free;
end;
end;

Related

How to encode the response of an TIdHTTP call?

In a project I use TIdHTTP to call a webserver.
The webserver is an asp.net test application that returns the following json:
{
"message":"test ÀÈÉÌÒÙàèéìòù"
}
The response I get in Delphi is a kind of not encoded string:
{"message":"test ÃÃÃÃÃÃàèéìòù"}
this is how I use TIdHTTP:
Result := '';
IdHTTP := TIdHTTP.Create;
IdHTTP.Request.MethodOverride := 'ForwardCommand';
IdSSLIOHandlerSocketOpenSSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
IdSSLIOHandlerSocketOpenSSL.SSLOptions.Mode := sslmClient;
IdSSLIOHandlerSocketOpenSSL.SSLOptions.SSLVersions:= [sslvTLSv1_2];
IdHTTP.IOHandler := IdSSLIOHandlerSocketOpenSSL;
IdHTTP.HandleRedirects := True;
IdHTTP.Response.ContentEncoding := 'UTF-8'; // I tried this but it seems not enough!
try
url := 'testappUrl';
try
IdHTTP.ConnectTimeout := 2000;
IdHTTP.ReadTimeout := 4000;
Response := IdHTTP.Get(url);
ShowMessage(response);
except
on E:Exception do
begin
response := StringReplace(E.Message,#10,' ',[rfReplaceAll]);
response := StringReplace(response,#13,' ',[rfReplaceAll]);
response := '{"errormessage": "'+response+'"}';
end;
end;
Result := response;
finally
IdHTTP.Free;
end;
please tell me how I can see the response correctly.
Is there a way to force encoding so that accented chars are read correctly?
Thanks.
Try to use a TStringStream forcing the encoding (UTF-8).
Test this code to get the response:
var
ts:TStringStream;
begin
...
ts := TStringStream.Create(string.Empty, TEncoding.UTF8);
IdHTTP1.Get('url', ts);
ShowMessage(ts.DataString);
or
ShowMessage(ts.ToString);
...

Why uploaded photo is much smaller than saved - Delphi 10.3.2, firemonkey

I have Delphi 10.3.2
I do not understand this situations:
1)
Uploading photo about 1M
image1.Bitmap.LoadFromFile('test.jpg');
Then I save the same photo
image1.Bitmap.SaveToFile('test_new.jpg');
and test_new.jpg is about 3M. Why ???
2)
I want to send a photo from the TImage (test1.jpg - 1MB) object using IdHTTP and POST request to server.
I use the function Base64_Encoding_stream to encode image.
Image size (string) after encoding the function is 20 MB! ? Why if the original file has 1MB ?
function Base64_Encoding_stream(_image:Timage): string;
var
base64: TIdEncoderMIME;
output: string;
stream_image : TStream;
begin
try
begin
base64 := TIdEncoderMIME.Create(nil);
stream_image := TMemoryStream.Create;
_image.Bitmap.SaveToStream(stream_image);
stream_image.Position := 0;
output := TIdEncoderMIME.EncodeStream(stream_image);
stream_image.Free;
base64.Free;
if not(output = '') then
begin
Result := output;
end
else
begin
Result := 'Error';
end;
end;
except
begin
Result := 'Error'
end;
end;
end;
....
img_encoded := Base64_Encoding_stream(Image1);
.....
procedure Send(_json:String );
var
lHTTP : TIdHTTP;
PostData : TStringList;
begin
PostData := TStringList.Create;
lHTTP := TIdHTTP.Create(nil);
try
PostData.Add('dane=' + _json );
lHTTP.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';
lHTTP.Request.Connection := 'keep-alive';
lHTTP.Request.ContentType := 'application/x-www-form-urlencoded';
lHTTP.Request.Charset := 'utf-8';
lHTTP.Request.Method := 'POST';
_dane := lHTTP.Post('http://......./add_photo.php',PostData);
finally
lHTTP.Free;
PostData.Free;
end;
To post your original file using base64 you can basically use your own code. You only need to change the used stream inside your base64 encoding routine like this:
function Base64_Encoding_stream(const filename: string): string;
var
stream_image : TStream;
begin
try
// create read-only stream to access the file data
stream_image := TFileStream.Create(filename, fmOpenRead or fmShareDenyWrite);
// the stream position will be ‘0’, so no need to set that
Try
Result := TIdEncoderMIME.EncodeStream(stream_image);
Finally
stream_image.Free;
End;
if length(result) = 0 then
begin
Result := 'Error';
end;
except
Result := 'Error'
end;
end;
Also, I refactored your code a bit with some try/finally sections, to ensure no memory leaks when errors occur. And I removed the begin/end inside the try/except as those are not needed.
Also removed the local string variable to avoid double string allocation and the unnecessary construction of the TIdEncoderMIME base64 object.

No mapping for the Unicode character exists in the target multi-byte code page : how to convert MemoryStream to String

My goal is to be able to convert TMemoryStream to string. I have this code to get the data into the TMemoryStream:
var
idHttp : TIdHTTPEx;
url : string;
slTemp : TStringList;
memoryStream : TMemoryStream;
begin
try
idHttp := TIdHTTPEx.Create(nil);
slTemp := TStringList.Create;
memoryStream := TMemoryStream.Create;
try
url := GetURL;
SetParams(slTemp);
idHttp.Request.Accept := 'application/json, text/javascript, */*; q=0.01';
idHttp.Request.AcceptEncoding := 'gzip, deflate, br';
idHttp.Request.AcceptLanguage := 'en-US,en;q=0.9';
idHttp.Request.CacheControl := 'no-cache';
idHttp.Request.Connection := 'keep-alive';
idHttp.Request.ContentLength := 16;
idHttp.Request.ContentType := 'application/x-www-form-urlencoded; charset=UTF-8';
idHttp.Post(url, slTemp, memoryStream);
Result := MemoryStreamToString(memoryStream);
finally
memoryStream.Free;
slTemp.Free;
idHttp.Free;
end;
except on E : Exception do
begin
Result := 'e:' + E.Message;
end;
end;
end;
And this is my code to convert it to a string:
function MemoryStreamToString(MemoryStream : TMemoryStream): string;
var
StringStream: TStringStream;
begin
Result:='';
StringStream:= TStringStream.Create('', TEncoding.UTF8);
try
MemoryStream.Position := 0;
StringStream.CopyFrom(MemoryStream, MemoryStream.Size);
Result:= StringStream.DataString;
Result := Result;
finally
FreeAndNil(StringStream);
end;
end;
My function works fine in most of the conversion but not this. I checked these links: link1, link2 but they are different than my situation. I tried link3 too but still fail.
Any idea how to solve the problem?
You don't need to decode the raw data manually. Just let TIdHTTP do it for you. The Post() method has an overload that returns a decoded string:
Result := idHttp.Post(url, slTemp);
Also, you need to get rid of this line completely:
idHttp.Request.AcceptEncoding := 'gzip, deflate, br';
Otherwise TIdHTTP will not be able to decode the response correctly if the server decides to send a compressed response. You are manually giving the server permission to do so, but you are not setting up the TIdHTTP.Compressor property so TIdHTTP can handle decompression. Do not set the AcceptEncoding manually unless you are willing and able to manually detect and decode a response that has been actually been encoded in one of the formats you specify. Otherwise, just let TIdHTTP manage the AcceptEncoding property internally based on its actual capabilites.

Using PayPal REST client with Delphi XE2

I am trying to interface with the PayPal REST client, following the instructions here:
https://developer.paypal.com/docs/integration/direct/make-your-first-call/
I can successfully obtain the access token using a TIdHttp component with this code:
http.Request.ContentType := 'application/x-www-form-urlencoded';
http.Request.Accept := 'application/json';
http.Request.AcceptLanguage := 'en_US';
http.Request.BasicAuthentication := True;
http.Request.Username := 'my paypal clientid';
http.Request.Password := 'my paypal secret';
slParameters := TStringList.Create;
Response := TStringStream.Create;
try
//get an access token
slParameters.Add('grant_type=client_credentials');
http.Post('https://api.sandbox.paypal.com/v1/oauth2/token', slParameters, Response);
json := Response.DataString;
PayPalObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(json), 0) as TJSONObject;
try
jTokenValue := PayPalObj.Get('access_token').JsonValue;
AccessToken := jTokenValue.Value;
jTokenValue := PayPalObj.Get('token_type').JsonValue;
TokenType := jTokenValue.Value;
finally
PayPalObj.Free;
end;
if TokenType <> 'Bearer' then
Exit;
if AccessToken = '' then
Exit;
....
finally
Response.Free;
slParameters.Free;
end;
Once I have the token I should be able to create a payment. On the PayPal website an example using cURL is given here:
https://developer.paypal.com/docs/integration/web/accept-paypal-payment/
This is what I have tried:
//create a payment
PayPalObj := TJSONObject.Create;
try
PayPalObj.AddPair(TJSONPair.Create('intent', TJSONString.Create('sale')));
RedirectObj := TJSONObject.Create;
try
RedirectObj.AddPair(TJSONPair.Create('return_url', TJSONString.Create('http://blahblah.com/return')));
RedirectObj.AddPair(TJSONPair.Create('cancel_url', TJSONString.Create('http://blahblah.com/cancel')));
except
RedirectObj.Free;
Exit;
end;
PayerObj := TJSONObject.Create;
try
PayerObj.AddPair(TJSONPair.Create('payment_method', TJSONString.Create('paypal')));
except
PayerObj.Free;
Exit;
end;
TransactionsArray := TJSONArray.Create;
AmountObj := TJSONObject.Create;
TransactionObj := TJSONObject.Create;
try
AmountObj.AddPair('total', TJSONString.Create('7.47'));
AmountObj.AddPair('currency', TJSONString.Create('USD'));
TransactionObj.AddPair('amount', AmountObj);
TransactionObj.AddPair('description', TJSONString.Create('payment description'));
TransactionsArray.Add(TransactionObj);
except
TransactionsArray.Free;
AmountObj.Free;
TransactionObj.Free;
Exit;
end;
PayPalObj.AddPair(TJSONPair.Create('redirect_urls', RedirectObj));
PayPalObj.AddPair(TJSONPair.Create('payer', PayerObj));
PayPalObj.AddPair(TJSONPair.Create('transactions', TransactionsArray));
slParameters.Clear;
Response.Clear;
http.Request.ContentType := 'application/json';
http.Request.CustomHeaders.Clear;
//http.Request.CustomHeaders.FoldLines := False; have tried this with no success
http.Request.CustomHeaders.AddValue('Authorization', Format('Bearer %s', [AccessToken])); //token obtained from first request
slParameters.Add(PayPalObj.ToString);
http.Post('https://api.sandbox.paypal.com/v1/payments/payment', slParameters, Response);
json := Response.DataString;
...
finally
PayPalObj.Free;
end;
I'm not getting any response. I am sure I have constructed the JSON string correctly as I have carefully compared it with the sample one. I have also tested the sample one using cURL and it does work. I'm not sure if it's right to add the JSON string into a string list as I have done. I'm also not sure if I need to include the "-d" cURL parameter somewhere. Any advice would be gratefully received.
In the second step, you cannot use a TStringList to post the JSON data. That only works for application/x-www-form-urlencoded posts. To post JSON, you need to use a TStream instead.
Also, you don't need to use a TStringStream to get a response as a String. Post() can return a String directly.
Try this:
json := http.Post('https://api.sandbox.paypal.com/v1/oauth2/token', slParameters);
...
ssJson := TStringStream.Create(PayPalObj.ToString, TEncoding.ASCII);
try
json := http.Post('https://api.sandbox.paypal.com/v1/payments/payment', ssJson);
finally
ssJson.Free;
end;

MultiPartEntity in Indy [Delphi]

I am trying to add attachement to one service.
This taken from documentation:
I wonder if an entity can be added in indy as if it could be done in for example Java:
postRequest.setHeader("X-Atlassian-Token","nocheck");
MultipartEntity entity = new MultipartEntity();
entity.addPart("file", new FileBody(fileUpload));
postRequest.setEntity(entity);
HttpResponse response = httpClient.execute(postRequest);
Found it:
uses IdMultipartFormData
...
Stream: TIdMultipartFormDataStream;
EDITED:
For this particular problem with Jira REST API, solution would be something like:
Posting against URL: BASE_URL+/rest/api/2/issue/{issueIdOrKey}/attachments
try
lHTTP.Request.CustomHeaders.AddValue('X-Atlassian-Token', 'nocheck');
FileSize := lHTTP.Response.ContentLength;
FileStrm := TFileStream.Create(AFile, fmOpenRead or fmShareDenyWrite);
try
if FileSize < FileStrm.Size then
begin
FileStrm.Position := FileSize;
Stream := TIdMultipartFormDataStream.Create;
try
Stream.AddFile('file', AFile);
with lHTTP do
begin
with Request do
begin
ContentRangeStart := FileSize + 1;
ContentRangeEnd := FileStrm.Size;
end;
Post(self.BASE_URL + SEND_ATTACHEMENT_TO_AN_ISSUE_URL +
IntToStr(IssueID) + '/attachments', Stream);
Result := true;
end;
finally
Stream.Free;
end;
end;
finally
FileStrm.Free;
end;
except
Result := false;
end;
Note: After that one should not forget to change back the headers and to change the "Content Type" to the one that is needed for future requests

Resources