how to make http get request using TclientSocket? - http

I tried the following HTTP GET request
function CreateHTTPRequest(Site: String): String;
var
Request: String;
begin
Randomize;
Request := 'GET ' + Site + ' HTTP/1.1' + #13#10;
Request := Request + 'Host: ' + Site + #13#10;
Request := Request + 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' + #13#10;
Request := Request + 'Accept-Language: en-us,en' + #13#10;
Request := Request + 'User-Agent: ' + UserAgent + #13#10;
Request := Request + 'Referer: ' + Referer + #13#10;
Request := Request + 'Connection: close' + #13#10#13#10;
Result := Request;
end;
var
httpSocket: TClientSocket;
Site: String;
Target : string;
begin
httpSocket := TClientSocket.Create(nil);
httpSocket.Host := 'www.google.com';
httpSocket.Port := 80;
httpSocket.ClientType := ctBlocking;
httpSocket.Active := True;
if httpSocket.Socket.Connected=True then
begin
memo1.Lines.Add('requested');
Site := 'http://' + 'google.com';
httpSocket.Socket.SendText(CreateHTTPRequest(Site));
memo1.Lines.Add(httpSocket.Socket.ReceiveText);
httpSocket.Active := False;
end;
httpSocket.Free;
end;
I don't get any response from this. What did I do wrong? I cannot do any more HTTPS requests with TclientSocket. Is it dead already?

Related

How to correctly send the request body?

I'm starting to work with fasthttp in Golang and I can't figure out how to send key:value format. In default net/http I did it via url.values. I would appreciate it if you could help me with some sample code!
Image from Burp Suite (How it must look like)
var client *fasthttp.Client
var headerContentTypeJson = []byte("application/json")
type loginData struct {
login string
pass string
}
func main() {
readTimeout, _ := time.ParseDuration("500ms")
writeTimeout, _ := time.ParseDuration("500ms")
maxIdleConnDuration, _ := time.ParseDuration("1h")
client = &fasthttp.Client{
ReadTimeout: readTimeout,
WriteTimeout: writeTimeout,
MaxIdleConnDuration: maxIdleConnDuration,
NoDefaultUserAgentHeader: true, //
DisableHeaderNamesNormalizing: true, //
DisablePathNormalizing: true,
Dial: (&fasthttp.TCPDialer{
Concurrency: 4096,
DNSCacheDuration: time.Hour,
}).Dial,
}
reqTimeout := time.Duration(100) * time.Millisecond
reqData := &loginData{
login: "login",
pass: "password",
}
reqDataByte, _ := json.Marshal(reqData)
req := fasthttp.AcquireRequest()
req.SetRequestURI("https://oskelly.ru/api/v2/account/rawauth")
req.Header.SetMethod(fasthttp.MethodPost)
req.Header.SetContentTypeBytes(headerContentTypeJson)
req.SetBodyRaw(reqDataByte)
resp := fasthttp.AcquireResponse()
err := client.DoTimeout(req, resp, reqTimeout)
fasthttp.ReleaseRequest(req)
if err == nil {
statusCode := resp.StatusCode()
respBody := resp.Body()
fmt.Printf("DEEBUG Response: %s\n", respBody)
if statusCode == http.StatusOK {
respData := &loginData{}
err := json.Unmarshal(respBody, respData)
if err == io.EOF || err == nil {
fmt.Printf("DEBUG Parsed data Response %v\n")
} else {
fmt.Printf("ERR invalid HTTP response code: %d\n", statusCode)
}
}
fasthttp.ReleaseResponse(resp)
}}
enter image description here
Tried to figure out how to integrate url.values ​​into fasthttp
For request Body parameters:
req.Header.SetContentType("application/x-www-form-urlencoded; charset=UTF-8")
Form the request body in key=val string and not json. Can do a simple Stringer impl or req.PostArgs().Add(key, val)
req.PostArgs().Add("login", reqData.Login)
req.PostArgs().Add("pass", reqData.Pass)
Output request
POST / HTTP/1.1
Host: ....
Content-Length: 25
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
login=login&pass=password

Set request body in httputil reverse proxy

I am doing a reverse proxy thing which just forwards your request on another server but I am unable to set the body.
// post request from endpoint /forwarder.
// Called this using Router.post('/forwarder', ReverseProxy())
func ReverseProxy() gin.HandlerFunc {
endpoint := "http://localhost:3001"
remote, _ := url.Parse(endpoint)
proxy := httputil.NewSingleHostReverseProxy(remote)
return func(c *gin.Context) {
body, _ := ioutil.ReadAll(c.Request.Body)
body_string := string(body)
fmt.Printf("this is data from rqeuest\n%v\n", c.Request.Body)
//Define the director func
proxy.Director = func(req *http.Request) {
req.Header = c.Request.Header
req.Body = ioutil.NopCloser(strings.NewReader(body_string))
req.ContentLength = int64(len(body_string))
fmt.Printf("this is data different \n%v\n", req.Body)
temp, _ := ioutil.ReadAll(req.Body)
fmt.Printf("this is data from req.body\n%v\n", string(temp))
req.Host = remote.Host
req.URL.Scheme = remote.Scheme
req.URL.Host = remote.Host
req.URL.Path = c.Param("proxyPath")
}
proxy.ServeHTTP(c.Writer, c.Request)
}
}
This results in
http: proxy error: http: ContentLength=43 with Body length 0
Removing the req.ContentLength = int64(len(body_string)) forwards the request to the server running at localhost:3001 but the body is undefined.
How do I set the body?

How to send a get Request in AL

I currently have 2 problems. I am trying to send a GetRequest to my web service. This is done with the SendNotify (phonenumber: text; template: text) method. When I call the method via an action, I get the following error message: Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.
When I debug, the program stops at the following line: ContentHeaders.Add('Authorization', 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2dsadaXdrZUZTTWpNcnlBc2s1IiwiZXhwIjoxNTk1NDA3NDgzLCJpYXQiOjE1OTQzNjgyNTR9.1tAsf-x2FEvhDMyB4dsvgVKfZMLwAHcr_OLRA8RBeiY');
The token is currently hard coded but should be removed from the service setup list.
Can anyone tell me what I am doing wrong?
codeunit 2020803 "Notify SMS Interface" implements SendNotifyInterface
{
procedure CheckInputData(NotifyEntry: Record "Notify Entry")
begin
NotifyEntry.Get();
end;
procedure SendNotify(phonenumber: text; template: text)
var
client: HttpClient;
RequestMessage: HttpRequestMessage;
RequestHeaders: HttpHeaders;
ResponseMessage: HttpResponseMessage;
NotifyServiceSetup: Record "Notify Service Setup";
JsonText: Text;
IsSuccessful: Boolean;
SendSMSURL: text;
begin
NotifyServiceSetup.Get();
SendSMSURL := NotifyServiceSetup."Service URL" + '/contacts/contacts/sms/' + 'sagos/' +
phonenumber + '/' + template;
JsonText := BuildJsonText();
InitHttpRequestContent(RequestMessage, JsonText);
InitHttpRequestMessage(RequestMessage, SendSMSURL, 'GET');
IsSuccessful := client.Send(RequestMessage, ResponseMessage);
if not IsSuccessful then
Error('Authentication failed!');
if not ResponseMessage.IsSuccessStatusCode then begin
Error('request was not successfully');
exit;
end;
end;
local procedure InitHttpRequestContent(var RequestMessage: HttpRequestMessage; JsonText: Text)
var
ContentHeaders: HttpHeaders;
NotifyServiceSetup: Record "Notify Service Setup WMR";
bearerToken: Text[250];
token: Text[250];
begin
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
bearerToken := 'Bearer ' + token;
NotifyServiceSetup.Get();
RequestMessage.Content().Clear();
RequestMessage.Content().WriteFrom(JsonText);
RequestMessage.Content().GetHeaders(ContentHeaders);
ContentHeaders.Clear();
ContentHeaders.Add('Content-Type', 'application/json');
ContentHeaders.Add('Authorization', 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2dsadaXdrZUZTTWpNcnlBc2s1IiwiZXhwIjoxNTk1NDA3NDgzLCJpYXQiOjE1OTQzNjgyNTR9.1tAsf-x2FEvhDMyB4dsvgVKfZMLwAHcr_OLRA8RBeiY');
end;
local procedure InitHttpRequestMessage(var RequestMessage: HttpRequestMessage; ServiceURL: Text; Method: Text)
var
RequestHeaders: HttpHeaders;
NotifyServiceSetup: Record "Notify Service Setup WMR";
token: Text[250];
bearerToken: Text[250];
begin
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
bearerToken := 'Bearer ' + token;
RequestMessage.GetHeaders(RequestHeaders);
RequestHeaders.Clear();
RequestHeaders.Add('Accept', 'application/json');
RequestHeaders.Add('Authorization', 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2dXdrZUZTTWpNcnlBc2s1IiwiZXhwIjoxNTk1NDA3NDgzLCJpYXQiOjE1OTQzNjgyNTR9.1tAsf-x2FEvhDMyB4dsvgVKfZMLwAHcr_OLRA8RBeiY');
RequestMessage.Method(Method);
RequestMessage.SetRequestUri(ServiceURL);
end;
local procedure BuildJsonText() ContentText: Text
var
ContentJson: JsonObject;
begin
ContentJson.WriteTo(ContentText);
end;
}
The second problem I have is checking the data in the CheckInputData (NotifyEntry: Record "Notify Entry") method. There is a field in the Notify Entry called Contact No. that has all the information about the customer. I want to ask in the method to have the phone number and the salutation available. Unfortunately I do not know how I got out of Contact No. Can request data. Would someone have a tip?
UPDATE 1
codeunit 2020808 Test
{
procedure sendNotify(phonenumber: text; template: text)
var
NotifyServiceSetup: Record "Notify Service Setup WMR";
IsSuccessful: Boolean;
client: HttpClient;
content: HttpContent;
contentHeaders: HttpHeaders;
request: HttpRequestMessage;
response: HttpResponseMessage;
txtResponse: InStream;
Url: Text;
token: Text[250];
begin
NotifyServiceSetup.Get();
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
content.GetHeaders(contentHeaders);
contentHeaders.Clear();
contentHeaders.Add('Content-Type', 'application/json');
request.GetHeaders(contentHeaders);
contentHeaders.Add('Authorization', StrSubstNo('Bearer %1', token));
request.Content := content;
Url := NotifyServiceSetup."Service URL" + '/contacts/contacts/sms/' + 'Tegos/' + phonenumber + '/' + template;
request.SetRequestUri(Url);
request.Method := 'GET';
client.Send(request, response);
response.Content().ReadAs(txtResponse);
end;[![enter image description here][1]][1]
If the problem seems to be in the contentHeader.Add() This happened to me too.
I leave you this code for you to take as a reference.
procedure CheckCodeWebService(_accessToken: Text; _salesHeader: record "Sales Header")
var
jsonRequest: Text;
txtResponse: InStream;
Url: Text;
client: HttpClient;
request: HttpRequestMessage;
response: HttpResponseMessage;
contentHeaders: HttpHeaders;
content: HttpContent;
begin
jsonRequest := '{' +
'"GetPurchaseOrder": {' +
'"value": {' +
'"DataArea": {' +
'"PurchaseOrder": [' +
'{' +
'"PurchaseOrderHeader": {' +
'"ID": {' +
'"value": ""' +
'},' +
'"DocumentReference": [' +
'{' +
'"ID": {' +
'"value": " ' + _salesHeader.DealID + ' "' +
'}' +
'}' +
'],' +
'"SalesOrderReference": [' +
'{' +
'"ID": {' +
'"value": " ' + _salesHeader.SalesOrderNroCisco + ' "' +
'}' +
'}' +
'],' +
'"Description": [' +
'{' +
'"value": "yes",' +
'"typeCode": "details"' +
'}' +
']' +
'}' +
'}' +
']' +
'},' +
'"ApplicationArea": {' +
'"CreationDateTime": "datetime",' +
'"BODID": {' +
'"value": "BoDID-test",' +
'"schemeVersionID": "V1"' +
'}' +
'}' +
'}' +
'}' +
'}';
content.WriteFrom(jsonRequest);
content.GetHeaders(contentHeaders);
contentHeaders.Clear();
contentHeaders.Add('Content-Type', 'application/json');
request.GetHeaders(contentHeaders);
contentHeaders.Add('Authorization', StrSubstNo('Bearer %1', _accessToken));
contentHeaders.Add('Accept', 'application/xml');
request.Content := content;
Url := 'https://api.xxxx.com/xxxxx/ORDER/v2/sync/xxxxxxxx';
request.SetRequestUri(Url);
request.Method := 'POST';
client.Send(request, response);
response.Content().ReadAs(txtResponse);
Okay problem solved. Instead of the content type I have now entered RequestHeaders.Add ('Accept', 'application / json'). Now the GetRequest works.
codeunit 2020808 Test
{
procedure sendNotify(phonenumber: text; template: text)
var
NotifyServiceSetup: Record "Notify Service Setup WMR";
IsSuccessful: Boolean;
client: HttpClient;
content: HttpContent;
contentHeaders: HttpHeaders;
request: HttpRequestMessage;
response: HttpResponseMessage;
txtResponse: InStream;
Url: Text;
token: Text[250];
begin
NotifyServiceSetup.Get();
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
content.GetHeaders(contentHeaders);
contentHeaders.Clear();
//contentHeaders.Add('Content-Type', 'application/json');
request.GetHeaders(contentHeaders);
contentHeaders.Add('Authorization', StrSubstNo('Bearer %1', token));
contentHeaders.Add('Accept', 'application/json');
//request.Content := content;
Url := NotifyServiceSetup."Service URL" + '/contacts/contacts/sms/' + 'Tegos/' + phonenumber + '/' + template;
request.SetRequestUri(Url);
request.Method := 'GET';
client.Send(request, response);
response.Content().ReadAs(txtResponse);
end;
}

How to send SMS using Delphi Code

I have made 3 attempts using Indy10.6.2 component, none of which show any errors, but the code is unable to send SMS. Please help me to send me the SMS through Delphi code.
Attempt 1
const
URL = 'https://api.bulksmsgateway.in/send/? username=****&hash=****&sender=TXTLCL&numbers=9198........&message=HISUNDAR';
//URL = 'https://api.textlocal.in/send/? username=*****&hash=******&sender=TXTLCL&numbers=9198...&message=HISUNDAR';
ResponseSize = 1024;
var
hSession, hURL: HInternet;
Request: String;
ResponseLength: Cardinal;
begin
hSession := InternetOpen('TEST', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
try
Request := Format(URL, [Username,Password,Sender,Numbers,HttpEncode(Message1)]);
hURL := InternetOpenURL(hSession, PChar(Request), nil, 0,0,0);
try
SetLength(Result, ResponseSize);
InternetReadFile(hURL, PChar(Result), ResponseSize, ResponseLength);
SetLength(Result, ResponseLength);
finally
InternetCloseHandle(hURL)
end;
showmessage(result);
finally
InternetCloseHandle(hSession)
end
Attempt 2
var
http : TIdHTTP;
IdSSL : TIdSSLIOHandlerSocketOpenSSL;
begin
http := TIdHTTP.Create(nil);
IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
Http.ReadTimeout := 30000;
Http.IOHandler := IdSSL;
IdSSL.SSLOptions.Method := sslvTLSv1;
Http.Request.BasicAuthentication := True;
// IdSSL.SSLOptions.Method := sslvTLSv1;
//IdSSL.SSLOptions.Method := sslvTLSv1;
// http.Get('https://www.smsgatewayhub.com/api/mt/SendSMS? APIKey=B215dPone0yVIJU2QDH&senderid=TESTIN&channel=2&DCS=0&flashsms=0&number= 9195.....&text=test message&route=1');
http.Get('http://login.bulksmsgateway.in/sendmessage.php? user=****&password=****&mobile=95661....&message=Good Morning&sender=PRAPUS&type=3 ');
finally
http.Free;
end;
Attempt 3
var
lHTTP: TIdHTTP;
lParamList: TStringList;
lResult: String;
IdSSL : TIdSSLIOHandlerSocketOpenSSL;
begin
lParamList := TStringList.Create;
lParamList.Add('username=****');
lParamList.Add('password=****');
lParamList.Add('msgtext=Hello World');
lParamList.Add('originator=TestAccount');
lParamList.Add('phone=+9195....');
lParamList.Add('showDLR=0');
lParamList.Add('charset=0');
lParamList.Add('msgtype=');
lParamList.Add('provider=bulksmsgateway.in');
lHTTP := TIdHTTP.Create(nil);
try
lResult := lHTTP.Post('http://login.bulksmsgateway.in/sendmessage.php?', lParamList);
//WriteLn(lResult);
// Readln;
finally
FreeAndNil(lHTTP);
FreeAndNil(lParamList);
end;
You are sending the wrong parameters to the wrong URLs using the wrong HTTP methods. Per the code examples on the Bulk SMS Gateway website, you need to use HTTP POST with the correct URL and parameters. Please follow the online examples.
Try something more like this instead:
var
lHTTP: TIdHTTP;
lParamList: TStringList;
lResult: String;
IdSSL : TIdSSLIOHandlerSocketOpenSSL;
begin
lParamList := TStringList.Create;
try
lParamList.Add('user=****');
lParamList.Add('password=****' );
lParamList.Add('message=Hello World');
lParamList.Add('sender=TestAccount');
lParamList.Add('mobile=+9195....');
lParamList.Add('type=1'); // or 3
lHTTP := TIdHTTP.Create(nil);
try
// note: if you are using an up-to-date version of Indy,
// assigning the IOHandler is optional:
//
// http://www.indyproject.org/sockets/blogs/ChangeLog/20141222.aspx
//
lHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(lHTTP);
try
lResult := lHTTP.Post('https://www.bulksmsgateway.in/sendmessage.php', lParamList);
// WriteLn(lResult);
// Readln;
except
on E: Exception do begin
//WriteLn('Error: ', e.Message);
end;
end;
finally
FreeAndNil(lHTTP);
end;
finally
FreeAndNil(lParamList);
end;
end;
If you want to send through the SMS Gateway Hub, you have a choice of using HTTP GET, or XML over HTTP POST:
var
lHTTP: TIdHTTP;
lParamList, lResult: String;
IdSSL : TIdSSLIOHandlerSocketOpenSSL;
begin
lParamList := Format('APIKey=%s&senderid=%s&channel=2&DCS=8&flashsms=0&number=%s&text=%s&route=1',
[
'****',
'TestAccount',
'9195....',
'Hello World'
]
);
lHTTP := TIdHTTP.Create(nil);
try
lHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(lHTTP);
try
lResult := lHTTP.Get('https://www.smsgatewayhub.com/api/mt/SendSMS?' + lParamList);
// WriteLn(lResult);
// Readln;
except
on E: Exception do begin
//WriteLn('Error: ', e.Message);
end;
end;
finally
FreeAndNil(lHTTP);
end;
end;
var
lHTTP: TIdHTTP;
lParamList: TStringStream;
lResult: String;
IdSSL : TIdSSLIOHandlerSocketOpenSSL;
begin
lParamList := TStringStream.Create(
'<SmsQueue>' +
'<Account>' +
'<User>****</User>' +
'<Password>****</Password>' +
'<SenderId>TestAccount</SenderId>' +
'<Channel>1</Channel>' +
'<DCS>0</DCS>' +
'<FlashSms>0</FlashSms>' +
'<Route>1</Route>' +
'</Account>' +
'<Messages>' +
'<Message>' +
'<Number>9195....</Number>' +
'<Text>Hello World</Text>' +
'</Message>' +
'</Messages>' +
'</SmsQueue>',
TEncoding.UTF8);
try
lHTTP := TIdHTTP.Create(nil);
try
lHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(lHTTP);
try
lHTTP.Request.ContentType := 'text/xml';
lHTTP.Request.Charset := 'utf-8';
lResult := lHTTP.Post('https://www.smsgatewayhub.com/RestAPI/MT.svc/mt', lParamList);
// WriteLn(lResult);
// Readln;
except
on E: Exception do begin
//WriteLn('Error: ', e.Message);
end;
end;
finally
FreeAndNil(lHTTP);
end;
finally
FreeAndNil(lParams);
end;
end;

IdHTTP how to send raw body

How i can use IdHTTP to send message as PostMan dos below:
My first attempt was as follow:
function TIdFoo.SendIM(const AID, AMessage: string): Boolean;
const
_URL = 'https://URL.com/SendMessage';
var
Params : TStringStream;
Response : string;
LMsg : string;
begin
Result := False;
LMsg := '-----------------------------13932'+
'Content-Type: application/json; charset=utf-8'+
'Content-Description: message'+ sLineBreak+ '{"message":{"Type":1,"body":"'+AMessage+'"},"to":["'+AID+'"]}'+
'-----------------------------13932--;'+sLineBreak;
Params := TStringStream.Create(LMsg, TEncoding.UTF8);
try
IdHTTP.Request.CustomHeaders.AddValue('authorization', 'Bearer ' + FToken);
IdHTTP.Request.CustomHeaders.AddValue('Origin', 'https://www.URL.com');
IdHTTP.Request.UserAgent := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36';
IdHTTP.Request.Accept := '*/*';
IdHTTP.Request.Referer := 'https://www.URL.com/en-us/';
IdHTTP.Request.Host := 'URL.com';
IdHTTP.Request.AcceptEncoding := 'gzip, deflate, br';
IdHTTP.Request.AcceptLanguage := 'Accept-Language';
IdHTTP.Request.ContentType := 'multipart/mixed; boundary="---------------------------13932"';
Params.Position := 0;
try
Response := IdHTTP.Post(_URL, Params);
Result := True;
except
on E: Exception do
Writeln('Error on Send Message request: '#13#10, e.Message);
end;
Writeln(IdHTTP.Request.RawHeaders.Text);
finally
Params.Free;
end;
end;
The second attempt i try it this way
function TIdFoo.SendIM(const AID, AMessage: string): Boolean;
const
_URL = 'https://URL.com/SendMessage';
var
Params : TStringStream;
Response : string;
LMsg : string;
begin
Result := False;
LMsg := '{"message":{"Type":1,"body":"'+AMessage+'"},"to":["'+AID+'"]}';
Params := TStringStream.Create(LMsg, TEncoding.UTF8);
try
IdHTTP.Request.CustomHeaders.AddValue('authorization', 'Bearer ' + FToken);
IdHTTP.Request.CustomHeaders.AddValue('Origin', 'https://www.URL.com');
IdHTTP.Request.CustomHeaders.AddValue('Content-Description', 'message'); // I addedd this as on PostMan Body
IdHTTP.Request.UserAgent := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36';
IdHTTP.Request.Accept := '*/*';
IdHTTP.Request.Referer := 'https://www.URL.com/en-us/';
IdHTTP.Request.Host := 'URL.com';
IdHTTP.Request.AcceptEncoding := 'gzip, deflate, br';
IdHTTP.Request.AcceptLanguage := 'Accept-Language';
IdHTTP.Request.ContentType := 'application/json; charset=utf-8'; // I alos changed this as it shown on PostMan body
Params.Position := 0;
try
Response := IdHTTP.Post(_URL, Params);
Result := True;
except
on E: Exception do
Writeln('Error on Send Message request: '#13#10, e.Message);
end;
Writeln(IdHTTP.Request.RawHeaders.Text);
finally
Params.Free;
end;
end;
Both attempts gives HTTP/1.1 400 Bad Request.
Can any advice my what i', doing wrong?
In your first example, your "raw" MIME data is not formatted correctly:
You are missing a bunch of required line breaks. And don't use the sLineBreak constant, as its value is platform-specific. MIME expects line breaks to use CRLF specifically. Indy has an EOL constant for that value.
You have an erroneous semicolon on the end of the closing boundary line.
You are also not setting the Request.AcceptEncoding property correctly. DO NOT enable encodings manually, unless you are prepared to actually handle them manually in responses (which your code is not). TIdHTTP handles gzip and deflate encodings for you, if you assign a TIdZLibCompressorBase-derived component, like TIdCompressorZLib, to the TIdHTTP.Compressor property. Don't worry about the br encoding, it is not widely used. In short, leave the Request.AcceptEncoding at its default and let TIdHTTP manage it for you.
You are also not setting the Request.AcceptLanguage property correctly. You should be setting it to 'en-US,en;q=0.8', not to 'Accept-Language'.
Your first example should work if you make these fixes, eg:
function TIdFoo.SendIM(const AID, AMessage: string): Boolean;
const
_URL = 'https://URL.com/SendMessage';
var
Params : TStringStream;
Response : string;
LMsg : string;
begin
Result := False;
LMsg := '-----------------------------13932' + EOL +
'Content-Type: application/json; charset=utf-8' + EOL +
'Content-Description: message' + EOL +
EOL +
'{"message":{"Type":1,"body":"'+AMessage+'"},"to":["'+AID+'"]}' + EOL +
'-----------------------------13932--' + EOL;
Params := TStringStream.Create(LMsg, TEncoding.UTF8);
try
IdHTTP.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FToken);
IdHTTP.Request.CustomHeaders.AddValue('Origin', 'https://www.URL.com');
IdHTTP.Request.UserAgent := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36';
IdHTTP.Request.Accept := '*/*';
IdHTTP.Request.Referer := 'https://www.URL.com/en-us/';
IdHTTP.Request.Host := 'URL.com';
IdHTTP.Request.AcceptLanguage := 'en-US,en;q=0.8';
IdHTTP.Request.ContentType := 'multipart/mixed; boundary="---------------------------13932"';
try
Response := IdHTTP.Post(_URL, Params);
Result := True;
except
on E: Exception do
Writeln('Error on Send Message request: '#13#10, e.Message);
end;
Writeln(IdHTTP.Request.RawHeaders.Text);
finally
Params.Free;
end;
end;
Alternatively:
function TIdFoo.SendIM(const AID, AMessage: string): Boolean;
const
_URL = 'https://URL.com/SendMessage';
var
Params : TMemoryStream;
Response : string;
LMsg : string;
begin
Result := False;
Params := TMemoryStream.Create;
try
WriteStringToStream(Params, '-----------------------------13932' + EOL);
WriteStringToStream(Params, 'Content-Type: application/json; charset=utf-8' + EOL);
WriteStringToStream(Params, 'Content-Description: message' + EOL);
WriteStringToStream(Params, EOL);
WriteStringToStream(Params, '{"message":{"Type":1,"body":"'+AMessage+'"},"to":["'+AID+'"]}' + EOL, IndyTextEncoding_UTF8);
WriteStringToStream(Params, '-----------------------------13932--' + EOL);
Params.Position := 0;
IdHTTP.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FToken);
IdHTTP.Request.CustomHeaders.AddValue('Origin', 'https://www.URL.com');
IdHTTP.Request.UserAgent := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36';
IdHTTP.Request.Accept := '*/*';
IdHTTP.Request.Referer := 'https://www.URL.com/en-us/';
IdHTTP.Request.Host := 'URL.com';
IdHTTP.Request.AcceptLanguage := 'en-US,en;q=0.8';
IdHTTP.Request.ContentType := 'multipart/mixed; boundary="---------------------------13932"';
try
Response := IdHTTP.Post(_URL, Params);
Result := True;
except
on E: Exception do
Writeln('Error on Send Message request: '#13#10, e.Message);
end;
Writeln(IdHTTP.Request.RawHeaders.Text);
finally
Params.Free;
end;
end;
Alternatively:
function TIdFoo.SendIM(const AID, AMessage: string): Boolean;
const
_URL = 'https://URL.com/SendMessage';
var
Params : TMemoryStream;
Response : string;
LMsg : string;
begin
Result := False;
Params := TMemoryStream.Create;
try
with TStreamWriter.Create(Params, TEncoding.UTF8) do
try
NewLine := EOL;
WriteLine('-----------------------------13932');
WriteLine('Content-Type: application/json; charset=utf-8');
WriteLine('Content-Description: message');
WriteLine;
WriteLine('{"message":{"Type":1,"body":"'+AMessage+'"},"to":["'+AID+'"]}');
WriteLine('-----------------------------13932--');
finally
Free;
end;
Params.Position := 0;
IdHTTP.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FToken);
IdHTTP.Request.CustomHeaders.AddValue('Origin', 'https://www.URL.com');
IdHTTP.Request.UserAgent := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36';
IdHTTP.Request.Accept := '*/*';
IdHTTP.Request.Referer := 'https://www.URL.com/en-us/';
IdHTTP.Request.Host := 'URL.com';
IdHTTP.Request.AcceptLanguage := 'en-US,en;q=0.8';
IdHTTP.Request.ContentType := 'multipart/mixed; boundary="---------------------------13932"';
try
Response := IdHTTP.Post(_URL, Params);
Result := True;
except
on E: Exception do
Writeln('Error on Send Message request: '#13#10, e.Message);
end;
Writeln(IdHTTP.Request.RawHeaders.Text);
finally
Params.Free;
end;
end;
In your second example, your "raw" data is just the JSON by itself, not any MIME wrapping it. You are putting MIME headers in the HTTP headers, where they don't belong. This example will not work if the server expects MIME data and not just raw JSON data.
You are also making the same mistakes with the Request.AcceptEncoding and Request.AcceptLanguage properties.
Since you are posting data in MIME format, an easier way to handle this would have been to use Indy's TIdMultipartFormDataStream class instead, and let it handle the MIME formatting for you. However, that class does not currently support:
setting the stream's RequestContentType property to a custom value (in this case, 'multipart/mixed' instead of 'multipart/form-data'). Though, you can use an accessor class to accomplish this, since the FRequestContentType member is protected.
omitting the Content-Disposition: form-data header on individual fields. This might trip up servers that are not expecting form-data submissions.
specifying the Content-Description MIME header at all (see Add support for user-defined MIME headers in TIdMultipartFormDataStream in Indy's issue tracker on GitHub).
So you will have to continue resorting to formatting the MIME data manually. You just have to make sure you get it right.

Resources