diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5eba875..8059ff3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,21 +1,31 @@ name: "Build & Test" -on: [push, pull_request] -jobs: +on: [push, pull_request, workflow_dispatch] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: macOS: - runs-on: macos-latest + runs-on: macos-14 timeout-minutes: 30 env: MACOSX_DEPLOYMENT_TARGET: "10.9" steps: - name: Checkout uses: actions/checkout@v4 - - name: Download LuaJIT + + - name: Checkout LuaJIT uses: actions/checkout@v4 with: repository: LuaJIT/LuaJIT ref: v2.1 path: LuaJIT + - name: Compile universal LuaJIT working-directory: ./LuaJIT run: | @@ -31,15 +41,19 @@ jobs: lipo -create -output ./src/libluajit.dylib ./src/libluajit_x64.dylib ./src/libluajit_arm.dylib lipo -create -output ./src/luajit ./src/luajit_x64 ./src/luajit_arm + - name: Configure run: cmake -Bbuild -S. -G Xcode -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DLUA_INCLUDE_DIR=$PWD/LuaJIT/src -DLUA_LIBRARIES=$PWD/LuaJIT/src/lua + - name: Build working-directory: build run: xcodebuild -configuration Release -scheme https -destination generic/platform=macOS + - name: Test working-directory: ./build/src/Release run: ../../../LuaJIT/src/luajit -l "https" ../../../example/test.lua - - name: Artifact + + - name: Upload Artifact if: always() uses: actions/upload-artifact@v4 with: @@ -48,43 +62,49 @@ jobs: Linux: name: ${{ matrix.mode.name }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 30 strategy: matrix: mode: - - name: Linux cURL - curl: 1 - openssl: 0 - artifact: 0 - - name: Linux OpenSSL - curl: 0 - openssl: 1 - artifact: 0 - - name: Linux cURL & OpenSSL - curl: 1 - openssl: 1 - artifact: 1 + - name: Linux cURL + curl: 1 + openssl: 0 + artifact: 0 + - name: Linux OpenSSL + curl: 0 + openssl: 1 + artifact: 0 + - name: Linux cURL & OpenSSL + curl: 1 + openssl: 1 + artifact: 1 steps: - name: Checkout uses: actions/checkout@v4 - - name: Update APT Repository - run: sudo apt-get update + - name: Install Dependencies - run: sudo apt-get install -y lua5.1 luajit liblua5.1-0-dev libcurl4-openssl-dev g++ libssl-dev + run: sudo apt-get update && sudo apt-get install -y lua5.1 luajit liblua5.1-0-dev libcurl4-openssl-dev g++ libssl-dev + - name: Configure run: cmake -Bbuild -S. -DCMAKE_INSTALL_PREFIX=$PWD/install -DCMAKE_BUILD_TYPE=Release -DUSE_CURL_BACKEND=${{ matrix.mode.curl }} -DUSE_OPENSSL_BACKEND=${{ matrix.mode.openssl }} + - name: Build run: cmake --build build --config Release --target install -j$(nproc) + - name: Test (Lua) if: matrix.mode.artifact == 0 + continue-on-error: true working-directory: ./install run: lua -l "https" ../example/test.lua + - name: Test (LuaJIT) if: matrix.mode.artifact == 0 + continue-on-error: true working-directory: ./install run: luajit -l "https" ../example/test.lua - - name: Artifact + + - name: Upload Artifact if: matrix.mode.artifact == 1 uses: actions/upload-artifact@v4 with: @@ -92,41 +112,48 @@ jobs: path: install/https.so Windows: - runs-on: windows-latest + runs-on: windows-2022 strategy: matrix: arch: - - Win32 - - x64 + - Win32 + - x64 defaults: run: shell: cmd steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Download LuaJIT - uses: actions/checkout@v4 - with: - repository: LuaJIT/LuaJIT - ref: v2.1 - path: LuaJIT - - name: Configure MSVC Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.arch }} - - name: Compile LuaJIT - working-directory: ./LuaJIT/src - run: msvcbuild.bat amalg - - name: Configure - run: cmake -Bbuild -S. -DCMAKE_INSTALL_PREFIX=%CD%\install -A ${{ matrix.arch }} -DLUA_INCLUDE_DIR=%CD%\LuaJIT\src -DLUA_LIBRARIES=%CD%\LuaJIT\src\lua51.lib - - name: Build - run: cmake --build build --config Release --target install - - name: Test - working-directory: ./install - run: ..\LuaJIT\src\luajit ..\example\test.lua - - name: Artifact - if: always() - uses: actions/upload-artifact@v4 - with: - name: https-windows-${{ matrix.arch }}.zip - path: install/https.dll + - name: Checkout + uses: actions/checkout@v4 + + - name: Checkout LuaJIT + uses: actions/checkout@v4 + with: + repository: LuaJIT/LuaJIT + ref: v2.1 + path: LuaJIT + + - name: Configure MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.arch }} + + - name: Compile LuaJIT + working-directory: ./LuaJIT/src + run: msvcbuild.bat amalg + + - name: Configure + run: cmake -Bbuild -S. -DCMAKE_INSTALL_PREFIX=%CD%\install -A ${{ matrix.arch }} -DLUA_INCLUDE_DIR=%CD%\LuaJIT\src -DLUA_LIBRARIES=%CD%\LuaJIT\src\lua51.lib + + - name: Build + run: cmake --build build --config Release --target install + + - name: Test + working-directory: ./install + run: ..\LuaJIT\src\luajit ..\example\test.lua + + - name: Upload Artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: https-windows-${{ matrix.arch }}.zip + path: install/https.dll diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8b80919 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,104 @@ +# AGENTS.md + +lua-https is a C++ Lua module providing HTTPS support via native platform backends. This fork's specific purpose is to build `https` libraries for **LÖVE 11.5** (the upstream targets LÖVE 12.0, which bundles lua-https natively). Targets Windows, Linux, macOS, iOS, and Android. + +## Build Commands + +### Linux +```bash +cmake -Bbuild -S. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$PWD/install +cmake --build build --target install +``` +Output: `install/https.so` + +### macOS (Xcode, universal binary) +```bash +cmake -Bbuild -S. -G Xcode -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DLUA_INCLUDE_DIR= -DLUA_LIBRARIES= +cmake --build build --config Release +``` +Output: `build/src/Release/https.so` + +### Windows (MSVC) +```bash +cmake -Bbuild -S. -DCMAKE_INSTALL_PREFIX=%CD%\install -A x64 -DLUA_INCLUDE_DIR= -DLUA_LIBRARIES= +cmake --build build --config Release --target install +``` +Output: `install/https.dll` + +### Android +Place entire lua-https source tree in `/love/src/jni/lua-modules/lua-https` and compile love-android as usual. Uses `Android.mk` (ndk-build), not CMake. + +### CMake Options (Linux) +- `-DUSE_CURL_BACKEND=ON/OFF` — enable cURL backend (default: ON) +- `-DUSE_OPENSSL_BACKEND=ON/OFF` — enable OpenSSL backend (default: ON) +- `-DLIBRARY_LOADER=unix|windows|linktime` — dynamic library loading method + +## Testing + +Tests are network-dependent integration tests (they hit real endpoints like `postman-echo.com` and GitHub raw content). Run with: +```bash +# After building and installing +cd install +lua -l "https" ../example/test.lua # Lua 5.1 +luajit -l "https" ../example/test.lua # LuaJIT +``` +There is no offline/unit test suite. + +## Architecture + +### Backend Selection (compile-time + runtime) +Platform backends are selected at **compile time** via CMake options (or auto-detected from `config.h` when CMake-generated config is absent). At **runtime**, `HTTPS.cpp` iterates a statically-ordered array of backend client pointers, calling `valid()` on each and using the first one that returns true. + +Backend priority order in `clients[]` array (`src/common/HTTPS.cpp`): +1. cURL +2. OpenSSL +3. WinINet (must be above SChannel per code comment) +4. SChannel +5. NSURL +6. Android + +### Platform Backends +| Platform | Backend | Source | Notes | +|----------|---------|--------|-------| +| Linux | cURL | `src/generic/CurlClient.cpp` | Dynamically loads `libcurl.so.4` | +| Linux | OpenSSL | `src/generic/OpenSSLConnection.cpp` | Raw socket + TLS via `ConnectionClient` | +| macOS/iOS | NSURL | `src/apple/NSURLClient.mm` | Objective-C++, ARC enabled | +| Windows | SChannel | `src/windows/SChannelConnection.cpp` | Raw socket + TLS via `ConnectionClient` | +| Windows | WinINet | `src/windows/WinINetClient.cpp` | Higher-level Windows API | +| Android | JNI | `src/android/AndroidClient.cpp` | Calls Java via JNI; requires `LuaHTTPS.java` from `src/android/java/` | + +### Key Abstractions +- **`HTTPSClient`** (`src/common/HTTPSClient.h`) — Abstract base. Defines `Request` (url, headers, postdata, method) and `Reply` (body, headers, responseCode) structs. Header maps use case-insensitive keys via `ci_string_less`. +- **`Connection`** (`src/common/Connection.h`) — Abstract TCP/TLS connection interface (connect, read, write, close). Used by OpenSSL and SChannel backends. +- **`ConnectionClient`** (`src/common/ConnectionClient.h`) — Template `HTTPSClient` that delegates to `HTTPRequest` with a `Connection` factory. Used by socket-based backends (OpenSSL, SChannel). +- **`HTTPRequest`** (`src/common/HTTPRequest.h`) — Implements HTTP protocol over a `Connection` (URL parsing, sending request, reading response). Takes a `ConnectionFactory` function. +- **`LibraryLoader`** (`src/common/LibraryLoader.h`) — Platform-abstracted dynamic library loading (dlopen/LoadLibrary). Used by CurlClient to load libcurl at runtime. Three implementations: `UnixLibraryLoader`, `WindowsLibraryLoader`, `LinktimeLibraryLoader`. + +### Configuration System +- **With CMake**: `config-generated.h.in` is processed into `config-generated.h` defining `HTTPS_BACKEND_*` macros based on CMake options. +- **Without CMake** (e.g., IDE builds): `config.h` auto-detects platform via preprocessor (`_WIN32`, `__APPLE__`, `__ANDROID__`, `linux`) and `__has_include` for available libraries. + +### Lua Binding +Entry point: `luaopen_https` in `src/lua/main.cpp`. Exposes a single `https.request` function. The module name is `"https"` (not `"lua-https"`). + +## Conventions + +- C++14 standard +- Headers use `#pragma once` +- All backend code is guarded by `#ifdef HTTPS_BACKEND_*` / `#endif` pairs in both headers and implementation files +- `extern "C"` wrapping for Lua API includes +- Symbols use `HTTPS_DLLEXPORT` macro for platform-appropriate export visibility +- GCC/Clang: `-fvisibility=hidden` on both compile and link (only `luaopen_https` is exported) +- The cURL backend dynamically loads libcurl symbols at runtime rather than linking at compile time, to avoid hard runtime dependencies +- `LUA_INCLUDE_DIR` and `LUA_LIBRARIES` CMake variables can be set manually; otherwise CMake tries `FindLuaJIT` first, then falls back to `FindLua 5.1` + +## Context for this Fork + +- **This fork targets LÖVE 11.5**, not LÖVE 12.0. LÖVE 12.0 bundles lua-https natively, but 11.5 does not — this fork exists to fill that gap. The built shared library (`https.so` / `https.dll`) should be placed alongside or loadable by LÖVE 11.5's Lua runtime. +- **LÖVE/LOVR support**: The CMakeLists has a special `LOVR` guard that uses `LOVR_LUA` instead of finding LuaJIT. +- **macOS linking**: Uses `-undefined dynamic_lookup` (not on iOS, which links Lua normally). +- **Windows linking**: Must explicitly link `${LUA_LIBRARIES}` on Windows; other platforms resolve Lua symbols at load time. +- **cURL backend**: Dynamically loads `libcurl.so.4` (Linux) or `libcurl.dll` (Windows) at runtime. The `linktime` library loader exists for static linking scenarios. +- **Android**: Requires Java file (`src/android/java/org/love2d/luahttps/LuaHTTPS.java`) added to the Android project. `java.txt` documents the path. +- **No unit tests**: All tests require network access. +- **The module output extension**: `.so` on Linux/macOS, `.dll` on Windows — but CMake `set_target_properties(https PROPERTIES PREFIX "")` strips the `lib` prefix on all platforms.