Skip to content
Snippets Groups Projects
README.md 20.1 KiB
Newer Older
Patrik Burzynski's avatar
Patrik Burzynski committed
# Extended HTTP Requests

With Extended HTTP Requests, additional functionalities are made available in
order to perform different types of HTTP/S requests (GET, PUT, POST, etc...)
with more control about the content that is sent (headers and body). The
requests can be performed directly from the ADOxx tool using AdoScript. This
functionality enables to retrieve data from resources on the internet or 
performing API calls to web services with custom content.


Patrik Burzynski's avatar
Patrik Burzynski committed
## Table of contents
1. [Details](#details)
2. [Use](#use)
3. [Extend](#extend)



Patrik Burzynski's avatar
Patrik Burzynski committed
## Details
[To Top](#)
Patrik Burzynski's avatar
Patrik Burzynski committed

This module enables the execution of HTTP/S requests from ADOxx or an ADOxx
Patrik Burzynski's avatar
Patrik Burzynski committed
based modelling tool using AdoScript. It provides several procedures, which
allow to perform a variety of different options to access resources and
services. The procedures use several parameters to handle things like
credentials, headers or the content body for both requests and their responses.


Patrik Burzynski's avatar
Patrik Burzynski committed
### Features and functionality
Patrik Burzynski's avatar
Patrik Burzynski committed

1. Perform synchronous HTTP/S calls to Web resources, services etc. using any
desired HTTP method (such as GET, PUT, POST, DELETE, etc.) through AdoScript.
2. (Almost) complete freedom about the sent request headers and body.
3. Use of basic authentication (username and password) supported.
4. Receive the response body in one of three formats:
    * As a string,
    * as a base64 encoded string (necessary when the response contains NUL
      bytes, e.g. PNG images) or
    * as an array of bytes.
5. Additional utility procedures for dealing with common HTTP tasks.


### Cases

One case of use for the module is with a Cyber-physical system, a robotic arm
to be more specific. The robotic arm provides a REST API to control it, which
is accessed from the [Bee-Up modelling tool](https://bee-up.omilab.org) during
processing of a model. Have a look at the following
[video/screencast](https://www.youtube.com/watch?v=_axMHumFdzQ) to see it in
action! For more information on the case, please visit
https://bee-up.omilab.org/activities/bee-up/scenario-details/
Patrik Burzynski's avatar
Patrik Burzynski committed
### How it works
Patrik Burzynski's avatar
Patrik Burzynski committed

This implementation uses a Dynamic Link Library (DLL), which is called by the
provided AdoScript procedures. As such, the actual HTTP/S request is performed
from the DLL and the AdoScript procedures provide a neat interface to the DLL.
The DLL itself uses libcurl to handle the network communication.

The following image shows the interaction when performing an HTTP/S call.  
![Composition of the Extended HTTP Requests.](Composition_v3.png)

The **Custom AdoScript** is using the Extended HTTP Requests. It wants to
access something from the Web, Internet or any kind of accessible network using
the Hypertext Transfer Protocol. To achieve this, it invokes the provided
AdoScript procedures.

The **Provided AdoScript Procedures** represent the procedures made available
to simplify calling the DLL, like using AdoScript maps to handle the HTTP/S
request/response headers.

The **ADOxx / ADOxx Modelling Tool** is the environment where the AdoScripts
are executed and which handles the details of calling the DLL and receiving the
result among other things, like creating and managing models.

The **Custom DLL** opens a connection, sends the request to the desired
endpoint on the Web, Internet or any kind of accessible network and waits for
the response. It provides several functions which are available through the C
type calling convention.


Patrik Burzynski's avatar
Patrik Burzynski committed
#### Libraries and modules
Patrik Burzynski's avatar
Patrik Burzynski committed
The project is mainly a wrapper around libcurl to simplify HTTP/S requests. It
provides functions for use from other software (e.g. ADOxx) to make synchronous
HTTP/S requests with a single function call. Furthermore it uses a library
(nlohmann\json) for handling JSON data structures where needed (e.g. HTTP
Headers as simple JSON objects). Additionally, a library (base64) for encoding
and decoding of strings (character data) as Base64 is being used.


### Further details / Acknowledgements

* [libcurl](https://curl.se/libcurl/)
* This product includes software developed by the OpenSSL Project for use in
  the OpenSSL Toolkit (http://www.openssl.org/).
* [nlohmann\json](https://github.com/nlohmann/json)
* [base64 encoder/decoder](https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp/)
### Appeal

If you use the Software then we would kindly ask that you do one or several of
the following:
* provide a notice and a link to the original project page on your webpage
  and/or part of the application it is used in at a fitting location.
* use the provided "powered-by-OMiLAB" image found under "res/imgs" on your
  webpage and/or part of the application it is used in at a fitting location.


[To Top](#)
Patrik Burzynski's avatar
Patrik Burzynski committed
The Extended HTTP Requests building block can be integrated in your modelling
tool implementation by downloading the necessary files and integrating them
into your library and modelling tool installation.


Patrik Burzynski's avatar
Patrik Burzynski committed
### Dependencies on other modules / Components
Patrik Burzynski's avatar
Patrik Burzynski committed

* libcurl (included in download)
* OpenSSL (included in download)
* Other C++ libraries (included in download)


### License of this code
For the license applying to the source code and the compiled binaries created
in this project see `LICENSE`.


### Other licenses
The license details of used libraries, modules etc. can be found in the 
`licenses` directory.


Patrik Burzynski's avatar
Patrik Burzynski committed
### Using the DLL directly
Patrik Burzynski's avatar
Patrik Burzynski committed

Patrik Burzynski's avatar
Patrik Burzynski committed
The DLL can be used directly from any program that supports executing DLL
functions using C deceleration calling conventions. Documentation on the
available functions can be found in `src\HttpRequestDll.h`.

A compiled version for Windows 32-bit is available in the `httpreq` folder as
Patrik Burzynski's avatar
Patrik Burzynski committed
`HttpRequestFunctions.dll`, together with the necessary DLLs, like
`libcurl.dll`, curl's certificate bundle file `curl-ca-bundle.crt` needed for
HTTPS (both from version 7.77.0-win32) or the libraries from Mingw-w64. For
more information about libcurl visit https://curl.se/libcurl/. For more
information about Mingw-w64 visit http://mingw-w64.org.

> Additional details beyond the here provided descriptions are documented as
> comments in the files located in the `src` folder.

Patrik Burzynski's avatar
Patrik Burzynski committed
### Setting up in ADOxx (integrated)
Patrik Burzynski's avatar
Patrik Burzynski committed

Additionally, `ASC_HttpRequestDll.asc` is provided for the use with ADOxx. It
contains an AdoScript with global variables and procedures to perform HTTP/S
Patrik Burzynski's avatar
Patrik Burzynski committed
calls through the `HttpRequestFunctions.dll`. To use it the intended way
perform the following steps:
1. Copy the `httpreq` folder into the ADOxx installation folder.
Patrik Burzynski's avatar
Patrik Burzynski committed

Patrik Burzynski's avatar
Patrik Burzynski committed
2. Add the file `ASC_HttpRequestDll.asc` (located in the `httpreq` folder) to
    the database of the ADOxx library.
Patrik Burzynski's avatar
Patrik Burzynski committed

3. (recommended) Add the files from the `res\em` folder to the database of the
Patrik Burzynski's avatar
Patrik Burzynski committed
    ADOxx library. They contain a list of all used identifiers for global
    variables, functions and procedures.

4. Add the following line in the library's `External coupling` in
Patrik Burzynski's avatar
Patrik Burzynski committed
    `ON_EVENT "AppInitialized"` at an appropriate place.
    ```AdoScript
    EXECUTE file:("db:\\ASC_HttpRequestDll.asc")
    ```
    This loads the necessary procedures on start-up of the tool. It is
    recommended to load the procedures before any other modules that depend
Patrik Burzynski's avatar
Patrik Burzynski committed
    on it.

Patrik Burzynski's avatar
Patrik Burzynski committed

Patrik Burzynski's avatar
Patrik Burzynski committed
### Using in ADOxx

The script file provides several procedures to execute HTTP/S requests
Patrik Burzynski's avatar
Patrik Burzynski committed
considering several aspects (detailed further below):
Patrik Burzynski's avatar
Patrik Burzynski committed
* Authentication.
* Encoding of the response (needed to deal with NUL characters).
* Encoding of the request (needed to deal with NUL characters).

> Additional details beyond the here provided descriptions are documented as
> comments in the AdoScript files located in the `httpreq` folder.

Patrik Burzynski's avatar
Patrik Burzynski committed
Furthermore, "Utility procedures" are provided to simplify some common tasks
when performing HTTP/S requests:
* `HTTP_URL_ENCODE` - escape unsafe characters in a text using URL encoding.
* `HTTP_URL_ENCODE_QUERY` - transform a map to a string following the structure
    of a URL query, e.g. for sending `application/x-www-form-urlencoded` data.

Patrik Burzynski's avatar
Patrik Burzynski committed
Additional aspects can be configured through global variables:
Patrik Burzynski's avatar
Patrik Burzynski committed
* `global_str_dll_dllfolder` – specifies the folder where the necessary DLL
    files are located. Default uses the `httpreq` folder in the ADOxx 
    installation directory.
* `global_str_dll_httprequest` – specifies the name of the DLL file. Default is
    `HttpRequestFunctions.dll`
* `global_val_skipVerification` - if set to 1 then the verification of
Patrik Burzynski's avatar
Patrik Burzynski committed
    certificates for HTTPS calls will be skipped. Default is 0.

Patrik Burzynski's avatar
Patrik Burzynski committed
Depending on the used procedure the following parameters are available:
* `str_url` - The main parameter should specify the URL where the request
    should be sent. In case of GET requests the "HTTP parameters" should be
    part of the URL query.
* `str_method` - Which HTTP method should be used. Common are GET, PUT, POST,
Patrik Burzynski's avatar
Patrik Burzynski committed
    DELETE, but also HEAD, OPTIONS, TRACE and others are possible. Just
    remember that the standardized HTTP methods should use upper case.
Patrik Burzynski's avatar
Patrik Burzynski committed
* `str_username` - The user name to use with basic authentication.
* `str_password` - The password to use with basic authentication.
* `map_reqheaders` - A map containing the headers to be sent with this request.
Patrik Burzynski's avatar
Patrik Burzynski committed
    Some seem to always be present automatically when needed (e.g. "Accept",
    "Content-Length"), but others like "Content-Type" or "Authorization"
    should be specified through this map. In any case both the keys and the
    values of the map should be strings, or if you don't want to specify any
    additional headers just use (map()) for this parameter.
Patrik Burzynski's avatar
Patrik Burzynski committed
* `str_reqbody` - The body that should be sent with the request. In case of
    "PUT" and "POST" requests it should contain the desired parameters, which
    can be simple in some cases (e.g. a string containing valid JSON code) or
Patrik Burzynski's avatar
Patrik Burzynski committed
    more complicated in others (e.g. a application/x-www-form-urlencoded 
    request has to url-encode the parameters). It is up to the procedure
    caller to produce the proper body content.
Patrik Burzynski's avatar
Patrik Burzynski committed
* `val_respcode` - a reference that will contain the HTTP status code answered
Patrik Burzynski's avatar
Patrik Burzynski committed
    by the server or possibly 0 if something went wrong before the request
Patrik Burzynski's avatar
Patrik Burzynski committed
    could be sent / the response be received.
* `map_respheaders` - a reference that will contain an AdoScript map with the
Patrik Burzynski's avatar
Patrik Burzynski committed
    response headers. Both the keys and the values will be of type string.
Patrik Burzynski's avatar
Patrik Burzynski committed
* `str_respbody` / `arr_respbody` - a reference that will contain the response
    of the server or the error message (format depends on used procedure).

The following global procedures are available from `ASC_HttpRequestDll.asc`:
```AdoScript
# Sends an HTTP/S Request to the specified URL. The returned body of the
# response is provided as a string terminated with a NUL byte (\0).
HTTP_SEND_REQUEST (str_url)
    str_method:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    str_respbody:reference

# Sends an HTTP/S Request to the specified URL with authentication information.
# The returned body of the response is provided as a string terminated with
# a NUL byte (\0).
HTTP_SEND_AUTH_REQUEST (str_url)
    str_method:string
    str_username:string
    str_password:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    str_respbody:reference

# Sends an HTTP/S Request to the specified URL. The returned body of the
# response is provided as a base64 encoded string. This is relevant for content
# that can contain a NUL byte (\0) in the middle, since the NUL byte is used to
# indicate the end of a string. For example when retrieving a PNG image.
HTTP_SEND_REQUEST_BASE (str_url)
    str_method:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    str_respbody:reference

# Sends an HTTP/S Request to the specified URL with authentication information.
# The returned body of the response is provided as a base64 encoded string.
# This is relevant for content that can contain a NUL byte (\0) in the middle,
# since the NUL byte is used to indicate the end of a string. For example when
# retrieving a PNG image.
HTTP_SEND_AUTH_REQUEST_BASE (str_url)
    str_method:string
    str_username:string
    str_password:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    str_respbody:reference

# Sends an HTTP/S Request to the specified URL. The returned body of the
# response is provided as an array containing the byte values. This is relevant
# for content that can contain a NUL byte (\0) in the middle, since the NUL
# byte is used to indicate the end of a string. For example when retrieving a
# PNG image.
HTTP_SEND_REQUEST_BYTES (str_url)
    str_method:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    arr_respbody:reference

# Sends an HTTP/S Request to the specified URL with authentication information.
# The returned body of the response is provided as an array containing the byte
# values. This is relevant for content that can contain a NUL byte (\0) in the
# middle, since the NUL byte is used to indicate the end of a string. For
# example when retrieving a PNG image.
HTTP_SEND_AUTH_REQUEST_BYTES (str_url)
    str_method:string
    str_username:string
    str_password:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    arr_respbody:reference

###############################################################################
# The following procedures are a special version of the previous procedures
# which will decode the str_reqbody using base64 before sending it to the
# specified URL. This is again relevant when sending data that can contain a
# NUL byte (\0) in the middle. Otherwise they behave the same.
###############################################################################

HTTP_SEND_REQUEST_INBASE (str_url)
    str_method:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    str_respbody:reference

HTTP_SEND_AUTH_REQUEST_INBASE (str_url)
    str_method:string
    str_username:string
    str_password:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    str_respbody:reference

HTTP_SEND_REQUEST_BASE_INBASE (str_url)
    str_method:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    str_respbody:reference

HTTP_SEND_AUTH_REQUEST_BASE_INBASE (str_url)
    str_method:string
    str_username:string
    str_password:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    str_respbody:reference

HTTP_SEND_REQUEST_BYTES_INBASE (str_url)
    str_method:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    arr_respbody:reference

HTTP_SEND_AUTH_REQUEST_BYTES_INBASE (str_url)
    str_method:string
    str_username:string
    str_password:string
    map_reqheaders:map
    str_reqbody:string
    val_respcode:reference
    map_respheaders:reference
    arr_respbody:reference


###############################################################################
# Following the utility procedures.
###############################################################################


HTTP_URL_ENCODE (str_content)
    str_allowedset:string
    str_encoded:reference
# str_content - The content that should be encoded using URL encoding style.
#   Consider providing the main parameter with the toutf8(...) function.
# str_allowedset - Specifies which of the four available sets containing the
#   "allowed characters" to use. Should be "JS", "Inter", "Lax" or "VeryLax".
# str_encoded - a reference that will contain the encoded content.

HTTP_URL_ENCODE_QUERY (map_content)
      str_allowedset:string
      str_encoded:reference
# map_content - a map containing keys and their values to transform.
# str_allowedset - Specifies which of the four available sets containing the
#   "allowed characters" to use. Should be "JS", "Inter", "Lax" or "VeryLax".
# str_encoded - a reference that will contain the encoded content.
```
Patrik Burzynski's avatar
Patrik Burzynski committed

Additional details on the available AdoScript procedures are documented in the
`ASC_HttpRequestDll.asc` file.

Patrik Burzynski's avatar
Patrik Burzynski committed

### Backwards compatibility
Patrik Burzynski's avatar
Patrik Burzynski committed

Patrik Burzynski's avatar
Patrik Burzynski committed
The `HttpRequestFunctions.dll` also provides functions that have the same
signature and functionality as the old `HttpRequestDll.dll`. Therefore it can
be used in place of the old version, however the necessary dependencies
(`libcurl`, `curl-ca-bundle.crt`) must be placed in the same folder.


Patrik Burzynski's avatar
Patrik Burzynski committed
### Other notes
Patrik Burzynski's avatar
Patrik Burzynski committed
* When using the DLLs directly from ADOxx it is necessary to change the
    "Current Working Directory" to the directory where they are located. This
    is not necessary when using the procedures provided in
    `ASC_HttpRequestDll.asc`.
* When creating a modelling tool installation package make sure it also
    contains the `httpreq` folder and is distributed with the installer.



Patrik Burzynski's avatar
Patrik Burzynski committed
## Extend
[To Top](#)
Patrik Burzynski's avatar
Patrik Burzynski committed

The core functionality is implemented using C++, which calls other libraries
(e.g. libcurl) and is built into a DLL. This DLL is then called from AdoScript
procedures.

It is recommended to have knowledge about:
* The Hypertext Transfer Protocol.
* C++ and building C++ projects.
* libcurl and its interfaces.
* ADOxx and AdoScript, especially maps, calling DLLs and translating between
    ADOxx data types.


Patrik Burzynski's avatar
Patrik Burzynski committed
### Setup of development environment
Patrik Burzynski's avatar
Patrik Burzynski committed

The following setup has been used to develop the project and has worked so far:
1. [Mingw-w64](http://mingw-w64.org): the compiler used for building the C++
    project. It should be installed for i686 architecture (32-bit), using posix
    threads and dwarf exception handling. The version used for building was
    8.1.0.
Patrik Burzynski's avatar
Patrik Burzynski committed
2. [Visual Studio Code](https://code.visualstudio.com/): Code editor for which
    several extensions are available for working with the relevant files.
Patrik Burzynski's avatar
Patrik Burzynski committed
3. [C/C++ for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools):
    Extension for Visual Studio Code to support writing and building C++
    projects.
4. [VSC AdoScript Extension](https://marketplace.visualstudio.com/items?itemName=ADOxxorg.adoxx-adoscript):
    An extension for Visual Studio Code to edit AdoScript and other ADOxx
    formats.


Patrik Burzynski's avatar
Patrik Burzynski committed
### Adapt the source code
Patrik Burzynski's avatar
Patrik Burzynski committed
The source code is written in C++ and is provided in the `src` folder. It
Patrik Burzynski's avatar
Patrik Burzynski committed
consists of three parts:
* HttpRequest - contains structures and classes to perform HTTP/S requests from
Patrik Burzynski's avatar
Patrik Burzynski committed
    mainly C++. The core in this case is the `LibcurlWrapper` class.
Patrik Burzynski's avatar
Patrik Burzynski committed
* HttpRequestDll - contains the functions for performing HTTP/S requests made
    available through the DLL using C declaration (cdecl) calling conventions.
    Also contains some other support functions provided by the DLL.
* StringHelper - contains some functions that work on/with C++ strings used by
    the other parts.

Patrik Burzynski's avatar
Patrik Burzynski committed
The source code for the AdoScript procedures is directly available in the
`ASC_HttpRequestDll.asc` file in the `httpreq` folder. It's main concern is
simplifying the use of the DLL through global procedures.

Patrik Burzynski's avatar
Patrik Burzynski committed
The files of the used libraries can be found in the `include` directory.
Patrik Burzynski's avatar
Patrik Burzynski committed
### Build the project
Patrik Burzynski's avatar
Patrik Burzynski committed
The project has been built for 32-bit using GCC through mingw-w64. So far the
project is not complicated enough to warrant a MAKE file or similar.
Used mingw-w64 version: i686-8.1.0-posix-dwarf-rt_v6-rev0.
Patrik Burzynski's avatar
Patrik Burzynski committed
Used command (in relation to the project directory):  
`g++.exe -std=c++17 -O3 .\src\*.cpp .\include\*.cpp -o .\httpreq\HttpRequestFunctions.dll -I .\include -L .\lib -l curl -mdll`


### How to contribute

Patrik Burzynski's avatar
Patrik Burzynski committed
There are different ways to contribute to the project:
* Spread the word and tell the others
* Report issues and problems
* Extend the functionality and fix existing issues

The easiest way to achieve the latter parts is by installing [git](https://git-scm.com/)
and using the [repository of the project](https://code.omilab.org/resources/adoxx-modules/extended-http-requests).

When deciding to implement a new feature or fix a specific bug then create an
"Issue" in the GitLab project repository first. This can be used for discussion
with other community members and help to keep track of work items. Also avoid
performing changes directly to the master branch if you are not the owner or
a maintainer of the project. Instead create a new branch that is descriptive of
the work to be done. Once the desired changes are implemented the result can be
committed to the GitLab repository and a merge request performed.