TIdTCPClient Write Bytes - delphi

if _msg.isRequest then
begin
req:= THTTPRequest(_msg);
msgBody:= req.getMessageBody;
// Adds the URI line.
str:= str + req.getMethod + ' ';
str:= str + req.getURI + ' ';
str:= str + versionText + CRLF;
// Sets the content length header if its a POST
if req.getMethod = 'POST' then
req.setHeader(THTTPHeaderKey.CONTENT_LENGTH.ToString, IntToStr(Length(msgBody) * SizeOf(Char)));
// Adds the headers
for i:= 0 to req.getHeaders.Count -1 do
str:= str + req.getHeaders.Names[i] + '=' + req.getHeaders.ValueFromIndex[i];
str:= str + CRLF;
// Adds the message body if its POST
if req.getMethod = 'POST' then
str:= str + msgBody;
// Writes the result to the output stream.
formPopupRemote.IdTCPClient1.IOHandler.Write(Byte(str)); -> ERROR LINE
// formPopupRemote.HTTP.Get(str, stream);
end
else
ShowMessage('Responses sending not yet supported!');
end;
I want to writes the result to the IOHandler. But how can i do this, i converted this code from JAVA.
Here is Java Codes :
if (_msg.isRequest()) {
HTTPRequest req = (HTTPRequest) _msg;
String msgBody = req.getMessageBody();
// Adds the URI line.
str.append(req.getMethod() + " ");
str.append(req.getURI() + " ");
str.append(versionText + CRLF);
// Sets the content length header if its a POST
if (req.getMethod() == HTTPRequest.Method.POST)
req.setHeader(HTTPHeaderKey.CONTENT_LENGTH.toString(), String.valueOf(msgBody.getBytes().length));
// Adds the headers
for (String key : req.getHeaders())
str.append(key + ": " + req.getHeader(key) + CRLF);
str.append(CRLF);
// Adds the message body if its POST
if (req.getMethod() == HTTPRequest.Method.POST)
str.append(msgBody);
// Writes the result to the output stream.
getOutputStream().write(str.toString().getBytes());
} else {
throw new ProtocolException("Responses sending not yet supported!");
}
}
Actually i want to convert to Delphi from Java codes. But i couldn' t find outputstream equals in Delphi. Because TIdClient.IOHandler.Write has no TBytes parameter or array of Byte. But outputstream' s parameter is array of byte. So how should i write str?

TIdIOHandler has a Write() overload that accepts a String as input, so you don't need to manually convert to bytes at all:
formPopupRemote.IdTCPClient1.IOHandler.Write(str);
But if you did, Indy has overloaded ToBytes() functions for that purpose, and one of them accepts a String as input:
formPopupRemote.IdTCPClient1.IOHandler.Write(ToBytes(str));
However, this is overkill, since this is essentially what TIdIOHandelr.Write(String) does internally for you.
That being said, you really should be using the TIdHTTP component instead of manually formatting an HTTP request and using TIdTCPClient to send it. TIdHTTP has Get() and Post() methods (amongst others). All you have to do is pass in the full URL, and in the case of Post() also pass in a TStream object containing the raw body data. TIdHTTP also has properties for customing the request so you can set things like HTTP version (TIdHTTP.ProtocolVersion), body Content Type (TIdHTTP.Request.ContentType) and charset (TIdHTTP.Request.Charset), custom request headers (TIdHTTP.Request.CustomHeaders), etc. TIdHTTP will handle the Content-Length header for you automatically.

Related

quickfixj DataDictionary Validation Issue

I'm new to Java. Working on QuikcFixJ.
I'm trying to load custom.xml file using datadictionary and later parsing msg string from this datadictionary. Not sure what is wrong with datadictionary , its not throwing any error whether I pass correct fix.xml file path or incorrect one.
Later when I pass msg string to Message object it just parse initial 3 tags irrespective of whatever xml file I mention in datadictionary.
Please give me some pointers to resolve it.
Adding code snippet:
public Message createMsg(String type, String message)
{
message = "35=" + type + "\001" + message;
message = "8=FIX4.2\0019=" + message.length() + "\001"+message ;
String msgCharStr = message.replaceAll("\\|", "\001");
int checksum = MessageUtils.checksum(msgCharStr);
msgCharStr = msgCharStr +"\00110=" + (1 +
MessageUtils.checksum(msgCharStr)) + "\001" ;
quickfix.Message msg = new Message();
msg.fromString(msgCharStr, null,true);
}
This code works fine for regular neworder or quoterequest msgs.
But, when I pass quoterequest msg with custom repeating group which I loaded via UseDictionary config settings, it gives undesired output msg.
e.g: Lets say if I pass input, "35=R|146=1|...|453=2|448=XX|447=G|452=1|448=YY|447=D|452=2|......"
parser gives output as :
"35=R|146=1|...|448=XX|447=G|452=1|453=2|448=YY|447=D|452=2|......"
----Code re-build steps for new custom FIX42.xml ---
Copied quickfixj2.3.1.zip (url: https://github.com/quickfix-j/quickfixj/releases )
Updated xml at path quickfixj-messages/quickfixj-messages-fix42/src/main/resources/FIX42.xml
run mvn build command.
Maven re-build jar for below:
quickfixj-all
quickfixj-core/
quickfixj-messages/
quickfixj-codegenerator/
quickfixj-dictgenerator/
Tried using all above jar files in my RobotFramework with an assumption that it will now refer the modified QuoteRequest msg which has repeating group support.
To my surprise, its output was exactly same. No changes.
After quickfixj rebuild for customised xml file.
Final version of code snippet:
public Message createMsg(String type, String message)
{
message = "35=" + type + "\001" + message;
message = "8=FIX4.2\0019=" + message.length() + "\001"+message ;
String msgCharStr = message.replaceAll("\\|", "\001");
int checksum = MessageUtils.checksum(msgCharStr);
msgCharStr = msgCharStr +"\00110=" + (1 +
MessageUtils.checksum(msgCharStr)) + "\001" ;
DataDictioanry dd = DataDictionary("FIX42.xml");
quickfix.Message msg = new Message();
msg.fromString(msgCharStr, dd ,true);
}

Valid URL for an FTP site with username containing #

I want to create a valid URL to send to Windows File Explorer (or other file managers like TotalCommander) using the format:
ftp://username:password#ftp.domain.ext/folder/
In Explorer, it works with very straight username and password. But I receive errors (or Explorer just display the My Document instead of the FTP site) when password contains certain special characters. I played with URI encoding to encode the password with some success but not 100% reliable.
Can someone help me finding the correct requirements for a valid FTP URL including username and password? Thanks.
Here is a sample of the code using AutoHotkey "Run" command (on Windows 7 64-bit environment):
#NoEnv
#SingleInstance force
strFTPUrl := "ftp://www.jeanlalonde.ca"
strLoginName := "username#jeanlalonde.ca"
strPassword := "********"
StringReplace, strFTPUrl, strFTPUrl, % "ftp://", % "ftp://" . strLoginName . ":" . UriEncode(strPassword) . "#"
; Before: ftp://ftp.jeanlalonde.ca
; After: ftp://testaccount#jeanlalonde.ca:********#ftp.jeanlalonde.ca
MsgBox, %strFTPUrl%
Run, Explorer "%strFTPUrl%"
return
;------------------------------------------------------------
UriEncode(str)
; from GoogleTranslate by Mikhail Kuropyatnikov
; http://www.autohotkey.net/~sumon/GoogleTranslate.ahk
;------------------------------------------------------------
{
b_Format := A_FormatInteger
data := ""
SetFormat,Integer,H
SizeInBytes := StrPutVar(str,var,"utf-8")
Loop, %SizeInBytes%
{
ch := NumGet(var,A_Index-1,"UChar")
If (ch=0)
Break
if ((ch>0x7f) || (ch<0x30) || (ch=0x3d))
s .= "%" . ((StrLen(c:=SubStr(ch,3))<2) ? "0" . c : c)
Else
s .= Chr(ch)
}
SetFormat,Integer,%b_format%
return s
}
;------------------------------------------------------------
;------------------------------------------------------------
StrPutVar(string, ByRef var, encoding)
;------------------------------------------------------------
{
; Ensure capacity.
SizeInBytes := VarSetCapacity( var, StrPut(string, encoding)
; StrPut returns char count, but VarSetCapacity needs bytes.
* ((encoding="utf-16"||encoding="cp1200") ? 2 : 1) )
; Copy or convert the string.
StrPut(string, &var, encoding)
Return SizeInBytes
}
;------------------------------------------------------------
If there are special characters (# being one) in the username too (not only in the password), you have to URL-encode the username too, the same way you URL-encode the password.
That means you have to apply the UriEncode to strLoginName, the same way you apply it to strPassword.
And you need to update the UriEncode to encode the #, as it does not.
The code for # is 0x40.
if ((ch>0x7f) || (ch<0x30) || (ch=0x3d) || (ch=0x40))
(Though you can compare to # literally too: ch="#").

403 Invalid token error on GET user info

UPDATE: I thought I had to pass the parameters as a JSON string in the request body, but actually I need to put them on the URL (the endpoint string), so it's working now.
I'm new to Valence. I have some Salesforce Apex code (written by someone else) that creates a D2L user. The code is working fine.
I want to add an Apex method to retrieve info for an existing D2L user using the userName parameter. I've copied the existing method, changed to a GET, set the query parameter to userName, and kept everything else the same.
When I call my method, I get a 403 Invalid Token error.
Do I need to use different authorization parameters for a GET? For example, do I still need to include a timestamp?
Here's a portion of the Salesforce Apex code:
public static final String USERS = '/d2l/api/lp/1.0/users/';
String TIMESTAMP_PARAM_VALUE = String.valueOf(Datetime.now().getTime()).substring(0,10);
String method = GETMETHOD;
String action = USERS;
String signData = method + '&' + action + '&' + TIMESTAMP_PARAM_VALUE;
String userSignature = sign(signData,USER_KEY);
String appSignature = sign(signData,APP_KEY);
String SIGNED_USER_PARAM_VALUE = userSignature;
String SIGNED_APP_PARAM_VALUE = appSignature;
String endPoint = DOMAIN + action + '?' +
APP_ID_PARAM + '=' + APP_ID + '&' +
USER_ID_PARAM + '=' + USER_ID + '&' +
SIGNED_USER_PARAM + '=' + SIGNED_USER_PARAM_VALUE + '&' +
SIGNED_APP_PARAM + '=' + SIGNED_APP_PARAM_VALUE + '&' +
TIMESTAMP_PARAM + '=' + TIMESTAMP_PARAM_VALUE;
HttpRequest req = new HttpRequest();
req.setMethod(method);
req.setTimeout(30000);
req.setEndpoint(endPoint);
req.setBody('{ "orgDefinedId"' + ':' + '"' + person.Id + '" }');
I thought I had to pass the parameters as a JSON string in the request body, but actually I need to put them on the URL (the endpoint string), so it's working now

String comparison in Delphi

I have two strings, which I need to compare for equality.
String 1 is created in this way:
var
inBuf: array[0..IN_BUF_SIZE] of WideChar;
stringBuilder : TStringBuilder;
mystring1:string;
...
begin
stringBuilder := TStringBuilder.Create;
for i := startOfInterestingPart to endOfInterestingPart do
begin
stringBuilder.Append(inBuf[i]);
end;
mystring1 := stringBuilder.ToString();
stringBuilder.Free;
String 2 is a constant string 'ABC'.
When string 1 is displayed in a debug console, it is equal to 'ABC'. But the comparisons
AnsiCompareText(mystring1, 'ABC')
mystring1 = 'ABC'
CompareStr(mystring1, 'ABC')
all report inequality.
I suppose that I need to convert string 2 ('ABC') to the same type as the string 1.
How can I do that?
Update 26.09.2012:
aMessage is displayed in the log output as {FDI-MSG-START-Init-FDI-MSG-END}
Here's the code for printing the length of strings:
StringToWideChar('{FDI-MSG-START-Init-FDI-MSG-END}', convString, iNewSize);
...
OutputDebugString(PChar('Len (aMessage): ' + IntToStr(Length(aMessage))));
OutputDebugString(PChar('Len (original constant): ' + IntToStr(Length('{FDI-MSG-START-Init-FDI-MSG-END}'))));
OutputDebugString(PChar('Len (convString): ' + IntToStr(Length(convString))));
And here's the log output:
[3580] Len (aMessage): 40
[3580] Len (original constant): 32
[3580] Len (convString): 0
It looks like you're keeping garbage data in your wide string after the meaningful part, in your update, Length(aMessage) returns 40, while your source string's length is 32.
In Delphi a wide string is COM BSTR compatible, meaning it can hold null characters, a null does not terminate it, it keeps its length at a negative offset of the character data. A possible null character in it helps it to be converted to other string types, but it doesn't alter its own termination.
Consider the below,
const
Source = '{FDI-MSG-START-Init-FDI-MSG-END}';
var
ws: WideString;
size: Integer;
begin
size := 40;
SetLength(ws, size);
StringToWideChar(Source, PWideChar(ws), size);
// the below assertion fails when uncommented
// Assert(CompareStr(Source, ws) = 0);
ws := PWideChar(ws); // or SetLength(ws, Length(Source));
// this assertion does not fail
Assert(CompareStr(Source, ws) = 0);
end;

JQUERY call to Controller Action: String Parameter truncated if containing 'space' character

I have a view that accepts 2 string parameters and 2 date values. User hits search button and they get filtered output to the screen. This all works perfectly well until a user inputs a string with a space. i.e. they can search for 'waste' but not 'waste oil'.
Interestingly, in the latter, the parameter is ok from Javascript before the call is made. But on entering the controller code it goes form being 'waste oil' on client to 'waste'. When this happens the other parameters get set to NULL crashing the system.
I've tried replacing the spaces if present with '#' character then stripping out and putting back in ' ' on the controller side. This is a messy fudge and only appears to work with one parameter.
There must be a simple explanation for this parameter data loss, any comments much appreciated
Not sure a code example is needed but here it is anyway if it help:
My controller header :
public ActionResult IndexSearch(int? page, string searchText,string searchTextSite,string StartDate,string EndDate)
{
My HTML Javascript :
function Search(sSearchText,sSite) {
sSearchText = sSearchText.toString().replace(" ", "#");
sSite = sSite.toString().replace(" ", "#");
debugger;
alert($("#AbsolutePath").val() + "Waste.mvc/IndexSearch?searchText=" + sSearchText + "&searchTextSite=" + sSite + "&StartDate=" + $('#StartDate').val() + "&EndDate=" + $('#EndDate').val());
$("#ResultsList").load($("#AbsolutePath").val() + "Waste.mvc/IndexSearch?searchText=" + sSearchText + "&searchTextSite=" + sSite + "&StartDate=" + $('#StartDate').val() + "&EndDate=" + $('#EndDate').val(),
function() {
$('#LoadingGif').empty();
});
$('#LoadingGif').empty().html('<img src="' + $("#AbsolutePath").val() + 'Content/images/ajax-loader.gif" alt="Loading image" />');
}
You are not URL encoding your parameters when sending the AJAX request because you are using string concatenations when building the url. You could use the following technique in order to have properly encoded values:
var url = $('#AbsolutePath').val() + 'Waste.mvc/IndexSearch';
var data = {
searchText: sSearchText,
searchTextSite: sSite ,
StartDate: $('#StartDate').val(),
EndDate: $('#EndDate').val()
};
$('#ResultsList').load(url, data, function() {
$('#LoadingGif').empty();
});
Now you will get correct values on the server.

Resources