I'm having a problem with Posting from an idHTTP component.
This works:
XMLResponse.XML.Text := idHTTP.Post( <url>, StringStream )
This does not work:
XMLResponse.XML.Text := idHTTP.Post( <url>, XMLRequest.XML )
I am creating an XML request in the XMLRequest ( IXMLDocument). If I copy
the XMLRequest.XML.Text to the StringStream, then the Post works fine; if I
use original XMLRequest.XML (which is of type TStrings), then I get an
access failure with a write address of 0000000000.
Any ideas of what is wrong?
Thanks,
Rick
That is not the latest version of Indy 9. You should consider installing
the latest.
> I'm having a problem with Posting from an idHTTP component.
That is because you are not using it properly to begin with.
> This works:
> XMLResponse.XML.Text := idHTTP.Post( <url>, StringStream )
As well it should.
> This does not work:
> XMLResponse.XML.Text := idHTTP.Post( <url>, XMLRequest.XML )
As well it should not. Post(TStrings) is not meant for posting data like
you are. It is meant for submitting input form values via the
"application/x-www-form-urlencoded" encoding - not what you want to do when
sending XML data.
> if I use original XMLRequest.XML (which is of type TStrings), then
> I get an access failure with a write address of 0000000000.
An AV at address 00000000 means that a nil pointer was accessed.
Post(TStrings) internally creates a TStringStream and then calls
Post(TStream). The only possible nil pointer involved in the whole
operation is the XMLRequest.XML pointer, but your description suggests that
it is never nil to begin with, so there can not be any other nil pointer
involved if Post(TStream) works fine for you when called directly.
In any case, I still say that you should upgrade your version of Indy 9 to
the latest, just to make sure that you have the latest bug fixes and such.
Gambit
I will download the latest version.
I agree that the logical assumption is that the XMLRequest.XML is nill,
however this is what I use to copy into the StringStream, so it is obviously
not nil.
We'll see if the upgrade helps, but it seems like from what you are saying,
I should do it via a Stream instead? I looked at the source and it seems
that it doesn't do anything special to the TStrings in the Post, however
maybe there is something I overlooked.
Rick
> I agree that the logical assumption is that the XMLRequest.XML is nill,
Even if it were nil, it would be simply be ignored. Unless the version you
are currently using does not ignore nil TStrings. The current version does.
> however this is what I use to copy into the StringStream, so
> it is obviously not nil.
Exactly as I mentioned earlier.
> We'll see if the upgrade helps, but it seems like from what
> you are saying, I should do it via a Stream instead?
You would have to do it via a stream anyway. Passing in a TStrings instead,
the data will be encoded and transformed in ways that are not valid for XML.
> I looked at the source and it seems that it doesn't do anything
> special to the TStrings in the Post
Yes, it does:
function TIdCustomHTTP.Post(AURL: string; const ASource: TStrings):
string;
var
LResponse: TStringStream;
begin
LResponse := TStringStream.Create('');
try
Post(AURL, ASource, LResponse); // <-- Post(String, TStrings,
TStream)
finally
result := LResponse.DataString;
LResponse.Free;
end;
end;
procedure TIdCustomHTTP.Post(AURL: string; const ASource: TStrings;
const AResponseContent: TStream);
var
LParams: TStringStream;
begin
//...
LParams := TStringStream.Create(SetRequestParams(ASource)); // <--
ASource data gets encoded
//...
end;
function TIdCustomHTTP.SetRequestParams(const AStrings: TStrings):
string;
begin
if Assigned(AStrings) then begin
if hoForceEncodeParams in FOptions then begin
EncodeRequestParams(AStrings); // <-- values get encoded
end;
if AStrings.Count > 1 then begin
// break trailing CR&LF
Result := StringReplace(Trim(AStrings.Text), sLineBreak,
'&', [rfReplaceAll]) // <-- data modified
end else begin
Result := Trim(AStrings.Text);
end;
end else begin
Result := '';
end;
end;
procedure TIdCustomHTTP.EncodeRequestParams(const AStrings: TStrings);
var
i: Integer;
S: string;
begin
for i := 0 to AStrings.Count - 1 do begin
S := AStrings.Names[i];
if Length(AStrings.Values[S]) > 0 then begin
AStrings.Values[S] :=
TIdURI.ParamsEncode(AStrings.Values[S]); // <-- data modified
end;
end;
end;
Gambit