Jump to content

omnibrain

Members
  • Content Count

    100
  • Joined

  • Last visited

Posts posted by omnibrain


  1. In the end each tool has their uses. 2 years ago I had to quickly add a customer portal to our software. A customer of one of our customers wanted to be able to access protocols and reports. Giving them direct access was no option. So I set up a DB server, built a custom periodic data export, and used a no/low code tool named Budibase to build a web frontend. Because I have total control over the data I export I could work around limitations regarding data representation by simply adjusting my export logic.


  2. Interesting, never heard of it before. It looks like it is more in the direction of WEB framework & components for Delphi & Visual Studio Code | TMS Software than FMSoft uniGUI Web Application Framework 

     

    There are of course also Elevate Software, Inc. Quartex Pascal – Research and development for the next generation object pascal (quartexdeveloper.com) and Smart Mobile Studio | About | Smart Mobile StudioAbout - Smart Mobile Studio but they are not 100% Delphi but rather Object Pascal and Delphi inspired.

     

    Perhaps a user of some of them can chime in.


  3. I debugged the issue for a bit:

    In THttpConnection.ProcessPostPutPat Flags gets changed from hg401 to hgAcceptData, so the "case Flags of hg401" never gets triggered.

     

    Perhaps there needs to be a check for the 40x-Flags before the     "if (FRequestMethod = httpMethodPost) then TriggerPostDocument(Flags) ..." block.

     

    Quick and dirty, seems to work, but I don't know if something further down the line breaks:

    {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
    procedure THttpConnection.ProcessPostPutPat;  { V8.08 }
    var
        Flags : THttpGetFlag;
    begin
        { POST and no content-length received, we treat this as "bad request"     }
        { and don't pass it to the component user.                                }
        if (not FRequestHasContentLength) or (FRequestContentLength < 0) then begin
            { HTTP/1.0
              A valid Content-Length is required on all HTTP/1.0 POST requests.
              An HTTP/1.0 server should respond with a 400 (bad request) message
              if it cannot determine the length of the request message's content.
    
              HTTP/1.1
              The presence of a message-body in a request is signaled by the
              inclusion of a Content-Length or Transfer-Encoding header field in
              the request's message-headers.
              For compatibility with HTTP/1.0 applications, HTTP/1.1 requests
              containing a message-body MUST include a valid Content-Length header
              field unless the server is known to be HTTP/1.1 compliant. If a
              request contains a message-body and a Content-Length is not given,
              the server SHOULD respond with 400 (bad request) if it cannot
              determine the length of the message, or with 411 (length required)
              if it wishes to insist on receiving a valid Content-Length.
    
              Currently we act as a HTTP/1.0 server. }
            FKeepAlive := FALSE;
            Answer400;
            { We close the connection non-gracefully otherwise we might receive
              data we cannot handle properly. }
            CloseDelayed;
            Exit;
        end;
    
    {$IFNDEF NO_AUTHENTICATION_SUPPORT}
        if not FAuthenticated then
            Flags := hg401
        else
    {$ENDIF}
        if FOutsideFlag and (not (hoAllowOutsideRoot in FOptions)) then
            Flags := hg403
        else
            Flags := hg404;
    
        case Flags of            // quick and dirty
        hg400:
            begin
                FKeepAlive := FALSE;
                Answer400;
                CloseDelayed;
                exit;
            end;                                                              {/V7.30 }
        hg401:
            begin
                if FKeepAlive = FALSE then {Bjornar}
                    PrepareGraceFullShutDown;
                Answer401;
                exit;
            end;
        hg403:
            begin
                if FKeepAlive = FALSE then {Bjornar}
                    PrepareGraceFullShutDown;
                Answer403;
                exit;
            end;
        hg404:
            begin
                if FKeepAlive = FALSE then {Bjornar}
                    PrepareGraceFullShutDown;
                Answer404;
                exit;
            end;
        end;
    
        FAcceptPostedData := FALSE;
        if (FRequestMethod = httpMethodPost) then
            TriggerPostDocument(Flags)
        else if (FRequestMethod = httpMethodPut) then
            TriggerPutDocument(Flags)
        else if (FRequestMethod = httpMethodPatch) then
            TriggerPatchDocument(Flags);
    
        if (not FAcceptPostedData) and (FRequestContentLength > 0) then begin { V7.30 }
        { The component user doesn't handle posted data.               }
        { Turn LineMode off if RequestContentLength > 0, we'll turn it }
        { back on again in our overridden method Receive.              }
            LineMode     := FALSE;
            FPostCounter := FRequestContentLength;
        end
        else
            FPostCounter := 0;
    
        case Flags of
        hg400:
            begin
                FKeepAlive := FALSE;
                Answer400;
                CloseDelayed;
            end;                                                              {/V7.30 }
        hg401:
            begin
                if FKeepAlive = FALSE then {Bjornar}
                    PrepareGraceFullShutDown;
                Answer401;
            end;
        hg403:
            begin
                if FKeepAlive = FALSE then {Bjornar}
                    PrepareGraceFullShutDown;
                Answer403;
            end;
        hg404:
            begin
                if FKeepAlive = FALSE then {Bjornar}
                    PrepareGraceFullShutDown;
                Answer404;
            end;
        hgAcceptData:
            FAcceptPostedData := TRUE;
        else
            if FKeepAlive = FALSE then {Bjornar}
                CloseDelayed;
        end;
    end;

     


  4. I got a (somewhat working example with minimal changes to the demo.

     

    I used the postinfo-Demo, because I think you added that specifically to test POST.

    \demos-data\WebAppServerData\Templates\postinfo.htm is missing, but that doesn't matter for the test.

     

    My one change:

    procedure TWeblServerForm.SslHttpAppSrv1AuthGetType(Sender, Client: TObject);
    var
        ClientCnx  : TMyHttpConnection;
    begin
        //{ It's easyer to do the cast one time. Could use with clause... }
        ClientCnx := TMyHttpConnection(Client);
        if CompareText(ClientCnx.Path, '/DemoBasicAuth.html') = 0 then begin
            ClientCnx.AuthTypes  := [atBasic];
            ClientCnx.AuthRealm := 'DemoBasicAuth';
        end
        else if CompareText(ClientCnx.Path, '/postinfo.html') = 0 then begin // Added for Debugging Basic Auth
            ClientCnx.AuthTypes  := [atBasic];
            ClientCnx.AuthRealm := 'DemoBasicAuth';
        end
    1. GET with no credentials
      Request requires authentication "/postinfo.html" AuthType is "atBasic"
      192.168.178.105 - WEB-APP /postinfo.htm

    2. Answer Log - 2024-03-27 23:35:45 WEB-APP SYCORAX 0.0.0.0 GET /postinfo.html - 86 - 192.168.178.105 HTTP/1.1 PostmanRuntime/7.37.0  192.168.247.109:86 401 337 218 0
    3. GET with wrong credentials
      Request requires authentication "/postinfo.html" AuthType is "atBasic"
      AuthGetPassword for "/postinfo.html" AuthType is "atBasic"
      [23:37:08 192.168.178.105] authentication result failed with type Basic for /postinfo.html
      192.168.178.105 - WEB-APP /postinfo.html
      Answer Log - 2024-03-27 23:37:08 WEB-APP SYCORAX 0.0.0.0 GET /postinfo.html - 86 test1 192.168.178.105 HTTP/1.1 PostmanRuntime/7.37.0  192.168.247.109:86 401 337 257 0
    4. GET with correct credentials

      Request requires authentication "/postinfo.html" AuthType is "atBasic"
      AuthGetPassword for "/postinfo.html" AuthType is "atBasic"
      [23:38:01 192.168.178.105] authentication result OK with type Basic for /postinfo.html
      192.168.178.105 - WEB-APP /postinfo.html
      POST/PUT Content Size 0
      Request Content Type

      Answer Log - 2024-03-27 23:38:01 WEB-APP SYCORAX 0.0.0.0 GET /postinfo.html - 86 test 192.168.178.105 HTTP/1.1 PostmanRuntime/7.37.0  192.168.247.109:86 200 563 261 0

    5. POST with no credentials

      Request requires authentication "/postinfo.html" AuthType is "atBasic"
      POST/PUT Content Size 8
      Request Content Type: text/plain
      Raw Params:
      Testdata


      Raw Params:


      Testdata=

      Post URL: http://192.168.247.109:86/postinfo.html
      From IP Address: 192.168.178.105
      Answer Log - 2024-03-27 23:39:25 WEB-APP SYCORAX 0.0.0.0 POST /postinfo.html - 86 - 192.168.178.105 HTTP/1.1 PostmanRuntime/7.37.0  192.168.247.109:86 200 563 272 0

    6. POST with wrong credentials

      Request requires authentication "/postinfo.html" AuthType is "atBasic"
      AuthGetPassword for "/postinfo.html" AuthType is "atBasic"
      [23:40:33 192.168.178.105] authentication result failed with type Basic for /postinfo.html
      POST/PUT Content Size 8
      Request Content Type: text/plain
      Raw Params:
      Testdata


      Raw Params:


      Testdata=

      Post URL: http://192.168.247.109:86/postinfo.html
      From IP Address: 192.168.178.105
      Answer Log - 2024-03-27 23:40:33 WEB-APP SYCORAX 0.0.0.0 POST /postinfo.html - 86 test1 192.168.178.105 HTTP/1.1 PostmanRuntime/7.37.0  192.168.247.109:86 200 563 311 0

    7. POST with correct credentials

      Request requires authentication "/postinfo.html" AuthType is "atBasic"
      AuthGetPassword for "/postinfo.html" AuthType is "atBasic"
      [23:41:23 192.168.178.105] authentication result OK with type Basic for /postinfo.html
      [23:41:23 192.168.178.105] 1: HTTP/1.1 POST /postinfo.html
      POST/PUT Content Size 8
      Request Content Type: text/plain
      Raw Params:
      Testdata


      Raw Params:


      Testdata=

      Post URL: http://192.168.247.109:86/postinfo.html
      From IP Address: 192.168.178.105
      Answer Log - 2024-03-27 23:41:23 WEB-APP SYCORAX 0.0.0.0 POST /postinfo.html - 86 test 192.168.178.105 HTTP/1.1 PostmanRuntime/7.37.0  192.168.247.109:86 200 563 315 0

    As you can see, with GET only with correct credentials .execute gets called. With POST .execute always gets called.


  5. I don't think this works properly in 9.1.

     

    On GET with failed Authentication I get a 401 from ICS with the following document (btw, where can I edit/override this?): 

    <HTML><HEAD><TITLE>401 Access Denied</TITLE></HEAD><BODY><H1>401 Access Denied</H1>The requested URL /ping requires authorization.<P></BODY></HTML>

    On POST I still land in my .Execute-Function. But Client.AuthUserName doesn't get cleared.

    I would expect, that like with GET I don"t even come into the .Execute-Function.

     

    The second best solution would be, if the FAuthenticated was available at the Client. So I could check this.

     

     

    (It took me two years to get back to this, because I was building other endpoints where I do custom jwt processing and had no need for basic auth, in case you wonder)


  6. 21 hours ago, Angus Robertson said:

    Thanks, if you retain your old Defs file,

    I never changed anything in there so I had no problem "overwriting" it. I prefer to understand the settings, and change them if needed, so this was alright to me.

    Starting with 9.0 I started using ICS "directly" instead of via GetIt and I also decided to vendor the used release into my git repo, so I can easily track the changes between the releases, or if I have to patch something.


  7. I downloaded and installed the latest daily snapshot from https://wiki.overbyte.eu/arch/icsv9w.zip but still can't get PUT to work. I still run into the "Flags"-check from my original post. Am I missing something else?

     

    The Flags in question contains hg404. The path I call the PUT with Postman is http://192.168.247.109:16008/v2/object/1004/person

    My other GET and POST Handlers work like they used to.

     

    Edit: If I comment out the Flags-Check like I did in my original post it now works. So your fix handling the uploads worked.

     


  8. When further testing I discovered an additional problem:
    My PUT obviously happens with data. But in my dispatched handler no data arrives. When debugging I noticed, that the handler get's dispatched before the data is received. An additional ConnectionDataAvailable where FState is hcPostedData happens after the dispatch.

    I meant to test it properly all earlier, after you implemented it for me, but other projects happened and my workaround with POST worked.


  9. I added a PUT handler to my API (so far I worked with POST, for my new API iteration I'm finally getting to implementing PUT), but it does not get dispatched.

    HttpAppSrv1.AddPutHandler('/'+porticoversion+'/object/*',Tlisaapiportico);    // Person anlegen PUT                                     /object/{oid}/person

    Tlisaapiportico is implementing TUrlHandler.

     

    I debugged, and it looks like the handler get's correctly added to the FPutHandler, but PutDispatchVirtualDocument gets never reached.

    Further debugging (and comparison with POST) lead me to TriggerPutDocument. When I comment out the "Flags-Check" it works.
     

    procedure THttpAppSrv.TriggerPutDocument(           { V8.67 }
         Sender     : TObject;
         var Flags  : THttpGetFlag);
    begin
    //OutputDebugString(PChar('HTTP_PUT  ' + (Sender as THttpAppSrvConnection).Path));
        inherited TriggerPutDocument(Sender, Flags);
     {   if Flags in [hgWillSendMySelf, hg404, hg403, hg401] then
            Exit ;   }
    
        // Handle all virtual documents. Returns TRUE if document handled.
        if PutDispatchVirtualDocument(Sender as THttpAppSrvConnection, Flags) then
            Exit;
    
        // Reject anything else
        Flags := hg404;
    end;

    In TriggerDeleteDocument is a similar check. I did not test it yet, but I imagine I'm going to run into the same problem.

    Of course I don't know if the real problem is, that the flag get's set wrong somewhere higher in the call stack, or if the inherited call should do something instead.


  10. I'm currently testing IcsTimeClient but I'm running into inexplicable timeouts when trying to get the time of ptbtime1.ptb.de. It looks like it's resolving the IP correctly (192.53.103.108) and when I try to get the time from the same server via the Indy-Component it works.

    Other servers, like the NIST-servers NIST Internet Time Service work with IcsTimeClient too.

     

    I tried both, with the OverbyteIcsTimeTst program and my own, reduced to the basics, one.


  11. 9 minutes ago, Fr0sT.Brutal said:

    SNTP just receives UTC time. Conversion to local time must be done with system functions using system's database of daylight zones. Probably you have obsolete DB

    Of course, but in the code of the component there is "NTPToDateTime" and in there "UTCTimeToLocalTime".
    And like I said. Last week it worked. I would have expected an error of 2 hours last week, if this was the case.


  12. I am using Delphi 11.2 (Patch 1) on Windows 11 (22H2):

    A few weeks ago, I added a check to our software to be able to verify against a time server independently of the rest of the system, as our customers had issues with internal network time synchronization in the past. Since Sunday, we "suddenly" have a one-hour deviation. Last weekend we went back from UTC+2 to UTC+1.

     

    I have simplified it to the most basic test possible, just a form with a TIdSNTP component and an edit box to enter the server. And even then, I still get a time that is exactly one hour in the future. Have I overlooked something? Since we are now on "standard time," I would have expected there to have been problems during development and testing in the past weeks.

      IdSNTP1.Host:=LabeledEdit1.Text;
      memo1.Lines.Add('Server: '+LabeledEdit1.Text+' Internet time: '+DateTimeToStr(IdSNTP1.DateTime)+' Local time: '+datetimetostr(now));

    The result is:

    Quote

    Server: ptbtime1.ptb.de Internet time: 30.10.2023 11:54:00 Local time: 30.10.2023 10:54:00
    Server: time.nist.gov Internet time: 30.10.2023 11:54:08 Local time: 30.10.2023 10:54:20

     


  13. This looks really great.
    But for some demos I still get the following error, I think the uecNativeMeasureMap dcu is outdated: 
    [dcc32 Fataler Fehler] UMainNativeLinesPolygones.pas(8): F2051 Unit uecNativeMeasureMap wurde mit einer unterschiedlichen Version von UECGraphics.TECCanvas compiliert


  14. Can you please provide me with a trial (your website says to ask for a trial)? I want to give it a spin, before I license it for me and my 3 other developers.

     

    Native Support for WFS and WMS layers so they can be used like in leaflet without having to build the URL by hand would be great. A time dimension function for WMS, like Leaflet.TimeDimension AddOn would be the cherry on the cake.

     

    Regarding the legends, you are correct, no special function is needed, they are just static images.


  15. "Manually" building URLs for WFS is easy, because it's more or less a "static" geojson endpoint.

    For WMS it is not really an option for me, because WMS (especially combined with a GeoServer) is a somewhat complex standard with spatial and temporal dimensions and way easier to use with ready made libraries.

×