본문 바로가기

프로그래밍/Chromium(CEF4Delphi)

[Chromium] CEF4Delphi - Javascript 유효성 체크(Evaluate Javascript)

크롬을 이용한 Javascript 유효성 체크(Evaluate Javascript)

웹페이지에 실행시킬 자바스크립트의 유효성을 검토하기 위해서는 다음 단계를 따른다.

1. 렌더링 프로세스 핸들러중 OnProcessMessageReceived 이벤트 핸들러를 작성하여 GlobalCEFApp.OnProcessMessageReceived에 할당한다.

 

const
  EVAL_JS         = 'JSContextEvalDemo';
  BINARY_PARAM_JS = 'JSBinaryParameter';
  ...

//일반적인 경우
procedure ParseEvalJsAnswer(const pMessage     : ICefProcessMessage;
                            const pBrowser     : ICefBrowser;
                            const pFrame       : ICefFrame;
                            const pReturnValue : ICefv8Value;
                            const pException   : ICefV8Exception);
var
  pAnswer       : ICefProcessMessage;
  strResult     : String;
  bGoodDataType : Boolean;
begin
  pAnswer := TCefProcessMessageRef.New(EVAL_JS);

  if (pReturnValue = nil) or not(pReturnValue.IsValid) then
    begin
      pAnswer.ArgumentList.SetBool(0, false);
      pAnswer.ArgumentList.SetString(1, pException.Message);
    end
   else
    begin
      bGoodDataType := True;

      if      pReturnValue.IsString then strResult := pReturnValue.GetStringValue
      else if pReturnValue.IsBool   then strResult := BoolToStr(pReturnValue.GetBoolValue)
      else if pReturnValue.IsInt    then strResult := IntToStr(pReturnValue.GetIntValue)
      else if pReturnValue.IsUInt   then strResult := IntToStr(pReturnValue.GetUIntValue)
      else if pReturnValue.IsDouble then strResult := FloatToStr(pReturnValue.GetDoubleValue)
      else bGoodDataType := False;

      if bGoodDataType then
        begin
          pAnswer.ArgumentList.SetBool(0, true);
          pAnswer.ArgumentList.SetString(1, strResult);
        end
       else
        begin
          pAnswer.ArgumentList.SetBool(0, false);
          pAnswer.ArgumentList.SetString(1, 'Result data type need to be string, int, uint or double!');
        end;
    end;

  pFrame.SendProcessMessage(PID_BROWSER, pAnswer);
end;

//바이너리 처리 경우
procedure ParseBinaryValue(const pBrowser : ICefBrowser; const pFrame : ICefFrame; const aBinaryValue : ICefBinaryValue);
var
  pAnswer     : ICefProcessMessage;
  TempBuffer  : TBytes;
  TempPointer : pointer;
  TempSize    : NativeUInt;
  TempString  : string;
begin
  if (aBinaryValue = nil) then exit;

  try
    try
      TempSize := aBinaryValue.GetSize;

      if (TempSize > 0) then
        begin
          SetLength(TempBuffer, TempSize);
          TempPointer := @TempBuffer[0];
          TempSize    := aBinaryValue.GetData(TempPointer, TempSize, 0);

          if (TempSize > 0) then
            begin
              pAnswer    := TCefProcessMessageRef.New(BINARY_PARAM_JS);
              TempString := 'Image size : ' + inttostr(TempSize) + #13 + #10 +
                            'Encoded image : ' + EncodeBase64(TempPointer, TempSize);

              if pAnswer.ArgumentList.SetString(0, TempString) then
                pFrame.SendProcessMessage(PID_BROWSER, pAnswer);
            end;
        end;
    except
      on e : exception do
        if CustomExceptionHandler('ParseBinaryValue', e) then raise;
    end;
  finally
    SetLength(TempBuffer, 0);
  end;
end;


procedure RenderProcessHandler_OnProcessMessageReceivedEvent(const pBrowser       : ICefBrowser;
                                                             const pFrame         : ICefFrame;
                                                                   uSourceProcess : TCefProcessId;
                                                             const pMessage       : ICefProcessMessage;
                                                             var   aHandled       : boolean);
var
  pV8Context   : ICefv8Context;
  pReturnValue : ICefv8Value;
  pException   : ICefV8Exception;
  TempScript   : string;
  TempBinValue : ICefBinaryValue;
begin
  aHandled := False;

  if (pMessage = nil) or (pMessage.ArgumentList = nil) then exit;

  //사용자가 정의한 메시지 이름에 따라 처리를 달리 한다.
  if (pMessage.Name = EVAL_JS) then
    begin
      TempScript := pMessage.ArgumentList.GetString(0);

      if (length(TempScript) > 0) then
        begin
          pV8Context := pBrowser.MainFrame.GetV8Context;

          if pV8Context.Enter then
            begin
              pV8Context.Eval(TempScript, '', 1, pReturnValue, pException);
              ParseEvalJsAnswer(pMessage, pBrowser, pFrame, pReturnValue, pException);
              pV8Context.Exit;
            end;
        end;

      aHandled := True;
    end
   else
    if (pMessage.Name = BINARY_PARAM_JS) then
      begin
        TempBinValue := pMessage.ArgumentList.GetBinary(0);
        ParseBinaryValue(pBrowser, pFrame, TempBinValue);
        aHandled := True;
      end;
end;

 

2. Javascript 평가를 위한 질의를 만든다

 

procedure TJSEvalFrm.EvalJSCodeMsg(var aMessage : TMessage);
var
  TempMsg    : ICefProcessMessage;
  TempScript : string;
begin
  //평가할 자바스크립트를 사용자에게 입력 받도록 한다.
  TempScript := InputBox('JSEval demo', 'Please type some JavaScript code', 'document.title;');

  if (length(TempScript) > 0) then
    begin
      TempMsg := TCefProcessMessageRef.New(EVAL_JS);

      if TempMsg.ArgumentList.SetString(0, TempScript) then
        Chromium1.SendProcessMessage(PID_RENDERER, TempMsg);
    end;
end;

 

3. 1항에서 작성한 "RenderProcessHandler_OnProcessMessageReceivedEvent" 이벤트 핸들러가 Chromium.SendProcessMessage(PID_RENDERER, TempMsg)요청을 받아서 코드를 평가 한다.

4. "ParseEvalJsAnswer" 는 요청된 자바스크립트를 평가하고 결과를 프로세스 메시지를 이용해 브라우저에 전달 한다.

5. TChromium.OnProcessMessageReceived가 이 메시지를 받아서 뷰어를 호출하도록 메시지를 보낸다.

 

procedure TJSEvalFrm.Chromium1ProcessMessageReceived(      Sender        : TObject;
                                                     const browser       : ICefBrowser;
                                                     const frame         : ICefFrame;
                                                           sourceProcess : TCefProcessId;
                                                     const message       : ICefProcessMessage;
                                                     out   Result        : Boolean);
begin
  Result := False;

  if (message = nil) or (message.ArgumentList = nil) then exit;

  if (message.Name = EVAL_JS) then
    begin
      FText := message.ArgumentList.GetString(1);
      PostMessage(Handle, MINIBROWSER_SHOWTEXTVIEWER, 0, 0); ; //메시지 뷰어를 호출한다
      Result := True;
    end
   else
    if (message.Name = BINARY_PARAM_JS) then
      begin
        FText := message.ArgumentList.GetString(0);
        PostMessage(Handle, MINIBROWSER_SHOWTEXTVIEWER, 0, 0); //메시지 뷰어를 호출한다
        Result := True;
      end;
end;

//뷰어는 일반적인 TEXT 뷰어를 만들어 TEST (메시지 함수 : MINIBROWSER_SHOWTEXTVIEWER)
procedure TJSEvalFrm.ShowTextViewerMsg(var aMessage : TMessage);
begin
  SimpleTextViewerFrm.Memo1.Lines.Text := FText;
  SimpleTextViewerFrm.ShowModal;
end;

...