⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iehttp3.pas

📁 Delphi7版飞信GreenFetion源码
💻 PAS
📖 第 1 页 / 共 4 页
字号:
    //wininet_receive_timeout := 0;
    //InternetSetOption(nil, INTERNET_OPTION_RECEIVE_TIMEOUT, @wininet_receive_timeout, sizeof(wininet_receive_timeout));

    // Make a connection to that host, raising an exception if no connection}
        //    aHConnect := InternetConnect(aHI, aURLc.lpSzHostName,
        //               INTERNET_INVALID_PORT_NUMBER, nil, nil,
        //               INTERNET_SERVICE_HTTP, 0, 0);
    context := 0;
    hConnect := InternetConnectW(hSession, aURLc2.lpSzHostName,
                aURLc2.nPort{INTERNET_DEFAULT_HTTPS_PORT}, aURLc2.lpszUserName, aURLc2.lpszPassword,
               INTERNET_SERVICE_HTTP, 0, context);

    if (hConnect = nil) then begin
      //raise exception.createFmt('Could not connect to server %s', [aURLc2.lpSzHostName]);
      error_msg := format('Could not connect to server %s', [aURLc2.lpSzHostName]);
      exit;
    end;

    // Open a reqest to get ready to GET data, raising an exception if not successful
    //    aHFile := HTTPOpenRequest(aHConnect, PChar(sMethod), aURLc.lpSzUrlPath, HTTP_VERSION, nil,
    //      nil, INTERNET_FLAG_DONT_CACHE, 0);
    if aURLc2.nPort = 443 then
      dwflags := INTERNET_FLAG_SECURE
              or INTERNET_FLAG_IGNORE_CERT_CN_INVALID
              or INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
              or SECURITY_FLAG_IGNORE_UNKNOWN_CA //avoid 12045 -> todo: not working here
      //dwflags := SECURITY_INTERNET_MASK
      //dwflags := 0
    else
      dwflags := 0;

    dwFlags := dwFlags or INTERNET_FLAG_RELOAD;

    PrepareHeaders1;

    setlasterror(0);
    hFile := HTTPOpenRequestW(hConnect, PWideChar( RequestMethod ),
                             aURLc2.lpSzUrlPath, HTTP_VERSION, nil, nil, dwflags, context);
    dwError := getlasterror;
    if dwError <> 0 then begin
      if dwError in [183,122] then
        //sometimes we may receive these errors
        //183: cannot create a file when that file already exists (win98/d6)
        //122: the data area passed to a system call is too small
        dwError := 0
      else begin
        //RaiseLastWin32Error; //no exceptions in the thread
        error := dwerror; //will be handled outside thread
        exit;
        //raise exception.create('error #' + inttostr(dwError));
      end;
    end;

    //if getlasterror <> 0 then RaiseLastWin32Error;

    if (hFile = nil) then begin
      //raise exception.create('Could not open HTTP request');
      error_msg := 'Could not open HTTP request';
      exit;
    end;

  {lStructSize := sizeof(DWORD);
  InternetQueryOption(nil, INTERNET_OPTION_SECURITY_FLAGS, @dwFlags, lStructSize);
  //showmessage(inttostr(dwflags)); //SECURITY_FLAG_SSL3
        dwflags := INTERNET_FLAG_SECURE
              or INTERNET_FLAG_IGNORE_CERT_CN_INVALID
              or INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
              or SECURITY_FLAG_IGNORE_UNKNOWN_CA
              or SECURITY_FLAG_SSL3
              or SECURITY_FLAG_SSL
              or SECURITY_FLAG_IGNORE_WRONG_USAGE
              or SECURITY_FLAG_IGNORE_REVOCATION;
  InternetSetOption(hFile, INTERNET_OPTION_SECURITY_FLAGS, @dwFlags, sizeof(dwFlags) );}

    // Add any extra headers to the request, raising an exception if not successful
    //   if not HTTPAddRequestHeaders(aHFile, PChar(s), length(s), HTTP_ADDREQ_FLAG_ADD) then
    //     raise(EHTTPAddReqError.create('Could not add HTTP request header'));

    // Send the request, raising an exception if not successful
    //    if not HTTPSendRequest(hFile, nil, 0, aURLc.lpSzExtraInfo, aURLc.dwExtraInfoLength) then begin
    //      dwError := getlasterror;

    PrepareHeaders2;

    //-------------------------
    //Connection Attempt
    //-------------------------

    if (error_msg <> '') or (error <> 0) then exit;

    //_lpSzExtraInfo_Bytes is used to send binary data
    if not HTTPSendRequestW(hFile, pwidechar( extraHeaders ), length(extraHeaders),
                                   //aURLc2.lpSzExtraInfo, aURLc2.dwExtraInfoLength) then begin
                                   //_lpSzExtraInfo_Ansi, _dwExtraInfoLength)) then begin
                                   pansichar(_lpSzExtraInfo_Bytes), length(_lpSzExtraInfo_Bytes)) then begin
      dwError := getlasterror;
      //if not HTTPSendRequestEx(hFile, extraHeaders, extraHeadersLength, aURLc2.lpSzExtraInfo, aURLc2.dwExtraInfoLength) then begin
      //  dwError := getlasterror;

      //if (dwError <> 0) then begin
      //showmessage(GetErrorString(dwError));
      //don't raise exception here because this procedure is called in a thread
      //RaiseLastWin32Error;
      //RaiseLastOSError;
      //end;

      if dwError = 12045 then begin
        //try again if Certificate is invalid

        {     x := nil;
        InternetErrorDlg(GetDesktopWindow(),
                           aHFile,
                           ERROR_INTERNET_INVALID_CA,
                           FLAGS_ERROR_UI_FILTER_FOR_ERRORS or
                           FLAGS_ERROR_UI_FLAGS_GENERATE_DATA or
                           FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS,
                           x);}

        InternetQueryOptionW( hFile, INTERNET_OPTION_SECURITY_FLAGS, @dwFlags, lpdwBufferLength);

        dwFlags := dwFlags or SECURITY_FLAG_IGNORE_UNKNOWN_CA;
        InternetSetOptionW( hFile, INTERNET_OPTION_SECURITY_FLAGS, @dwFlags, sizeof(dwFlags) );

        //verify: InternetQueryOption(hFile, INTERNET_OPTION_SECURITY_FLAGS,
        //         @dwFlags, lpdwBufferLength);
        {    hFile := HTTPOpenRequest(hConnect, PChar(sMethod),
        aURLc.lpSzUrlPath, HTTP_VERSION, nil, nil, dwflags, context);
        dwError := getlasterror;
        if dwError <> 0 then RaiseLastWin32Error;}

        //this incorrectly reports error 2 : file not found..., so do not handle the error
        if not HTTPSendRequestW(hFile, pwidechar(extraHeaders), length(extraHeaders),
                                 //aURLc2.lpSzExtraInfo, aURLc2.dwExtraInfoLength)
                                 //_lpSzExtraInfo_Ansi, _dwExtraInfoLength)
                                 pansichar(_lpSzExtraInfo_Bytes), length(_lpSzExtraInfo_Bytes))
        then ;
        dwError := getlasterror;
        //if getlasterror <> 0 then RaiseLastWin32Error;
      end; //retry invalid certificate
    end;

    if dwError > 0 then exit;

    dwBufLen := sizeof(ContentSize);
    ContentSize := 0;
    dwIndex := 0;
    HttpQueryInfoW(hFile, HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER, @ContentSize, dwBufLen, dwIndex );
    if ContentSize=0 then ContentSize:=1; //avoid division by 0
    //bytes_total := ContentSize;

    bytes_read_total := 0;

    ReadCookiesAndHeaders(hFile);

    //asp.net (aspx) disabled content-length even if it is set manually
    //WRONG, content length is being removed from iis-gzip compression filter
    //in such case content is always compressed
    if ContentSize <= 1 then begin
      ContentSize_custom := GetResponseHeaderValue('Custom-Content-Length');
      if (ContentSize_custom <> '') and (ContentSize_custom<>'0') then
        ContentSize := strtoint(ContentSize_custom);
    end;

    {
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&th=e9372deb72b03c8d&rnum=15
InternetReadFile does not work Async.
It blocks until a least some data are read,
and you have no way to stop it other than killing the thread.
Using ReadFileEx, you can use the callback function so you don't need
a thread, and you can stop the call whenever you want, thus respecting timeout values.
}

    CalcTimeoutDatetime;

    //
    // Loop to read the content from the URL in chunks
    ReadResponse;

    //if (not flag_request_to_stop) and (not flag_timeout_occured) then begin
    //end;

    //moved before read response because we may need Custom-Content-Length
    //ReadCookiesAndHeaders(hFile);

  finally
    CleanUpConnectionMemory;
    error := dwError;

  end;

end;

procedure TIEHTTP.CrackURL;
var
  s1, s2, s3 : array[1..INTERNET_MAX_PATH_LENGTH] of widechar;
begin
  //Clear the structure
  FillChar(aURLC2, sizeOf(TURLComponents), 0);
  aURLC2.lpszUrlPath := nil;
  aURLC2.lpszExtraInfo := nil;

  aURLC2.dwStructSize := sizeOf(TURLComponents);
  aURLC2.lpSzExtraInfo := @s1[1];
  aURLC2.dwExtraInfoLength := INTERNET_MAX_PATH_LENGTH;
  aURLC2.lpSzHostName := @s2[1];
  aURLC2.dwHostNameLength := INTERNET_MAX_PATH_LENGTH;
  aURLC2.lpszUrlPath := @s3[1];
  aURLC2.dwUrlPathLength := INTERNET_MAX_PATH_LENGTH;

  _lpSzExtraInfo_Bytes := '';

  if not InternetCrackUrlW( PWideChar(furl), 0, ICU_ESCAPE, aURLC2) then begin
    //raise exception.createFmt('TIE: Invalid URL. Error - %d = ', [GetLastError, SysErrorMessage(GetLastError)]);
    error_msg := format('tiehttp: Invalid URL. Error - %d = %s', [GetLastError, SysErrorMessage(GetLastError)]);
    exit;
  end;

  if widestring(aurlc2.lpszUrlPath) = '' then begin
    error_msg := 'tiehttp: Empty URL';
    exit;
  end;

  //remove only on post
  //if pos('?', aURLc.lpSzExtraInfo) = 1 then begin
  //   aURLc.lpSzExtraInfo := pchar(copy(aURLc.lpSzExtraInfo,2, aURLc.dwExtraInfoLength));
  //   dec(aURLc.dwExtraInfoLength);
  // end;

  //todo: add urldecode?
  _lpSzExtraInfo_Bytes := _WideStringToUTF8(aURLC2.lpszExtraInfo);
  if pos('+', _lpSzExtraInfo_Bytes) > 0 then  //v=1+2 even if passed as 1%2B2, crack url set's it to 1+2
    _lpSzExtraInfo_Bytes := {ansi}stringreplace(_lpSzExtraInfo_Bytes, '+', '%2B', [rfReplaceAll] );

  if (widestring(aURLC2.lpszUserName)='') and (username <> '') then begin
    aURLC2.lpszUserName := pwidechar(Username);
    aURLC2.lpszPassword := pwidechar(Password);
  end;
end;

procedure TIEHTTP.ExecuteURL(url: widestring);
begin
  SetURL(url);
  Execute;
end;

procedure TIEHTTP.Execute;
//var ie_thread : ttimeout;
var
  msg : widestring;
  tmp_dt : tdatetime;
  s : bytestring;
  //response_charset : widestring;
begin
  if working_status <> 0 then begin
    if MessageDlg('Request is in progress (iehttp). Override and continue?', mtConfirmation, [mbOK, mbCancel], 0) <> mrOK then
      exit;
    //raise exception.create('tiehttp: Cannot reuse TIE, while processing request');
    //exit;
  end;
  working_status := 1;

  error_code := 0;
  error := 0;
  error_msg := '';
  bytes_read_total := 0;
  contentSize := 0;

  if furl = '' then raise exception.create('TIEHTTP: no url in execute method');

  try
    result_sl.Clear;
    result_ms.Clear;

    //CrackURL; //crack occurs every time we set the url
    //CrackURL; //FIXED there is a bug that causes the script path to disappear if we progressivly call the same execute command.
    //ProcessReadRequest;

    CalcTimeoutDatetime;
    flag_timeout_occured := false;

    flag_request_to_stop := false;
    flag_cleanup_completed := false;

    last_packet_read_dt := now;
    last_packet_processed_dt := now;

    //create event first
    //create event must be in the same thread as the waitforsingleobject
    //event_handle := CreateEvent(nil, False, False, nil);
    event_handle := CreateEvent(nil, TRUE, False, nil); //2nd param=true means we can reset the event by calling resetEvent

    ie_thread_finished := false;
    //ie_thread_ready := false;
    ie_thread := ttimeout.create(true);
    ttimeout(ie_thread).owner_ie := self;
    ie_thread.Resume;

    //waitForSingleObjectEx(0,infinite,true);

    {$IFDEF tie_debug} LogStr('cp1'); {$endif}
    repeat
      //event_handle := CreateEvent(nil, False, False, nil);

      //check timeout every 500 milliseconds,
      //if request processed before 500ms, WaitForSingleObject will continue
      {$IFDEF tie_debug} LogStr('cp1a'); {$endif}
      try
      {$IFDEF tie_debug} LogStr('about to call WaitForSingleObject. Event handle =' + inttostr(event_handle) + ' .thread done=' + booltostr(ie_thread_finished)); {$endif}

        //mainwait
        //flag_WaitForSingleObject := true;
        WaitForSingleObject(event_handle, 500); //if wfso = WAIT_TIMEOUT then
        //flag_WaitForSingleObject := false;
        ResetEvent(event_handle); //set to non-signeled, resetEvent cancels setEvent
        //CloseHandle( event_handle ); //don't close handle, since event is reusable

        {$IFDEF tie_debug} LogStr('ok. Event handle =' + inttostr(event_handle) + ' .thread done=' + booltostr(ie_thread_finished)); {$endif}
      except
        {$IFDEF tie_debug} LogStr('tiehttp: CANNOT call WaitForSingleObject. Event handle =' + inttostr(event_handle) + ' .thread done=' + booltostr(ie_thread_finished)); {$endif}
        raise exception.create('CANNOT call WaitForSingleObject. Event handle =' + inttostr(event_handle) + ' .thread done=' + booltostr(ie_thread_finished));
        break;
      end;
      {$IFDEF tie_debug} LogStr('cp2'); {$endif}

      //use copy to avoid inconcistency of last_packet_read_dt value, since it may change in thread
      tmp_dt := last_packet_read_dt;
      if assigned(FOnPacketRead) and (tmp_dt>last_packet_processed_dt) then begin
        last_packet_processed_dt := tmp_dt;

        //if not flag_process_onpacketread then
        //  showmessage('managed to process lost packet');

        inc(debug_total_packet_events);
        FOnPacketRead(self);

        //after processing because thread will wait for this flag to continue after successfully processing packet
        //flag_process_onpacketread := false;
      end;

      if assigned(FOnTimer) and (fTimerIntervalSeconds>0)
                            and (last_timer_procesed_dt + (fTimerIntervalSeconds/SecsPerDay) < now) then
      begin
        last_timer_procesed_dt := now;

        //if not flag_process_onpacketread then
        //  showmessage('managed to process lost packet');

        inc(debug_total_timer_events);
        FOnTimer(self);

        //after processing because thread will wait for this flag to continue after successfully processing packet
        //flag_process_onpacketread := false;
      end;


      if not fBlockingMode then //allows user to cancel request
        application.processmessages;

      {$IFDEF tie_debug} LogStr('cp3'); {$endif}

      if (flag_request_to_stop) then begin
        self.working_status := 0; //12mar05
        InternetCloseHandle( hSession );
        //request_to_stop := false;
        result_ms.Clear;
        //msg := '[error 101: canceled by user]';
        //result_ms.Write(pchar(msg)[1], length(msg));
        msg := '';
        error_code := 101; //canceled
        break; //thread may never finish, but there is nothing we can do
      end;
      {$IFDEF tie_debug} LogStr('cp4'); {$ENDIF}

      if ((fTimeout>0) and (now > timeout_datetime)) then begin
        InternetCloseHandle( hSession );
        flag_timeout_occured := true;
        result_ms.Clear;
        result_ms.position := 0;
        //08feb08
        //msg := '[error 100: tiehttp timeout expired]';
        //result_ms.Write(pchar(msg)[1], length(msg));
        //result_ms.WriteBuffer(msg[1], length(msg));
        msg := '';
        error_code := 100; //timeout
        break; //thread may never finish, but there is nothing we can do
      end;
      {$IFDEF tie_debug} LogStr('cp5'); {$endif}
    until ie_thread_finished;
    //if (ie_thread.finished) and (ie_thread <> nil) then
    //  raise exception.create('thread finished but is not nil');

    CloseHandle( event_handle ); //caused crash because we were closing in the thread

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -