Daraja HTTP Framework 1.2.9 released

dj

The Daraja HTTP Framework is a free open source library for Object Pascal (Free Pascal 3.0.4, Delphi 2009+), based on the stand-alone HTTP server component in Internet Direct (Indy). The 1.2.9 release contains a new example project and improved example code:

The example projects can be used with Delphi 2009+ and with the Lazarus IDE. For Delphi, the SuperObject library is required. Also, OpenSSL libraries are required for GitHub API access.

More information
– GitHub: https://github.com/michaelJustin/daraja-framework
– API documentation: https://michaeljustin.github.io/daraja-framework/
– Resources: https://www.habarisoft.com/daraja_framework.html
– Wiki: https://github.com/michaelJustin/daraja-framework/wiki

Advertisements

Lazarus Form Parser for GitHub repositories

lfmparser

The Lazarus Form Parser uses the official GitHub REST API to collect all Lazarus form files in a GitHub repository, and then parses the form files to extract data.

User Interface

The web interface allows to enter a GitHub repo name, a page number, and a page size, and then uses these parameters to build an GitHub API request to find lfm files in this repository. The “page” and “page size” parameters limit the result size.

Result table columns:

  • Code contains a hyperlink to the raw lfm file on GitHub
  • LCL contains the version of the Lazarus Component Library which generated the form
  • Form Class is the class name of the form (or frame)
  • Components is the number of components in the form
  • Frames is the number of frames in the form
  • SQL shows the raw content of all SQL.Forms properties in the form
  • Errors is the number of parser errors which occured during parsing of the form

Parser Limitations

The parser is still work in progress. Binary and XML forms will not be supported.  

Benefits

The application provides valuable data without the need to download a complete GitHub repository first. Only Lazarus form files (lfm), which are typically small in size, will be read from the repository. With the parser, custom form data extraction use cases and more services are easy to implement, from string extraction for translation to quality assurance.

Terms of Service

Usage of the Lazarus Form Parser web application is only permitted within the limits of the GitHub Terms of Service and the API Terms.

First Milestone in March

The first milestone of the Lazarus Form Parser web application will be ready for release in a couple of days.

Roadmap and Feedback

There is no roadmap for this project yet. However, feedback and suggestions are very welcome.

GitHub API access with OAuth 2.0 authorization for web applications

The develop branch of the Daraja HTTP Framework contains a new tutorial which contains the full source code for a web server application which implements OAuth 2.0 authorization to access the GitHub REST API. The example calls the user API  to display the user profile in JSON format.

Requirements

OAuth App configuration

You need a OAuth App in the GitHub developer settings screen. If you created it, copy the Client ID and the Client Secret to the source file GitHubHelper.pas.

config

Callback URL

In the GitHub developer settings screen, configure the callback URL http://localhost/oauth2callback. The GitHub authorization flow will send a redirect to this URL.

callback

What it does

  1. the program starts the local web server on localhost
  2. the program launches your web browser and navigates to http://localhost/index.html
  3. the start page redirects to the GitHub server which asks to log in and give permission to access user data
  4. after the user signed in, the code sends a request to the GitHub API and displays the result

Authorization screen

The example program requests read-only access to the user profile by specifying only the scopes read:user and read:email:

  • read:user grants access to read a user’s profile data.
  • user:email grants read access to a user’s email addresses

For more details about scopes, see https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/

With these scopes, the authorization prompt indicates that the app requests read access to your private profile information:

authorize

 

Example Response

{
  "login" : "michaelJustin",
  "id" : ****,
  "node_id" : "****",
  "avatar_url" : "https://avatars0.githubusercontent.com/u/****?v=4",
  "gravatar_id" : "",
  "url" : "https://api.github.com/users/michaelJustin",
  "html_url" : "https://github.com/michaelJustin",
  ...
  }
}

GitHub OAuth 2.0 Apps

Read more about GitHub OAuth apps: https://developer.github.com/apps/about-apps/#about-oauth-apps

Usage as Identity Provider

OAuth2 is a protocol that lets external applications request authorization to private details in a user’s GitHub account without accessing their password.

An OAuth App can be used as an identity provider by enabling a “Login with GitHub” for the authenticated user.

Security note

After testing, you should revoke the user tokens. To do so, go to the OAuth App settings screen and click on “Revoke all user tokens”.

About Daraja HTTP Framework

dj

The Daraja HTTP Framework is a free open source library for Object Pascal (Free Pascal 3.0.4, Delphi 2009+), based on the stand-alone HTTP server component in Internet Direct (Indy).

Project GitHub page:
–  https://github.com/michaelJustin/daraja-framework

Resources

 

Daraja HTTP Framework 1.2.8 released

dj

The Daraja HTTP Framework is a free open source library for Object Pascal (Free Pascal 3.0.4, Delphi 2009+), based on the stand-alone HTTP server component in Internet Direct (Indy).

The 1.2.8 release contains two new example projects:

  • Google API access with OAuth 2.0 authorization – see here for a detailed description
  • Google OpenID Connect for authentication – see here for more information

The example projects can be used with Delphi 2009+ and with the Lazarus IDE. For Delphi, the SuperObject library is required. Also, OpenSSL libraries are required for server-side validation of the client token.

More information
– GitHub: https://github.com/michaelJustin/daraja-framework
– API documentation: https://michaeljustin.github.io/daraja-framework/
– Resources: https://www.habarisoft.com/daraja_framework.html
– Wiki: https://github.com/michaelJustin/daraja-framework/wiki

Google API access with OAuth 2.0 authorization for Daraja HTTP Server Applications (full source code)

The develop branch of the Daraja HTTP Framework contains a new tutorial which contains the full source code for a web server application which implements OAuth 2.0 authorization to access Google APIs. The example calls the Google Drive API to display the result of a ‘files’ request, which contains the files on the My Drive page of the user account in JSON format.

Requirements

  • Google account – with access to the developer console
  • a Google API project with an OAuth 2.0 client ID and the authorised redirect URI http://localhost/oauth2callback
  • the client_secret.json file with the project configuration – this file must be saved in the tutorial8 folder
  • OpenSSL DLLs – 32 or 64 bit depending on your target
  • Lazarus 2.0 or Delphi 2009+ IDE
  • for Delphi, the SuperObject JSON parser library is required

What it does

  1. the program loads the configuration from client_secret.json and starts the local web server on localhost
  2. the program launches your web browser and navigates to the start page http://localhost/
  3. the start page redirects to the Google server and asks to log in and give permission to access the Google Drive API
  4. after the user signed in, the code sends a request to the Google Drive API and displays the result

signintest

drive
Drive API response

The Google Drive API server response is shown below:

{
 "kind": "drive#fileList",
 "etag": "\"nXSjiG018zLTxfo-c5q0BWoTPz8/NS6IZ34tXCSkWGa3gedAvR0dcok\"",
 "selfLink": "https://www.googleapis.com/drive/v2/files",
 "nextPageToken": "~!!~AI9FV7Syo7vCeDrvDNfNUYuVuiX8usRekeUGHhzvyx8Qv3bQAko75vqOY8YcXvs1EW_u_BLtMO-s85rDajdFDKbGMrNJMEjqSPooycUBEECRvcS18istQ6xEHQnQaylfLD-k09uLBLJPtyBpDt3mCwQjzxcDinBWIe39Oy1BXDXpZSUK2ajU2nvETYJWEf1pJyD4qlbDe6r7x7hzEy-RUWD1gbnxS4bWtlelWEU9jcx100ytR1tWa-NHpwPpvASEb5qyscZ3s-xE4-CpNamfN1OAH0stbeUi3J--BfaREKI-ERYvbuyq3Cb3OPyuA_jeRHgTExq2as-GZ3adV1hmed5REWjK6dpeQXXOPFO4vbR8DQnmsszu9R_ZtUgRH2LTWnd7nr6HSXxj",
 "nextLink": "https://www.googleapis.com/drive/v2/files?pageToken=~!!~AI9FV7Syo7vCeDrvDNfNUYuVuiX8usRekeUGHhzvyx8Qv3bQAko75vqOY8YcXvs1EW_u_BLtMO-s85rDajdFDKbGMrNJMEjqSPooycUBEECRvcS18istQ6xEHQnQaylfLD-k09uLBLJPtyBpDt3mCwQjzxcDinBWIe39Oy1BXDXpZSUK2ajU2nvETYJWEf1pJyD4qlbDe6r7x7hzEy-RUWD1gbnxS4bWtlelWEU9jcx100ytR1tWa-NHpwPpvASEb5qyscZ3s-xE4-CpNamfN1OAH0stbeUi3J--BfaREKI-ERYvbuyq3Cb3OPyuA_jeRHgTExq2as-GZ3adV1hmed5REWjK6dpeQXXOPFO4vbR8DQnmsszu9R_ZtUgRH2LTWnd7nr6HSXxj",
 "incompleteSearch": false,
 "items": [
  {
   "kind": "drive#file",
   "id": "17Llqfqu6LTsRg2ZSA6o75IREsrmktJYr",
   "etag": "\"nXSjiG018zLTxfo-c5q0BWoTPz8/MTU1MTQzNDE4ODk4OA\"",
   "selfLink": "https://www.googleapis.com/drive/v2/files/17Llqfqu6LTsRg2ZSA6o75IREsrmktJYr",
   "webContentLink": "https://drive.google.com/uc?id=17Llqfqu6LTsRg2ZSA6o75IREsrmktJYr&export=download",
   "alternateLink": "https://drive.google.com/file/d/17Llqfqu6LTsRg2ZSA6o75IREsrmktJYr/view?usp=drivesdk",
   "embedLink": "https://drive.google.com/file/d/17Llqfqu6LTsRg2ZSA6o75IREsrmktJYr/preview?usp=drivesdk",
   "iconLink": "https://drive-thirdparty.googleusercontent.com/16/type/text/plain",
   "title": "Formes.txt",
   "mimeType": "text/plain",
   "labels": {
    "starred": false,
    "hidden": false,
    "trashed": false,
    "restricted": false,
    "viewed": true
   },

(parsing the JSON response and conversion to HTML is left as an exercise to the reader)

Code of the HTTP GET handler

The handler of main page at http://localhost/ is shown below. In line 17, a TidHTTP instance is created to invoke the Drive API.

procedure TPublicResource.OnGet(Request: TdjRequest; Response: TdjResponse);
var
  Credentials: TCredentials;
  IdHTTP: TIdHTTP;
begin
  if Request.Session.Content.Values['credentials'] = '' then begin
    Response.Redirect(MY_CALLBACK_URL)
  end else begin
    Credentials := ToCredentials(Request.Session.Content.Values['credentials']);
    if Credentials.expires_in <= 0 then begin
      Response.Redirect(MY_CALLBACK_URL)
    end else begin
      IdHTTP := TIdHTTP.Create;
      try
        IdHTTP.Request.CustomHeaders.Values['Authorization'] :=
          'Bearer ' + Credentials.access_token;
        Response.ContentText := IdHTTP.Get('https://www.googleapis.com/drive/v2/files');
        Response.ContentType := 'text/plain';
        Response.CharSet := 'utf-8';
      finally
        IdHTTP.Free;
      end;
    end;
  end;
end;

Security note

After testing, you should revoke the account access of your test application. To do so, visit https://myaccount.google.com/security where all third-party apps with account access are listed.

security

About Daraja HTTP Framework

dj

The Daraja HTTP Framework is a free open source library for Object Pascal (Free Pascal 3.0.4, Delphi 2009+), based on the stand-alone HTTP server component in Internet Direct (Indy).

Project GitHub page:
–  https://github.com/michaelJustin/daraja-framework

 

Resources

Message exchange example for Delphi and WildFly 16 application server

Red Hat yesterday released the WildFly 16 Final Java EE 8 application server. WildFly uses Apache ActiveMQ Artemis as the the default messaging provider. Artemis supports STOMP, which allows to connect from clients written in many programming languages.

If you need to exchange data between Delphi or Free Pascal programs and applications running on WildFly, you can follow these simple configuration steps and run a demonstration of bidirectional message exchange using the Habari Client for Artemis library from Habarisoft.

Read the full article here: https://habarisoft.wordpress.com/2019/02/28/connect-delphi-and-free-pascal-applications-with-wildfly-16/

Daraja HTTP Framework 1.2.7 released

dj

The Daraja HTTP Framework is a free open source library for Object Pascal (Free Pascal 3.0.4, Delphi 2009+), based on the stand-alone HTTP server component in Internet Direct (Indy).

The 1.2.7 release contains a new tutorial which uses Google Sign-In, including server-side validation and retrieval of user data.

The example project can be used with Delphi 2009+ and with the Lazarus IDE. For Delphi, the SuperObject library is required. Also, OpenSSL libraries are required for server-side validation of the client token.

More information
– GitHub: https://github.com/michaelJustin/daraja-framework
– API documentation: https://michaeljustin.github.io/daraja-framework/
– Resources: https://www.habarisoft.com/daraja_framework.html
– Getting started PDF: https://www.habarisoft.com/daraja_framework/1.2/docs/DarajaFrameworkGettingStarted.pdf
– Wiki: https://github.com/michaelJustin/daraja-framework/wiki

Consuming Server-Sent Events (SSE) with Indy TIdHTTP and TIdEventStream

A new Indy HTTP client / JAX-RS server example is now available on GitHub. The server side generates Server-sent events. Server-sent events (SSE) is a technology enabling a browser to receive automatic updates from a server via HTTP connection.

The example code uses TIdHTTP and TIdEventStream to connect to the server, and writes the incoming events to the console window.

indy-sse-jaxrs

Requirements

  • Delphi or Lazarus IDE
  • Indy 10.6.2
  • Java IDE
  • Java EE 8 application server

Client

The SSE client setup in the TIndySSEClient.Create creates a TIdHTTP instance and a TIdEventStream instance.
As recommended, the Accept header is set to 'text/event-stream'. It also sets the Cache-Control header to 'no-store' to prevent proxy servers from caching the result.
Our event handler TIndySSEClient.MyOnWrite is assigned to the TIdEventStreamOnWrite property.

constructor TIndySSEClient.Create;
begin
  inherited Create;

  SSE_URL := URL;

  EventStream := TIdEventStream.Create;
  EventStream.OnWrite := MyOnWrite;

  IdHTTP := TIdHTTP.Create;
  IdHTTP.Request.Accept := 'text/event-stream';
  IdHTTP.Request.CacheControl := 'no-store';
end;

The OnWrite handler decodes the UTF-8 encoded event data and writes it to the console:

procedure TIndySSEClient.MyOnWrite;
begin
  WriteLn('Received ' + IntToStr(Length(ABuffer)) + ' bytes');
  WriteLn;
  WriteLn(IndyTextEncoding_UTF8.GetString(ABuffer));
  ...
end;

Server (main REST method)

The server generates the server-sent event and places a Stock instance in its data part:

  @GET
  @Path("prices")
  @Produces(MediaType.SERVER_SENT_EVENTS)
  public void getStockPrices(@Context SseEventSink sseEventSink) {
    int lastEventId = 1;

    while (running) {
      Stock stock = getNextTransaction();

      System.out.println("Send event ...");
      OutboundSseEvent sseEvent = this.eventBuilder
              .name("stock")
              .id(String.valueOf(lastEventId))
              .mediaType(MediaType.APPLICATION_JSON_TYPE)
              .data(Stock.class, stock)
              .reconnectDelay(3000)
              .comment("price change")
              .build();

      sseEventSink.send(sseEvent);
      lastEventId++;
    }
    sseEventSink.close();
  }

Additional notes

  • this is the first draft of a SSE client, which does not support features such as reconnect
  • the example assumes that every call of MyOnWrite contains exactly one event, teminated by a sequence of two line separators (cr lf / cr / lf) so that no extra code is required to do proper event stream parsing

Full source code

https://github.com/michaelJustin/indy-sse-jaxrs

References

OpenCTF 1.6.0 component test framework released

The Open Component Test Framework (OpenCTF) is a test case generator framework for Delphi VCL applications, which creates DUnit tests at run time.

The new version 1.6.0 is a maintenance release and is now available on GitHub at https://github.com/michaelJustin/openctf

Example project

program FormTests;

uses
  OpenCTF, ctfStandardTests,
  GUITestRunner,
  TestForm in 'TestForm.pas' {Form1};

begin
  OpenCTF.RegisterFormClasses([TForm1]);

  RunRegisteredTests;
end.

When run, the FormTests example project dynamically creates tests for visual and non-visual components of the form and reports bad property values and other “errors”.

openctf-1.6.0

Note

  • to run the project, the path ‘..\..\source’ to the OpenCTF source directory must be added to the project search path
  • developed and tested with Delphi 2009, newer Delphi versions might need an older version of DUnit (9.3.0 or 9.4.0)

Single file upload example using Indy TidHTTP and multipart/form-data

A new cross-language example for HTTP and REST is now available on GitHub.

Description

Single file upload example using Delphi client and Java server code and HTTP multipart/form-data

Requirements

  • Delphi 2009 or newer
  • Indy 10.6.2
  • Java JDK 8 or newer
  • Apache Maven
  • WildFly application server

Client

program IndyPostFormData;

{$APPTYPE CONSOLE}

uses
  IdHTTP, IdMultipartFormData, SysUtils;

const
  URL = 'http://localhost:8080/indy-post-formdata-1.0-SNAPSHOT/webresources/generic/pdf';

var
  Indy: TIdHTTP;
  Params: TIdMultiPartFormDataStream;
  Response: string;

begin
  Indy := TIdHTTP.Create;
  Params :=  TIdMultiPartFormDataStream.Create;
  try
    try
      Params.AddFile('file', 'client.pdf');
      Response := Indy.Post(URL, Params);
      WriteLn(Response);
    except
      on E:Exception do
        Writeln(E.Classname, ': ', E.Message);
    end;
  finally
    Params.Free;
    Indy.Free;
  end;
  ReadLn;
end.

 

Server (main REST method)

  @POST
  @Path("/pdf")
  @Consumes({MediaType.MULTIPART_FORM_DATA})
  public Response upload(MultipartFormDataInput input) {
    String UPLOAD_PATH = "c:/tmp/";
    try {
      InputStream fileInputStream = input.getFormDataPart("file", InputStream.class, null);
      String fileName = "test.pdf";

      int read;
      byte[] bytes = new byte[1024];

      try (OutputStream out = new FileOutputStream(new File(UPLOAD_PATH + fileName))) {
        while ((read = fileInputStream.read(bytes)) != -1) {
          out.write(bytes, 0, read);
        }
      }
    } catch (IOException e) {
      throw new WebApplicationException("Error while uploading file. Please try again");
    }
    return Response.ok("Data uploaded successfully").build();
  }

 

Full source code

https://github.com/michaelJustin/indy-post-formdata