📄 soaphttptrans.pas
字号:
if not (URLComp.nScheme in [INTERNET_SCHEME_HTTP, INTERNET_SCHEME_HTTPS]) then
raise ESOAPHTTPException.CreateFmt(SInvalidURL, [Value]);
FURLScheme := URLComp.nScheme;
FURLPort := URLComp.nPort;
FURLHost := Copy(Value, URLComp.lpszHostName - P + 1, URLComp.dwHostNameLength);
FURLSite := Copy(Value, URLComp.lpszUrlPath - P + 1, URLComp.dwUrlPathLength);
{$ELSE}
IndyHTTP := TIDHttp.Create(Nil);
try
URI := Value;
ParseURI(URI, Protocol, Host, Path, Document, Port, Bookmark);
if Port <> '' then
FURLPort := StrToInt(Port)
else
FURLPort := IndyHTTP.Port;
if Host <> '' then
FURLHost := Host
else
FURLHost := Copy(Value, Length(http)+1,
Pos(':' + IntToStr(FURLPort), Value) - (Length(http)+1));
finally
IndyHTTP.Free;
end;
{$ENDIF}
end else
begin
FURLPort := 0;
FURLHost := '';
FURLSite := '';
FURLScheme := 0;
end;
FURL := Value;
end;
procedure THTTPReqResp.SetMimeBoundary(Value: string);
begin
FMimeBoundary := Value;
end;
function THTTPReqResp.GetMimeBoundary: string;
begin
Result := FMimeBoundary;
end;
procedure THTTPReqResp.SetUsername(const NameValue: string);
begin
FUserName := NameValue;
if Assigned(WSDLView) then
WSDLView.UserName := NameValue;
end;
procedure THTTPReqResp.SetPassword(const PasswordValue: string);
begin
FPassword := PasswordValue;
if Assigned(WSDLView) then
WSDLView.Password := PasswordValue;
end;
procedure THTTPReqResp.SetProxy(const ProxyValue: string);
begin
FProxy := ProxyValue;
if Assigned(WSDLView) then
WSDLView.Proxy := ProxyValue;
end;
const
MaxStatusTest = 4096;
MaxContentType= 256;
function THTTPReqResp.GetSOAPActionHeader: string;
begin
if (SoapAction = '') then
Result := SHTTPSoapAction + ':'
else if (SoapAction = '""') then
Result := SHTTPSoapAction + ': ""'
else
Result := SHTTPSoapAction + ': ' + '"' + SoapAction + '"';
end;
{$IFNDEF USE_INDY}
procedure THTTPReqResp.Connect(Value: Boolean);
var
AccessType: Integer;
begin
if Value then
begin
{ Yes, but what if we're connected to a different Host/Port?? }
{ So take advantage of a cached handle, we'll assume that
Connect(False) will be called explicitly when we're switching
Host. To that end, SetURL always disconnects }
if (FConnected) then
Exit;
{ Proxy?? }
if Length(FProxy) > 0 then
AccessType := INTERNET_OPEN_TYPE_PROXY
else
AccessType := INTERNET_OPEN_TYPE_PRECONFIG;
{ Also, could switch to new API introduced in IE4/Preview2}
if InternetAttemptConnect(0) <> ERROR_SUCCESS then
SysUtils.Abort;
FInetRoot := InternetOpen(PChar(FAgent), AccessType, PChar(FProxy), PChar(FProxyByPass), 0);
Check(not Assigned(FInetRoot));
try
FInetConnect := InternetConnect(FInetRoot, PChar(FURLHost), FURLPort, PChar(FUserName),
PChar(FPassword), INTERNET_SERVICE_HTTP, 0, Cardinal(Self));
Check(not Assigned(FInetConnect));
FConnected := True;
except
InternetCloseHandle(FInetRoot);
FInetRoot := nil;
raise;
end;
end
else
begin
if Assigned(FInetConnect) then
InternetCloseHandle(FInetConnect);
FInetConnect := nil;
if Assigned(FInetRoot) then
InternetCloseHandle(FInetRoot);
FInetRoot := nil;
FConnected := False;
end;
end;
procedure THTTPReqResp.Receive(Context: Integer; Resp: TStream; IsGet: Boolean);
var
Size, Downloaded, Status, Len, Index: DWord;
S: string;
begin
Len := SizeOf(Status);
Index := 0;
{ Handle error }
if HttpQueryInfo(Pointer(Context), HTTP_QUERY_STATUS_CODE or HTTP_QUERY_FLAG_NUMBER,
@Status, Len, Index) and (Status >= 300) and (Status <> 500) then
begin
Index := 0;
Size := MaxStatusTest;
SetLength(S, Size);
if HttpQueryInfo(Pointer(Context), HTTP_QUERY_STATUS_TEXT, @S[1], Size, Index) then
begin
SetLength(S, Size);
raise ESOAPHTTPException.CreateFmt('%s (%d) - ''%s''', [S, Status, FURL], Status);
end;
end;
{ Ask for Content-Type }
Size := MaxContentType;
SetLength(FContentType, MaxContentType);
HttpQueryInfo(Pointer(Context), HTTP_QUERY_CONTENT_TYPE, @FContentType[1], Size, Index);
SetLength(FContentType, Size);
{ Extract Mime-Boundary }
FMimeBoundary := GetMimeBoundaryFromType(FContentType);
{ Read data }
Len := 0;
repeat
Check(not InternetQueryDataAvailable(Pointer(Context), Size, 0, 0));
if Size > 0 then
begin
SetLength(S, Size);
Check(not InternetReadFile(Pointer(Context), @S[1], Size, Downloaded));
Resp.Write(S[1], Size);
{ Receiving Data event }
if Assigned(FOnReceivingData) then
FOnReceivingData(Size, Downloaded)
end;
until Size = 0;
{ Check that we have a valid content type}
{ Ideally, we would always check but there are several WebServers out there
that send files with .wsdl extension with the content type 'text/plain' or
'text/html' ?? }
if not IsGet then
CheckContentType;
end;
function HandleWinInetError(LastError: DWord; Request: HINTERNET): DWord;
var
Flags, FlagsLen: DWord;
P: Pointer;
begin
Result := ERROR_INTERNET_FORCE_RETRY;
{ Handle INVALID_CA discreetly }
if (LastError = ERROR_INTERNET_INVALID_CA) then
begin
FlagsLen := SizeOf(Flags);
InternetQueryOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(@Flags), FlagsLen);
Flags := Flags or SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(@Flags), FlagsLen);
end
{$IFDEF PICK_FIRST_CERTIFICATE}
{ Handle request for a Client Certificate }
else if (LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) then
begin
{ This will pick the first client cerficated registered with WinInet}
FlagsLen := SizeOf(Flags);
InternetSetOption(Request, INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT,
Pointer(@Flags), FlagsLen);
end
{$ENDIF}
else
begin
Result := InternetErrorDlg(GetDesktopWindow(), Request, LastError,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS or
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS or
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, P);
end;
end;
function THTTPReqResp.Send(const ASrc: TStream): Integer;
var
Request: HINTERNET;
RetVal, Flags: DWord;
P: Pointer;
ActionHeader: string;
ContentHeader: string;
BuffSize, Len: Integer;
INBuffer: INTERNET_BUFFERS;
Buffer: TMemoryStream;
StrStr: TStringStream;
begin
{ Connect }
Connect(True);
Flags := INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_NO_CACHE_WRITE;
if FURLScheme = INTERNET_SCHEME_HTTPS then
begin
Flags := Flags or INTERNET_FLAG_SECURE;
if (soIgnoreInvalidCerts in InvokeOptions) then
Flags := Flags or (INTERNET_FLAG_IGNORE_CERT_CN_INVALID or
INTERNET_FLAG_IGNORE_CERT_DATE_INVALID or
SECURITY_FLAG_IGNORE_UNKNOWN_CA);
end;
Request := nil;
try
Request := HttpOpenRequest(FInetConnect, 'POST', PChar(FURLSite), nil,
nil, nil, Flags, 0{Integer(Self)});
Check(not Assigned(Request));
{ Timeouts }
if FConnectTimeout > 0 then
Check(not InternetSetOption({Request}nil, INTERNET_OPTION_CONNECT_TIMEOUT, Pointer(@FConnectTimeout), SizeOf(FConnectTimeout)));
if FSendTimeout > 0 then
Check(not InternetSetOption({Request}nil, INTERNET_OPTION_SEND_TIMEOUT, Pointer(@FSendTimeout), SizeOf(FSendTimeout)));
if FReceiveTimeout > 0 then
Check(not InternetSetOption({Request}nil, INTERNET_OPTION_RECEIVE_TIMEOUT, Pointer(@FReceiveTimeout), SizeOf(FReceiveTimeout)));
if (soIgnoreInvalidCerts in InvokeOptions) then
InternetSetOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(@Flags), Sizeof(Flags));
{ Setup packet based on Content-Type/Binding }
if FBindingType = btMIME then
begin
ContentHeader := Format(ContentHeaderMIME, [FMimeBoundary]);
ContentHeader := Format(ContentTypeTemplate, [ContentHeader]);
HttpAddRequestHeaders(Request, PChar(MIMEVersion), Length(MIMEVersion), HTTP_ADDREQ_FLAG_ADD);
{ SOAPAction header }
{ NOTE: It's not really clear whether this should be sent in the case
of MIME Binding. Investigate interoperability ?? }
if not (soNoSOAPActionHeader in FInvokeOptions) then
begin
ActionHeader:= GetSOAPActionHeader;
HttpAddRequestHeaders(Request, PChar(ActionHeader), Length(ActionHeader), HTTP_ADDREQ_FLAG_ADD);
end;
end else { Assume btSOAP }
begin
{ SOAPAction header }
if not (soNoSOAPActionHeader in FInvokeOptions) then
begin
ActionHeader:= GetSOAPActionHeader;
HttpAddRequestHeaders(Request, PChar(ActionHeader), Length(ActionHeader), HTTP_ADDREQ_FLAG_ADD);
end;
if UseUTF8InHeader then
ContentHeader := Format(ContentTypeTemplate, [ContentTypeUTF8])
else
ContentHeader := Format(ContentTypeTemplate, [ContentTypeNoUTF8]);
end;
{ Content-Type }
HttpAddRequestHeaders(Request, PChar(ContentHeader), Length(ContentHeader), HTTP_ADDREQ_FLAG_ADD);
{ Before we pump data, see if user wants to handle something - like set Basic-Auth data?? }
if Assigned(FOnBeforePost) then
FOnBeforePost(Self, Request);
ASrc.Position := 0;
BuffSize := ASrc.Size;
if BuffSize > FMaxSinglePostSize then
begin
Buffer := TMemoryStream.Create;
try
Buffer.SetSize(FMaxSinglePostSize);
{ Init Input Buffer }
INBuffer.dwStructSize := SizeOf(INBuffer);
INBuffer.Next := nil;
INBuffer.lpcszHeader := nil;
INBuffer.dwHeadersLength := 0;
INBuffer.dwHeadersTotal := 0;
INBuffer.lpvBuffer := nil;
INBuffer.dwBufferLength := 0;
INBuffer.dwBufferTotal := BuffSize;
INBuffer.dwOffsetLow := 0;
INBuffer.dwOffsetHigh := 0;
{ Start POST }
Check(not HttpSendRequestEx(Request, @INBuffer, nil,
HSR_INITIATE or HSR_SYNC, 0));
try
while True do
begin
{ Calc length of data to send }
Len := BuffSize - ASrc.Position;
if Len > FMaxSinglePostSize then
Len := FMaxSinglePostSize;
{ Bail out if zip.. }
if Len = 0 then
break;
{ Read data in buffer and write out}
Len := ASrc.Read(Buffer.Memory^, Len);
if Len = 0 then
raise ESOAPHTTPException.Create(SInvalidHTTPRequest);
Check(not InternetWriteFile(Request, @Buffer.Memory^, Len, RetVal));
RetVal := InternetErrorDlg(GetDesktopWindow(), Request, GetLastError,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS or FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS or
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, P);
case RetVal of
ERROR_SUCCESS: ;
ERROR_CANCELLED: SysUtils.Abort;
ERROR_INTERNET_FORCE_RETRY: {Retry the operation};
end;
{ Posting Data Event }
if Assigned(FOnPostingData) then
FOnPostingData(ASrc.Position, BuffSize);
end;
finally
Check(not HttpEndRequest(Request, nil, 0, 0));
end;
finally
Buffer.Free;
end;
end else
begin
StrStr := TStringStream.Create('');
try
StrStr.CopyFrom(ASrc, 0);
while True do
begin
Check(not HttpSendRequest(Request, nil, 0, @StrStr.DataString[1], Length(StrStr.DataString)));
RetVal := InternetErrorDlg(GetDesktopWindow(), Request, GetLastError,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS or FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS or
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, P);
case RetVal of
ERROR_SUCCESS: break;
ERROR_CANCELLED: SysUtils.Abort;
ERROR_INTERNET_FORCE_RETRY: {Retry the operation};
end;
end;
finally
StrStr.Free;
end;
end;
except
if (Request <> nil) then
InternetCloseHandle(Request);
Connect(False);
raise;
end;
Result := Integer(Request);
end;
function THTTPReqResp.SendGet: Integer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -