• Wininet请求包装类简稿


    unit uWnWinetClass;

    interface

    uses
      Windows,Messages,SysUtils,Classes,WinInet;

    const
      CONST_AGENT = 'Wininet by Enli';
      BUFFER_SIZE = 4096;

    type
      //定义http的请求调用方式
      //TWinWrapVerbs = (wwvGET, wwvPOST, wwvMPOST);
      //定义协议版本
      TWinHttpVersion = (wwvHttp1,wwvHttp11);
      //错误类型,没有错误为wwecNil
      TWinInetErrorCauses = (wwecNil,                             //0
                             wwecAttemptConnect,                  //1
                             wwecOpen,                            //2
                             wwecConnect,                         //3
                             wwecOpenRequest,                     //4
                             wwecConfigureRequest,                //5
                             wwecExecRequest,                     //6
                             wwecEndRequest,                      //7
                             wwecTimeOut,                         //8
                             wwecUPD,                             //9
                             wwecAbort,                           //10
                             wwecStatus,                          //11
                             wwecHeader,                          //12
                             wwecContentLength,                   //13
                             wwecContentType,                     //14
                             wwecReadFile,                        //15
                             wwecWriteFile);                      //16

      TProxyInfo = record
        FProxyType : Integer; //-1: preConfig 0: noproxy 1: sock4 2: sock5 3: http
        FProxyServer : string;
        FProxyPort : Integer;
        FProxyUserName : string;
        FProxyUserPass : string;
      end;
      TWnWinetClass = class
      private
        FNet: HINTERNET;
        FRequest: HINTERNET;
        FSession: HINTERNET;
        FRequestStream: TMemoryStream;
        FResponseStream: TMemoryStream;
        FVerb: string;
        FAbort: Boolean;
        FWininetStateChanged: Boolean;
        FTimeOut: Integer;
        FSecure: Boolean;
        FProxyInfo: TProxyInfo;
        FServerPort: Integer;
        FEncodeUrl: string;
        FErrInfo: string;
        FServerPass: string;
        FServerUser: string;
        FServerName: string;
        FProxy : string;
        FHttpHeader: string;
        FData: array [0 .. BUFFER_SIZE] of Char;
        FErrorCause: TWinInetErrorCauses;
        FHttpVersion: TWinHttpVersion;
        FStatus: integer;
        FContentType: string;
        FContentLength: Int64;
        FTotal: Int64;
        FResponseHeader: string;
        procedure SetAbort(const Value: Boolean);
        procedure FixServerInfo;
        procedure FixProxyServerInfo;
        function OpenConnection: Boolean;
        function OpenRequest: Boolean;
        function ConfigureRequest: Boolean;
        function PerformMethod: Boolean;
        function DetectProxyServer: DWORD;
        function PortToUse(APort: Integer): Integer;
        function FetchHeader(AFlags: integer): Boolean;
        function ReadResponse: Boolean; // 读取接受数据
        function ReadResponseHeader: Boolean;  //获取返回数据包头
        function FixContentLength: Boolean; // 获取接受数据的大小
        function FixContentType: Boolean; // 获取接受数据的类型
        function FixWinINetError(AError: integer): string;
        function GetHttpVersion: string;
        procedure AssignError(AError: TWinInetErrorCauses);
      public
        constructor Create;
        destructor Destroy; override;
        property Abort: Boolean read FAbort write SetAbort;
        property Response: TMemoryStream read FResponseStream;
        property HttpVersion: TWinHttpVersion read FHttpVersion write FHttpVersion;
        property ServerName: string read FServerName write FServerName;
        property ServerPort: Integer read FServerPort write FServerPort;
        property ServerUser: string read FServerUser write FServerUser;
        property ServerPass: string read FServerPass write FServerPass;
        property ProxyInfo: TProxyInfo read FProxyInfo write FProxyInfo;
        property HttpHeader: string read FHttpHeader write FHttpHeader;
        property ResponseHeader: string read FResponseHeader write FResponseHeader;
        property Status: Integer read FStatus;
        property ContentLength: Int64 read FContentLength;
        property Total: Int64 read FTotal;
        property ErrInfo: string read FErrInfo;
        property ErrorCause: TWinInetErrorCauses read FErrorCause;
        procedure CleanUp(isAll: Boolean);
        function HttpGet(isUrl:string;iiTimeout:Integer;ASecure:Boolean = False):boolean;
        function HttpPost(isUrl:string;AStream:TMemoryStream;iiTimeout:Integer;ASecure:Boolean = False):boolean;
        class function StreamToHex(AStream: TMemoryStream): string;
        class procedure HexToStream(AStream: TMemoryStream;AHex: string);
      end;

    implementation

    { TWnWinetClass }

    procedure TWnWinetClass.AssignError(AError: TWinInetErrorCauses);
    var
      I, H: Integer;
      LTemp: string;
      LR: Cardinal;
    begin
      FErrorCause := AError;
      if Length(FErrInfo) = 0 then
      begin
        LR := GetLastError;
        if (LR < 12000or (LR < 12175then
        begin
          H := GetModuleHandle('wininet.dll');
          SetLength(LTemp, 256);
          I := FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, Pointer(H), LR, 0,
            PChar(LTemp), 256nil);
          SetLength(LTemp, I);
          FErrInfo := 'Error '+IntTostr(LR)+':'+LTemp;
        end
        else
          FErrInfo := 'Error '+IntTostr(LR)+':'+SysErrorMessage(GetLastError);
      end;
    end;

    procedure TWnWinetClass.CleanUp(isAll: Boolean);
    begin
      if isAll then
      begin
        if Assigned(FRequest) then
        begin
          InternetCloseHandle(FRequest);
          FRequest := nil;
        end;
        if Assigned(FSession) then
        begin
          InternetCloseHandle(FSession);
          FSession := nil;
        end;
        if Assigned(FNet) then
        begin
          InternetCloseHandle(FNet);
          FNet := nil;
        end;
      end;
      //FResponse.Clear;
      SetLength(FProxy,0);
    end;


    function TWnWinetClass.ConfigureRequest: Boolean;
      function SetUPD(AOption: DWORD; AUPD: PChar): Boolean;
      begin
        Result := (Length(AUPD) = 0or InternetSetOption
          (FRequest, AOption, AUPD, Length(AUPD));
      end;

    begin
      Result := False;
      if FAbort then
        Exit;
      // 设置HTTP头
      {if FFileSize > 0 then
      begin
        if Length(FHttpHeader) > 0 then
          FHttpHeader := FHttpHeader + #13#10'Range: bytes=' + IntTostr(FFileSize)
            + '-'#13#10
        else
          FHttpHeader := 'Range: bytes=' + IntTostr(FFileSize) + '-'#13#10;
      end;
    }
      if Length(FHttpHeader) > 0 then
      begin
        Result := HttpAddRequestHeaders(FRequest, PWideChar(FHttpHeader), Cardinal
            (-1), HTTP_ADDREQ_FLAG_ADD or HTTP_ADDREQ_FLAG_REPLACE);

        if not Result then
        begin
          AssignError(wwecConfigureRequest);
          Exit;
        end;
      end;
      // 设置超时
      if (FTimeOut < 1or (FTimeOut > 999then
        FTimeOut := 30;
      FTimeOut := FTimeOut * 1000;
      Result := InternetSetOption(FNet, INTERNET_OPTION_CONNECT_TIMEOUT, @FTimeOut,
        SizeOf(integer)) and InternetSetOption
        (FNet, INTERNET_OPTION_RECEIVE_TIMEOUT, @FTimeOut, SizeOf(integer))
        and InternetSetOption(FNet, INTERNET_OPTION_SEND_TIMEOUT, @FTimeOut, SizeOf
          (integer));

      if not(Result) then
      begin
        AssignError(wwecTimeOut);
        Exit;
      end;
      // 设置代理用户密码,访问用户密码
      if SetUPD(INTERNET_OPTION_PROXY_USERNAME, PChar(FProxyInfo.FProxyUserName))
        and SetUPD(INTERNET_OPTION_PROXY_PASSWORD, PChar(FProxyInfo.FProxyUserPass)
        ) and SetUPD(INTERNET_OPTION_USERNAME, PChar(FServerPass)) and SetUPD
        (INTERNET_OPTION_PASSWORD, PChar(FServerUser)) then
      else
        AssignError(wwecUPD);

    end;

    constructor TWnWinetClass.Create;
    begin
      inherited;
      FResponseStream := TMemoryStream.Create;
      FRequest := nil;
      FSession := nil;
      FRequestStream := nil;
      FNet := nil;
      FAbort := False;
      FSecure := False;
      FWininetStateChanged := False;
      SetLength(FEncodeUrl,0);
      SetLength(FErrInfo,0);
      SetLength(FServerUser,0);
      SetLength(FServerPass,0);
      SetLength(FProxy,0);
      FVerb := 'GET';

    end;

    destructor TWnWinetClass.Destroy;
    begin
      FResponseStream.Free;
      inherited;
    end;

    function TWnWinetClass.DetectProxyServer: DWORD;
    begin
       //-1: preConfig 0: noproxy 1: sock4 2: sock5 3: http
      //Result:
      //INTERNET_OPEN_TYPE_PRECONFIG                   0
      //INTERNET_OPEN_TYPE_DIRECT                      1
      //INTERNET_OPEN_TYPE_PROXY                       3
      //INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY 4
      with FProxyInfo do
      case (FProxyType-1of
        0: Result := INTERNET_OPEN_TYPE_DIRECT;
        1:
        begin
          Result := INTERNET_OPEN_TYPE_PROXY;
          FProxy := Format('socks=%s:%s',[FProxyServer,Inttostr(FProxyPort)]);
        end;
        2:
        begin
          Result := INTERNET_OPEN_TYPE_PROXY;
          FProxy := Format('socks5=%s:%s',[FProxyServer,Inttostr(FProxyPort)]);
        end;
        3:
        begin
          Result := INTERNET_OPEN_TYPE_PROXY;
          FProxy := Format('%s:%s',[FProxyServer,Inttostr(FProxyPort)]);
        end;
      else
          Result := INTERNET_OPEN_TYPE_PRECONFIG;
      end;
    end;

    function TWnWinetClass.FetchHeader(AFlags: integer): Boolean;
    var
      BufLen, Index: DWORD;
    begin
      Result := False;
      if FAbort then Exit;
      Index := 0;
      BufLen := BUFFER_SIZE;
      FillChar(FData, BufLen, 0);
      Result := HttpQueryInfo(FRequest, AFlags, @FData, BufLen, Index);
    end;

    function TWnWinetClass.FixContentLength: Boolean;
    var
      LTemp: string;
    begin
      Result := False;
      if FAbort then Exit;
      Result := FetchHeader(HTTP_QUERY_CONTENT_LENGTH);
      LTemp := FData;
      if Result then
        FContentLength := StrToInt64Def(LTemp, 0)
      else
        AssignError(wwecContentLength);
    end;

    function TWnWinetClass.FixContentType: Boolean;
    begin
      Result := False;
      if FAbort then Exit;
      Result := FetchHeader(HTTP_QUERY_CONTENT_TYPE);
      if Result then
        FContentType := FData
      else
        AssignError(wwecContentType);
    end;

    procedure TWnWinetClass.FixProxyServerInfo;
    var
      ls1ServerName, lsPort: string;
      liLoc: Integer;
    begin
      ls1ServerName := LowerCase(FServerName);
      liLoc := Pos(':', ls1ServerName);
      if liLoc = 0 then Exit;
      lsPort := Copy(ls1ServerName, liLoc + 1, Length(ls1ServerName) - liLoc);
      FServerName := PChar(Copy(ls1ServerName, 1, liLoc - 1));
      FServerPort := StrToIntDef(lsPort,FServerPort);
    end;

    procedure TWnWinetClass.FixServerInfo;
    var
      ls1ServerName, lsPort: string;
      liLoc: Integer;
    begin
      if FProxyInfo.FProxyType = 0 then Exit;
      ls1ServerName := LowerCase(FProxyInfo.FProxyServer);
      liLoc := Pos(':', ls1ServerName);
      if liLoc = 0 then Exit;
      lsPort := Copy(ls1ServerName, liLoc + 1, Length(ls1ServerName) - liLoc);
      FProxyInfo.FProxyServer := PChar(Copy(ls1ServerName, 1, liLoc - 1));
      FProxyInfo.FProxyPort := StrToIntDef(lsPort,FProxyInfo.FProxyPort);
    end;

    function TWnWinetClass.FixWinINetError(AError: integer): string;
    begin
      //Result := 'Http Status: ' + IntTostr(AError);
      if FetchHeader(HTTP_QUERY_STATUS_TEXT) then
        Result := FData
      //if not Result then
      else
      begin
        AssignError(wwecStatus);
        Exit;
      end;
    end;

    function TWnWinetClass.GetHttpVersion: string;
    begin
      if FHttpVersion = wwvHttp1 then
        Result := 'HTTP/1.0'
      else
        Result := 'HTTP/1.1';
    end;

    class procedure TWnWinetClass.HexToStream(AStream: TMemoryStream;AHex: string);
    var
      I,iLen: Integer;
      LTemp: string;
      LB : Byte;
    begin
      iLen := Length(AHex);
      if (iLen mod 3) <> 0 then
      begin
        Assert(False,'hex字符串错误');
        Exit;
      end;
      for I := 0 to (iLen div 3) - 1 do
      begin
        LTemp := Copy(AHex,I*3+1,2);
        LB := StrToIntDef('$'+LTemp,0);
        AStream.WriteBuffer(Lb,1);
        //Assert(Pos(IntToStr(LB),LTemp)=0,'asdf');
      end;


    end;

    function TWnWinetClass.HttpGet(isUrl: string; iiTimeout: integer;
      ASecure: Boolean): boolean;
    begin
      FVerb := 'GET';
      FRequest := nil;
      FRequestStream := nil;
      SetLastError(0);
      FErrInfo := '';
      FErrorCause := wwecNil;
      Result := False;
      FEncodeUrl := isUrl;
      FTimeOut := iiTimeout;
      FSecure := ASecure;
      FixServerInfo;
      FixProxyServerInfo;
      Result := OpenConnection
      and OpenRequest
      and ConfigureRequest
      and PerformMethod;
      CleanUp(True);
    end;

    function TWnWinetClass.HttpPost(isUrl: string; AStream: TMemoryStream;
      iiTimeout: Integer; ASecure: Boolean): boolean;
    begin
      FVerb := 'POST';
      FRequestStream := AStream;
      SetLastError(0);
      FErrInfo := '';
      FErrorCause := wwecNil;
      Result := False;
      FEncodeUrl := isUrl;
      FTimeOut := iiTimeout;
      FSecure := ASecure;
      FixServerInfo;
      FixProxyServerInfo;
      Result := OpenConnection
      and OpenRequest
      and ConfigureRequest
      and PerformMethod;
      CleanUp(True);
    end;

    function TWnWinetClass.OpenConnection: Boolean;
    var
      LProxyType: DWORD;

      function WW_AttemptConnect: Boolean;
      begin
        Result := (CompareText(FServerName, 'localhost') = 0or
          (InternetAttemptConnect(0) = ERROR_SUCCESS);
        if not (Result) then AssignError(wwecAttemptConnect);
      end;

      procedure CancelMaxConnectLimite();
      var
        liPerServer1, liPerServer2: Integer;
      begin
        try
          liPerServer1 := 5;
          liPerServer2 := 10;
          //INTERNET_OPTION_MAX_CONNS_PER_SERVER  73
          InternetSetOption(nil73, @liPerServer1, SizeOf(Integer));
          //INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER  74
          InternetSetOption(nil74, @liPerServer2, SizeOf(Integer));
        except
        end;
      end;

      function WW_InternetOpen: Boolean;
      var
        ltInfo: INTERNET_CONNECTED_INFO;
      begin
        FNet := InternetOpen(PChar(CONST_AGENT), LProxyType, PChar(FProxy), nil0);

        Result := (FNet <> nil);
        if Result then begin
          try
            if not FWininetStateChanged then begin
              //INTERNET_OPTION_CONNECTED_STATE  50
              //取消IE的脱机状态
              ltInfo.dwConnectedState := INTERNET_STATE_CONNECTED;
              ltInfo.dwFlags := 0;          // ISO_FORCE_DISCONNECTED;
              InterNetSetOption(FNet, INTERNET_OPTION_CONNECTED_STATE, @ltInfo, SizeOf(ltInfo));
            end;
          except
          end;
          //InternetSetStatusCallBack(FNet, @StatusCallBack);

          //INTERNET_OPTION_HTTP_DECODING
          if InternetSetOption(FNet, 65, @Result, 1then begin
            Beep;
          end;
        end else begin
          AssignError(wwecOpen);
        end;
      end;

      function WW_InternetConnect: Boolean;
      var
        context: dword;
      begin
        //同步通讯设置
        context := 0;
        //异步通讯需要设置特定值
        //FCallBackContext.CallbackID := 0;
        //context:=dword(@FCallBackContext);
        FSession := InternetConnect(FNet, PChar(FServerName),
            PortToUse(FServerPort), '''', INTERNET_SERVICE_HTTP, 0, context);
        Result := (FSession <> nil);
        if not (Result) then AssignError(wwecConnect);
      end;

    begin
      Result := False;
      if FAbort then Exit;
      if WW_AttemptConnect then
      begin
        LProxyType := DetectProxyServer;
        SetLastError(0);
        if not FWininetStateChanged then CancelMaxConnectLimite();
        Result := WW_InternetOpen and WW_InternetConnect;
        FWininetStateChanged := True;
      end;
    end;

    function TWnWinetClass.OpenRequest: Boolean;
    var
      context, ATimeOut, dwFlags: DWORD;
    begin
      Result := False;
      if FAbort then
        Exit;
      context := 0;
      if FSecure then
      begin
        FRequest := HTTPOpenRequest(FSession, PChar(FVerb), PChar(FEncodeUrl), PChar
            (GetHttpVersion), nilnil,
          INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_SECURE or
            SECURITY_FLAG_IGNORE_UNKNOWN_CA or SECURITY_FLAG_IGNORE_CERT_CN_INVALID
            or SECURITY_FLAG_IGNORE_CERT_DATE_INVALID, context);
        ATimeOut := 0;
        dwFlags := 0;

        if (FRequest <> niland (not InternetQueryOption(FRequest,
            INTERNET_OPTION_SECURITY_FLAGS, Pointer(@ATimeOut), dwFlags)) then
        begin
          GetLastError;
        end;
      end
      else
      begin
        FRequest := HTTPOpenRequest(FSession, PChar(FVerb), PChar(FEncodeUrl), PChar
            (getHttpVersion), nilnil{ Ord(FSecure) * INTERNET_FLAG_SECURE or }
          INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_RELOAD or
            INTERNET_FLAG_KEEP_CONNECTION, context);
      end;
      Result := (FRequest <> nil);
      if not(Result) then
        AssignError(wwecOpenRequest);
    end;

    function TWnWinetClass.PerformMethod: Boolean;
    var
      ATimeOut, dwFlags: DWORD;
      // LErr: Cardinal;
    begin
      Result := False;
      if FAbort then Exit;
      if Assigned(FRequestStream) and (FRequestStream.Size > 0then
        Result := HTTPSendRequest(FRequest, nil0, FRequestStream.Memory, FRequestStream.Size)
      else
        Result := HTTPSendRequest(FRequest, nil0nil0);
      // Result := HTTPSendRequest(FRequest, D_C_T, D_C_T_S, nil0);
      if not(Result) then
      begin
        if GetLastError = ERROR_INTERNET_INVALID_CA then // WinInet 无效证书颁发机构错误
        begin
          ATimeOut := 0;
          dwFlags := 0;
          InternetQueryOption(FRequest, INTERNET_OPTION_SECURITY_FLAGS, Pointer
              (@ATimeOut), dwFlags);
          dwFlags := dwFlags or SECURITY_FLAG_IGNORE_UNKNOWN_CA;
          InternetSetOption(FRequest, INTERNET_OPTION_SECURITY_FLAGS, @dwFlags,
            SizeOf(integer));
          Result := HTTPSendRequest(FRequest, nil0nil0);
        end
        else
        begin
          AssignError(wwecExecRequest);
          Exit;
        end;
      end;

      Result := ReadResponseHeader
        and FixContentLength and FixContentType and ReadResponse;

    end;

    function TWnWinetClass.PortToUse(APort: Integer): Integer;
    begin
      if APort > 0 then
        Result := APort
      else
        if FSecure then
          Result := INTERNET_DEFAULT_HTTPS_PORT
        else
          Result := INTERNET_DEFAULT_HTTP_PORT;
    end;

    function TWnWinetClass.ReadResponse: Boolean;
    var
      ASize, ARead: DWORD;
      ABuffer: Pointer;
    begin
      Result := False;
      if FAbort then Exit;
      FResponseStream.Clear;
      ASize := BUFFER_SIZE;
      FTotal := 0;
      ABuffer := AllocMem(ASize);
      try
        // HookDataReadSized;
        repeat
          Result := InternetReadFile(FRequest, ABuffer, ASize, ARead);
          if not Result then
          begin
            AssignError(wwecReadFile);
            Break;
          end;
          if (ARead > 0then
          begin
            FResponseStream.WriteBuffer(ABuffer^, ARead);
            Inc(FTotal, ARead);
            //FTotal := ARead;
            //HookDataReadSized;
          end;
        until ((ARead = 0or FAbort);
        FResponseStream.Seek(0,0);
      finally
        FreeMem(ABuffer, 0);
      end;
    end;

    function TWnWinetClass.ReadResponseHeader: Boolean;
    begin
      Result := False;
      if FAbort then Exit;
      Result := FetchHeader(HTTP_QUERY_STATUS_CODE);
      if not Result then
      begin
        AssignError(wwecStatus);
        Exit;
      end;
      FStatus := StrToIntDef(FData, -1);
      if FAbort then Exit;
      Result := FetchHeader(HTTP_QUERY_RAW_HEADERS_CRLF);
      if Result then
        FResponseHeader := FData
      else
        AssignError(wwecHeader);
    end;

    procedure TWnWinetClass.SetAbort(const Value: Boolean);
    begin
      FAbort := Value;
    end;

    class function TWnWinetClass.StreamToHex(AStream: TMemoryStream): string;
    var
      I: Integer;
      Lb: Byte;
    begin
      Result := '';
      AStream.Seek(0,0);
      for I := 1 to AStream.Size do
      begin
        AStream.ReadBuffer(LB,1);
        Result := Result + IntToHex(Ord(Lb),2)+ ' ';
        //if (I mod ALen) = 0 then
        //  Result := Result + #13#10;
      end;

    end;

    end.
  • 相关阅读:
    比较.NET程序集(DLL或EXE)是否相同
    [转] JavaScript数组去重(12种方法)
    [转] js网络请求跨域问题汇总(携带cookie)
    [转] JS中arr.forEach()如何跳出循环
    [转] vue前端异常监控sentry实践
    [转] vue父组件触发子组件事件
    [转] vue 自定义组件使用v-model
    [转] Nginx配置性能优化
    [转] linux 查找文本过滤grep正则表达式命令详解用法
    [转] Nginx配置中的location、root、alias
  • 原文地址:https://www.cnblogs.com/enli/p/2406495.html
Copyright © 2020-2023  润新知