#1 2015-12-18 09:49:52

EvaF
Member
Registered: 2014-07-19
Posts: 40

CallBackGet function and GET parameters

Hi,
thanks for a great framework....

I am working on a REST communication with Wordpress ( via Wordpress plugin WP REST API with Oauth 1.0a authenification)
I would like to use the TSQLHttpClient class and CallBackGet function  but I ran into troubles with limited GET parameters names - only ['a'..'z','A'..'Z'] charset is allowed  in parameter names in mormot. However Oauth 1.0 requires parameters with underscores (f.e. oauth_signature,..).
Is it possible to add underscore into the allowed characters for parameter names?


here is the modification that could accomplish it... As you can see 1 line is changed.

function TSQLRestClientURI.CallBackGet(const aMethodName: RawUTF8;
  const aNameValueParameters: array of const; out aResponse: RawUTF8;
  aTable: TSQLRecordClass; aID: TID; aResponseHead: PRawUTF8): integer;
var url, header: RawUTF8;
begin
  if self=nil then
    result := HTML_UNAVAILABLE else begin
{$ifdef WITHLOG}
    fLogClass.Enter(Self,pointer(aMethodName),true);
{$endif}
    url := Model.getURICallBack(aMethodName,aTable,aID)+
      UrlEncode(aNameValueParameters);
     ....
  end;
end;

function UrlEncode(const NameValuePairs: array of const): RawUTF8;
// (['select','*','where','ID=12','offset',23,'object',aObject]);
var A, n: PtrInt;
    name, value: RawUTF8;
  function Invalid(P: PAnsiChar): boolean;
  begin
    result := true;
    if P<>nil then begin
      repeat
        if not (P^ in ['a'..'z','_','A'..'Z']) then       //  <--- originally if not (P^ in ['a'..'z','A'..'Z']) 
          exit else
          inc(P);
      until P^=#0;
      result := false;
    end;
  end;
begin
  result := '';
  n := high(NameValuePairs);
  if n>0 then begin
    for A := 0 to n shr 1 do begin
      VarRecToUTF8(NameValuePairs[A*2],name);
      if Invalid(pointer(name)) then
        continue;
      with NameValuePairs[A*2+1] do
        if VType=vtObject then
          value := ObjectToJSON(VObject,[]) else
          VarRecToUTF8(NameValuePairs[A*2+1],value);
      result := result+'&'+name+'='+UrlEncode(value);
    end;
    result[1] := '?';
  end;
end;

Eva

Offline

#2 2015-12-18 16:48:00

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: CallBackGet function and GET parameters

The framework version you are using is clearly deprecated.

This has already been included in the trunk:

function UrlEncode(const NameValuePairs: array of const): RawUTF8;
// (['select','*','where','ID=12','offset',23,'object',aObject]);
var A, n: PtrInt;
    name, value: RawUTF8;
  function Invalid(P: PAnsiChar): boolean;
  begin
    result := true;
    if P<>nil then begin
      repeat // cf. rfc3986 2.3. Unreserved Characters
        if not (P^ in ['a'..'z','A'..'Z','0'..'9','_','.','~']) then
          exit else
          inc(P);
      until P^=#0;
      result := false;
    end;
  end;

Ensure you use the latest "unstable" version, not the "stable" version which is clearly deprecated.
See http://synopse.info/files/html/Synopse% … l#TITL_113

Offline

#3 2015-12-21 09:27:38

EvaF
Member
Registered: 2014-07-19
Posts: 40

Re: CallBackGet function and GET parameters

o, sorry, thanks for the info...
But I ran into another problem ( this time I have checked (to be the sure) in the latest unstable version too)
The problem is still related to the TSQLHttpClient. I  would like to set both the Content-Type  and also Cookies in the request.

something like

lHead := 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8'+#13#10 +
              'Cookie: a=1111111111' ;

But InternalURI works like this: if Header contains any Content-type then all other settings in Header are neglected
( // header is processed -> no need to send Content-Type twice )

procedure TSQLHttpClientGeneric.InternalURI(var Call: TSQLRestURIParams);
var Head, Content, ContentType: RawUTF8;
    P: PUTF8Char;
begin
  ..
  Head := Call.InHead;
  Content := Call.InBody;
  if InternalCheckOpen then begin
    if Head<>'' then begin
      P := pointer(Head);
      if IdemPChar(P,'CONTENT-TYPE:') then begin
        inc(P,14);
        if Content<>'' then begin
          ContentType := GetMimeContentType(pointer(Content),Length(Content));
          if ContentType='application/octet-stream' then
            ContentType := '';
        end;
        if ContentType='' then
          ContentType := GetNextLine(P,PEnd);
        Head := ''; // header is processed -> no need to send Content-Type twice
      end;
    end;

IMHO it would cause trouble also in the case when TSQLHttpClient has set both Content-Type and fSessionHttpHeader

It is possible to preserve other settings in Header?
at least something like this: ( I maybe wrong )

procedure TSQLHttpClientGeneric.InternalURI(var Call: TSQLRestURIParams);
var Head, Content, ContentType, lContentypeInHead: RawUTF8;
    P,PBegin, pEnd: PUTF8Char;
begin
  ...
  Head := Call.InHead;
  Content := Call.InBody;
  if InternalCheckOpen then begin
    if Head<>'' then begin
      P := pointer(Head);
      if IdemPChar(P,'CONTENT-TYPE:') then begin
        PBegin := P;                                                  // <--- added
        inc(P,14);
        lContentypeInHead := GetNextLine(P,PEnd);                     // <--- added
        if Content<>'' then begin
          ContentType := GetMimeContentType(pointer(Content),Length(Content));
          if ContentType='application/octet-stream' then
            ContentType := '';
        end;
        if ContentType='' then
          ContentType := lContentypeInHead;                            // <--- changed
        system.delete(Head, PBegin - pointer(Head) + 1, pEnd-pBegin ); // <--- added
      end;
    end;
    ...
end;

P.S. I have just checked the IdemPChar function  - "Content-Type" should be the first parameter in the request-header because of using this IdemPChar  function

Last edited by EvaF (2015-12-21 11:35:53)

Offline

#4 2015-12-21 13:19:09

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: CallBackGet function and GET parameters

Should be fixed by http://synopse.info/fossil/info/8ede0e28bb

Thanks for the feedback!

Offline

#5 2015-12-21 15:16:26

EvaF
Member
Registered: 2014-07-19
Posts: 40

Re: CallBackGet function and GET parameters

hi ab,

thanks for modification - the last wish (hope) is replacing IdemPChar function by some Pos function ( f.e. StrPosI function)
for the case:

lHead := 'Cookie: a=1111111111' +#13#10 +
            'Content-Type: application/x-www-form-urlencoded;charset=UTF-8';

can look something like this:

  if InternalCheckOpen then begin
    if Head<>'' then begin
      P := pointer(Head);
      P := StrPosI('CONTENT-TYPE:',P);
      if assigned(P) then begin
        PBegin := P;
        inc(P,14);
        lContentypeInHead := GetNextLine(P,PEnd);
        if not assigned(pEnd) then          // Content-type parameter is the last
        begin
          pEnd := Pointer(Head);
          Inc(pEnd, length(Head));
        end;
        system.delete(Head, PBegin - pointer(Head) + 1, pEnd-pBegin );
       ...

thanks again

ef

Offline

#6 2015-12-21 17:02:52

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: CallBackGet function and GET parameters

Using StrPosI() may be unsafe, since the text may appear as part of a header value, not as a header entry name...

Please try http://synopse.info/fossil/info/241300a272 which sounds safer.
It would let TSQLHttpClientGeneric.InternalURI recognize Content-Type: header on any position.

Offline

#7 2015-12-21 19:15:35

EvaF
Member
Registered: 2014-07-19
Posts: 40

Re: CallBackGet function and GET parameters

Using StrPosI() may be unsafe, since the text may appear as part of a header value, not as a header entry name...

You are right, I will use it your way, thx
ef

Offline

#8 2015-12-21 20:11:53

EvaF
Member
Registered: 2014-07-19
Posts: 40

Re: CallBackGet function and GET parameters

only small question - I cannot find  GetMimeContentTypeFromBuffer function
I suppose that it looks something like that:

function GetMimeContentTypeFromBuffer(Content: Pointer; Len: integer;
  const ContentType: RawUTF8 =''): RawUTF8;
begin
  Result := GetMimeContentType(Content, Len);
  if (Result = '') or (Result = 'application/octet-stream') then
    Result := ContentType;
end;

Offline

#9 2015-12-21 22:53:25

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: CallBackGet function and GET parameters

Upgrade your source code from the repository....

Offline

#10 2015-12-22 05:40:14

EvaF
Member
Registered: 2014-07-19
Posts: 40

Re: CallBackGet function and GET parameters

ok, thanks for everything

Offline

Board footer

Powered by FluxBB