How to post binary jpg file using Indy10 Http? - http-post

I have to post a jpg file using TIdHTTP component (Indy 10). What I need is to upload a file to a Drupal 8 field. I can do it with Advanced Rest Client following this documentation:
https://www.drupal.org/docs/8/core/modules/jsonapi-module/file-uploads
https://www.drupal.org/node/3024331#comment-13387295
But I'm tring to do it with Delphi 2010 and Indy 10 without success. I always get a "415 Unsupported media type" error with this detail:
"No route found that matches "Content-Type: multipart/form-data".
This is the code I use:
var
response: string;
Params: TIdMultiPartFormDataStream;
begin
Result := '';
IdHTTP1.ConnectTimeout := 10000;
IdHTTP1.Request.Clear;
IdHTTP1.Request.CustomHeaders.Clear;
IdHTTP1.Request.BasicAuthentication := false;
IdHTTP1.Request.ContentType := 'application/octet-stream';
IdHTTP1.Request.Accept := 'application/vnd.api+json';
IdHTTP1.Request.ContentLanguage := 'es';
IdHTTP1.Request.CustomHeaders.AddValue('api-key', 'my_api_key_here');
IdHTTP1.Request.ContentDisposition:= 'file; filename="testimage.jpg"';
IdHTTP1.Request.Charset := 'utf-8';
IdHTTP1.AllowCookies := True;
IdHTTP1.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36';
IdHTTP1.HandleRedirects := True;
Params := TIdMultiPartFormDataStream.Create;
try
try
Params.AddFile('testimage.jpg','c:\tmp\testimage.jpg','application/octet-stream').ContentTransfer:='binary';
response:= IdHTTP1.Post('<my_url_to_the_field_as_instructions>', Params);
except
on E: Exception do
begin
memo1.Lines.add('Error ' + E.message);
end;
end;
finally
Params.Free;
end;

You can't post the file using TIdMultiPartFormDataStream, because the server is explicitly telling you that it does not support multipart/form-data requests (calling TIdHTTP.Post() with a TIdMultiPartFormDataStream overwrites the Request.ContentType).
You will have to post the file use a plain vanilla TStream instead, such as TFileStream:
var
response: string;
PostData: TStream;
begin
Result := '';
IdHTTP1.ConnectTimeout := 10000;
IdHTTP1.Request.Clear;
IdHTTP1.Request.BasicAuthentication := false;
IdHTTP1.Request.ContentType := 'application/octet-stream';
IdHTTP1.Request.Accept := 'application/vnd.api+json';
IdHTTP1.Request.ContentLanguage := 'es';
IdHTTP1.Request.CustomHeaders.AddValue('api-key', 'my_api_key_here');
IdHTTP1.Request.ContentDisposition := 'file; filename="testimage.jpg"';
IdHTTP1.AllowCookies := True;
IdHTTP1.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36';
IdHTTP1.HandleRedirects := True;
PostData := TFileStream.Create('<path_to>\testimage.jpg', fmOpenRead or fmShareDenyWrite);
try
try
response := IdHTTP1.Post('<my_url_to_the_field_as_instructions>', PostData);
except
on E: Exception do
begin
Memo1.Lines.Add('Error ' + E.message);
end;
end;
finally
PostData.Free;
end;
end;
Alternatively, TIdHTTP has an overload of Post() that takes a file path as input:
var
response: string;
begin
Result := '';
IdHTTP1.ConnectTimeout := 10000;
IdHTTP1.Request.Clear;
IdHTTP1.Request.BasicAuthentication := false;
IdHTTP1.Request.ContentType := 'application/octet-stream';
IdHTTP1.Request.Accept := 'application/vnd.api+json';
IdHTTP1.Request.ContentLanguage := 'es';
IdHTTP1.Request.CustomHeaders.AddValue('api-key', 'my_api_key_here');
IdHTTP1.Request.ContentDisposition := 'file; filename="testimage.jpg"';
IdHTTP1.AllowCookies := True;
IdHTTP1.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36';
IdHTTP1.HandleRedirects := True;
try
response := IdHTTP1.Post('<my_url_to_the_field_as_instructions>', '<path_to>\testimage.jpg');
except
on E: Exception do
begin
Memo1.Lines.Add('Error ' + E.message);
end;
end;
end;

Related

Indy IdHttp Digest Authentication - 401

When you try to take a picture from a camera, the authentication function does not work. I read all the other posts on the subject, but without success with this device.
Indy 10.6.2.0
Uses ..., IdAuthentication, IdAuthenticationDigest;
...
addr := 'cgi-bin/snapshot.cgi?1';
myADR := 'http://87.126.245.25:8181/' + addr;
rStream := TMemoryStream.Create;
try
H1 := TIdHttp.Create();
{$IFDEF DEBUG}
idLogFile := TIdLogFile.Create( H1 );
with idLogFile do begin
Filename := IncludeTrailingPathDelimiter( ExtractFileDir( Application.ExeName ) ) + 'indy_log.txt';
Active := true;
end;
{$ENDIF}
with H1 do begin
Response.KeepAlive := true;
ReadTimeout := selCAM.Timeout;
Request.BasicAuthentication := false;
Request.Username := selCAM.User;
Request.Password := selCAM.Pass;
Request.ContentType := 'image/jpeg';
Request.UserAgent := 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/97.0.4692.71';
Request.ContentVersion := '1.0';
Request.IPVersion := Id_IPv4;
Request.Host := 'http://' + addr;
HTTPOptions := [hoInProcessAuth, hoForceEncodeParams];
OnSelectAuthorization := IdHTTP_SelectAuthorization;
OnHeadersAvailable := IdHTTP_HeadersAvailable;
OnAuthorization := IdHTTP_Authorization;
{$IFDEF DEBUG} Intercept := idLogFile; {$ENDIF}
end;
try
H1.Get( myADR, rStream); except
on E: EIdHTTPProtocolException do begin SB1.Panels[0].Text := E.Message; er := true; end;
on E: EIdException do begin SB1.Panels[0].Text := E.Message; er := true; end;
on E: Exception do begin SB1.Panels[0].Text := E.Message; er := true; end;
end;
finally
H1.Free;
FreeAndNil(rStream);
end;
It works correctly through a browser
Attach wireshark from Browser, from Indy and Indy Log:
https://1drv.ms/u/s!AubiEh1vqvRLkr01GzXCf_T0yLgmfQ?e=69dqaD

adsweb getting http 402 using TidHTTP

I'm sometimes getting http 402 payment required when using TidHTTP accessing the Adsweb, but it is not on all computers. The same program run on one computer fine and on another I will get the 402 error running the same statement.
CSHttp: TidHTTP;
Try
CSHttp := TidHTTP.Create(nil);
MyURL := MasterTbl.FieldByName('DatabaseUrl').AsString;
MyUrl := MyUrl + '__query?statement=select%20name,accountnum%20from%20customer%20where%20accountnum=''' + Myphone + '''&$format=json'
with CSHttp do
begin
Request.CacheControl := 'no-cache';
Request.BasicAuthentication := True;
Request.Username := MasterTbl.FieldByName('DBlogin').AsString;
Request.Password := MasterTbl.FieldByName('DBPassword').AsString;
Request.UserAgent := 'Mozilla/3.0 (compatible; Indy Library)';
end;
Try
MyResult := CShttp.Get(MyURL);
Except
on E:Exception do
Myerror := E.Message;
End;
Finally
CSHttp.Free;
end;
If I restart the ADS 11 it will sometimes fix it.
Maybe it is something do wrong in the call?
Thanks,
Kim

RAD Studio 10.2 Indy doesn't send email using gmail

My problem is that when I use Indy to send email using Gmail it works ok in this computer where RAD Studio is installed. But when I copy my release version to different computer where is installed Windows 10 it gives an error "SSL negotiation failed"
My code is:
lIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
lIOHandler.SSLOptions.Method := sslvTLSv1;
lIOHandler.SSLOptions.Mode := sslmClient;
strA := EditOsoite.Text;
charArray[0] := ';';
o := 0;
IdSMTP1.IOHandler := lIOHandler;
IdSMTP1.UseTLS := utUseRequireTLS;
IdSMTP1.Host := 'smtp.gmail.com'; // EditPalvelin.Text;
//IdSMTP1.Authenticate;
// IdSMTP1.UseTLS := utUseExplicitTLS;
IdSMTP1.Username := EditPalvelin.Text;
IdSMTP1.Password := EditSalasana.Text;
IdSMTP1.Port := 587;
try
try
IdSMTP1.Connect;
IdSMTP1.Send(IdMessage1);
IdMessage1.Clear;
Sleep(1000);
//IdMessage1.Free;
except on E:Exception do begin
ShowMessage('Virhe lähetettäessä');
ShowMessage('There was an error: ' + E.Message);
//StatusMemo.Lines.Insert(0, 'ERROR: ' + E.Message) ;
end;
end;
finally
if IdSMTP1.Connected then begin
IdSMTP1.Disconnect;
//IdSMTP1.Free;
//IdMessage1.Free;
end;
end;

Copy Email Program to another computer

I wrote a program to send email in delphi xe3 , and it works fine , when I copy the program to another computer (windows 8) it works fine but on Computer (Windows 7) the stmp.send did not respond Unless I install embarcadero on it .I Think the problem is in the files libeay32.dll and ssleay32.dll
Here is the code
var
SMTP: TIdSMTP;
Email: TIdMessage;
SSLHandler: TIdSSLIOHandlerSocketOpenSSL;
begin
SMTP := TIdSMTP.Create(nil);
Email := TIdMessage.Create(nil);
SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
SSLHandler.MaxLineAction := maException;
SSLHandler.SSLOptions.Method := sslvTLSv1;
SSLHandler.SSLOptions.Mode := sslmUnassigned;
SSLHandler.SSLOptions.VerifyMode := [];
SSLHandler.SSLOptions.VerifyDepth := 0;
SMTP.IOHandler := SSLHandler;
SMTP.Host := 'smtp.gmail.com';
SMTP.Username := 'Username#gmail.com';
SMTP.UseTLS := utUseExplicitTLS;
SMTP.Port := 587;
SMTP.Password := 'Password';
SMTP.Connect;
Email.Clear;
Email.AttachmentEncoding:='MIME' ;
Email.IsEncoded := true;
Email.Charset := 'utf-8';
Email.ContentType :='multipart/alternative';
Email.Encoding := meMime;
Email.UseNowForDate := true;
Email.From.Address := 'Address' ;
Email.Recipients.EmailAddresses := 'Recipients';
Email.Subject := 'Subject';
Email.Body.Text :='Body' ;
SMTP.Send(Email);
SMTP.Disconnect;
except on E:Exception do
Button1.Caption:=E.Message;
end;
SMTP.Free;
Email.Free;
SSLHandler.Free;
end;
Any idea Thanks
The files libeay32.dll and ssleay32.dll are needed by the executable. Place them in the same folder as the executable and it should work, even when you don't install Delphi on the target computer.

Windows firewall rule for XP

How to programmatically add an application or port to Windows Firewall on Windows XP?
Try this code extracted from our open source SQlite3UI.pas unit:
function GetXPFirewall(var fwMgr, profile: OleVariant): boolean;
begin
Result := (Win32Platform=VER_PLATFORM_WIN32_NT) and
(Win32MajorVersion>5) or ((Win32MajorVersion=5) and (Win32MinorVersion>0));
if result then // need Windows XP at least
try
fwMgr := CreateOleObject('HNetCfg.FwMgr');
profile := fwMgr.LocalPolicy.CurrentProfile;
except
on E: Exception do
result := false;
end;
end;
const
NET_FW_PROFILE_DOMAIN = 0;
NET_FW_PROFILE_STANDARD = 1;
NET_FW_IP_VERSION_ANY = 2;
NET_FW_IP_PROTOCOL_UDP = 17;
NET_FW_IP_PROTOCOL_TCP = 6;
NET_FW_SCOPE_ALL = 0;
NET_FW_SCOPE_LOCAL_SUBNET = 1;
procedure AddApplicationToXPFirewall(const EntryName, ApplicationPathAndExe: string);
var fwMgr, profile, app: OleVariant;
begin
if GetXPFirewall(fwMgr,profile) then
try
if profile.FirewallEnabled then begin
app := CreateOLEObject('HNetCfg.FwAuthorizedApplication');
try
app.ProcessImageFileName := ApplicationPathAndExe;
app.Name := EntryName;
app.Scope := NET_FW_SCOPE_ALL;
app.IpVersion := NET_FW_IP_VERSION_ANY;
app.Enabled :=true;
profile.AuthorizedApplications.Add(app);
finally
app := varNull;
end;
end;
finally
profile := varNull;
fwMgr := varNull;
end;
end;
procedure AddPortToXPFirewall(const EntryName: string; PortNumber: cardinal);
var fwMgr, profile, port: OleVariant;
begin
if GetXPFirewall(fwMgr,profile) then
try
if profile.FirewallEnabled then begin
port := CreateOLEObject('HNetCfg.FWOpenPort');
port.Name := EntryName;
port.Protocol := NET_FW_IP_PROTOCOL_TCP;
port.Port := PortNumber;
port.Scope := NET_FW_SCOPE_ALL;
port.Enabled := true;
profile.GloballyOpenPorts.Add(port);
end;
finally
port := varNull;
profile := varNull;
fwMgr := varNull;
end;
end;
It will allow you to add an application or a port to the XP firewall.
Should work from Delphi 6 up to XE.
Scripting the Windows Firewall is possible, see Scripting the Windows Firewall
And code examples for example here

Resources