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
Related
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);
...
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;
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.
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;
I'm making requests to the webaddress to get XML files throught the HTTPS connection. But this connection works like 50%. In most cases it fails. Usual error is "socket error #10060". Or "Error connecting with SSL. EOF was observed that violates the protocol". What I'm doing wrong?
function SendRequest(parameters: string): IXMLDocument;
var
sPostData: TStringList;
sHttpSocket: TIdHTTP;
sshSocketHandler: TIdSSLIOHandlerSocketOpenSSL;
resStream: TStringStream;
xDoc: IXMLDocument;
begin
sPostData := TStringList.Create;
try
sPostData.Add('add some parameter to post' + '&');
sPostData.Add('add some parameter to post' + '&');
sPostData.Add('add some parameter to post' + '&');
sPostData.Add(parameters);
sHttpSocket := TIdHTTP.Create;
sshSocketHandler := TIdSSLIOHandlerSocketOpenSSL.Create;
sHttpSocket.IOHandler := sshSocketHandler;
sHttpSocket.Request.ContentType := 'application/x-www-form-urlencoded';
sHttpSocket.Request.Method := 'POST';
resStream := TStringStream.Create;
sHttpSocket.Post(Self.sUrl, sPostData, resStream);
xDoc := CreateXMLDoc;
xDoc.LoadFromStream(resStream);
Result := xDoc;
resStream.Free;
sHttpSocket.Free;
sshSocketHandler.Free;
sPostData.Free;
except on E: Exception do
begin
TCommon.ErrorLog('errorLog.txt', DateTimeToStr(Now) + ' ' + E.Message);
end
end;
end;
Maybe I can do this in another way, that works like 100%, when internet connection is available?
Regards,
evilone
An "EOF" error suggests you are connnecting to a server that is not actually using SSL to begin with, or the SSL data may be corrupted.
Besides that, why are you including explicit '&' characters between your post data parameters? Don't do that, Indy will just encode them and send its own '&' characters. Also, consider using TMemoryStream instead of TStringStream to ensure IXMLDocumect.LoadFromStream() is loading the server's original raw XML data as-is, and not an altered version that the RTL/VCL produces due to Unicode handling (TStringStream is TEncoding-enabled).
Edit: Given the URL you provided, an example of calling verifyUser() would look like this:
const
ERPLYAccountCode = '...';
function verifyUser(const user, pass: string; const sessionLength: Integer = 3600): IXMLDocument;
var
sPostData: TStringList;
sHttpSocket: TIdHTTP;
sshSocketHandler: TIdSSLIOHandlerSocketOpenSSL;
resStream: TMemoryStream;
xDoc: IXMLDocument;
begin
Result := nil;
try
resStream := TMemoryStream.Create;
try
sPostData := TStringList.Create;
try
sPostData.Add('clientCode=' + ERPLYAccountCode);
sPostData.Add('request=verifyUser');
sPostData.Add('version=1.0');
sPostData.Add('responseType=XML');
sPostData.Add('responseMode=normal');
sPostData.Add('username=' + user);
sPostData.Add('password=' + pass);
sPostData.Add('sessionLength=' + IntToStr(sessionLength));
sHttpSocket := TIdHTTP.Create;
try
sshSocketHandler := TIdSSLIOHandlerSocketOpenSSL.Create(sHttpSocket);
sHttpSocket.IOHandler := sshSocketHandler;
sHttpSocket.Request.ContentType := 'application/x-www-form-urlencoded';
sHttpSocket.Post('https://www.erply.net/api/', sPostData, resStream);
finally
sHttpSocket.Free;
end;
finally
sPostData.Free;
end;
resStream.Position := 0;
xDoc := CreateXMLDoc;
xDoc.LoadFromStream(resStream);
Result := xDoc;
finally
resStream.Free;
end;
except
on E: Exception do
begin
TCommon.ErrorLog('errorLog.txt', DateTimeToStr(Now) + ' ' + E.Message);
end;
end;
end;