Uploading a bitmap with idHTTP from a Delphi 10.3 multidevice app - http

I have read many related posts about sending data with idHTTP but still I can't manage it.
I use this code :
updated
procedure TTabbedForm.SpeedButton1Click(Sender: TObject);
var
fName : string;
mStream : TMemoryStream;
begin
fName := 'image.jpg';
mStream := TMemoryStream.Create;
myImage.Bitmap.SaveToStream(mStream);
mStream.Position := 0;
try
IdHTTP1.Request.ContentType := 'application/octet-stream';
IdHTTP1.PUT('http://www.example.com/'+fName, mStream);
finally
mStream.free;
end;
end;
but i receive the error "Method not allowed".
What i'm doing wrong, please ?

For uploads to Google Drive, some additional steps are required. For example, the HTTP POST request must include a auth token which in turn is provided to you only after authentication (log in with a Google account). For Google Drive you must also use secure connections (https) which require SSL libraries such as OpenSSL.
Example from the API docs:
POST https://www.googleapis.com/upload/drive/v3/files?uploadType=media HTTP/1.1
Content-Type: image/jpeg
Content-Length: [NUMBER_OF_BYTES_IN_FILE]
Authorization: Bearer [YOUR_AUTH_TOKEN]
[JPEG_DATA]
The file simple upload API for Google Drive is documented here:
https://developers.google.com/drive/api/v3/simple-upload
Update
Try this example, it requires a valid auth token:
procedure TDriveAPITest.Run;
var
PostData: TStream;
Response: string;
begin
PostData := TFileStream.Create('test.png', fmOpenRead or fmShareDenyWrite);
try
IdHTTP := TIdHTTP.Create;
try
IdHTTP.HTTPOptions := IdHTTP.HTTPOptions + [hoNoProtocolErrorException];
IdHTTP.Request.CustomHeaders.Values['Authorization'] := 'Bearer [YOUR_AUTH_TOKEN]';
Response := IdHTTP.Post('https://www.googleapis.com/upload/drive/v3/files?uploadType=media', PostData);
if IdHTTP.ResponseCode = 200 then begin
WriteLn('Response: ' + Response);
end else begin
WriteLn('Error: ' + IdHTTP.ResponseText);
end;
finally
IdHTTP.Free;
end;
finally
PostData.Free;
end;
end;
Output:
Error: HTTP/1.0 401 Unauthorized

Related

Delphi Indy http.get with curl returns: unauthorized

According to the suppliers data i should have:
Http type GET
Response type: application/json
Parameter: Authorization: bearer + Token
Curl: curl -X GET --header 'Accept: application/json' --header 'Authorization: Bearer + Token, 'http://localhost:8080/api/v1/doors'
Request URL: 'http://localhost:8080/api/v1/doors'
I have translated this to Delphi(Indy TidHttp):
procedure TForm42.Button2Click(Sender: TObject);
var
resp: TMemoryStream;
begin
resp := TMemoryStream.Create;
try
IdHTTP1.Request.Clear;
IdHTTP1.Request.Accept := 'application/json';
IdHTTP1.Request.BasicAuthentication := True;
IdHTTP1.Request.CustomHeaders.FoldLines := False;
IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + TokenStr;
IdHTTP1.Get('http://10.10.1.62:8080/api/v1/doors', resp);
resp.Position := 0;
memCall.Lines.LoadFromStream(resp);
finally
resp.Free;
end;
end;
I read a lot about it here, so finally i also added 'foldlines (Adding custom header to TIdHttp request, header value has commas)
I also tried 'X-Authorization' as parameter, something i read from R. Lebeau, but the only reaction i get is an errordialog saying '401 unauthorized'.
I'm sure about the Token string (-> 'bearer ' + TokenStr) because i get an answer when putting the string in the suppliers trial.
Does someone have an idea what i'm doing wrong?
Request.BasicAuthentication should be False not True when using custom authentications.
And you don't need to set CustomHeaders.FoldLines as TIdHTTP already disables folding by default (it wasn't disabled by default at the time the other question was posted).
Otherwise, the rest of the code looks fine.
Though, I would suggest specifying TEncoding.UTF8 on the call to LoadFromStream()), eg:
procedure TForm42.Button2Click(Sender: TObject);
var
resp: TMemoryStream;
begin
resp := TMemoryStream.Create;
try
IdHTTP1.Request.Clear;
IdHTTP1.Request.Accept := 'application/json';
IdHTTP1.Request.BasicAuthentication := False;
IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + TokenStr;
IdHTTP1.Get('http://10.10.1.62:8080/api/v1/doors', resp);
resp.Position := 0;
memCall.Lines.LoadFromStream(resp, TEncoding.UTF8);
finally
resp.Free;
end;
end;
Or, using the overload of TIdHTTP.Get() that returns a string:
procedure TForm42.Button2Click(Sender: TObject);
begin
IdHTTP1.Request.Clear;
IdHTTP1.Request.Accept := 'application/json';
IdHTTP1.Request.BasicAuthentication := False;
IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + TokenStr;
memCall.Text := IdHTTP1.Get('http://10.10.1.62:8080/api/v1/doors');
end;

Uploading images to a WordPress WP REST api in Delphi 10.4 via RESTClient or INDY or any others

Can't upload image to my Wordpress site via REST api in Delphi 10.4.
I published a post via the REST api (in the REST Debugger and directly in the program), but without pictures it makes no sense.
Most recent code with RESTClient components:
procedure TForm1.Button1Click(Sender: TObject);
var jpgFoto: TMemoryStream;
begin
HTTPBasicAuthenticator1.Username := 'myuser';
HTTPBasicAuthenticator1.Password := 'mypass';
RESTRequest1.Method := TRESTRequestMethod.rmPOST;
RESTRequest1.Resource := 'wp/v2/media';
RESTClient1.BaseURL := 'https://*.ru/wp-json';
RESTRequest1.Params.AddHeader('Content-Disposition', 'attachment; filename="00s.jpg"');//I tried different options
RESTRequest1.Params.AddHeader('Content-Type', 'image/jpeg');//tried different types, for example multipart or without this line
RESTRequest1.Params.AddItem('data-binary', 'D:\Europe\00s.jpg');//does it make sense?
RESTRequest1.Params[0].Kind := pkGETorPOST;
jpgFoto := TMemoryStream.Create;
jpgFoto.LoadFromFile('D:\Europe\00s.jpg');
RESTRequest1.AddBody(jpgFoto, TRESTContentType.ctIMAGE_JPEG);
jpgFoto.Position := 0;
try
RESTRequest1.Execute;
except
memo1.Text := RESTResponse1.Content;
end;
jpgFoto.Free;
end;
raised exceptions: rest_upload_invalid_disposition, rest_upload_invalid_disposition or rest_upload_no_data (depends on the settings I used in Header RESTRequest)
I found a solution that helped at least one person: switch to INDY to the idHTTP component. But there are no details. I couldn't login through the Basic Authentication method. I set parameters in IDHTTP.Request.Username and IDHTTP.Request.Password, but received a response from Wordpress - 403 Forbidden. It's not clear format to fill params, in JSON or just parameter = value.
I just started learning REST and am stuck for so many hours. Please do not leave in trouble, help upload images in Wordpress api REST with delphi REST or Indy components or any other working way, I will be sooo grateful
It's work:
var
Params: TIdMultipartFormDataStream;
begin
Params := TIdMultipartFormDataStream.Create;
Params.AddFormField('content-type','image/jpeg');
Params.AddFile('file', 'c:\images\sdsd.jpg', '');
idhttp2.Request.Accept := 'application/json; charset= UTF-8';
idhttp2.Request.Authentication := TIdBasicAuthentication.Create;
idhttp2.Request.Authentication.Username:= 'Username';
idhttp2.Request.Authentication.Password := 'Password';
idhttp2.Request.BasicAuthentication := true;
idhttp2.Request.ContentDisposition := 'form-data; filename="anyname.jpg"';//
idhttp2.Request.ContentType := 'application/json; charset= UTF-8';
try
idhttp2.Post('htts://mysite/wp-json/wp/v2/media/', Params);
except
memo1.Text := idhttp2.ResponseText;
end;
end;

How to receive remote push notifications in android using GCM in Delphi 10

i am trying to send and receive remote push notifications using GCM services, when i had Delphi xe7 this method in the answer 2 in this question was working [Google Cloud Messaging in Delphi XE5?, but in Seattle it dosent, i get java errors, however, i've followed the answer in this question, and managed to get the device Token id, but i cant dont receive the notification when i send it to my mobile phone, this is the code to send :
const
sendUrl = 'https://android.googleapis.com/gcm/send';
var
Params: TStringList;
AuthHeader: STring;
idHTTP: TIDHTTP;
SSLIOHandler: TIdSSLIOHandlerSocketOpenSSL;
begin
idHTTP := TIDHTTP.Create(nil);
try
SslIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
idHTTP.IOHandler := SSLIOHandler;
idHTTP.HTTPOptions := [];
Params := TStringList.Create;
try
Params.Add('registration_id='+ Memo1.Lines.Text);
Params.Values['data.message'] := Edit1.Text;
idHTTP.Request.Host := sendUrl;
AuthHeader := 'Authorization: key=' + MyServerKey;
idHTTP.Request.CustomHeaders.Add(AuthHeader);
IdHTTP.Request.ContentType := 'application/x-www-form-urlencoded;charset=UTF-8';
idHTTP.Post(sendUrl, Params);
finally
Params.Free;
end;
finally
FreeAndNil(idHTTP);
end;
Added <service android:name="com.embarcadero.gcm.notifications.GCMIntentService" /> in my AndroidManifest.template.xml and checked receive remote push notifications in Entitlement List.

Add Cookie field to header of post request

I would like to send post request like following by program is written in delphi.
There is a cookie field in request header (in red rectangle).
I wrote following source code.
procedure TForm1.Button2Click(Sender: TObject);
var
uri : TIdURI;
cookie : TIdCookieManager;
HTTP : TIdHTTP;
vals: TStringList;
url : String;
response : TStringStream;
begin
HTTP := TIdHTTP.Create();
HTTP.AllowCookies := True;
HTTP.Request.ContentType := 'application/x-www-form-urlencoded';
HTTP.HandleRedirects := True;
cookie := TIdCookieManager.Create();
uri := TIdURI.Create('www.hoge.com');
cookie.AddServerCookie('ASP.NET_SessionId=test', uri);
HTTP.CookieManager := cookie;
vals := TStringList.Create;
response := TStringStream.Create('');
vals.Add('__EVENTTARGET=');
vals.Add('__EVENTARGUMENT=');
vals.Add('__VIEWSTATE=/wEPDwUINzcxNjQyMjkPFgIeE1ZhbGlkYXRlUmVxdWVzdE1vZGUCAWRkEHyFbwQQE8tM5FKRr3UELd00osRNQBzu31XZl1yd86A=');
vals.Add('__VIEWSTATEGENERATOR=A7C0DD1C');
vals.Add('__EVENTVALIDATION=/wEdAAZkcRcs1jgA2rEUAtpu7qzIhFuNiVVNuLciluwM7Vty0gJCK50467l5FRCktGxHOlNKe/Y7d9SBufbGEp2w5OLHqFe59uEio+bAp/33YZOR3aKeKEbp39eHc9mbdvkCgxAPflO5NLAHc5uwdZn6JOnwKMi9h+dluqFLpmg3gO25cg==');
vals.Add('ddlLanguage=ja-JP');
vals.Add('tbUserId=myid');
vals.Add('tbPassword=hoge');
vals.Add('btnLogin=login');
url := TIdURI.ParamsEncode('ReturnUrl=/GssNet/main/default.aspx');
url := TIdURI.URLEncode('www.hoge.com/GssNet/login,aspx?ReturnUrl=/GssNet/main/default.aspx');
try
HTTP.Post('http://www.hoge.com/GssNet/login,aspx', vals, response);
Except
on EIdHTTPProtocolException do
begin
ShowMessage(Memo1.TextHint);
end;
end;
end;
But cookie field is not included in request header. Following is result of packet capture. when I execute my program. Please teach me the way to add cookie field to request header.
As #smooty86 said in comments, you need to include the http:// portion of the URL when adding a cookie manually. You also need to include the full path to the resource that is being requested, otherwise the cookie will only be valid for requests to the root / path.
Also, your calls to TIdURI.ParamsEncode() and TIdURI.URLEncode() are useless since you are not using the encoded url variable. If you are going to take the time to encode a URL than make sure to actually use it.
You are also leaking all of your objects.
Try this instead:
procedure TForm1.Button2Click(Sender: TObject);
var
uri : TIdURI;
HTTP : TIdHTTP;
vals : TStringList;
url : String;
response : TStringStream;
begin
try
response := TStringStream.Create('');
try
vals := TStringList.Create;
try
vals.Add('__EVENTTARGET=');
vals.Add('__EVENTARGUMENT=');
vals.Add('__VIEWSTATE=/wEPDwUINzcxNjQyMjkPFgIeE1ZhbGlkYXRlUmVxdWVzdE1vZGUCAWRkEHyFbwQQE8tM5FKRr3UELd00osRNQBzu31XZl1yd86A=');
vals.Add('__VIEWSTATEGENERATOR=A7C0DD1C');
vals.Add('__EVENTVALIDATION=/wEdAAZkcRcs1jgA2rEUAtpu7qzIhFuNiVVNuLciluwM7Vty0gJCK50467l5FRCktGxHOlNKe/Y7d9SBufbGEp2w5OLHqFe59uEio+bAp/33YZOR3aKeKEbp39eHc9mbdvkCgxAPflO5NLAHc5uwdZn6JOnwKMi9h+dluqFLpmg3gO25cg==');
vals.Add('ddlLanguage=ja-JP');
vals.Add('tbUserId=myid');
vals.Add('tbPassword=hoge');
vals.Add('btnLogin=login');
HTTP := TIdHTTP.Create;
try
HTTP.HandleRedirects := True;
HTTP.AllowCookies := True;
HTTP.CookieManager := TIdCookieManager.Create(HTTP);
uri := TIdURI.Create('http://www.hoge.com/GssNet/login,aspx');
try
HTTP.CookieManager.AddServerCookie('ASP.NET_SessionId=test', uri);
finally
uri.Free;
end;
url := TIdURI.URLEncode('http://www.hoge.com/GssNet/login,aspx?ReturnUrl=/GssNet/main/default.aspx');
HTTP.Request.ContentType := 'application/x-www-form-urlencoded';
HTTP.Post(url, vals, response);
finally
HTTP.Free;
end;
finally
vals.Free;
end;
// use response as needed...
finally
response.Free;
end;
except
on EIdHTTPProtocolException do
begin
ShowMessage(Memo1.TextHint);
end;
end;
end;
Lastly, why are you sending a request to login,aspx? The correct name is login.aspx instead. login,aspx does not exist on the server.

Calculate installation count with Inno Setup

Does anyone know what's the best approach to calculate installation count of an installer using Inno Setup? Can it be integrated with GA?
I read somewhere that by opening a PHP page at the end of installation, we can calculate installation count, but it is still too vague for me to understand.
For offline integration Google Analytics must be accessed via the new Measurement Protocol. Here is the same example from Martin but modified to access the Measurement Protocol:
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
WinHttpReq: Variant;
Url: string;
begin
if CurStep = ssDone then
begin
try
Url := 'http://www.google-analytics.com/collect';
Log('Sending GA request: ' + Url);
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
WinHttpReq.Open('POST', Url, False);
// see here the parameters : https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide#required
WinHttpReq.Send('v=1&tid=UA-XXXXX-Y&cid=555&t=pageview&dp=%2mywebpage');
Log('GA request result: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
except
Log('Error sending GA request: ' + GetExceptionMessage);
end;
end;
end;
Read about the Measurement protocol.
You can use CurStepChanged event function to send HTTP request.
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
WinHttpReq: Variant;
Url: string;
begin
if CurStep = ssDone then
begin
try
Url := 'http://....';
Log('Sending GA request: ' + Url);
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
WinHttpReq.Open('GET', Url, False);
WinHttpReq.Send('');
Log('GA request result: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
except
Log('Error sending GA request: ' + GetExceptionMessage);
end;
end;
end;
Not sure however what URL you need to use to link it to GA. There's another question that covers this part of the problem:
Using Google Analytics without Javascript?
You can of course query your own web page (e.g. PHP) that does the calculation.

Resources