123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- {
- This file is part of the Pas2JS run time library.
-
- Provides a Webassembly module with HTTP protocol capabilities
- Copyright (c) 2024 by Michael Van Canneyt
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit wasm.pas2js.httpapi;
- {$mode ObjFPC}
- {$modeswitch externalclass}
- { $DEFINE NOLOGAPICALLS}
- interface
- uses
- {$IFDEF FPC_DOTTEDUNITS}
- System.SysUtils, JSApi.JS, BrowserApi.WebOrWorker, {$IFDEF JOB_WORKER} BrowserApi.WebWorker {$ELSE} BrowserApi.Web {$ENDIF}, Wasi.Env, wasm.http.shared, Rtl.WorkerCommands;
- {$ELSE}
- SysUtils, JS, WebOrWorker, {$IFDEF JOB_WORKER} WebWorker {$ELSE} Web {$ENDIF}, WasiEnv, types, wasm.http.shared, Rtl.WorkerCommands;
- {$ENDIF}
- const
- cmdOpenURL = 'openUrl';
- Type
- TWasmHTTPAPI = Class;
- TWasmHTTPFetch = Class;
- TOpenURLCommand = class external name 'Object' (TCustomWorkerCommand)
- URL : String;
- Flags : Integer;
- end;
- { TOpenURLCommandHelper }
- TOpenURLCommandHelper = class helper (TCustomWorkerCommandHelper) for TOpenURLCommand
- class function CreateURL(aURL : String; aFlags : Integer) : TOpenURLCommand; static;
- end;
- TWasmHTTPRequest = Record
- Url : String;
- Method : String;
- Headers : TStringDynArray;
- BodyIsString : Boolean;
- Body : TJSArrayBuffer;
- BodyAsText : string;
- Integrity : String;
- Redirect: string;
- Cache : String;
- KeepAlive : Boolean;
- Mode : String;
- Priority : String;
- Referrer : String;
- ReferrerPolicy : String;
- AbortSignal : Boolean;
- Credentials: String;
- end;
- PWasmHTTPRequest = TWasmPointer;
- PLongint = TWasmPointer;
- PByte = TWasmPointer;
- { TWasmHTTPFetch }
- TWasmHTTPFetch = Class(TObject)
- Private
- FAPI : TWasmHTTPAPI;
- FID : TWasmHTTPRequestID;
- FUserData : TWasmPointer;
- FRequestData : TWasmHTTPRequest;
- FResponse : TJSResponse;
- FheaderNames : TStringDynArray;
- FAbortController : TJSAbortController;
- FResultBody : TJSArrayBuffer;
- FRequestError : String;
- FInProgress : Boolean;
- function GetHeaderName(aIndex : Longint): String;
- function GetHeaderCount: Integer;
- Public
- Constructor Create(aAPI: TWasmHTTPAPI; aID : TWasmHTTPRequestID; aUserData : TWasmPointer; const aRequestData : TWasmHTTPRequest);
- Procedure Execute; async;
- Property ID : TWasmHTTPRequestID Read FID;
- Property UserData : TWasmPointer Read FUserData;
- Property RequestData : TWasmHTTPRequest Read FRequestData;
- Property Response : TJSResponse Read FResponse;
- Property HeaderNames[aIndex : Longint] : String Read GetHeaderName;
- Property HeaderCount : Integer Read GetHeaderCount;
- Property InProgress : Boolean Read FInProgress;
- Property RequestError : String Read FRequestError;
- end;
- { TWasmHTTPAPI }
- TWasmHTTPAPI = class(TImportExtension)
- private
- FNextRequestID : TWasmHTTPRequestID;
- FRequests : TJSOBject;
- class function ContentTypeIsString(aType: String): boolean;
- function GetLogApiCalls: Boolean;
- procedure HandleOpenURLMessage(aCommand: TOpenURLCommand);
- function ReadRequest(aRequest :PWasmHTTPRequest) : TWasmHTTPRequest;
- function RequestExecute(aRequestID: TWasmHTTPRequestID): TWasmHTTPResult;
- procedure SetLogApiCalls(AValue: Boolean);
- Protected
- Procedure LogCall(const Msg : String);
- Procedure LogCall(Const Fmt : String; const Args : Array of const);
- Procedure DoneRequest(aFetch : TWasmHTTPFetch);
- Function CreateRequestID : TWasmHTTPRequestID;
- Function FetchByID(aID : TWasmHTTPRequestID) : TWasmHTTPFetch;
- procedure DoOpenURL(aURL: String; aFlags: integer);
- function HandleOpenURL(aURL: TWasmPointer; aURLLen: Longint; aFlags: Integer): Integer;
- function RequestAllocate(aRequest : PWasmHTTPRequest; aUserData : TWasmPointer; aRequestID : PWasmHTTPRequestID) : TWasmHTTPResult;
- function RequestDeallocate(aRequestID : TWasmHTTPRequestID) : TWasmHTTPResult;
- function RequestAbort(aRequestID : TWasmHTTPRequestID) : TWasmHTTPResult;
- function ResponseGetStatus(aRequestID : TWasmHTTPRequestID; aStatus : PLongint) : TWasmHTTPResult;
- function ResponseGetStatusText(aRequestID: TWasmHTTPRequestID; aStatusText: PByte; aMaxTextLen: PLongint): TWasmHTTPResult;
- function ResponseGetHeaderCount(aRequestID : TWasmHTTPRequestID; aHeaderCount : PLongint) : TWasmHTTPResult;
- function ResponseGetHeaderName(aRequestID : TWasmHTTPRequestID; aHeaderIdx: Longint; aHeader : PByte; aMaxHeaderLen : PLongint) : TWasmHTTPResult;
- function ResponseGetHeader(aRequestID : TWasmHTTPRequestID; aHeaderName: PByte; aHeaderLen : PLongint; aHeader : PByte; aMaxHeaderLen : Longint) : TWasmHTTPResult;
- function ResponseGetBody(aRequestID : TWasmHTTPRequestID; aBody : PByte; aMaxBodyLen : PLongint) : TWasmHTTPResult;
- Public
- Constructor Create(aEnv: TPas2JSWASIEnvironment); override;
- Procedure FillImportObject(aObject: TJSObject); override;
- Function ImportName : String; override;
- property LogApiCalls : Boolean Read GetLogApiCalls Write SetLogApiCalls;
- end;
- Function CacheToString(aCache : Integer) : String;
- implementation
- uses strutils;
- Const
- CacheNames : Array[0..5] of string = ('default','no-store','reload','no-cache','force-cache','only-if-cached');
- ModeNames : Array[0..4] of string = ('cors','same-origin','no-cors','navigate','websocket');
- PriorityNames : Array[0..2] of string = ('auto','low','high');
- RedirectNames : Array[0..2] of string = ('follow','error','manual');
- CredentialNames : Array[0..2] of string = ('same-origin','omit','include');
- Function CacheToString(aCache : Integer) : String;
- begin
- Result:='';
- if (aCache>=0) and (aCache<=5) then
- Result:=CacheNames[aCache];
- end;
- Function RedirectToString(aRedirect : Integer) : String;
- begin
- Result:='';
- if (aRedirect>=0) and (aRedirect<=2) then
- Result:=RedirectNames[aRedirect];
- end;
- function KeepAliveToBool(const aKeepAlive : Integer) : boolean;
- begin
- Result:=aKeepAlive<>0;
- end;
- function AbortSignalToBool(const aKeepAlive : Integer) : boolean;
- begin
- Result:=aKeepAlive<>0;
- end;
- function ModeToString(const aMode : Integer) : string;
- begin
- Result:='';
- if (aMode>=0) and (aMode<=4) then
- Result:=ModeNames[aMode];
- end;
- function PriorityToString(const aPriority : Integer) : string;
- begin
- Result:='';
- if (aPriority>=0) and (aPriority<=2) then
- Result:=PriorityNames[aPriority];
- end;
- function CredentialsToString(const aCredentials : Integer) : string;
- begin
- Result:='';
- if (aCredentials>=0) and (aCredentials<=2) then
- Result:=CredentialNames[aCredentials];
- end;
- { TWasmHTTPFetch }
- function TWasmHTTPFetch.GetHeaderCount: Integer;
- var
- It : TJSIterator;
- Itm : TJSIteratorValue;
- begin
- if (Length(FheaderNames)=0) and Assigned(FResponse) then
- begin
- It:=FResponse.headers.Keys;
- Itm:=It.next;
- While not Itm.done do
- begin
- TJSArray(FheaderNames).Push(Itm.value);
- Itm:=It.Next;
- end;
- end;
- Result:=Length(FHeaderNames);
- end;
- function TWasmHTTPFetch.GetHeaderName(aIndex : Longint): String;
- begin
- if (aIndex>=0) and (aIndex<Length(FHeaderNames)) then
- Result:=FHeaderNames[aIndex]
- else
- Result:='';
- end;
- constructor TWasmHTTPFetch.Create(aAPI: TWasmHTTPAPI; aID: TWasmHTTPRequestID; aUserData: TWasmPointer;
- const aRequestData: TWasmHTTPRequest);
- begin
- FAPI:=aAPI;
- FID:=aID;
- FUserData:=aUserData;
- FRequestData:=aRequestData;
- FheaderNames:=[];
- FInProgress:=True;
- end;
- procedure TWasmHTTPFetch.Execute; async;
- var
- lResponse : TJSResponse;
- lBuf : TJSarrayBuffer;
- lRequest : TJSRequest;
- lHeaders,lRequestInit : TJSObject;
- HNV : TStringDynArray;
- H,N,V : String;
- Procedure MaybeInit(const aName,aValue : String);
- begin
- if aValue<>'' then
- lRequestInit[aName]:=aValue;
- end;
- begin
- lRequestInit:=TJSObject.New;
- if Length(FRequestData.Headers)>0 then
- begin
- lHeaders:=TJSObject.new;
- lRequestInit['headers']:=lHeaders;
- for H in FRequestData.Headers do
- begin
- HNV:=TJSString(H).split(':');
- V:='';
- N:=Trim(HNV[0]);
- if Length(HNV)>1 then
- V:=Trim(HNV[1]);
- lHeaders[N]:=V;
- end;
- end;
- With FRequestData do
- begin
- MaybeInit('mode',Mode);
- MaybeInit('method',Method);
- MaybeInit('cache',Cache);
- MaybeInit('integrity',Integrity);
- if Assigned(Body) then
- lRequestInit['body']:=Body
- else if BodyIsString and (BodyAsText<>'') then
- lRequestInit['body']:=BodyAsText;
- if KeepAlive then
- lRequestInit['keepalive']:=KeepAlive;
- MaybeInit('redirect',Redirect);
- MaybeInit('priority',Priority);
- MaybeInit('referrer',Referrer);
- MaybeInit('referrerPolicy',ReferrerPolicy);
- if AbortSignal then
- begin
- FAbortController:=TJSAbortController.New;
- lRequestInit['signal']:=FAbortController.Signal;
- end;
- end;
- lRequest:=TJSRequest.New(FRequestData.Url,lRequestInit);
- lBuf:=Nil;
- try
- {$IFDEF JOB_WORKER}
- lResponse:=aWait(TJSResponse,webworker.fetch(lRequest));
- {$ELSE}
- lResponse:=aWait(Window.Asyncfetch(lRequest));
- {$ENDIF}
- lBuf:=aWait(TJSArrayBuffer,lResponse.arrayBuffer);
- fResultBody:=lBuf;
- FResponse:=lResponse;
- except
- on E : TJSError do
- FRequestError:=e.Message;
- on O : TJSObject do
- if O.hasOwnProperty('message') and IsString(O.Properties['message']) then
- FRequestError:=String(O.Properties['message']);
- end;
- FInProgress:=False;
- // Notify the API
- if assigned(FAPI) then
- FAPI.DoneRequest(Self);
- end;
- { TOpenURLCommandHelper }
- class function TOpenURLCommandHelper.CreateURL(aURL: String; aFlags: Integer): TOpenURLCommand;
- begin
- Result:=TOpenURLCommand(CreateCommand(cmdOpenURL));
- TOpenURLCommand(Result).URL:=aURL;
- TOpenURLCommand(Result).Flags:=aFlags;
- end;
- { TWasmHTTPAPI }
- class function TWasmHTTPAPI.ContentTypeIsString(aType : String) : boolean;
- begin
- Result:=False;
- aType:=LowerCase(ExtractWord(1,aType,';'));
- case LowerCase(aType) of
- 'application/json',
- 'text/text',
- 'text/html' : Result:=True;
- end;
- end;
- function TWasmHTTPAPI.GetLogApiCalls: Boolean;
- begin
- Result:=LogAPI;
- end;
- function TWasmHTTPAPI.ReadRequest(aRequest: PWasmHTTPRequest): TWasmHTTPRequest;
- Var
- P : TWasmPointer;
- V : TJSDataView;
- HeaderCount : Integer;
- Function GetInt32 : longint;
- begin
- Result:=v.getInt32(P,Env.IsLittleEndian);
- Inc(P,SizeInt32);
- end;
- Function GetString : string;
- var
- Ptr,Len : Longint;
- begin
- Ptr:=v.getInt32(P,Env.IsLittleEndian);
- Inc(P,SizeInt32);
- Len:=v.getInt32(P,Env.IsLittleEndian);
- Inc(P,SizeInt32);
- Result:=Env.GetUTF8StringFromMem(Ptr,Len);
- end;
- Function GetStringFromAddr(Ptr : Longint) : string;
- var
- SPtr,Len : Longint;
- begin
- SPtr:=v.getInt32(Ptr,Env.IsLittleEndian);
- Inc(Ptr,SizeInt32);
- Len:=v.getInt32(Ptr,Env.IsLittleEndian);
- Result:=Env.GetUTF8StringFromMem(SPtr,Len);
- end;
- Function GetBuffer : TJSArrayBuffer;
- var
- Ptr,Len : Longint;
- begin
- Result:=Nil;
- Ptr:=v.getInt32(P,Env.IsLittleEndian);
- Inc(P,SizeInt32);
- Len:=v.getInt32(P,Env.IsLittleEndian);
- Inc(P,SizeInt32);
- if Len>0 then
- Result:=Env.Memory.buffer.slice(Ptr,Ptr+Len);
- end;
- var
- i : Integer;
- Hdrs : Longint;
- lHeader,lHeaderName,lHeaderValue : String;
- begin
- v:=getModuleMemoryDataView;
- P:=aRequest;
- // Order is important !
- Result.Url:=GetString;
- Result.Method:=GetString;
- HeaderCount:=v.getInt32(P,Env.IsLittleEndian);
- SetLength(Result.Headers,HeaderCount);
- inc(P,SizeInt32);
- // Pointer to list of strings
- Hdrs:=v.getInt32(P,Env.IsLittleEndian);
- inc(P,SizeInt32);
- for I:=0 to HeaderCount-1 do
- begin
- lHeader:=GetStringFromAddr(Hdrs);
- Result.Headers[i]:=lHeader;
- lHeaderName:=Trim(ExtractWord(1,lHeader,':'));
- lHeaderValue:=Trim(ExtractWord(2,lHeader,':'));
- if SameText(lheaderName,'Content-Type') then
- Result.BodyIsString:=ContentTypeIsString(lHeaderValue);
- inc(Hdrs,SizeInt32*2);
- end;
- if Result.BodyIsString then
- Result.BodyAsText:=GetString
- else
- Result.Body:=GetBuffer;
- Result.Integrity:=GetString;
- Result.Redirect:=RedirectToString(GetInt32);
- Result.Cache:=CacheToString(GetInt32);
- Result.KeepAlive:=KeepAliveToBool(GetInt32);
- Result.Mode:=ModeToString(GetInt32);
- Result.Priority:=PriorityToString(GetInt32);
- Result.Referrer:=GetString;
- Result.ReferrerPolicy:=GetString;
- Result.AbortSignal:=AbortSignalToBool(GetInt32);
- Result.Credentials:=CredentialsToString(GetInt32);
- end;
- procedure TWasmHTTPAPI.LogCall(const Msg: String);
- begin
- {$IFNDEF NOLOGAPICALLS}
- if LogAPI then
- DoLog(Msg);
- {$ENDIF}
- end;
- procedure TWasmHTTPAPI.LogCall(const Fmt: String; const Args: array of const);
- begin
- {$IFNDEF NOLOGAPICALLS}
- if LogAPI then
- DoLog(Fmt,Args);
- {$ENDIF}
- end;
- type
- TDoneCallback = Function(aRequestID : TWasmHTTPRequestID; aUserData : TWasmPointer; aStatus : TWasmHTTPResponseStatus) : TWasmHTTPResponseResult;
- procedure TWasmHTTPAPI.DoneRequest(aFetch: TWasmHTTPFetch);
- var
- Exp : JSValue;
- Callback : TDoneCallback absolute exp;
- Res,Stat : Longint;
- doDispose : Boolean;
- begin
- doDispose:=True;
- Exp:=InstanceExports[httpFN_ResponseCallback];
- if aFetch.FRequestError<>'' then
- Stat:=-1
- else
- Stat:=aFetch.Response.status;
- if isFunction(Exp) then
- begin
- Res:=Callback(aFetch.ID,aFetch.UserData,Stat);
- DoDispose:=(Res=WASMHTTP_RESPONSE_DEALLOCATE);
- end
- else
- console.error('No request callback available!');
- if DoDispose then
- begin
- FRequests[IntToStr(aFetch.ID)]:=undefined;
- FreeAndNil(aFetch);
- end;
- end;
- function TWasmHTTPAPI.CreateRequestID: TWasmHTTPRequestID;
- begin
- Inc(FNextRequestID);
- Result:=FNextRequestID;
- end;
- function TWasmHTTPAPI.FetchByID(aID: TWasmHTTPRequestID): TWasmHTTPFetch;
- var
- Value : JSValue;
- begin
- Value:=FRequests[IntToStr(aID)];
- if isObject(Value) then
- Result:=TWasmHTTPFetch(Value)
- else
- Result:=Nil;
- end;
- function TWasmHTTPAPI.RequestAllocate(aRequest: PWasmHTTPRequest; aUserData: TWasmPointer; aRequestID: PWasmHTTPRequestID
- ): TWasmHTTPResult;
- var
- lReq : TWasmHTTPRequest;
- lID : TWasmHTTPRequestID;
- lfetch : TWasmHTTPFetch;
- begin
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.RequestAllocate([%x],[%x],[%x])',[aRequest,aUserData,aRequestID]);
- {$ENDIF}
- lReq:=ReadRequest(aRequest);
- if (lReq.Url='') then
- Exit(WASMHTTP_RESULT_NO_URL);
- lID:=CreateRequestID;
- lFetch:=TWasmHTTPFetch.Create(Self,lID,aUserData,lReq);
- FRequests[IntToStr(lID)]:=lFetch;
- env.SetMemInfoInt32(aRequestID,lID);
- Result:=WASMHTTP_RESULT_SUCCESS;
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.RequestAllocate([%x],[%x]) => %d',[aRequest,aUserData,lID]);
- {$ENDIF}
- end;
- function TWasmHTTPAPI.RequestExecute(aRequestID: TWasmHTTPRequestID): TWasmHTTPResult;
- var
- lfetch : TWasmHTTPFetch;
- begin
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.RequestExecute(%d)',[aRequestID]);
- {$ENDIF}
- lfetch:=FetchByID(aRequestID);
- if not Assigned(lFetch) then
- Exit(WASMHTTP_RESULT_INVALIDID);
- lFetch.Execute;
- Result:=WASMHTTP_RESULT_SUCCESS;
- end;
- procedure TWasmHTTPAPI.SetLogApiCalls(AValue: Boolean);
- begin
- LogAPI:=aValue;
- end;
- function TWasmHTTPAPI.RequestDeallocate(aRequestID: TWasmHTTPRequestID): TWasmHTTPResult;
- var
- lFetch : TWasmHTTPFetch;
- begin
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.RequestDeAllocate(%d)',[aRequestID]);
- {$ENDIF}
- lfetch:=FetchByID(aRequestID);
- if not Assigned(lFetch) then
- Exit(WASMHTTP_RESULT_INVALIDID);
- end;
- function TWasmHTTPAPI.RequestAbort(aRequestID: TWasmHTTPRequestID): TWasmHTTPResult;
- var
- lFetch : TWasmHTTPFetch;
- begin
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.RequestAbort(%d)',[aRequestID]);
- {$ENDIF}
- lfetch:=FetchByID(aRequestID);
- if not Assigned(lFetch) then
- Exit(WASMHTTP_RESULT_INVALIDID);
- end;
- function TWasmHTTPAPI.ResponseGetStatus(aRequestID: TWasmHTTPRequestID; aStatus: PLongint): TWasmHTTPResult;
- var
- lFetch : TWasmHTTPFetch;
- begin
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.ResponseGetStatus(%d,[%x])',[aRequestID,aStatus]);
- {$ENDIF}
- lfetch:=FetchByID(aRequestID);
- if not Assigned(lFetch) then
- Exit(WASMHTTP_RESULT_INVALIDID);
- if lFetch.InProgress then
- Exit(WASMHTTP_RESULT_INPROGRESS);
- Env.SetMemInfoInt32(aStatus,lFetch.Response.status);
- Result:=WASMHTTP_RESULT_SUCCESS;
- end;
- function TWasmHTTPAPI.ResponseGetStatusText(aRequestID: TWasmHTTPRequestID; aStatusText: PByte; aMaxTextLen: PLongint
- ): TWasmHTTPResult;
- var
- lFetch : TWasmHTTPFetch;
- v : TJSDataView;
- Written,MaxLen : Longint;
- S : String;
- begin
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.ResponseGetStatusText(%d,[%x],[%x])',[aRequestID,aStatusText,aMaxTextlen]);
- {$ENDIF}
- lfetch:=FetchByID(aRequestID);
- if not Assigned(lFetch) then
- Exit(WASMHTTP_RESULT_INVALIDID);
- if lFetch.InProgress then
- Exit(WASMHTTP_RESULT_INPROGRESS);
- v:=getModuleMemoryDataView;
- MaxLen:=v.getInt32(aMaxTextLen,Env.IsLittleEndian);
- S:=lFetch.Response.statusText;
- Written:=Env.SetUTF8StringInMem(aStatusText,MaxLen,S);
- Env.SetMemInfoInt32(aMaxTextLen,Abs(Written));
- if Written<0 then
- Result:=WASMHTTP_RESULT_INSUFFICIENTMEM
- else
- Result:=WASMHTTP_RESULT_SUCCESS;
- end;
- function TWasmHTTPAPI.ResponseGetHeaderCount(aRequestID: TWasmHTTPRequestID; aHeaderCount: PLongint): TWasmHTTPResult;
- var
- lFetch : TWasmHTTPFetch;
- lCount : Longint;
- begin
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.ResponseGetHeaderCount(%d,[%x])',[aRequestID,aHeaderCount]);
- {$ENDIF}
- lfetch:=FetchByID(aRequestID);
- if not Assigned(lFetch) then
- Exit(WASMHTTP_RESULT_INVALIDID);
- if lFetch.InProgress then
- Exit(WASMHTTP_RESULT_INPROGRESS);
- lCount:=lFetch.HeaderCount;
- Env.SetMemInfoInt32(aHeaderCount,lCount);
- Result:=WASMHTTP_RESULT_SUCCESS;
- end;
- function TWasmHTTPAPI.ResponseGetHeaderName(aRequestID: TWasmHTTPRequestID; aHeaderIdx: Longint; aHeader: PByte;
- aMaxHeaderLen: PLongint): TWasmHTTPResult;
- var
- lFetch : TWasmHTTPFetch;
- S : String;
- MaxLen,Written : Longint;
- v : TJSDataView;
- begin
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.RequestGetHeaderName(%d,%d,[%x],[%x])',[aRequestID,aHeaderIdx,aHeader,aMaxHeaderLen]);
- {$ENDIF}
- lfetch:=FetchByID(aRequestID);
- if not Assigned(lFetch) then
- Exit(WASMHTTP_RESULT_INVALIDID);
- if lFetch.InProgress then
- Exit(WASMHTTP_RESULT_INPROGRESS);
- V:=getModuleMemoryDataView;
- MaxLen:=v.getInt32(aMaxheaderLen,Env.IsLittleEndian);
- S:=lFetch.HeaderNames[aHeaderIdx];
- Written:=Env.SetUTF8StringInMem(aHeader,MaxLen,S);
- Env.SetMemInfoInt32(aMaxheaderLen,Abs(Written));
- if Written<0 then
- Result:=WASMHTTP_RESULT_INSUFFICIENTMEM
- else
- Result:=WASMHTTP_RESULT_SUCCESS;
- end;
- function TWasmHTTPAPI.ResponseGetHeader(aRequestID: TWasmHTTPRequestID; aHeaderName: PByte; aHeaderLen: PLongint; aHeader: PByte;
- aMaxHeaderLen: Longint): TWasmHTTPResult;
- var
- lFetch : TWasmHTTPFetch;
- lHeader, lName : String;
- Written,Maxlen : Longint;
- v : TJSDataView;
- begin
- v:=getModuleMemoryDataView;
- lName:=Env.GetUTF8StringFromMem(aHeaderName,aHeaderLen);
- MaxLen:=v.getInt32(aMaxHeaderLen,Env.IsLittleEndian);
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.ResponseGetHeader(%d,"%s",[%x])',[aRequestID,lName,aHeader,aMaxHeaderLen]);
- {$ENDIF}
- lfetch:=FetchByID(aRequestID);
- if not Assigned(lFetch) then
- Exit(WASMHTTP_RESULT_INVALIDID);
- if lFetch.InProgress then
- Exit(WASMHTTP_RESULT_INPROGRESS);
- lHeader:=lfetch.Response.headers[lName];
- Written:=Env.SetUTF8StringInMem(aHeader,MaxLen,lheader);
- Env.SetMemInfoInt32(aMaxheaderLen,Abs(Written));
- if Written<0 then
- Result:=WASMHTTP_RESULT_INSUFFICIENTMEM
- else
- Result:=WASMHTTP_RESULT_SUCCESS;
- end;
- function TWasmHTTPAPI.ResponseGetBody(aRequestID: TWasmHTTPRequestID; aBody: PByte; aMaxBodyLen: PLongint): TWasmHTTPResult;
- var
- lFetch : TWasmHTTPFetch;
- lwasmMem,lUint8Array : TJSUint8Array;
- v : TJSDataView;
- bodyLen,maxLen : longint;
- begin
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.ResponseGetBody([%x],[%x],[%x])',[aRequestID,aBody,aMaxBodyLen]);
- {$ENDIF}
- lfetch:=FetchByID(aRequestID);
- if not Assigned(lFetch) then
- Exit(WASMHTTP_RESULT_INVALIDID);
- if lFetch.InProgress then
- Exit(WASMHTTP_RESULT_INPROGRESS);
- if Not Assigned(lFetch.FResultBody) then
- begin
- Env.SetMemInfoInt32(aMaxBodyLen,0);
- exit;
- end;
- v:=getModuleMemoryDataView;
- MaxLen:=v.getInt32(aMaxBodyLen,Env.IsLittleEndian);
- bodyLen:=lFetch.FResultBody.byteLength;
- Env.SetMemInfoInt32(aMaxBodyLen,bodyLen);
- if (MaxLen<bodyLen) then
- Exit(WASMHTTP_RESULT_INSUFFICIENTMEM);
- lUint8Array:=TJSUint8Array.new(lFetch.FResultBody);
- lwasmMem:=TJSUint8Array.New(v.buffer);
- lWasmMem._set(lUint8Array,aBody);
- Exit(WASMHTTP_RESULT_SUCCESS);
- end;
- constructor TWasmHTTPAPI.Create(aEnv: TPas2JSWASIEnvironment);
- begin
- inherited Create(aEnv);
- FRequests:=TJSOBject.new;
- TCommandDispatcher.Instance.specialize AddCommandHandler<TOpenURLCommand>(cmdOpenURL,@HandleOpenURLMessage);
- end;
- procedure TWasmHTTPAPI.DoOpenURL(aURL : String; aFlags : integer);
- {$IFNDEF JOB_WORKER}
- var
- win: TJSWindow;
- {$ENDIF}
- begin
- {$IFNDEF JOB_WORKER}
- win:=Window.open(aURL,'_blank');
- {$ENDIF}
- end;
- procedure TWasmHTTPAPI.HandleOpenURLMessage(aCommand : TOpenURLCommand);
- begin
- {$IFNDEF JOB_WORKER}
- Writeln('Handling open url message');
- DoOpenURL(aCommand.URL,aCommand.Flags);
- {$ELSE}
- Writeln('forwarding open url message');
- aCommand[cFldSender]:=undefined;
- TCommandDispatcher.Instance.SendCommand(aCommand);
- {$ENDIF}
- end;
- function TWasmHTTPAPI.HandleOpenURL(aURL : TWasmPointer; aURLLen : Longint; aFlags : Integer) : Integer;
- var
- lURL : String;
- begin
- Result:=WASMHTTP_RESULT_SUCCESS;
- lURL:=Env.GetUTF8StringFromMem(aURL,aURLLen);
- Writeln('Handling open url call ',aURL);
- {$IFNDEF NOLOGAPICALLS}
- If LogAPICalls then
- LogCall('HTTP.OpenURL(%s,%d)',[lURL,aFlags]);
- {$ENDIF}
- {$IFDEF JOB_WORKER}
- Writeln('sending openurl command');
- TCommandDispatcher.Instance.SendCommand(TOpenURLCommand.CreateURL(lURL,aFlags));
- {$ELSE}
- DoOpenURL(lURL,aFlags);
- {$ENDIF}
- end;
- procedure TWasmHTTPAPI.FillImportObject(aObject: TJSObject);
- begin
- AObject[httpFN_RequestAllocate]:=@RequestAllocate;
- AObject[httpFN_RequestExecute]:=@RequestExecute;
- AObject[httpFN_RequestDeAllocate]:=@RequestDeallocate;
- AObject[httpFN_RequestAbort]:=@RequestAbort;
- AObject[httpFN_ResponseGetStatus]:=@ResponseGetStatus;
- AObject[httpFN_ResponseGetStatusText]:=@ResponseGetStatusText;
- AObject[httpFN_ResponseGetHeaderName]:=@ResponseGetHeaderName;
- AObject[httpFN_ResponseGetHeaderCount]:=@ResponseGetHeaderCount;
- AObject[httpFN_ResponseGetHeader]:=@ResponseGetHeader;
- AObject[httpFN_ResponseGetBody]:=@ResponseGetBody;
- AObject[httpFN_OpenURL]:=@HandleOpenURL;
- end;
- function TWasmHTTPAPI.ImportName: String;
- begin
- Result:=httpExportName
- end;
- end.
|