Add Cookie field to header of post request - http

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.

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;

Uploading a bitmap with idHTTP from a Delphi 10.3 multidevice app

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

Golang 'http.NewRequest(method, url, body)' fails to create correctly formatted request

I'm trying to send a GET request to the following api:
https://poloniex.com/public?command=returnOrderBook
w/ URL parameters:
currencyPair=BTC_ETH
depth=20
--> &currencyPair=BTC_ETH&depth=20
I try to setup and execute my request as so: (note I've removed error checking for brevity)
pair := "BTC_ETH"
depth := 20
reqURL := "https://poloniex.com/public?command=returnOrderBook"
values := url.Values { "currencyPair": []string{pair}, "depth": []string{depth}}
fmt.Printf("\n Values = %s\n", values.Encode()) //DEBUG
req, err := http.NewRequest("GET", reqURL, strings.NewReader(values.Encode()))
fmt.Printf("\nREQUEST = %+v\n", req) //DEBUG
resp, err := api.client.Do(req)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Printf("\nREST CALL RETURNED: %X\n",body) //DEBUG
My DEBUG print statements print out the following:
Values = currencyPair=BTC_ETH&depth=20
REQUEST = &{Method:GET URL:https://poloniex.com/public?command=returnOrderBook Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[User-Agent:[Poloniex GO API Agent]] Body:{Reader:0xc82028e840} ContentLength:29 TransferEncoding:[] Close:false Host:poloniex.com Form:map[] PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr: RequestURI: TLS:<nil> Cancel:<nil>}
REST CALL RETURNED: {"error":"Please specify a currency pair."}
Playing around with Postman I figured out the API only returns this error when the currencyPair parameter is not specified (including miscapitalized). I can't figure out why the request doesn't include the URL parameters I specified as it's obvious from my debug print statements that the values.Encode() is correct. The content length in the request corresponds to the right amount of chars (bytes) needed for URL parameters.
Now after playing around a bit I found a solution.
If I replace the http.NewRequest() line with the following it works:
req, err := http.NewRequest(HTTPType, reqURL + "&" + values.Encode(), nil)
However, it's really bothering me why the original statement doesn't work.
The new DEBUG output is:
Values = currencyPair=BTC_ETH&depth=20
REQUEST = &{Method:GET URL:https://poloniex.com/public?command=returnOrderBook&currencyPair=BTC_ETH&depth=5 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[User-Agent:[Poloniex GO API Agent]] Body:<nil> ContentLength:0 TransferEncoding:[] Close:false Host:poloniex.com Form:map[] PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr: RequestURI: TLS:<nil> Cancel:<nil>}
REST CALL RETURNED: *way too long, just assume it's the correct financial data*
Would love some input on what I did wrong in the original statement. I used the same method (original) for a different api endpoint w/ URL parameters and it worked fine. Confused on why it didn't work in this case.
GET requests should not contain a body. Instead, you need to put the form into the query string.
Here's the proper way to do that, without hacky string concatenation:
reqURL := "https://poloniex.com/public"
values := url.Values { "currencyPair": []string{pair}, "depth": []string{depth}}
values.Set("command", "returnOrderBook")
uri, _ := url.Parse(reqURL)
uri.Query = values.Encode()
reqURL = uri.String()
fmt.Println(reqURL)
req, err := http.NewRequest("GET", reqURL, nil)
if err != nil {
panic(err) // NewRequest only errors on bad methods or un-parsable urls
}
https://play.golang.org/p/ZCLUu7UgZL

How to send HTTP data and get response with Synapse (Delphi)

I think the title was clear enough.
I want to know how to send HTTP POST request with parameters/arguments and receive HTML response back - using Synapse library for Delphi.
Try to use HttpPostURL function.
function HttpPostURL(const URL, URLData: string; const Data: TStream): Boolean;
URL - target URL
URLData - URL parameters; must be encoded e.g. using EncodeURLElement function
Data - target stream, where the response will be stored
The following example uses testing POST server where send two POST parameters. Note using of EncodeURLElement function for encoding parameter data. If the POST succeed the server response is saved into the file.
uses HTTPSend, Synacode;
procedure TForm1.Button1Click(Sender: TObject);
var URL: string;
Params: string;
Response: TMemoryStream;
begin
Response := TMemoryStream.Create;
try
URL := 'http://posttestserver.com/post.php?dump&html';
Params := 'parameter1=' + EncodeURLElement('data1') + '&' +
'parameter2=' + EncodeURLElement('data2');
if HttpPostURL(URL, Params, Response) then
Response.SaveToFile('c:\response.txt');
finally
Response.Free;
end;
end;

Resources