From c06d3ddfb4f01ada2182c5bc34890a22d7e29246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 14:10:50 +0200 Subject: [PATCH 01/18] Change proposal --- README.md | 388 ++++++++++-------------------------------------------- 1 file changed, 66 insertions(+), 322 deletions(-) diff --git a/README.md b/README.md index 8077ed3..e1a4444 100644 --- a/README.md +++ b/README.md @@ -1,351 +1,95 @@ -

🚀 NLAP - FalconAS

-

XML based Next Level Application Protocol including a lightning-fast Python / Java Application Server (FalconAS)

+![FalconAS Logo](./image/falconas-logo.png) -
- - CodeQL - - - Docs Oxygen - - - Docs Sphinx - - - Release - -
+Falcon Application Server - NLAP (Next Level Application Protocol) ---- - -This project includes: - -- A rock-solid, fast, and secure HTTP/1.1 parser and generator C++ library for use in microcontroller (e.g., Arduino) projects -- A (not-yet-finished) XML-based (NLAP protocol) application server (Python or Java) for real-time or high-security requirements - -## :pushpin: Overview - -**NLAP (Next Level Application Protocol)** is an XML-based protocol designed to replace HTTP -for modern web application requirements. - -**NLAP solves these problems** with a clean, XML-based transport encapsulation that natively supports: - -- ✅ **Robust** parallel **multi-response** transmission **over a single socket** -- ✅ **Elimination** of **head-of-line blocking** (time-consuming responses do not block follow-ups) -- ✅ Structured, **XML-encapsulated transport** data, including **validatable** XML schemas -- ✅ Firewall-friendly, **port-separated protocol subtypes** (NLAFP for files, NLAMP for application server requests) -- ✅ Simple, non-TLS, HSM- and TPM-based X.509 authentication, signing and encryption - -**FalconAS Server Features**: - -- ✅ **Kernel Mutex-Less**: Built with on-chip atomic user space locks -- ✅ **Lightning-Fast Performance**: Epoll-based / multi-socket optimized architecture -- ✅ **Sendfile Static File Delivery**: In-kernel sendfile() decrease scheduling latency -- ✅ **Rock-Solid App-Server Security**: Runs with tight backend process-separation model (non-threaded) -- ✅ **SPA Realtime Demands**: Built for modern browser applications (SPAs) real-time demands -- ✅ **Zero Bloat**: Eliminates unnecessary complexity while maintaining compatibility -- ✅ **Python-Powered**: FalconAS application server with embedded Python scripting -- ✅ **Java-Powered**: FalconAS application server with embedded Java scripting - -## :bookmark_tabs: Table of Contents - -1. [Quick Start](#racehorse-quick-start) -2. [Features](#star2-features) -3. [Why NLAP Instead of HTTP/1.2?](#mega-why-nlap-instead-of-http12) -4. [Build & Installation](#hammer_and_wrench-build--installation) -5. [Testing](#test_tube-testing) -6. [Technical Architecture](#gear-technical-architecture) -7. [Documentation](#page_with_curl-documentation) -8. [Community & Support](#globe_with_meridians-community--support) -9. [Contributing](#wave-contributing) -10. [Future Milestones](#alarm_clock-future-milestones) -11. [License](#memo-license) - ---- - -## :racehorse: Quick Start - -Get FalconAS (using HTTP/1.1 or NLAP) running in minutes: - -```bash -# clone repository -git clone https://github.com/WEBcodeX1/http-1.2.git -cd http-1.2 - -# install dependencies (Ubuntu 22.04/Debian 12) -apt-get install git cmake python3-pip libboost-all-dev python3-dev nlohmann-json3-dev - -# build and install -cmake . -make -sudo make install - -# start using systemd (automatically configured during install) -sudo systemctl daemon-reload -sudo systemctl enable falcon-as -sudo systemctl start falcon-as - -# OR start manually -. ./scripts/ulimit.sh -. ./scripts/set-transparent-hugepages.sh -/usr/local/bin/falcon-as -``` - -The server will be available with test applications at: -- `http://testapp1.local/` (HTTP/1.1 compatibility mode) -- `http://testapp2.local/` (HTTP/1.1 compatibility mode) - -For detailed installation instructions, see [BUILD.md](BUILD.md). - ---- - -## :star2: Features - -### Core Advantages -- **🚀 Lightning-Fast**: Epoll-based architecture for maximum performance -- **🔒 Secure by Design**: Interpreters run non-threaded / unix process isolated -- **⚡ Zero Bloat**: Clean XML-based protocol without HTTP's legacy complexity -- **🎯 SPA-Optimized**: Perfect for modern Single Page Applications real-time demands -- **🐍 Python-Powered**: Embedded Python interpreter / scripting integration -- **☕ Java-Powered**: Embedded Java JNI / scripting integration - -### NLAP Protocol Innovations -- **XML-Based Transport**: Clean, structured request/response format -- **Native UUID System**: Built-in request/response matching -- **Multiple Subtypes**: NLAFP for file transfer, NLAMP for application metadata -- **Extensible Architecture**: XML schemas enable easy protocol evolution -- **Partial File Transfer**: Efficient handling of large files with chunked transfer -- **Request/Response Signing**: Built-in cryptographic signing support - -### Technical Features -- **Static Content Server**: High-performance file serving with sendfile() -- **Application Server**: Python scripting with shared memory architecture -- **Memory Management**: Huge pages support and optimized memory layout -- **Process Architecture**: Separate processes to avoid Python GIL limitations -- **JSON Configuration**: Clean, maintainable configuration system -- **JSON Powered By**: [nlohmann/json](https://github.com/nlohmann/json) C++ JSON library - ---- - -## :mega: Why NLAP Instead of HTTP/1.2? - -### The Problem with HTTP/1.2 - -**HTTP/1.2 is not being pursued** - The original plan to extend HTTP/1.1 with UUID headers faces insurmountable challenges: - -- **Ancient Text-Based Protocol Design**: HTTP's line-based parsing is incompatible with efficient UUID integration -- **Client Library Overhead**: Client processing must be re-implemented for a dead protocol, this means unnecessary effort, -better implement intop modern NLAP design - -### The Problem with HTTP/2 & HTTP/3 - -**HTTP/2 Complexity Crisis:** -- Excessive complexity destroys HTTP/1.1's elegant simplicity -- Everything packed into one "black box" without logical separation -- Libraries are confusing and difficult to understand -- TLS/SSL handling unnecessarily embedded in protocol - -**HTTP/3 UDP Issues:** -- Solves core issues but moves unneccessary (already worldwide approved and adopted) complexity -from TCP into UDP (application) layer - -### Our Solution: NLAP (Next Level Application Protocol) - -NLAP replaces HTTP's legacy concepts with a clean, modern XML-based and application-centric (not document-centric) protocol. - -> **🎯 Key Innovation**: XML transport encapsulation, structured data, reliable concurrent-response transmission and extensibility that HTTP's ancient text format cannot match. - -**NLAP Protocol Specifications:** -- **XML-Based**: Structured, parseable, extensible format -- **Built-in UUID**: Native request/response correlation -- **Multiple Subtypes**: NLAFP for file protocol, NLAMP for metadata protocol -- **First Specs Available**: See `/specs/xml/` for NLAFP and NLAMP documentation +[![CodeQL](https://github.com/WEBcodeX1/http-1.2/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/WEBcodeX1/http-1.2/actions/workflows/github-code-scanning/codeql) +[![License](https://img.shields.io/github/license/WEBcodeX1/http-1.2?style=flat)](https://github.com/WEBcodeX1/http-1.2/tree/main/LICENSE) +[![Doxygen API](https://img.shields.io/badge/docs-sphinx-blue)](https://docs.webcodex.de/developer/falconas/v0.3/doxygen/index.html) +[![Sphinx Docs](https://img.shields.io/badge/docs-sphinx-blue)](https://docs.webcodex.de/x0/v1.0/) --- -## :hammer_and_wrench: Build & Installation - -### Prerequisites +# 1. Overview -**Operating System Support:** -- Ubuntu 22.04 (Jammy Jellyfish) -- Ubuntu 24.04 (Noble Numbat) -- Debian 12 +An advanced architectural paradigm for *low-latency* **TCP**/IP transport tailored for +modern browser web-applications and high-throughput data aggregation middleware. -**Required Dependencies:** -```bash -# core build tools -apt-get install git cmake +It incorporates a high-speed *Python 3* or *Java* application server that natively utilizes +NLAP as its core transport protocol to minimize execution and scheduling overhead. -# c++ boost libraries -apt-get install libboost-all-dev +# 2. Project Evolution & History -# python development headers -apt-get install python3-dev +The project was originally conceptualized under the designation `HTTP/1.2`. The initial +objective was to mitigate the limitations of the flawed HTTP/1.1 pipelining specification +by injecting unique UUIDs into individual requests. -# c++ json library -apt-get install nlohmann-json3-dev -``` +However, practical implementation demonstrated that this approach introduces severe +technical problems. -### Build Options +Because the `HTTP/1.1` specification relies strictly on synchronous, serial processing, +it remains fundamentally incompatible with modern, deterministic zero-latency architectures. +Consequently, the `HTTP/1.2` pipelining methodology was deprecated in favor of a novel +architectural framework: **NLAP**. -**Standard Build:** -```bash -cmake . -make -make install -``` +# 3. What is NLAP? What problems does NLAP solve? -**Debug Build:** -```bash -cmake -DDEBUG_BUILD=1 . -make -make install -``` +NLAP (Next Level Application Protocol) is a deterministic, transaction-oriented transport +framework that formally resolves long-standing architectural omissions in Layer 5 (Session) +and Layer 6 (Presentation) of the OSI model over standard TCP. Originally conceptualized by +IETF engineers as an in-kernel transactional framed protocol, NLAP realizes this design paradigm +in user space while maintaining full compatibility with standard `TCP_STREAM` sockets. -**Java Backend Build:** -```bash -export JAVA_HOME=/usr/lib/jvm/jdk-24.0.2-oracle-x64/ -cmake -DJAVA_BACKEND=1 . -make -make install -``` +By replacing traditional, continuous stream-based processing with discrete, strictly validated +XML message frames, NLAP achieves exceptional throughput, structural security, and minimal +latency. -For complete build instructions, see [BUILD.md](BUILD.md). +**Core Architectural Characteristics:** ---- - -## :test_tube: Testing - -Comprehensive testing infrastructure ensures reliability: +- **Strict XML Message Framing:** Eliminates stream-parsing ambiguities by processing strictly bounded data packets. This non-streamed approach significantly enhances parsing security, mitigates memory-corruption vectors, and maximizes raw processing performance. +- **Formalized Model Descriptions:** Reduces protocol complexity to a bare minimum by enforcing a 100% complete structural and semantic definition via Document Type Definitions (DTD) and YANG modeling schemas. +- **Granular Protocol Sub-typing:** Sub-divides transport traffic into distinct, functional protocol variants to maximize scalability and simplify network firewalls (see chapter ). +- **Simplified High-Integrity Cryptography**: Drastically reduces cryptographic complexity. Because data is processed as static, complete messages rather than continuous streams, the entire frame is signed and encrypted atomically. This enables hardware-native X.509 standard compliance with direct HSM and TPM integration without complex TLS state-machines. +- **End-to-End Non-Blocking Architecture:** Features non-blocking execution primitives across all protocol layers. This design integrates seamlessly with Linux Kernel 7.0 AccECN (Accurate ECN) to optimize TCP retransmission timeouts (RTO) and low-latency feedback loops. +- **Near-Kernel Latency & Zero HoL Blocking**: Inherently eliminates head-of-line (HoL) blocking over a single socket connection. By deploying hybridized io_uring and epoll I/O frameworks, NLAP achieves deterministic processing speeds that mirror kernel-level transport latencies. -- **Unit Tests**: Core component validation (`/test/unit/`) -- **Integration Tests**: End-to-end functionality (`/test/integration/`) -- **Performance Tests**: Benchmarking and optimization (`/test/performance/`) -- **Evaluation Tests**: Protocol compliance (`/test/eval/`) +# 4. Achievements -See [test documentation](/test/README.md) for detailed testing procedures. - ---- +The technical progression and current state of the NLAP implementation comprise the following structural phases and components: -## :gear: Technical Architecture +1. **Protocol Paradigm Validation:** Analytical evaluation of HTTP/1.1 pipeline extensions resulted in the complete deprecation of stream-oriented processing for the FalconAS architecture in favor of a transactional framework. +2. **I/O Subsystem Evaluation:** Systematic review of synchronous Berkeley Sockets and multi-threaded processing layouts identified critical architectural bottlenecks, leading to the rejection of traditional multi-threading paradigms. +3. **Reference Socket Specification:** Formulated and published a verified, non-blocking, and deterministic Berkeley Sockets blueprint on *Der IT Prüfer* ([Technical Insight](https://der-it-pruefer.de)). +4. **Cross-Platform Verification:** Demonstrated the portability of the socket layer by adapting the core FalconAS network-handling runtime to resource-constrained environments, utilizing the ESP32-S3 microcontroller as a reference platform. +5. **C++23 Parsing Library:** Engineered a specialized, performance- and heap-optimized C++23 validation library for low-level HTTP/1.1 parsing and message generation. +6. **Architectural Refactoring:** Executed a comprehensive code-base refactoring based on the empirical performance metrics gathered from the initial reference implementations. +7. **Schema Implementation:** Developed the comprehensive structural boundaries for all NLAP protocol subtypes, formalized through complete Document Type Definitions (DTD) and YANG modeling layouts compiled with AI assistance. +8. **Zero-Copy XML Parsing Engine:** Implemented a memory-optimized XML parsing layer utilizing C++23 features (`std::generator`) and non-allocating string views (`std::string_view`) to minimize data-handling overhead, developed with AI assistance. -### Process Model +# 5. Working Components -```text -+----------------+---------------+---------------+----------------+ -| Server Process | AS Process 1 | AS Process x | Result Process | -| | Python Interp.| Python Interp.| | -+-----------------------------------------------------------------+ -| Shared Memory | -| - StaticFS Requests | -| - AS Metadata | -| - AS Requests | -| - AS Results | -+-----------------------------------------------------------------+ -``` +Below is a brief overview of the currently functional and production-ready components: -**Design Principles:** -- **Process-Based**: Separate processes avoid Python GIL limitations -- **Shared Memory**: High-performance IPC with atomic locks (kernel mutex-less) -- **Huge Pages**: Memory optimization for better performance +- **Memory (heap)-optimized HTTP/1.1 library:** Features a fast parser and message generator (`/lib/http/`). +- **Microcontroller portability:** The HTTP/1.1 parser library is fully ported to the ESP-IDF based ESP32-S3 and ESP32-C3 platforms (`/ports/arduino/`). +- **Structural specifications:** Includes core XML and workflow schemas formalized via DTD and YANG models (`/specs/`). +- **Optimized XML processing:** A memory-optimized Apache Xerces-based parser tailored for NLAP validation and message processing. -### Performance Philosophy: Epoll vs Coroutines +# 6. Milestones -**⚠️ Coroutine Warning**: While trending, coroutines can be **counterproductive** for scalability if implemented incorrectly. +The following developments are scheduled for immediate implementation: -**The Problem with incorrectly implemented Coroutines:** -- In case a single connection awaits a syscall `read()` result -- Its similar to one `poll()` for a single connection file descriptor -- 10,000 connections = 10,000 syscalls (context switches) -- Massive overhead for checking received data (unscalable) - -**Our Epoll Advantage:** -- **Single syscall** informs about multiple FDs with pending data -- Used by nginx and other high-performance servers - ---- - -## :page_with_curl: Documentation - -### Official Documentation -- **Build Instructions**: [BUILD.md](BUILD.md) -- **Testing Guide**: [test/README.md](/test/README.md) -- **Technical Specifications**: [specs/md/README.md](/specs/md/README.md) -- **Feature Comparison**: [FEATURE-MATRIX.md](FEATURE-MATRIX.md) -- **Sphinx Rendered**: [Detailed Sphinx](https://docs.webcodex.de/developer/falconas/sphinx/index.html) -- **Doxygen Rendered**: [Doxygen - UML relations](https://docs.webcodex.de/developer/falconas/doxygen/index.html) - -### Online Resources -- **CI Documentation**: [/doc/README.md](/doc/README.md) -- **RFP/RFC Specs**: [http://docs.webcodex.de/wacp/rfp/](http://docs.webcodex.de/wacp/rfp/) -- **Detailed Analysis**: [Der IT Prüfer](http://der-it-pruefer.de) - -### Protocol Specifications -- **NLAP XML Specs**: See [/specs/xml/](/specs/xml/) for detailed protocol documentation - - [NLAFP (Next Level Application File Protocol)](/specs/xml/NLAFP-XML-SPECS.md) - - [NLAMP (Next Level Application Metadata Protocol)](/specs/xml/NLAMP-XML-SPECS.md) -- **Internal Libraries**: [lib/README.md](lib/README.md) - ---- +- **Kernel I/O Integration:** Adaptation of Linux `io_uring` (for asynchronous zero-copy receiving and sending) and `epoll` (restricted to transmission operations), adhering to the architectures validated in sections 4.2, 4.3, and 4.4. +- **NLAMP Prototype:** Initial development of the Application Server Metadata ("M") prototype, featuring process-based Shared Memory (SHM) isolation within *FalconAS*. +- **NLAFP Prototype:** Initial development of the File-Transport ("F") prototype, utilizing high-speed, direct user-space I/O. +- **NLAPS Integration:** Full architectural implementation of the ("S") Security Extensions layer. -## :globe_with_meridians: Community & Support +# 7. NLAP Subtypes -### Get Help & Discuss -- **Issues**: [GitHub Issues](https://github.com/WEBcodeX1/http-1.2/issues) - Bug reports and feature requests -- **Email**: [http1-2@webcodex.de](mailto:http1-2@webcodex.de) - Questions and improvement ideas -- **Security**: [SECURITY.md](SECURITY.md) - Security vulnerability reporting +Each NLAP sub-protocol operates on a dedicated TCP port and is structured as follows: -### Stay Updated -- **Documentation**: [Official Docs](http://docs.webcodex.de/wacp/rfp/) -- **RFC Updates**: [Der IT Prüfer](http://der-it-pruefer.de) - Detailed protocol analysis - ---- - -## :wave: Contributing - -We welcome contributions! Whether you're: -- 🐛 **Reporting bugs** -- 💡 **Suggesting features** -- 📝 **Improving documentation** -- 🔧 **Submitting code** - -Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. - -**Code Quality Standards:** -- Clean, readable, maintainable code -- Comprehensive testing -- Security-conscious development -- Commit signing with GPG/SSH keys - ---- - -## :alarm_clock: Future Milestones - -### Short-term Goals -- [x] **HTTP/1.1 Compatibility**: Minimal SPA related features -- [x] **x0 Framework Integration**: Seamless SPA framework compatibility -- [ ] **NLAP Protocol Implementation**: Complete NLAFP and NLAMP implementation -- [ ] **NLAP Client Library**: Reference implementation for clients -- [ ] **Performance Benchmarks**: Comprehensive HTTP/1.1, HTTP/2, HTTP/3, and NLAP comparisons - -### Long-term Vision -- [ ] **Protocol Standardization**: Submit NLAP as official RFC -- [ ] **Enterprise Features**: Advanced monitoring, analytics, management -- [ ] **Proxy Server Component**: Complete the load balancing/reverse proxy module -- [ ] **NLAP Browser Support**: Native NLAP support in modern browsers - -See [GitHub Milestones](https://github.com/WEBcodeX1/http-1.2/milestones) for detailed roadmap. - ---- - -## :memo: License - -**GNU Affero General Public License v3.0** - See [LICENSE](LICENSE) for details. - ---- +- **NLAFP:** File-transport operations. +- **NLAMP:** Application server Metadata (JSON) exchange. +- **NLAPP:** Upcoming Proxy Server implementation, featuring auto-scaling and multi-endpoint support. +- **NLAPS:** Security Extensions, handling cryptographic signing, encryption, and authentication. -

- 🚀 Ready to experience the future of web protocols?
- Made with ❤️ by Claus Prüfer / clickIT / WEBcodeX -

+Detailed specifications for each sub-protocol are available in the `/specs` directory. From 353beb4366547e730c15e9ce08bfd958c929ffca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 14:11:14 +0200 Subject: [PATCH 02/18] Add falcon-as logo proposals --- image/falconas-logo.png | Bin 0 -> 48703 bytes image/falconas-logo.xcf | Bin 0 -> 85962 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 image/falconas-logo.png create mode 100644 image/falconas-logo.xcf diff --git a/image/falconas-logo.png b/image/falconas-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a0fe2d3edd8b432be5354760a6f9dc0faaab9f69 GIT binary patch literal 48703 zcmZ5{1ymf}(k&9)B{;#|-QAr4!QI{6-5r8^kl+vocL?t8?(ROooBO|a@BQ9CYt5YQ zp0%b=pHo$P*RGlk=WFi0Ti7yt_m`lJ!1vH%U>E-F%@;435a z0icsF79t8FU|{tL2tXq!&^fV*w2A^4m^URDSYRj^*emE#;4v7O8#5T#sUa8`Zw43` zwqs7)cYe?p(8h97;-C@qdJ${?*RR1jN^7}*fg%6>*BksN9Wp-XB8;nyf&|PdED{_O zecBg$EznKCWW+_(JXg;f8@p-$l5#V62Kla{gj#}zt`sPCspQ(=PaE)dZw;TKJHzsS(S2^{WkUr6k zO~YU>0qh*7d{XdN&zgdf58RrMLmmcKQLN%Fh0rQlFgoG5jwb>OLfwzp&{Z%UQ}*>= zfOjOKx;7k#JBg)MEF0ok+E`d;Vx!W7$^{bhBw?b3%G8+fpkY}E(C_79g|4Ln9c^z_ zGFu`doaI^qOL1-IV82++x?O-s_UH$pnz4$$!%Gz+guVG$g_lg49E8~M^JhW&>>FCr zkG~&vJ(3M__vu{!2%Sv^vYb1FJ;cSMU_;6i6+5N;hO-cVO)c(Ia zg9fSm?dAm$73ioRXuo4a#JeNKZQ)XUQ*t4`i<8=u%{Z{uWlNG+Q;GrAGpJN?tONMD@hI_aY|~HCvfrv(HGKcL1YaN>TMN2yN3@?I;*x9HPpi#=sKsuDiHi2p=0ElpRjk^svqfLn}7HI&tBOXqbIT zFmpd?hG$6(q-1}9R{6hc40=+Sxc(aM*!HbKg&$~=EV6rw%T%&=mWj^I}6 zMywD>4qeRvWf#hlZ-st+OsJhJ2(gMEc@{Tql(2OD5nB~AUO~)=Rk=yxu5Mjz&UV;% zTu02X-*k2Ys4Fd497fl0MbDd8I(Hzk-ji9!OSbFhao%Xfa9HLUyZ^J>+{5C8n`>j& z5n)3p#A=4_J&HAnkGrFWdZ^}mBB8Hp!_)6bs}yN(g%J#RiQzu@NMPV3V5KlJNJHu`h0iMeYF5n1P9(TrrI9O zn|%EeOA$(H^!fi~YyY$HyW3>Q9%&zu3J|lu@`?eQ8$Z9a9qEJ{jv1DLndp!fGhd|U zAEL#~Bk4|O`YL@9XNB#q!bYP!VvC?RoZKgpDFe#f@WM!afw~`4G=Quf6W4tIW;GJ( zXkun7=^meZ0o0z9Z8>0op#M5ce{UDQHOWcV86%71bBfQU`T?n+%J}||smw5ZjX*5? z(+6ivQyrG|W87PqRRDK69H24$QFSMZ!#b@)t!%|f4;!M>C9@1)yPRHVTEzp^jaVqz zf2y1C<}Iub7IW@5Yp8V%w-D+47B-@TYQI@6-bt0yn{#9kiu$UD`Zj3M(84ZUr6Ug* zViWdUvao;zha*J_A^T48@;@HfN4BSrV^j^T>VqiGyghG%&>vJ@8ujU+ld|PkQ zS<3}9w%h)#0CXf&4|9Fsv##W_w-l_IdZr|;fRhrrSUoTO()0^QwvsQkG_#Bnmcp0& zDyh7{c&!zSd%-}-%1j{Up5}(=$$A!*G#H@3g0o{wotyb+7DytD*L98irPwSPmg4s7 zzt?5pGh@3sb$(WRR`$-mtxkFpt4=J=VBYO=*n^W;UJD{SYfY=(nyQ*%k_aGXN0Zu5 zst+4Tm31(EYQ|C*W5VgKlLr@ zoUZ0zZ;Eqz@e;Y7#EzNvSrpEc+HE9gYTSN#1&b3pA+a+(m+wZGnYK{82Lwnc<)MjLUJEeaZ~``J)Zse4>L^tp958{BFr z3ar>kS76oc2m3=GsZGEabJ%{n5>#-#Bt2&HFI$Uia#x{nMvwhZ@rhxbV&QOwiGxE; zXW8|@f>>gTpyNIl+W#8v4E6Jbu{7T9U`Uf6%g@<<{WIRnyty6IARp?z6A?;&P{|`_^lWAS+Tz*7Pvz#5;#F;(BUcUC_fKU6Z z?@Z&cwqTE?UF~+Fa4KspV5$)kv#_MCur*|I@@F-7)oh^x2Wy|0^M2Vshi4Wn*@WNC8$d;dClT zt21(OyWAt%Yq#8ihM^J#-3eI%^}w;t$VAY7W3_RMQK#K&YE{-B!3Cnv5e{nHK$fnP zak=&ud@vNE?=r&*Jq`{cEN&kO^^kO%0If+pker$&q}<5Lh!hpe0Kc2;-3rkzmJn+T z-F*btEJNyl0O)^wDjG6&@3Q@>>+O0&KU__?Px2Z=v^0Elm8foxmV|>NsQ63n8_|~R zWK$<1ZjP+EB>c>GJn6_Nr^F1@{->=2)$g?p47Ev`c$v&iLN_-o&$`!P)0URDJDp)? z8P4a1=orQ!9{Z5)ULik>s6G6;>9MgS(diEGtTsH`MH=pq6ZJAXCvp7GSYWxV`dCW^ zr`hzO+XZoqdH5-y%>rk{A}1RSv36!14W=Hu5HH&S$P&z(`i3)I0}Tj;^Z$TzYp8$% z>6GOm*BD|WtW0+bVfvV!CJvFS&GKWyM*jAK*!77wX@#IJKOb~#A|&+L*%T}Lilc0Y z%HwInrAcUSavofkA`~a5nUBjem0KX44K6=(<~d2{3_F@ApUxF83=S1+Bc#1cVO>M2 zrVn(6$tFYcJ&b`N8_Z#stjVl^YTCedG+ghk)^aKqs`{>=A%9p2c2M2TD_6{Wpo4ZO z4vs|I&xR1#9e2_YS_SIf|8l>0m0kzMuT)iyC5_ML!Q1KRyu9nF8l31D7sR85FH><* zF_Z!VLA!bq^sDpZgAZoxTY($F*`H{udJ(n@ls52t#mi!GM6ODk=y(f62Czog92 z2r_lh8pdxLPiG_xHe6)>b=H zz#BnO9v7}Bl6AdH2U9X|Vkp@| zQHvksMI$-YtEo#07Duus8r8n0GkZEJ&CVuE%f^eHPSERV1<6Ica^_ZNkB*$;57Zg? zMMmEORMpk{?;I}7gqd>T_F#6VdCz8XB?=Me`+6U?7>sd4Ytc+v+D0N#wc}y}Jw4at z5T9T>a_brpmc2(}LN#$l-R}b`07{ zsT=aqf&bbJwdW{tg0Itol&1vd>=p-53;` zslNI;#l`gL9U$UojR$_5wCFJ|RU z73j#Tf~wo(L>H3I3N6nuq|o&RPRb)}b>n>0+g8<{n7~{=G-K)Wsaq)->Aeip#Ly}3 z$6UC#jzQ!(FNk*Z;IzlYf~c>u*Z%>&=ufC#B4U5Bb9DqGXW?{77Mr~_2lP6@B&@Fo z1p(?x>x3NqZ?E6fYgXk%JF+)BRZo5<$tI{R18PDmC=*x;0gDr_4+rFfP0aSb0nSaB zs=5dF2rYf^R6foK8Qg*?{(iH|0Gj--I(Q=!<;IKmf{4fY<}~M3p}$bEqK>LrFV_Yl zvj>@po$_}4yQU)p<-{}KVJKS}N#Ux>?lMu$Wf;X)*?kvdQP~JQeXP)LNUt**Z+eUL z&_pJ|0@fs%FhwKGHF3mKw>AC)i&E9w*rL$U>TgI}+vn#+bEd>qy(P%Z;*S}!|nK1<)H3%-rwqzjenz;nTk0zU6_e^MN8UT@bibx z>2iGuY@ECKB+kgPt;lzOq=gCn2q&aPJBOm8)hJbL|K4*K>@BV7@XFRKKrE(uZFQ-F zY&5(MZfXgOyLXYlq&q;A`ycuPv~NW9BcmetOSIh*_lhLxBLSxxPfiDf^nx z_guuzM%qZEp}NhCJkid*2?1+# z{cm2`_P?@CmN<@Q$b!xbX)w>Jjg>M}ifF0i)YWFyR7Vn~^8cP=yw0d=OiTv5J9M-2 zuJ>W~Tv*MN^dEMZ-#*Q&sMnHF0JsaQYm(sh*iIJc7DTt9=#CO)u0`!fU|w$#jK*t; z7{j^|X&&R6>oB`!A9X~aA&jtg($?NG+}Fh9n@$oViAy*Chz2Q;itg2P)o!VTYkHI3 zy8Z8IbG>z7_6EyA+f|28hJV9+v!4x}V7LIK6l9c?(Z@Iu-D(E4v6!!qaTE?VGy@#= zx+;I%ED$8x#Sl>`bs23er>?)W<+v#>G@Ng-R+&)1uGF7?1 zY{GiH#5BRH+5uR8+02jg3Mmx!d_QR~rZWqDf-{Ll7~WG0RkvqF@BHAzI}Y(j}~ zGj$$?b!A3fBo(q0fJfL1guQ766QqgLm%Oe8ZhzqM)DniOt#h>jIn zA%2^W0f*duIltQgzLyiGVqwkB%!q;_(%v8v`Q*&->x3J(0RFpci;=26okV*~CVL?Y zRW5t-$BBKDLv2~B7*6OfVb}@LX*hQ9uW`KEK7>Q^r%KMU9T$h5Wg#E}aG&`{N@R5(0}z zR3~e1`IxBuPnyygY)}M)z0jaAOVr^;lu^0$?6;#NW??_MGd(;yYB*dV{&+#N(|>iQ z1t<<(uMSiDu`t{2fpS`bPebqF4*#8GS@qC#uMHi2Z#~C<^$TU30;N!G@Tg?7Ssd@@ zXD8pHil~zle&?JUh}=ur%BPx{Ki8bP8ez_+c_D@xbx1symdLc?^HYl}6STw1;-e}C z!QeT^7HQy_s}PsmZ_Tj^1!(BPB5JR3Iu!j_4vt*ULRHfv$svJi?Ef!wL}nC~r9sKw zPQNt#{sCz`G11<|8Vc*e>(-^!kr^P+nas4rzLShsKNB1)4l{8vJzW8#d;S)no4Q}6 zCD8JyK{dU)*t_OXyO%=IIN$6=UVd*zf>?3Fm?RDTIPZBgl9DN4!#?vp%Wcr3fv#nT zr|SN9K)M!mT5kivx6j88L@r;FF5I9$rEKzKj+2lvV6x!$&GD${3ZA$4$0~oC>$3d) zyitj;zXpwntv>cD_QMEdmE-C_iex0hL|I*S*i(y2cUy#C5h%>f<4gaSLb4+}Aa?(t zVHc%gZJ2BE!wZPXu?2scWA7~p%9JO_A1T;WPTi9B%2ia2DBk$$TJqUng5Z3sz0zjI zv^P}hG`pU3e^p&?^Q+(FU57rsqcamcc|*4sJL=2 zozGgQ#Lnn=0q0guhFX0oiK>)qrzf) z7?~x(8a3bKp1PjU>$l~$WLUDYse(~cR~dh_f$|fkP{48_Wx;MPrsNH+T`c%Ayj}x=?U`e}>x(^YC0s(r=rjs+CpYolC#*JeCaALqy6|y{Q_Y z`sxPy#Cgb-pQK)2o`3@4IUNp95fckbe2vBalNkUz>9^dJ^t0~A#K?6Uw-t^xq2&Bk zpmS8I4IbW_r^61kii$BVCxA=(+5W{njh=4%Z>HGDxHJovNFeGU=2)Wtl|a8YzIbAZ z5ODcRjK9%W{p~5Af`0>M1V>@v2#{FRHBBy0jn7#1jIz&cCWM|D;GYBGYXu!_4DQ#nJAs1&>GM;3m*C{@L8 z6T>9mZMW1V^kU+vOm};T2+9a368; z*x5#vfku4guP7d>c+Mt0L@Ib_+| zdSUl82*lw;qQYxzXvpZgQDjS+RfV;KG#Ar0No`!ag6jT>QU;3q)1R@zbzX94Pl8>! zv1-^Bd7SZWZRS`V-C+~03OSq}U}6#Xte&hHOA*AZSJ1TNb*y-bLWOBd^vVKQ1#!}w1I^tP$m zqM`)9hD_1u@H86=SaP#7 z_;T`CSr6IUlGgtYC6vYuGU_Rg4~d0_D4UyjBdR%Cc!5I1ClFKb&g*y{)o#LMM>`6f zQ^b@0;f7J$)ftn8mCK{bmci~sJTs#W>t?6XNup~28RjW&51h3PLW_j0QqCG+f8`hZ zhs^dH6F8eVwaMg1?^`AzJ%blz39sfOxKRoxVk}Cq((k=vU2eM9M48jJ^sWyp&ThN1 z(3gfZ(88;o$?FDtl*f_mDFqn@H38s;yxPHV6osw8cT=ySk!a##^?8InoII7%62X=D z$#|vumJ77HOeD9wh$UJ|xYF34Df3X;HU1@Lo{rLF6sh=wmXuo0qRcnMeY~WXpRB53 zDQ0-E8&DO$w5d5YI}yjeG@q3AZDI|kHoE1UcRKMCX7pnNwUpo^q4$8n=`d# z87CViL77=fxsz#K8h7s#ZLgJMm`vA9%t)Rz{)JQMSDBLi&F@13tsN49GO`BuL+hm1-}7t z$jx>4@|G^LoR^m5Ol6UKWsiH~Y?4XmmPIXfVc|`R8omlW@txH}gK&3xBomoc(MhCT@3Nr^@Bd`TKVnmFv7hB%~%GfhM#+<8@l&g}8?r3@yCk ze+y)cNJm>woW&|ASdacN-gW%uOphf4JY7Jrk&&p_ZyVUFm0ArYXijuX;>s%p zcMHkzSvCUp9}VV6M!;*&(WeC!^>Q+TzS-jMnkT#217V0G(YyO8gUs&Y=svf!G_`JI z>_MpL77f`+Vqe&la3(pLYfCLXNUQ`*ju+^DE@%8keOCsH&N-H zv?*z}n}PBPuB~nhSEr@Rj*NG{KG0b6JoshIPOfsQ#&LQq7!sI@cv?NvAVoUHHD81v z?J7Mf;KLpz<76pH?0bVs(uqyqG&g|4`~~*cZxnWBnf|)$N(ETeQ^?9h@c%`>{aB@U zN3=Iv8E7HhRo=fpZ}uGrvC5F;w53qq2@8wxf-9ygM$9QVJ41*?m`|(e4KC(ZA9wlS z)h>O}ac}%%bRoE2qh6{=I0_0jq`foJA|h-Iik%Jq?Lw0})2E>i_?4Cwm1eIuV%#qJ zoD7YU580Xj?gjX{kKMeNOiYNrvN*0~5!<_>Jb+K6k=W3h5g$(pjVw(@Ln9cw+!SNP zRXTy9c#55>W{^>|T2e?#B;KXU2-U`@)xepLZJDXtnSmP%rCy5t z|1Ax}b4e;z-)QqM`7f@A zb@j3vrXzMEaMe0k?p1p%-PSJM$wXQo7N30q4#9=8b69IT~c79g&uDR_DPlA*YOzBmmQ3B`2%A`SLX|0oNZrb$a8(rKHNa_DKe3uJW6Px_tLc6$Pz=@rv!o>1r7d)0^$; z_?x_DpkfKxuIujQmMDZ;_bCK57Y%(Tg&gqv6}a+BDQ{3GeLVD-PA$Hp(U_Svnkx7o zz%;V>snPd0q#SQCMaf{iu^4+2Nyd+pQc`Lo)rod$AfvACba+|F@FlR`!cu}76UJ&{ zc+l3<5LpR?MRhT$rf`RH1F}TqQzzqhk*C~ilybFJCHULtwPOe0;g)968-hy-hPokUEmh+>{W`qo#88bt+x$ms_Nv5fSz4HBTMvs(L4;=qR`X4Er)L zyCVXp$!$EE9N+xTTAx0qG~4}|6wB=ELm0$jlV0A`Uobk_C;N_K>{)*g4^uT&Zw$Z? zIhgr$VFVQv>mTJ$*;*{sIM;N$LpM-TW~`=QE*%p?m5(4#^`$1_K;c^5SQ-l*39a{W zCn^jFS|=_pfJ4E|f4gaZ>n`csDBtXZ59>=4crhax5bW8Tx+o|q(L+iTE#xk)8n!!X zRH|sbdVyekoq(szeH66Fdm<$Y_@n;r_e+_882Jn<&naE|b?>2&4YrF;ML{!KQ%5dj zhkVP+sUG<-hdb}loeD*$DcVeDH4$0NGDzh9O>Q0zoO?QSFpt*LUxX(nUBmf6Vnx?` z#5JC;CRIsjZL-MBEtS&}wwev8a1QFqU$y_S@2#KYR4i~f~&Pfh0b)TIziE@YK)kVdw zPRdI=cMC{Q8-yP_YEaZNbkt02>c0-T?=H`t1)%yF$i4Rf5&i0_f~LBcd%TVmRUH~2 z|N5c$O55vKAJhj3JYuM*qAw8B#8am+O(FP9Zd!BcG+{Ze1JJB{Fi!=lxT}2I%YQlq zJP>yCGo|}n^2P}Ic~@}ME_Uojeg#U-F!;SSlT!NxSPn3XMf=mi**2bCorDl`4)$8z zQKlrK4!xuJ4K<(X^pJ@D7B%7Fk7DF-mRkqD1nExdejhi(PS`s&7&pAkVby}ZNlQTirjY>b%Mse+T3B&Ar7KT&sfnH*e_oxSq-Rs#H3 zGShYZs7J(K#h*a4&Izq1PTTZ{{UzIoCn*NOTU_=hu=PHtrhl`~y66|X`{552l?!<0 zO;|&Zu*o|nyX`~#vb&hd!Mdm3iFrWFd-K?e{zOy*ObUUHMB|!-N{6Jm`6-Hy<<9vR z(pz)U@C}_W4=_jvB9WZW8y9q$PJPm>tSSrm7hrX@ElHog`X*lIaC#NsDg@uTa~VJ0 zcbg(7_3qtjK((NUZ|bi2`oMzZ&akWN#k2IJw6v`BBKiY}rP5{AtHg`)NTa;8S|t(`n(j zbk%^HR_q_IGxIL7U(_89pQGORb;QP--$B@yuWGq zwv(qXs#`>g)H^GngS_zi$IPr|n&gzAbf4TI`0TJ=a^ z9{uKgpImK~*?eRdaHlP4Q&BpUa;2_1C{F-gS_$n~B{`WIRMV1g@kJ83qpgbsLnVRo zUk(IsAC3pBlrB&hxPme=%jOk6uXew?tsI+QlP^^MlGM-{xxh!}vhX?7;A3fN`8}jm znYs`t7#8I~dVT@ofTCeHYAydHRhGMCB5 z^6exUnuMw|dFgs5;o*uvTLCuOnt~}nt@p~|GhRt>>K$7qvu(rY|Y!oQpfEe{3spX%+nk^HA7c& zVffO%>35x_zRFs^q3rzB+x1{S;KAkqz=ON>u1RYhIQJ2IUg`CAh_;WAzIb@v(FMov^06T)N?F3rD*OiYqa<9l;a|^AX&7gd zM2RstLd8g@<&C$N`GV#tUViWf_&B4`si(WFP?)p;Z>@5;+oL_OY!CVeCL(brYA@t$ z)_q@BIQ?BV_!aXrhmR_=rU~*Mi<@I}Q;AE!^y(V=1|9-dr1kYFH1q|-oJ?LZF!qR( zw_VTb;psyxdAy;qKbttQ4H#GZvahgaXGzdRE&RGtbUxeC3=CK@T3w`=UzR^Q-Y2m( z-%7#Jpt4FEw%4p*pSFfOR6#wFo8$QT8o`V-H04I4^?on=DR_S(9*Idv2H9)SaJ-6n zXvo7K$mFM(g5?R&jXeEvaXy%;;=VWiM1d-mhQr-#Ya{~hB{_KQtk6Y9JOAd&7A-7j zZHa?$Qw=U%}g80VdQFT zR8UjrWDV$5*Z-`dG}U4107RFohF6OGppIt;RSc!zj_-UKtMuj> zu4pgb_P)A<8X$%Uxq^-QUsbd=W&=>hhvO%4w)MoeUu5uzC>Z*KU5B z*C1i<*8Hk}6jJfmCtzx!(g)kH1Q%lW_aLoGzdbuZ zur-LVL{Ui^`rA@cg?VnbPSR>`Y z&UASp08~q8z+-$fN4PswP;uZ46YU*Tcv0i@n8-ce(RgwiyTTtHmi`XunK&{m{i9W5 ze)-!1s4zOX-P_rp=ds!$quc6=e^>Los(;N?wIB4Bb-Y3*gH$EzL=N`>_Cj_(dYyS- zb;KgFy;)hOrqQR~Hv;RXkt&v$LolVWWov%%$|{MZWC08n$#I?aTwT>Juc|7uG+>~h zKuXmBsOWDh_I9bm)9JA{`Z#QFSTBB=ZObyl2NcMmME7iv)-iPd3(>! zx8YCxtt1zUU~a#d2jxwBwqn6W;ni|$dst`-wF)%CpVtTRxpUp;5S6R!anVu-1YC1B zO_Wq-+ZmW*XyzQoFX}Z^P5m^;vr{wG9*icd0Hb^Ezul<0irDQ>srB}Hf~|bCD>~CX z;ni`7OplBmq_Iq80C@3h9wem%4 zHP;086?wZKaV0l2WU};Q;Ib1ZMPa-$yUSyl3?hR1vFy9A_T0}vej&O!snT?in$%pG zHv5Ou{nF0Fa0}=4A&Sh$68@LegYk0RW-LD6b>yd(bL%=Lrdpku4O(_{s*VzyEvflMk^+>75jzpXtO|8mpVN8jI{M<8M4v)iGf0`J*+#=Oav?r5##U_D^U z7DOvABeOoq%r?GNJk2BtN_}DkZ?!bg2b=n}%-WC^FedfGc(=!cpWo`{~lCSf8*H!#p>J5_D8@T%Q( z~SuDd+;xV2-%gpU`}JD^+5<*^vMWNGx8y@O-ir zd>;2RiG6Bk3b3K5u%OWCakGrj4pL$cD(Do6DJU3I!>>+@z5I8iMZU`*P4TzKGA#m# z0g5vWaV}?s`=?kVs>-NvL#Kx1CjGR*6Jgx1vg7SHROg>|1H`I@%{(~pO% zYCvLKUJm7(NB!_Pl{I|B~S z54qXr30oeBLZ2%HYkQz*ET8#~?o+vuHpGSjb%tdiqOJ}NO0awzf8U|R+O1uj{p^02 zltq6hp>$j+VRPaJ{5nnV>&=*3ZKGrze}5b5CvsW)#mA7)d2_7B z*lBu5qF1@`v!Vj}%oL zt;q>p4gh`&2RAxfJ1FZQ2r%d}zLq-_jF#=8IcY`3x{gcX?g*6m$(%H&i`qMK*^fV}`ucagAz`qLbPnO{=q2M3M7i>v&b z@%96(t2*B2HsoO{8grTipcw=R*khKL$%Xpdrc^E6zw4Fav$V4}n+@IUcyc2I z$?C<|?d4;EeOG*6glvaPWWL;(c7b;sT#@ zdQ;Pynf>LV1$@Y}z0J7NIUBz)pr3^KpE}YCG3N=X4EaWpeC~?W)Hv@6=Vp+`6<{u?mk9DVh9J# zZ!GKY?%r`}Qh zq3vwS(&Lc%vxF8d*7*vk-;>_76fQvXmm`;Tk~UQs&!*CAAPbCjHo4{Y78m$B`|(!_ zAyiDv63%Ac{s>U~%_OW-^U@CmESrHA%rM1b5j?!~6sayZmUpYVQn95yc$+^__WSqjttY5Z^t9n(JuGCt>FENBBDc5N_FX=|E*drR^G7l* zab{9XXFMrhgOu~(TT0h?|!~K^n%^JU`AqOx^an2nO~nMVc_uE z`%c4HzGJcEi<7j>bqk7j{CDR|QsX{!w4=T2dlxQDuC6WZ>xU6U)hBzNMYiQwQ>0|D`g*7ci7iUw;6BYmH;JI63EFR3ftjJ#q(TvPM zIK3PCN0Ms|9{NY?Cad=^yu4C~M z&9Cq625ADrBP|QaJl>$h*rb?!Y74Wbd7ZLm&wBjbfoB1A` zag0MCdR=LdGhUwpqpGPU=O;#1mdBb#$QLc682=9Lvb6x_jjM%WEaY(UfSCkiiAzNx zant^pJ?3)NY4;-cQH0P;lxn-in4Zmd^%@D%L+(OWwb~kg#?)j?0Y7z3Tif}JfQET3 zCiGkzHiQwtp$L!by*nxxt&q>RN7^wxxxiwa-uzE)r5~)^h%UTNeTHkf*+ZMuJ4_zz zDOt%lf8MLtqHPoOyjHlyo~H^yupHOdC#(Nfyt>HDYFRL(?0G9g)_OJ~kaqO`bOEY6 zP0mB^E_S(iuq}N)j=i@%#t(V0nBQwp@_DSHd4LRP^e11-e(6u4mRwMft!e%6+w^%W zYpSWv52z0U-4_&N^qbp5()C~Bb^HU=o8Mn(m}>WS^BGO$lI{Wl9w6JRyPPwnRKRQ7 zvI8C-Drq&hn{?N7J`@rHk2^;6R(S+;rD;~`8fP9oot>9-yXfffTW%8Q;-6oxF5d-H zuYQqv#eYOVb%*)GpO6uLf4vL2hCc0Rtc3}IdDtDqS1f9LkkkLDgJ`y|YNtf)J3GFd zI<66+N2Rm!=-Yj$29=&+<4I>RIG~@R3In<|y)8i1g}k1g4}nN$OF$!!6E{JQ)2p<; zSNkl}GvD3|+@YLG>hFS*z5g?h?Nzg%_5f5)*V#Z zQO)McB!-fIf5?-8B@KPe>j}N!Gx-)L<5??q+D(t2&`p4zvU2Yg(X#zoGd2;==4|eL zK&}`|SyYtMy7N1%z29(~yso`H%a8&-+Mj%b0F&-Bemm<&Balr+eWkk)pk(Yet=eK{ z^*9+!NiV z=jRRnMiUs3Rw}M9&&|15=(u(IdGQk9O`c#=lP6|vZQT5};>4@B?z3fK6!tgFMU}^1 z+rYSp&~~DHzx7G%msLOB%NO!X0@`*mFRXtaw#z0LJMwlPa8g^ED@e$nJ)s>lh z@Yw!LGottAbC_w-9pf3>b_eu0@&^@4W|H`&WUt>?52Zl)=u@Q|+6-4emuW{krQz_l zynTle=LCbn&7#Ib&@c28^MTq+xw)3GV6pnI5t-N;-oR-8`B1_kZh5tZMj} zC@|9(Z|+@UwCexhr0eXu%jq&Ixq<1Wx2&V5>ukIGj6SrwPM4Gc^HRT!Ri~myg{MN$ zQ1IflG0v34r}DPV^BCz8XndY){(-STC%mZ3fJL(})SPOp)Ah<7M2lg8tHX%Awi(fc zp5{Cjb{1}U)N^`4%=4pQIzDKnFN=e^sy(crQ{p##s;G20)aceT_o8R}etqade z;0>g4+P(Q7;97w~QEI_e0!~s``+oCBEtw3ME4vf*k?Unnk|Ei%M)fEP&GXq=w%x!R zMcF;#s+Z8bO=J7E`&kFj+tR~-Z)%CCmT)vz>AWd3MGr>&8lQ)gFI?&}e{7znKQiWy zypWcu_Fx0b#E~9*ms<&y)9H2VCD) z%Drs7FGA1Y+Zzn=SSTT*?|`KL&~fc>Ik-Lf7W?k@Aab8?Xs+o8KTdobLb z@m+?K#%Z(Iua82GzFRbm>O&}hov*5RjEzpcK`H_4u^ zx}L5T7V4GF(140V0Dv4Le>L_K@PM81dFF?{ zCW^xYwO2hp_;= zvy!EzZ_~QOb5aAhJHW9F4wqO1N67ojjTHQv{GoQGd_$iLfvNq^0*{rQj;EmFl9D(Y zaM8Gb_X5CtTeI~6b~EKpMp4Bh!0X7$$ZUt7DIT=t-#2mC+HRtsZ~Sq$3%cn1*7b?F zwqLg*_U1g5+hA8)U2b=pHu&dAUl(7+w)=j)Botm05H*5U*>N2C3wn)S5aGx(#su=AP{^bZ2RzvBTOAbWiEb1j}s zLI=9PjvPrc3go}JHN?svBly4_f0}c*nw6nJuBH@N1`ToX}`rW*oSET1O zs-iL~RXOwXB7&>;VDE$m(sumX5DKMW13>zx*Ys9(--(UurvP~v#$y`i*0c`3TZu6yUn^UXXy1iV)oRmxiX|ux6fwRy0 zx|>RjzTp!cXwHqiRKay4CfS}OQ?IntX8+V!+0uA~M#N|{)X~aFoE?$2GzAe_j~a--)yc-9Er7B)+#k=#tXMfwJ%(Bz~fz%*X=Y zECY8YYj~8F_tn5{g^8`z6QP4E5uE~uC+WMgm&2Km17`~K3sJ9<|IyCyWO9#3>@|UC z^6@d#yX%?3rry2LbZvyuhutC3RpQ$LQe=F5xAv}i0l+PLH5oCFwwS9cp0*)p0(?}e z9>vs_y2-~;b#)xC{daY~9hn>*)b#SMx|lhDqdl|e`^;y&4O3;y2{LG%CEd-I(rz`$ zousrC1qRSvDEcER<6<*5rn0^!TPM9eWNA z0lF{V)5Y>LxJuAb!=)Pevcz>7*?NJBw40r8!WdmwSYIG%4zYT3{o0G#90Lx{^M{oc zzjR@?&DjP2iMDTF7B#h%cS=$b!OBX?v8eKiKNvhBI<#YxH?I6zScm*=9oiZkbYKz1 ztgUH0wgiHVH|z~RSWK)+9A*iWj`;x|Jmz{ko4p?u57+sHJ@3Z!)}H$EEcVZvF?IBh z{+{k&D&{n=RXny>V*3y1CS z1YoGmYcP_+Z-3~_CpKdRy{phe8eE7t+bPkNE_|D9dDT4j90Ly>w;hqlFc6(;Ir;M8 zBp_ddieKs$1gAqe%+{XnWpFojd?8K6(~b&}3~;=gjzUHFQM%1zVTTF;N{wwpgmTR* zN^XUv=G)`0-;PT;DyIF{BFja|9tt{LrGZ1)1_R;37f6-rI|?CGym5Xj4JcKK4^9u#P-C zg*>k*t^B@ed0KA{eF2jzw)dnomg9vx{vhY1sWTIUMO+2!*=_3eekfT62lHLFV6OuM z1X;r5{uT-ayp6R(5gHBbWX)mI)}`??#G3Q>2>M; zpbY593p+iPhR6eA(|jnc2-rU~5NczCYR??4*4==L?iWq5`0jv*z}HPiMaqQ(5rHf= zt%~&?6$d?k$qr2IiU!KH93$-3nP*5|FE}PGt*a(pbfau-QMK8R68$I3kNvcn69{uO z_h_h-9HtE*nb>}lZSetTB|!>i!n^<&2sr!(tl zrX{`!<@XF@`{~v*Dq9Qrmsy;+S z-k#FpzPTAXYq@5edjec!366dFSup%gG;(U0<9Ia3j`F-QkyqXIn9E0J8;7yk zjIz8M8KJQ&nbL%v(4#FyQH=eUcJHJ5wuBaJzK!WaL8fR1v=i+5cTW!$Y!4ZKL}4%> z{mfrDtDKE^oObG}XywPfM~$q8rR@^%4WoI#(F1jaqAgp2O(1)}P$vY6AUS#A=IZG8 z^~|hZXh`6MGqExhX;WjEc)!BV$gC(II$M_`R@d`NBpO9p?2w$ebc-6xI2X-)8IrH7 ziKR%q)+WuYX?Z-g`-}Ou9=a7{a^((HDcGpP`+BO2a!9HRxk}Jy&#pX8*hV8h?N@T0 zGjO$q)}r$v1o(bYtYyIFF`U)%4|l!~YW?H6Luj%lcob^J)@dd1>yozwVu2VH_3ajG zP5HUpZ6KdBy_k=)m~V9JPeZ=4v)Ojc911YxMAOsKVogkbMN$ z6D-QjorikG>GRd_t8Reg22gBv)!O0s4>$Kid?;x{qgxGYNxa>fyw0N^HM_s+$c&i2 zeuTM~e2%A_viz}{k2+&Xt!sH>UR_bq*WdO@x*8*dnV7wQ52o63 zzpCoOqu62D;P|Y*H>uCyGKXHmWfre}zSib}
NFO$u`zA&_Pl`i88 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'+H?i_5VbzR|vRm?^}* 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 N6V&y?pp?Om{{y=O(?|dS literal 0 HcmV?d00001 From a03eeeaab7981af0cd06609477211a195c4e271a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 14:17:33 +0200 Subject: [PATCH 03/18] Fix link to chapter 7 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e1a4444..168d51d 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,8 @@ NLAP as its core transport protocol to minimize execution and scheduling overhea # 2. Project Evolution & History The project was originally conceptualized under the designation `HTTP/1.2`. The initial -objective was to mitigate the limitations of the flawed HTTP/1.1 pipelining specification -by injecting unique UUIDs into individual requests. +objective was to mitigate the limitations of the flawed `HTTP/1.1` pipelining specification +by injecting unique **UUIDs** into individual requests. However, practical implementation demonstrated that this approach introduces severe technical problems. @@ -47,7 +47,7 @@ latency. - **Strict XML Message Framing:** Eliminates stream-parsing ambiguities by processing strictly bounded data packets. This non-streamed approach significantly enhances parsing security, mitigates memory-corruption vectors, and maximizes raw processing performance. - **Formalized Model Descriptions:** Reduces protocol complexity to a bare minimum by enforcing a 100% complete structural and semantic definition via Document Type Definitions (DTD) and YANG modeling schemas. -- **Granular Protocol Sub-typing:** Sub-divides transport traffic into distinct, functional protocol variants to maximize scalability and simplify network firewalls (see chapter ). +- **Granular Protocol Sub-typing:** Sub-divides transport traffic into distinct, functional protocol variants to maximize scalability and simplify network firewalls (see chapter [7. NLAP Subtypes](#nlap-subtypes)). - **Simplified High-Integrity Cryptography**: Drastically reduces cryptographic complexity. Because data is processed as static, complete messages rather than continuous streams, the entire frame is signed and encrypted atomically. This enables hardware-native X.509 standard compliance with direct HSM and TPM integration without complex TLS state-machines. - **End-to-End Non-Blocking Architecture:** Features non-blocking execution primitives across all protocol layers. This design integrates seamlessly with Linux Kernel 7.0 AccECN (Accurate ECN) to optimize TCP retransmission timeouts (RTO) and low-latency feedback loops. - **Near-Kernel Latency & Zero HoL Blocking**: Inherently eliminates head-of-line (HoL) blocking over a single socket connection. By deploying hybridized io_uring and epoll I/O frameworks, NLAP achieves deterministic processing speeds that mirror kernel-level transport latencies. From 1c8c587aaadc324daa198e362047b43b56457261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 14:38:10 +0200 Subject: [PATCH 04/18] Fix external link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 168d51d..f64a650 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ The technical progression and current state of the NLAP implementation comprise 1. **Protocol Paradigm Validation:** Analytical evaluation of HTTP/1.1 pipeline extensions resulted in the complete deprecation of stream-oriented processing for the FalconAS architecture in favor of a transactional framework. 2. **I/O Subsystem Evaluation:** Systematic review of synchronous Berkeley Sockets and multi-threaded processing layouts identified critical architectural bottlenecks, leading to the rejection of traditional multi-threading paradigms. -3. **Reference Socket Specification:** Formulated and published a verified, non-blocking, and deterministic Berkeley Sockets blueprint on *Der IT Prüfer* ([Technical Insight](https://der-it-pruefer.de)). +3. **Reference Socket Specification:** Formulated and published a verified, non-blocking, and deterministic Berkeley Sockets blueprint on *Der IT Prüfer* ([Technical Insight](https://www.der-it-pruefer.de/network/Network-Sockets-Insight)). 4. **Cross-Platform Verification:** Demonstrated the portability of the socket layer by adapting the core FalconAS network-handling runtime to resource-constrained environments, utilizing the ESP32-S3 microcontroller as a reference platform. 5. **C++23 Parsing Library:** Engineered a specialized, performance- and heap-optimized C++23 validation library for low-level HTTP/1.1 parsing and message generation. 6. **Architectural Refactoring:** Executed a comprehensive code-base refactoring based on the empirical performance metrics gathered from the initial reference implementations. From f6adfc9ccaccc5431311fe7b2f20a0a11a098a09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 14:48:36 +0200 Subject: [PATCH 05/18] Remove NLAP session subtype, move yang to own subdir --- specs/xml/NLASP-XML-SPECS.md | 7 ------- specs/xml/README.md | 5 ++--- specs/{xml => yang}/nlap.yang | 0 3 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 specs/xml/NLASP-XML-SPECS.md rename specs/{xml => yang}/nlap.yang (100%) diff --git a/specs/xml/NLASP-XML-SPECS.md b/specs/xml/NLASP-XML-SPECS.md deleted file mode 100644 index 8f299dd..0000000 --- a/specs/xml/NLASP-XML-SPECS.md +++ /dev/null @@ -1,7 +0,0 @@ -# 3. Next Level Application Session Protocol (NLASP) - -## 3.1. Overview - -This specification is currently under development. - -Please refer to the [development status page](https://www.der-it-pruefer.de/network/Exemplary-HTTP-Processing-Protocol-Design) for the latest updates. diff --git a/specs/xml/README.md b/specs/xml/README.md index f10a2e6..434f4c7 100644 --- a/specs/xml/README.md +++ b/specs/xml/README.md @@ -6,9 +6,8 @@ This directory contains XML service metadata specifications for the Next Level A 1. [Next Level Application Metadata Protocol (NLAMP)](./NLAMP-XML-SPECS.md) 2. [Next Level Application File Protocol (NLAFP)](./NLAFP-XML-SPECS.md) -3. [Next Level Application Session Protocol (NLASP)](./NLASP-XML-SPECS.md) -4. [Next Level Application Proxy Protocol (NLAPP)](./NLAPP-XML-SPECS.md) -5. [Next Level Application Protocol Secure Extension (NLAPS)](./NLAPS-XML-SPECS.md) +3. [Next Level Application Proxy Protocol (NLAPP)](./NLAPP-XML-SPECS.md) +4. [Next Level Application Protocol Secure Extension (NLAPS)](./NLAPS-XML-SPECS.md) ## 1.2. Development Status diff --git a/specs/xml/nlap.yang b/specs/yang/nlap.yang similarity index 100% rename from specs/xml/nlap.yang rename to specs/yang/nlap.yang From 579dcaf77909524a715ffa54427e1dafe83cc173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 14:53:48 +0200 Subject: [PATCH 06/18] Fix links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f64a650..04bab63 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Falcon Application Server - NLAP (Next Level Application Protocol) [![CodeQL](https://github.com/WEBcodeX1/http-1.2/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/WEBcodeX1/http-1.2/actions/workflows/github-code-scanning/codeql) [![License](https://img.shields.io/github/license/WEBcodeX1/http-1.2?style=flat)](https://github.com/WEBcodeX1/http-1.2/tree/main/LICENSE) [![Doxygen API](https://img.shields.io/badge/docs-sphinx-blue)](https://docs.webcodex.de/developer/falconas/v0.3/doxygen/index.html) -[![Sphinx Docs](https://img.shields.io/badge/docs-sphinx-blue)](https://docs.webcodex.de/x0/v1.0/) +[![Sphinx Docs](https://img.shields.io/badge/docs-sphinx-blue)](https://docs.webcodex.de/developer/falconas/v0.3/sphinx/index.html) --- @@ -47,7 +47,7 @@ latency. - **Strict XML Message Framing:** Eliminates stream-parsing ambiguities by processing strictly bounded data packets. This non-streamed approach significantly enhances parsing security, mitigates memory-corruption vectors, and maximizes raw processing performance. - **Formalized Model Descriptions:** Reduces protocol complexity to a bare minimum by enforcing a 100% complete structural and semantic definition via Document Type Definitions (DTD) and YANG modeling schemas. -- **Granular Protocol Sub-typing:** Sub-divides transport traffic into distinct, functional protocol variants to maximize scalability and simplify network firewalls (see chapter [7. NLAP Subtypes](#nlap-subtypes)). +- **Granular Protocol Sub-typing:** Sub-divides transport traffic into distinct, functional protocol variants to maximize scalability and simplify network firewalls (see chapter [7. NLAP Subtypes](#7--nlap-subtypes)). - **Simplified High-Integrity Cryptography**: Drastically reduces cryptographic complexity. Because data is processed as static, complete messages rather than continuous streams, the entire frame is signed and encrypted atomically. This enables hardware-native X.509 standard compliance with direct HSM and TPM integration without complex TLS state-machines. - **End-to-End Non-Blocking Architecture:** Features non-blocking execution primitives across all protocol layers. This design integrates seamlessly with Linux Kernel 7.0 AccECN (Accurate ECN) to optimize TCP retransmission timeouts (RTO) and low-latency feedback loops. - **Near-Kernel Latency & Zero HoL Blocking**: Inherently eliminates head-of-line (HoL) blocking over a single socket connection. By deploying hybridized io_uring and epoll I/O frameworks, NLAP achieves deterministic processing speeds that mirror kernel-level transport latencies. @@ -69,7 +69,7 @@ The technical progression and current state of the NLAP implementation comprise Below is a brief overview of the currently functional and production-ready components: -- **Memory (heap)-optimized HTTP/1.1 library:** Features a fast parser and message generator (`/lib/http/`). +- **Memory (heap)-optimized HTTP/1.1 library:** Features a fast parser and message generator ([/lib/http/](`/lib/http/`)). - **Microcontroller portability:** The HTTP/1.1 parser library is fully ported to the ESP-IDF based ESP32-S3 and ESP32-C3 platforms (`/ports/arduino/`). - **Structural specifications:** Includes core XML and workflow schemas formalized via DTD and YANG models (`/specs/`). - **Optimized XML processing:** A memory-optimized Apache Xerces-based parser tailored for NLAP validation and message processing. From fb2ec9c137fc8255ebf8f36be3b32b1e25cbdf59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 14:57:27 +0200 Subject: [PATCH 07/18] Fix links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 04bab63..8263dd9 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ latency. - **Strict XML Message Framing:** Eliminates stream-parsing ambiguities by processing strictly bounded data packets. This non-streamed approach significantly enhances parsing security, mitigates memory-corruption vectors, and maximizes raw processing performance. - **Formalized Model Descriptions:** Reduces protocol complexity to a bare minimum by enforcing a 100% complete structural and semantic definition via Document Type Definitions (DTD) and YANG modeling schemas. -- **Granular Protocol Sub-typing:** Sub-divides transport traffic into distinct, functional protocol variants to maximize scalability and simplify network firewalls (see chapter [7. NLAP Subtypes](#7--nlap-subtypes)). +- **Granular Protocol Sub-typing:** Sub-divides transport traffic into distinct, functional protocol variants to maximize scalability and simplify network firewalls (see chapter [7. NLAP Subtypes](#7-nlap-subtypes)). - **Simplified High-Integrity Cryptography**: Drastically reduces cryptographic complexity. Because data is processed as static, complete messages rather than continuous streams, the entire frame is signed and encrypted atomically. This enables hardware-native X.509 standard compliance with direct HSM and TPM integration without complex TLS state-machines. - **End-to-End Non-Blocking Architecture:** Features non-blocking execution primitives across all protocol layers. This design integrates seamlessly with Linux Kernel 7.0 AccECN (Accurate ECN) to optimize TCP retransmission timeouts (RTO) and low-latency feedback loops. - **Near-Kernel Latency & Zero HoL Blocking**: Inherently eliminates head-of-line (HoL) blocking over a single socket connection. By deploying hybridized io_uring and epoll I/O frameworks, NLAP achieves deterministic processing speeds that mirror kernel-level transport latencies. @@ -69,7 +69,7 @@ The technical progression and current state of the NLAP implementation comprise Below is a brief overview of the currently functional and production-ready components: -- **Memory (heap)-optimized HTTP/1.1 library:** Features a fast parser and message generator ([/lib/http/](`/lib/http/`)). +- **Memory (heap)-optimized HTTP/1.1 library:** Features a fast parser and message generator ([`/lib/http/`](/lib/http/)). - **Microcontroller portability:** The HTTP/1.1 parser library is fully ported to the ESP-IDF based ESP32-S3 and ESP32-C3 platforms (`/ports/arduino/`). - **Structural specifications:** Includes core XML and workflow schemas formalized via DTD and YANG models (`/specs/`). - **Optimized XML processing:** A memory-optimized Apache Xerces-based parser tailored for NLAP validation and message processing. From 037a6bf07222fc1602724879613f6b1f1df53b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 14:59:06 +0200 Subject: [PATCH 08/18] Add links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8263dd9..8b14bfc 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,8 @@ The technical progression and current state of the NLAP implementation comprise Below is a brief overview of the currently functional and production-ready components: - **Memory (heap)-optimized HTTP/1.1 library:** Features a fast parser and message generator ([`/lib/http/`](/lib/http/)). -- **Microcontroller portability:** The HTTP/1.1 parser library is fully ported to the ESP-IDF based ESP32-S3 and ESP32-C3 platforms (`/ports/arduino/`). -- **Structural specifications:** Includes core XML and workflow schemas formalized via DTD and YANG models (`/specs/`). +- **Microcontroller portability:** The HTTP/1.1 parser library is fully ported to the ESP-IDF based ESP32-S3 and ESP32-C3 platforms ([`/ports/arduino/`](/ports/arduino/)). +- **Structural specifications:** Includes core XML and workflow schemas formalized via DTD and YANG models ([`/specs/`](/specs/)). - **Optimized XML processing:** A memory-optimized Apache Xerces-based parser tailored for NLAP validation and message processing. # 6. Milestones @@ -92,4 +92,4 @@ Each NLAP sub-protocol operates on a dedicated TCP port and is structured as fol - **NLAPP:** Upcoming Proxy Server implementation, featuring auto-scaling and multi-endpoint support. - **NLAPS:** Security Extensions, handling cryptographic signing, encryption, and authentication. -Detailed specifications for each sub-protocol are available in the `/specs` directory. +Detailed specifications for each sub-protocol are available in the [`/specs/`](/specs/) directory. From 3645c03bc428edc296a895984808a4d1fc2fb3d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 15:01:36 +0200 Subject: [PATCH 09/18] Correct content --- specs/README.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/specs/README.md b/specs/README.md index 4abacf5..992862c 100644 --- a/specs/README.md +++ b/specs/README.md @@ -4,21 +4,16 @@ Main Specs in [./md/](./md/README.md). ## 1.1. Database -Database Definitions / Performance Test Data [./database/](./database). +Database Definitions / Performance Test Data: [./database/](./database). ## 1.2. Markup -Main Specs / Markup Documents [./md/](./md/README.md). +Main Specs / Markup Documents: [./md/](./md/README.md). -## 1.3. Portable Document Format +## 1.3. XML -PDF rendered / from Visio [./pdf/](./pdf). +Service Specifications in XML format: [./xml/](./xml). -## 1.4. MS Visio - -Microsoft Visio Slides [./visio/](./visio). - -## 1.5. XML - -XML Service Specifications [./xml/](./xml). +## 1.4. YANG +Service Specifications in YANG format: [./yang/](./yang). From 0039a8bcfdbcebf8b5f66d3a4c4c6409e34b5bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 15:03:49 +0200 Subject: [PATCH 10/18] Correct --- specs/README.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/specs/README.md b/specs/README.md index 992862c..988150a 100644 --- a/specs/README.md +++ b/specs/README.md @@ -1,19 +1,15 @@ # 1. Specifications -Main Specs in [./md/](./md/README.md). +This folder contains service specifications in XML (including DTD) and YANG format. -## 1.1. Database +## 1.1. XML -Database Definitions / Performance Test Data: [./database/](./database). +Service specifications in XML format: [./xml/](./xml). -## 1.2. Markup +## 1.2. YANG -Main Specs / Markup Documents: [./md/](./md/README.md). +Service specifications in YANG format: [./yang/](./yang). -## 1.3. XML +## 1.3. Database -Service Specifications in XML format: [./xml/](./xml). - -## 1.4. YANG - -Service Specifications in YANG format: [./yang/](./yang). +Database definitions / performance-test data: [./database/](./database). From da0a3f4dfe15922cabbb085a5591e4c2f25353ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 15:18:32 +0200 Subject: [PATCH 11/18] Add hiliting --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8b14bfc..d011122 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ Falcon Application Server - NLAP (Next Level Application Protocol) # 1. Overview -An advanced architectural paradigm for *low-latency* **TCP**/IP transport tailored for -modern browser web-applications and high-throughput data aggregation middleware. +An advanced architectural paradigm for **low-latency** **TCP**/IP transport tailored for +modern browser web-applications and **high-throughput** data aggregation middleware. It incorporates a high-speed *Python 3* or *Java* application server that natively utilizes -NLAP as its core transport protocol to minimize execution and scheduling overhead. +**NLAP** as its core transport protocol to minimize execution and scheduling overhead. # 2. Project Evolution & History From 0667d378a08b1e073028f2913d82b201bb9261e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20Pr=C3=BCfer?= Date: Thu, 13 Aug 2026 15:30:03 +0200 Subject: [PATCH 12/18] Fix doxygen batch link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d011122..6e8444b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Falcon Application Server - NLAP (Next Level Application Protocol) [![CodeQL](https://github.com/WEBcodeX1/http-1.2/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/WEBcodeX1/http-1.2/actions/workflows/github-code-scanning/codeql) [![License](https://img.shields.io/github/license/WEBcodeX1/http-1.2?style=flat)](https://github.com/WEBcodeX1/http-1.2/tree/main/LICENSE) -[![Doxygen API](https://img.shields.io/badge/docs-sphinx-blue)](https://docs.webcodex.de/developer/falconas/v0.3/doxygen/index.html) +[![Doxygen API](https://img.shields.io/badge/docs-doxygen-blue)](https://docs.webcodex.de/developer/falconas/v0.3/doxygen/index.html) [![Sphinx Docs](https://img.shields.io/badge/docs-sphinx-blue)](https://docs.webcodex.de/developer/falconas/v0.3/sphinx/index.html) --- From 7a3dc9c4571769cbf06a4af283b2d9b4d0d4b668 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 13:31:39 +0000 Subject: [PATCH 13/18] Audit subdirectory documentation Co-authored-by: clauspruefer <17313789+clauspruefer@users.noreply.github.com> --- config/README.md | 7 ++ image/README.md | 8 ++ lib/README.md | 17 ++-- lib/event/README.md | 9 ++ lib/http/README.md | 11 +++ lib/xml/README.md | 10 +++ ports/README.md | 10 ++- ports/arduino/README.md | 13 ++- scripts/README.md | 14 ++- scripts/startup/README.md | 89 ++----------------- scripts/startup/init.d/README.md | 7 ++ scripts/startup/openrc/README.md | 7 ++ scripts/startup/systemd/README.md | 7 ++ specs/README.md | 24 ++--- specs/database/README.md | 7 ++ specs/xml/README.md | 17 ++-- specs/yang/README.md | 7 ++ src/ASBackend/README.md | 8 ++ src/README.md | 14 +++ test/README.md | 14 +-- test/eval/JavaJNI/README.md | 10 +++ test/eval/README.md | 11 +++ test/eval/ResultOrder/README.md | 8 ++ test/integration/README.md | 16 ++++ test/integration/custom-vector/README.md | 9 ++ test/integration/event/README.md | 9 ++ test/integration/request-validation/README.md | 10 +++ test/integration/string-functions/README.md | 8 ++ test/integration/vector-multi-erase/README.md | 8 ++ test/integration/xml-parser/README.md | 8 ++ test/performance/README.md | 73 ++------------- test/performance/http-parser/README.md | 11 +++ test/performance/xml-parser/README.md | 8 ++ test/unit/README.md | 11 +++ test/unit/http-generator/README.md | 8 ++ test/unit/http-parser/README.md | 9 ++ test/unit/memory-alignment/README.md | 8 ++ test/unit/memory-manager/README.md | 8 ++ test/unit/xml-parser/README.md | 9 ++ www/README.md | 9 +- 40 files changed, 351 insertions(+), 200 deletions(-) create mode 100644 config/README.md create mode 100644 image/README.md create mode 100644 lib/event/README.md create mode 100644 lib/http/README.md create mode 100644 lib/xml/README.md create mode 100644 scripts/startup/init.d/README.md create mode 100644 specs/database/README.md create mode 100644 specs/yang/README.md create mode 100644 src/ASBackend/README.md create mode 100644 src/README.md create mode 100644 test/eval/JavaJNI/README.md create mode 100644 test/eval/README.md create mode 100644 test/eval/ResultOrder/README.md create mode 100644 test/integration/README.md create mode 100644 test/integration/custom-vector/README.md create mode 100644 test/integration/event/README.md create mode 100644 test/integration/request-validation/README.md create mode 100644 test/integration/string-functions/README.md create mode 100644 test/integration/vector-multi-erase/README.md create mode 100644 test/integration/xml-parser/README.md create mode 100644 test/performance/http-parser/README.md create mode 100644 test/performance/xml-parser/README.md create mode 100644 test/unit/README.md create mode 100644 test/unit/http-generator/README.md create mode 100644 test/unit/http-parser/README.md create mode 100644 test/unit/memory-alignment/README.md create mode 100644 test/unit/memory-manager/README.md create mode 100644 test/unit/xml-parser/README.md diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000..dd27bf8 --- /dev/null +++ b/config/README.md @@ -0,0 +1,7 @@ +# 1. Runtime Configuration + +This directory contains the JSON configuration used by the server runtime. + +## 1.1. Contents + +- `config.json`: sample / default server configuration covering base paths, TCP options, runtime user/group, MIME types, CPU binding, and virtual host namespace routing. diff --git a/image/README.md b/image/README.md new file mode 100644 index 0000000..dc4134a --- /dev/null +++ b/image/README.md @@ -0,0 +1,8 @@ +# 1. Project Artwork + +This directory contains the FalconAS logo assets used by the project documentation. + +## 1.1. Contents + +- `falconas-logo.png`: rendered logo used by the root `README.md`. +- `falconas-logo.xcf`: editable GIMP source file for the logo artwork. diff --git a/lib/README.md b/lib/README.md index ca482f2..5e03fa9 100644 --- a/lib/README.md +++ b/lib/README.md @@ -1,14 +1,9 @@ -# Internal C++ Libraries +# 1. Internal C++ Libraries -The following C++ Libraries are used internally by the project. +This directory contains the reusable libraries that are built before the main `falcon-as` server and linked into tests. -## 1. Event Library +## 1.1. Subdirectories -The **Event Library** is a tiny library providing a simple callback mechanism. - -## 2. HTTP/1.1 Library - -The **HTTP/1.1 Library** is used to - -- Parse HTTP Requests / Headers -- Generate HTTP Requests / Headers +- [`event/`](./event/): small shared callback / event helper library (`libevent2`). +- [`http/`](./http/): static HTTP parsing and message generation library (`httpparser`). +- [`xml/`](./xml/): static Xerces-C++ backed XML parsing library (`xmlparser`). diff --git a/lib/event/README.md b/lib/event/README.md new file mode 100644 index 0000000..bc81785 --- /dev/null +++ b/lib/event/README.md @@ -0,0 +1,9 @@ +# 1. Event Helper Library + +This directory contains the lightweight event / callback helper that is built as the shared library `libevent2`. + +## 1.1. Contents + +- `Event.hpp`: public interface for registering and dispatching callbacks. +- `Event.cpp`: implementation of the event helper. +- `CMakeLists.txt`: builds and installs the shared library. diff --git a/lib/http/README.md b/lib/http/README.md new file mode 100644 index 0000000..cf107cf --- /dev/null +++ b/lib/http/README.md @@ -0,0 +1,11 @@ +# 1. HTTP Parser / Generator Library + +This directory contains the internal static library `httpparser` that is linked into the server, unit tests, and benchmark targets. + +## 1.1. Contents + +- `httpparser.cpp` / `httpparser.hpp`: default C++23 parser implementation using `std::string_view`, `std::span`, and heterogeneous lookups. +- `httpparser-cpp11.cpp` / `httpparser-cpp11.hpp`: legacy parser implementation enabled with `-DUSE_LEGACY_CPP11=ON`. +- `httpgenerator.cpp` / `httpgenerator.hpp`: HTTP response / message generation helpers. +- `httpconstants.hpp` and `httpconstants-cpp11.hpp`: parser and generator constants for the corresponding implementation. +- `CMakeLists.txt`: selects the active parser implementation and builds the static archive. diff --git a/lib/xml/README.md b/lib/xml/README.md new file mode 100644 index 0000000..c3f2258 --- /dev/null +++ b/lib/xml/README.md @@ -0,0 +1,10 @@ +# 1. XML Parser Library + +This directory contains the internal static library `xmlparser` used for XML validation and message parsing. + +## 1.1. Contents + +- `xmlparser.hpp` / `xmlparser.cpp`: parser interface and implementation. +- `xmlconstants.hpp`: XML-related constants used by the parser. +- `static-dtd.hpp`: embedded DTD support used by the parser layer. +- `CMakeLists.txt`: resolves the Xerces-C++ dependency and builds the static archive. diff --git a/ports/README.md b/ports/README.md index 8bcac27..5de3025 100644 --- a/ports/README.md +++ b/ports/README.md @@ -1,5 +1,7 @@ -# Ported Systems -This directory contains ports to multiple systems. +# 1. Ported Systems -## Arduino -The ./arduino subdir contains ports to arduino based microcontrollers. +This directory contains platform-specific ports of reusable FalconAS components. + +## 1.1. Subdirectories + +- [`arduino/`](./arduino/): microcontroller-focused cross-builds of the HTTP parser library for ESP32 targets. diff --git a/ports/arduino/README.md b/ports/arduino/README.md index 34b2d4b..e930ab4 100644 --- a/ports/arduino/README.md +++ b/ports/arduino/README.md @@ -1,5 +1,10 @@ -# ESP32-C3 -The `./esp32c3` subdir contains the first port to the ESP32-C3 based RISCV32 single core SoC board (ESPRESSIF). +# 1. Arduino / ESP-IDF Ports -# ESP32-S3 -The `./esp32s3` subdir contains the port to the ESP32-S3 based XTENSA 32-bit dual core SoC board (ESPRESSIF). +This directory contains cross-build configurations for reusing the internal HTTP parser library on ESP-IDF based ESP32 targets. + +## 1.1. Subdirectories + +- [`esp32c3/`](./esp32c3/): RISCV32 based ESP32-C3 build configuration. +- [`esp32s3/`](./esp32s3/): Xtensa based ESP32-S3 build configuration. + +Each port builds and installs a target-specific static `httpparser.a` archive together with its public headers. diff --git a/scripts/README.md b/scripts/README.md index afe541a..9d2dfd4 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,4 +1,14 @@ -# Install Scripts +# 1. Installation and System Scripts -OS install scripts reside here. +This directory contains helper scripts used during installation and system preparation. +## 1.1. Contents + +- `add_user_group.sh`: creates the runtime user and group expected by the server. +- `cp_etc.sh`: copies packaged configuration files into their target location. +- `install_startup_script.cmake`: selects the startup integration matching the detected init system. +- `mk_www.sh`: prepares the web root used by the example setup. +- `patch_etc_hosts.sh`: adds local hostname mappings used by the sample namespaces. +- `set-transparent-hugepages.sh`: applies hugepage related runtime settings. +- `ulimit.sh`: raises the open-file limit for high-connection workloads. +- [`startup/`](./startup/): init-system specific service definitions. diff --git a/scripts/startup/README.md b/scripts/startup/README.md index 83fa8ec..a215781 100644 --- a/scripts/startup/README.md +++ b/scripts/startup/README.md @@ -1,86 +1,11 @@ -# Startup Scripts +# 1. Startup Script Variants -This directory contains startup scripts for the Falcon HTTP Application Server. +This directory contains service definitions for the init systems currently supported by the installer. -## SystemD (Ubuntu, Debian 12+) +## 1.1. Subdirectories -To install and enable the systemd service: +- [`systemd/`](./systemd/): service unit for modern Linux distributions. +- [`openrc/`](./openrc/): OpenRC service wrapper. +- [`init.d/`](./init.d/): SysVinit compatible startup script. -```bash -# Copy service file to systemd directory -sudo cp systemd/falcon-as.service /etc/systemd/system/ - -# Reload systemd configuration -sudo systemctl daemon-reload - -# Enable service to start on boot -sudo systemctl enable falcon-as - -# Start the service -sudo systemctl start falcon-as - -# Check service status -sudo systemctl status falcon-as -``` - -## OpenRC (Devuan, Gentoo, Alpine) - -To install and enable the OpenRC init script: - -```bash -# Copy init script to init.d directory -sudo cp openrc/falcon-as /etc/init.d/ - -# Make it executable (if not already) -sudo chmod +x /etc/init.d/falcon-as - -# Add to default runlevel -sudo rc-update add falcon-as default - -# Start the service -sudo rc-service falcon-as start - -# Check service status -sudo rc-service falcon-as status -``` - -## SysVinit (Debian <= 11, Ubuntu <= 14.04, older systems) - -To install and enable the SysVinit init script: - -```bash -# Copy init script to init.d directory -sudo cp init.d/falcon-as /etc/init.d/ - -# Make it executable (if not already) -sudo chmod +x /etc/init.d/falcon-as - -# Enable service to start on boot -sudo update-rc.d falcon-as defaults - -# Start the service -sudo service falcon-as start -# or -sudo /etc/init.d/falcon-as start - -# Check service status -sudo service falcon-as status -# or -sudo /etc/init.d/falcon-as status - -# Stop the service -sudo service falcon-as stop - -# Restart the service -sudo service falcon-as restart -``` - -## Important Notes - -All startup scripts include: -- **ulimit settings**: Sets maximum open files to 1,000,000 -- **Transparent hugepages**: Sets vm.nr_hugepages to 1024 -- **User/Group**: Runs as `falcon-http` user and group -- **Working directory**: `/var/www` - -Make sure the `falcon-http` user and group exist before starting the service (see `/scripts/add_user_group.sh`). +The top-level installer logic in `../install_startup_script.cmake` chooses one of these variants during installation. diff --git a/scripts/startup/init.d/README.md b/scripts/startup/init.d/README.md new file mode 100644 index 0000000..8146d51 --- /dev/null +++ b/scripts/startup/init.d/README.md @@ -0,0 +1,7 @@ +# 1. SysVinit Startup Files + +This directory contains the classic `/etc/init.d` startup script variant used on SysVinit based systems. + +## 1.1. Contents + +- `falcon-as`: init script for starting, stopping, and restarting the `falcon-as` service. diff --git a/scripts/startup/openrc/README.md b/scripts/startup/openrc/README.md index e69de29..11f4b2c 100644 --- a/scripts/startup/openrc/README.md +++ b/scripts/startup/openrc/README.md @@ -0,0 +1,7 @@ +# 1. OpenRC Startup Files + +This directory contains the OpenRC service wrapper used on systems that manage services with OpenRC. + +## 1.1. Contents + +- `falcon-as`: OpenRC service script for starting and stopping the `falcon-as` server binary. diff --git a/scripts/startup/systemd/README.md b/scripts/startup/systemd/README.md index e69de29..bea5653 100644 --- a/scripts/startup/systemd/README.md +++ b/scripts/startup/systemd/README.md @@ -0,0 +1,7 @@ +# 1. systemd Startup Files + +This directory contains the service unit used on systemd-based Linux distributions. + +## 1.1. Contents + +- `falcon-as.service`: systemd unit file for starting the `falcon-as` server process at boot. diff --git a/specs/README.md b/specs/README.md index 988150a..0ced424 100644 --- a/specs/README.md +++ b/specs/README.md @@ -1,15 +1,9 @@ -# 1. Specifications - -This folder contains service specifications in XML (including DTD) and YANG format. - -## 1.1. XML - -Service specifications in XML format: [./xml/](./xml). - -## 1.2. YANG - -Service specifications in YANG format: [./yang/](./yang). - -## 1.3. Database - -Database definitions / performance-test data: [./database/](./database). +# 1. Specifications + +This directory groups the protocol and benchmark specification material that accompanies the implementation. + +## 1.1. Subdirectories + +- [`xml/`](./xml/): XML / DTD protocol definitions and per-subtype specification drafts. +- [`yang/`](./yang/): YANG representation of the NLAP message model. +- [`database/`](./database/): database notes for performance-test result storage. diff --git a/specs/database/README.md b/specs/database/README.md new file mode 100644 index 0000000..f92f1f0 --- /dev/null +++ b/specs/database/README.md @@ -0,0 +1,7 @@ +# 1. Database Notes + +This directory contains database-oriented notes for storing and analysing performance measurements. + +## 1.1. Contents + +- `test-performance-db.md`: draft schema and workflow notes for persisting benchmark runs and result metadata. diff --git a/specs/xml/README.md b/specs/xml/README.md index 434f4c7..8c4071a 100644 --- a/specs/xml/README.md +++ b/specs/xml/README.md @@ -1,14 +1,15 @@ # 1. XML Service Metadata Specifications -This directory contains XML service metadata specifications for the Next Level Application Protocol (NLAP) sub-protocols. +This directory contains the XML-oriented protocol material for NLAP. -## 1.1. Table of Contents +## 1.1. Contents -1. [Next Level Application Metadata Protocol (NLAMP)](./NLAMP-XML-SPECS.md) -2. [Next Level Application File Protocol (NLAFP)](./NLAFP-XML-SPECS.md) -3. [Next Level Application Proxy Protocol (NLAPP)](./NLAPP-XML-SPECS.md) -4. [Next Level Application Protocol Secure Extension (NLAPS)](./NLAPS-XML-SPECS.md) +- `nlap.dtd`: shared DTD describing the common NLAP message envelope and elements. +- `NLAMP-XML-SPECS.md`: metadata protocol draft. +- `NLAFP-XML-SPECS.md`: file-transfer protocol draft. +- `NLAPP-XML-SPECS.md`: proxy protocol draft. +- `NLAPS-XML-SPECS.md`: security extension draft. -## 1.2. Development Status +## 1.2. Notes -Ongoing RFP / RFC development status: [Exemplary HTTP Processing Protocol Design](https://www.der-it-pruefer.de/network/Exemplary-HTTP-Processing-Protocol-Design) +The XML parser library and XML parser tests in this repository use these definitions as the current structural reference point. diff --git a/specs/yang/README.md b/specs/yang/README.md new file mode 100644 index 0000000..a634e07 --- /dev/null +++ b/specs/yang/README.md @@ -0,0 +1,7 @@ +# 1. YANG Specifications + +This directory contains the YANG representation of the NLAP message model. + +## 1.1. Contents + +- `nlap.yang`: YANG 1.1 module derived from `../xml/nlap.dtd`, covering the shared NLAP envelope and the currently modelled sub-protocol fields. diff --git a/src/ASBackend/README.md b/src/ASBackend/README.md new file mode 100644 index 0000000..47ca9d0 --- /dev/null +++ b/src/ASBackend/README.md @@ -0,0 +1,8 @@ +# 1. Application Server Backend Headers + +This directory contains the backend-specific interface headers used by the application-server process layer. + +## 1.1. Contents + +- `PythonBackend.hpp`: Python embedding interface used by the default build. +- `JavaBackend.hpp`: JNI-based backend interface enabled when the project is configured with `-DJAVA_BACKEND=1`. diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..b1cfaa3 --- /dev/null +++ b/src/README.md @@ -0,0 +1,14 @@ +# 1. FalconAS Server Sources + +This directory contains the main application sources that build the `falcon-as` executable. + +## 1.1. Main Components + +- `main.cpp`: entry point that constructs and starts the server. +- `Server.*`: socket setup, accept loop, shared-memory setup, and process termination orchestration. +- `Client*` and `ClientHandler*`: client connection tracking, epoll integration, and request processing. +- `Configuration*`: JSON configuration loading and namespace / MIME type setup. +- `Filesystem*`: static file namespace helpers. +- `ASProcessHandler*`: application-server child process handling for Python or Java backends. +- `CPU*`, `MemoryManager.hpp`, `SHMVector.hpp`, `Vector.hpp`: low-level runtime helpers. +- [`ASBackend/`](./ASBackend/): backend-specific interface headers. diff --git a/test/README.md b/test/README.md index f4c106d..61d9c69 100644 --- a/test/README.md +++ b/test/README.md @@ -1,8 +1,10 @@ -# Tests +# 1. Tests -Tests are devided into the following Sub-Sections. +This directory contains the CMake-organized test and benchmark tree for FalconAS. -- Evaluation Tests [./eval](./eval) -- Unit Tests [./unit](./unit) -- Integration Tests [./integration](./integration) -- Performace Tests [./performance](./performance) +## 1.1. Subdirectories + +- [`eval/`](./eval/): exploratory and feature-evaluation executables. +- [`integration/`](./integration/): cross-component tests and end-to-end style checks. +- [`unit/`](./unit/): focused tests for individual libraries and helpers. +- [`performance/`](./performance/): benchmark and measurement-oriented executables. diff --git a/test/eval/JavaJNI/README.md b/test/eval/JavaJNI/README.md new file mode 100644 index 0000000..489f63b --- /dev/null +++ b/test/eval/JavaJNI/README.md @@ -0,0 +1,10 @@ +# 1. Java JNI Evaluation + +This directory contains the optional JNI-based evaluation target for the Java backend path. + +## 1.1. Contents + +- `test-run-jni.cpp`: Boost.Test executable that exercises the JNI bridge. +- `WebApp.java` / `WebApp.class`: small Java test application used by the JNI test. +- `json-java.jar`: bundled JSON dependency required by the Java sample. +- `CMakeLists.txt`: resolves Java / JNI packages and builds `test-run-jni`. diff --git a/test/eval/README.md b/test/eval/README.md new file mode 100644 index 0000000..8cbef4f --- /dev/null +++ b/test/eval/README.md @@ -0,0 +1,11 @@ +# 1. Evaluation Tests + +This directory contains exploratory targets used to validate implementation ideas or optional runtime integrations. + +## 1.1. Contents + +- `test-boost-python.cpp`: experiments with the embedded Python integration layer. +- `test-pointer-ref.cpp`: pointer / reference behavior checks. +- `test-shmem-vector.cpp`: shared-memory vector experimentation. +- [`ResultOrder/`](./ResultOrder/): focused result-ordering evaluation target. +- [`JavaJNI/`](./JavaJNI/): optional JNI evaluation target, built only when `JAVA_BACKEND` is enabled. diff --git a/test/eval/ResultOrder/README.md b/test/eval/ResultOrder/README.md new file mode 100644 index 0000000..c03219a --- /dev/null +++ b/test/eval/ResultOrder/README.md @@ -0,0 +1,8 @@ +# 1. Result Order Evaluation + +This directory contains an evaluation test for ordering-related behavior. + +## 1.1. Contents + +- `test-result-order.cpp`: Boost.Test executable built as `test-result-order`. +- `test-result-order-class.cpp` and `test-result-order.hpp`: helper implementation and declarations used by the test. diff --git a/test/integration/README.md b/test/integration/README.md new file mode 100644 index 0000000..86eb774 --- /dev/null +++ b/test/integration/README.md @@ -0,0 +1,16 @@ +# 1. Integration Tests + +This directory contains tests that exercise multiple components together. + +## 1.1. CMake-Managed Targets + +- [`event/`](./event/): validates the internal event library in a linked executable. +- [`string-functions/`](./string-functions/): checks shared string helper behavior. +- [`vector-multi-erase/`](./vector-multi-erase/): verifies vector erase semantics. +- [`signal-termination/`](./signal-termination/): validates process shutdown and SIGTERM propagation. +- [`custom-vector/`](./custom-vector/): integration coverage for the shared-memory vector implementation. +- [`xml-parser/`](./xml-parser/): end-to-end XML parser integration coverage. + +## 1.2. Manual Checks + +- [`request-validation/`](./request-validation/): shell-based request validation scripts that are currently stored in the repository but not added to the integration CMake tree. diff --git a/test/integration/custom-vector/README.md b/test/integration/custom-vector/README.md new file mode 100644 index 0000000..6967107 --- /dev/null +++ b/test/integration/custom-vector/README.md @@ -0,0 +1,9 @@ +# 1. Custom Vector Integration Test + +This directory contains the integration test target for the shared-memory vector implementation. + +## 1.1. Contents + +- `test-SHMVector.cpp`: Boost.Test source built as `test-SHMVector`. +- `test-CustomVector`: auxiliary file kept alongside the test sources. +- `CMakeLists.txt`: registers the executable and test entry. diff --git a/test/integration/event/README.md b/test/integration/event/README.md new file mode 100644 index 0000000..d754466 --- /dev/null +++ b/test/integration/event/README.md @@ -0,0 +1,9 @@ +# 1. Event Library Integration Test + +This directory contains the integration test that links against the internal `libevent2` shared library. + +## 1.1. Contents + +- `test-Event.cpp`: Boost.Test executable source built as `test-event`. +- `TestClass.cpp` / `TestClass.hpp`: helper class used by the event test. +- `CMakeLists.txt`: links the test against both Boost.Test and `libevent2`. diff --git a/test/integration/request-validation/README.md b/test/integration/request-validation/README.md new file mode 100644 index 0000000..d760170 --- /dev/null +++ b/test/integration/request-validation/README.md @@ -0,0 +1,10 @@ +# 1. Request Validation Scripts + +This directory contains manual shell-script checks for validating request samples. + +## 1.1. Contents + +- `test-valid-requests.sh`: validates request cases expected to pass. +- `test-invalid-requests.sh`: validates request cases expected to fail. + +These scripts are not currently wired into the repository's CMake-driven test targets. diff --git a/test/integration/string-functions/README.md b/test/integration/string-functions/README.md new file mode 100644 index 0000000..33f5848 --- /dev/null +++ b/test/integration/string-functions/README.md @@ -0,0 +1,8 @@ +# 1. String Function Integration Test + +This directory contains the integration test for shared string helper behavior. + +## 1.1. Contents + +- `test-string-functions.cpp`: Boost.Test source built as `test-string-functions`. +- `CMakeLists.txt`: registers the executable. diff --git a/test/integration/vector-multi-erase/README.md b/test/integration/vector-multi-erase/README.md new file mode 100644 index 0000000..a6403ce --- /dev/null +++ b/test/integration/vector-multi-erase/README.md @@ -0,0 +1,8 @@ +# 1. Vector Multi-Erase Integration Test + +This directory contains the integration test for multi-element erase behavior in the custom vector implementation. + +## 1.1. Contents + +- `test-Vector-multi-erase.cpp`: Boost.Test source built as `test-Vector-multi-erase`. +- `CMakeLists.txt`: registers the executable. diff --git a/test/integration/xml-parser/README.md b/test/integration/xml-parser/README.md new file mode 100644 index 0000000..8497c37 --- /dev/null +++ b/test/integration/xml-parser/README.md @@ -0,0 +1,8 @@ +# 1. XML Parser Integration Test + +This directory contains the end-to-end integration coverage for the XML parser library. + +## 1.1. Contents + +- `test-xml-parser-e2e.cpp`: Boost.Test executable source built as `test-xml-parser-e2e`. +- `CMakeLists.txt`: links the test against the internal `xmlparser` library. diff --git a/test/performance/README.md b/test/performance/README.md index 5fc041a..3470e3b 100644 --- a/test/performance/README.md +++ b/test/performance/README.md @@ -1,70 +1,11 @@ -# Performance Tests +# 1. Performance Tests -Performance Tests will record statistical data about *Static File* and *Application Server* components. +This directory contains benchmark-oriented targets and measurement notes. -# 1. Global Settings +## 1.1. Contents -Tests include the following subsections: - -- Static File Performance -- Performance under Idle Keep-Alive Connections -- Application Server Dynamic Data -- Proxy Server Performance -- Comparison to Apache2 and nginX external Web-Servers - -All Tests will be primarily done on FalconAS Server using HTTP/1.2 and HTTP/1.1 protocol. - -All Tests will be repeated externally on different web-servers using protocols: - -- HTTP/1.1 -- HTTP/2 - -# 2. External Products - -All Tests will be repeated on the following web-server products: - -- Apache2 Threaded Model -- Apache2 Event Driven Model -- nginX - -# 3. Detailed Workflow (SQL Database) - -1. Insert (TestID, TestIDRepeat) INTO "Test" table -2. Insert Server Test Parameter into "TestParameter" table -3. Write Server XML configuration -4. Start Server -5. Run / Loop Tests, write stat results into C++ structs -6. Insert Test Results into "TestMeasurement" table - -# 4. Test Specs (Google Sheet) - -https://docs.google.com/spreadsheets/d/1Da3KsIfTPGJOpeS1Ns2pHvEU_RpdWwx8kU5Ug-b_ZAE/edit?usp=drive_link - -# 5. Linux Sysctl Values - -- Disable Kernel Scheduler Autogrouping -- Disable Kernel Scheduler Energy Awareness -- Prevent Kernel Scheduler from collection Statistics -- Disable Virtual Memory Subsystem Memory Compaction -- Reduce Virtual Memory Subsystem Memory Swap Behaviour - -```bash - -# Kernel Scheduler Settings -sysctl -w kernel.sched_autogroup_enabled=0 -sysctl -w kernel.sched_energy_aware=0 -sysctl -w kernel.sched_schedstats=0 - -# Disable VM Memeory Compation -sysctl -w vm.compact_unevictable_allowed=0 -sysctl -w vm.compaction_proactiveness=0 - -# Disable Watchdogs -sysctl -w kernel.soft_watchdog=0 -sysctl -w kernel.watchdog=0 - -# Reduce Swappiness -sysctl -w vm.swappiness=0 - -``` +- `00_test-performance-nokeepalive.cpp`: root performance test source collected into the `test-performance` executable. +- [`http-parser/`](./http-parser/): parser wall-clock and memory benchmarks, including recorded CSV result snapshots. +- [`xml-parser/`](./xml-parser/): XML parser benchmark target. +The database notes used to persist benchmark runs are tracked separately in [`../../specs/database/`](../../specs/database/). diff --git a/test/performance/http-parser/README.md b/test/performance/http-parser/README.md new file mode 100644 index 0000000..299fd03 --- /dev/null +++ b/test/performance/http-parser/README.md @@ -0,0 +1,11 @@ +# 1. HTTP Parser Benchmarks + +This directory contains benchmark targets and stored result snapshots for the internal HTTP parser. + +## 1.1. Contents + +- `test-parser-performance.cpp`: wall-clock performance benchmark. +- `test-parser-memory.cpp`: heap-allocation / memory benchmark. +- `results-performance.csv`: recorded parser timing results. +- `results-memory.csv`: recorded parser memory results. +- `CMakeLists.txt`: builds the benchmark executables against `httpparser`. diff --git a/test/performance/xml-parser/README.md b/test/performance/xml-parser/README.md new file mode 100644 index 0000000..15ebf7e --- /dev/null +++ b/test/performance/xml-parser/README.md @@ -0,0 +1,8 @@ +# 1. XML Parser Benchmarks + +This directory contains the benchmark target for the internal XML parser. + +## 1.1. Contents + +- `test-xml-parser-performance.cpp`: XML parser performance benchmark source. +- `CMakeLists.txt`: builds the benchmark executable against `xmlparser`. diff --git a/test/unit/README.md b/test/unit/README.md new file mode 100644 index 0000000..e55c4cf --- /dev/null +++ b/test/unit/README.md @@ -0,0 +1,11 @@ +# 1. Unit Tests + +This directory contains focused tests for individual libraries and low-level helpers. + +## 1.1. Subdirectories + +- [`http-parser/`](./http-parser/): request parsing tests for the internal HTTP parser. +- [`http-generator/`](./http-generator/): response generation tests for the HTTP generator. +- [`memory-alignment/`](./memory-alignment/): checks alignment-related helper behavior. +- [`memory-manager/`](./memory-manager/): tests the custom memory manager. +- [`xml-parser/`](./xml-parser/): unit coverage for the XML parser library, including fuzz-style inputs. diff --git a/test/unit/http-generator/README.md b/test/unit/http-generator/README.md new file mode 100644 index 0000000..dfa3d16 --- /dev/null +++ b/test/unit/http-generator/README.md @@ -0,0 +1,8 @@ +# 1. HTTP Generator Unit Tests + +This directory contains unit coverage for the HTTP response / message generation helpers. + +## 1.1. Contents + +- `test-generator-responses.cpp`: Boost.Test executable source built as `test-generator-responses`. +- `CMakeLists.txt`: links the test against the internal `httpparser` library. diff --git a/test/unit/http-parser/README.md b/test/unit/http-parser/README.md new file mode 100644 index 0000000..b8e6c61 --- /dev/null +++ b/test/unit/http-parser/README.md @@ -0,0 +1,9 @@ +# 1. HTTP Parser Unit Tests + +This directory contains focused unit coverage for the internal HTTP request parser. + +## 1.1. Contents + +- `test-parser-requests.cpp`: Boost.Test executable source built as `test-parser-requests`. +- `as-get.json`: sample request / payload fixture used by the test set. +- `CMakeLists.txt`: links the test against the internal `httpparser` library. diff --git a/test/unit/memory-alignment/README.md b/test/unit/memory-alignment/README.md new file mode 100644 index 0000000..e69fd0c --- /dev/null +++ b/test/unit/memory-alignment/README.md @@ -0,0 +1,8 @@ +# 1. Memory Alignment Unit Tests + +This directory contains focused tests for alignment-related helper behavior. + +## 1.1. Contents + +- `test-memory-alignment.cpp`: Boost.Test executable source built as `test-memory-alignment`. +- `CMakeLists.txt`: registers the executable and CTest entry. diff --git a/test/unit/memory-manager/README.md b/test/unit/memory-manager/README.md new file mode 100644 index 0000000..bd25a3b --- /dev/null +++ b/test/unit/memory-manager/README.md @@ -0,0 +1,8 @@ +# 1. Memory Manager Unit Tests + +This directory contains focused tests for the custom memory manager helpers. + +## 1.1. Contents + +- `test-memory-manager.cpp`: Boost.Test executable source built as `test-memory-manager`. +- `CMakeLists.txt`: registers the executable and CTest entry. diff --git a/test/unit/xml-parser/README.md b/test/unit/xml-parser/README.md new file mode 100644 index 0000000..f434624 --- /dev/null +++ b/test/unit/xml-parser/README.md @@ -0,0 +1,9 @@ +# 1. XML Parser Unit Tests + +This directory contains focused unit coverage for the internal XML parser library. + +## 1.1. Contents + +- `test-xml-parser.cpp`: primary Boost.Test executable for parser behavior. +- `test-xml-parser-fuzz.cpp`: fuzz-style input coverage for the parser. +- `CMakeLists.txt`: links both executables against the internal `xmlparser` library. diff --git a/www/README.md b/www/README.md index 2a9db81..e64f81e 100644 --- a/www/README.md +++ b/www/README.md @@ -1,4 +1,9 @@ -# WWW Examples +# 1. WWW Example Content -Files used for Examples reside here. +This directory contains the static and dynamic example assets used by the sample FalconAS setup. +## 1.1. Contents + +- `index-app1.html` and `index-app2.html`: example static entry pages for the configured namespaces. +- `WebApp.py`: sample Python application backend. +- `falcon-robotics.jpg` and `favicon.ico`: assets referenced by the example pages. From e62b53cf1f8cf96b2fb6b49a9dcf1a1fbfa1d0b1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 13:32:36 +0000 Subject: [PATCH 14/18] Clarify result-order documentation Co-authored-by: clauspruefer <17313789+clauspruefer@users.noreply.github.com> --- test/eval/ResultOrder/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/eval/ResultOrder/README.md b/test/eval/ResultOrder/README.md index c03219a..68ee038 100644 --- a/test/eval/ResultOrder/README.md +++ b/test/eval/ResultOrder/README.md @@ -5,4 +5,5 @@ This directory contains an evaluation test for ordering-related behavior. ## 1.1. Contents - `test-result-order.cpp`: Boost.Test executable built as `test-result-order`. -- `test-result-order-class.cpp` and `test-result-order.hpp`: helper implementation and declarations used by the test. +- `test-result-order-class.cpp`: helper implementation used by the test executable. +- `test-result-order.hpp`: declarations shared by the result-order test sources. From 45e981b5400c8e2fc734621680fa9361bc63e17b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 13:33:25 +0000 Subject: [PATCH 15/18] Refine README cross-references Co-authored-by: clauspruefer <17313789+clauspruefer@users.noreply.github.com> --- scripts/startup/README.md | 2 +- test/unit/http-generator/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/startup/README.md b/scripts/startup/README.md index a215781..95bdbb0 100644 --- a/scripts/startup/README.md +++ b/scripts/startup/README.md @@ -8,4 +8,4 @@ This directory contains service definitions for the init systems currently suppo - [`openrc/`](./openrc/): OpenRC service wrapper. - [`init.d/`](./init.d/): SysVinit compatible startup script. -The top-level installer logic in `../install_startup_script.cmake` chooses one of these variants during installation. +The top-level installer logic in [`../install_startup_script.cmake`](../install_startup_script.cmake) chooses one of these variants during installation. diff --git a/test/unit/http-generator/README.md b/test/unit/http-generator/README.md index dfa3d16..0eb8075 100644 --- a/test/unit/http-generator/README.md +++ b/test/unit/http-generator/README.md @@ -5,4 +5,4 @@ This directory contains unit coverage for the HTTP response / message generation ## 1.1. Contents - `test-generator-responses.cpp`: Boost.Test executable source built as `test-generator-responses`. -- `CMakeLists.txt`: links the test against the internal `httpparser` library. +- `CMakeLists.txt`: links the test against the internal `httpparser` static archive, which also contains the HTTP generator helpers. From 441c2c33628ff25fd43adbfba1294c31bee4e736 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 13:34:22 +0000 Subject: [PATCH 16/18] Restore startup README usage note Co-authored-by: clauspruefer <17313789+clauspruefer@users.noreply.github.com> --- scripts/startup/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/startup/README.md b/scripts/startup/README.md index 95bdbb0..54f0b06 100644 --- a/scripts/startup/README.md +++ b/scripts/startup/README.md @@ -9,3 +9,5 @@ This directory contains service definitions for the init systems currently suppo - [`init.d/`](./init.d/): SysVinit compatible startup script. The top-level installer logic in [`../install_startup_script.cmake`](../install_startup_script.cmake) chooses one of these variants during installation. + +For manual installation, copy the file from the matching subdirectory into the init-system specific service location and enable it with the native service manager for that platform. From 88076ec3d821153ce151e111e43a1fb0a975d9ab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 13:35:24 +0000 Subject: [PATCH 17/18] Polish startup and test docs Co-authored-by: clauspruefer <17313789+clauspruefer@users.noreply.github.com> --- scripts/startup/README.md | 6 +++++- test/integration/custom-vector/README.md | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/startup/README.md b/scripts/startup/README.md index 54f0b06..2ed46e9 100644 --- a/scripts/startup/README.md +++ b/scripts/startup/README.md @@ -10,4 +10,8 @@ This directory contains service definitions for the init systems currently suppo The top-level installer logic in [`../install_startup_script.cmake`](../install_startup_script.cmake) chooses one of these variants during installation. -For manual installation, copy the file from the matching subdirectory into the init-system specific service location and enable it with the native service manager for that platform. +## 1.2. Manual Installation Quick Reference + +- **systemd:** copy `systemd/falcon-as.service` to `/etc/systemd/system/`, then run `systemctl daemon-reload` and `systemctl enable --now falcon-as`. +- **OpenRC:** copy `openrc/falcon-as` to `/etc/init.d/`, make it executable, then run `rc-update add falcon-as default` and `rc-service falcon-as start`. +- **SysVinit:** copy `init.d/falcon-as` to `/etc/init.d/`, make it executable, then run `update-rc.d falcon-as defaults` and `service falcon-as start`. diff --git a/test/integration/custom-vector/README.md b/test/integration/custom-vector/README.md index 6967107..70e454a 100644 --- a/test/integration/custom-vector/README.md +++ b/test/integration/custom-vector/README.md @@ -5,5 +5,5 @@ This directory contains the integration test target for the shared-memory vector ## 1.1. Contents - `test-SHMVector.cpp`: Boost.Test source built as `test-SHMVector`. -- `test-CustomVector`: auxiliary file kept alongside the test sources. +- `test-CustomVector`: prebuilt ELF test artifact committed alongside the source tree for this integration test. - `CMakeLists.txt`: registers the executable and test entry. From 063152a4913afac851bb71364c5595c392301641 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 13:40:09 +0000 Subject: [PATCH 18/18] Fix signal termination README Co-authored-by: clauspruefer <17313789+clauspruefer@users.noreply.github.com> --- test/integration/signal-termination/README.md | 61 ++++++------------- 1 file changed, 18 insertions(+), 43 deletions(-) diff --git a/test/integration/signal-termination/README.md b/test/integration/signal-termination/README.md index 10f50c3..e198388 100644 --- a/test/integration/signal-termination/README.md +++ b/test/integration/signal-termination/README.md @@ -1,57 +1,32 @@ -# Signal Termination Handling Test +# 1. Signal Termination Integration Test -## Overview +This directory contains a self-contained Boost.Test executable that models the server's +child-process shutdown flow. -This integration test verifies that the server properly handles SIGTERM signals and propagates them to all child processes. +## 1.1. Contents -## Test Description +- `test-signal-termination.cpp`: forks helper child processes, installs `SIGTERM` + handlers, and verifies orderly shutdown behavior. +- `CMakeLists.txt`: registers the `test-signal-termination` executable. -The test validates the following behavior: +## 1.2. Covered Behavior -1. **Parent Process Tracking**: When child processes are forked, their PIDs are registered with the parent process -2. **Signal Propagation**: When the parent process receives a SIGTERM signal, it sends SIGTERM to all tracked child processes -3. **Clean Shutdown**: All child processes handle SIGTERM gracefully and exit cleanly +The test mirrors the shutdown pattern implemented in the runtime sources without starting +the full server: -## Test Cases +- `src/Server.cpp`: keeps track of child PIDs and terminates them during shutdown. +- `src/ASProcessHandler.cpp`: registers forked application-server processes with the + server-side PID tracker. -### Test 1: Parent Sends SIGTERM to Children -- Creates a parent process with two child processes -- Registers child PIDs with the parent -- Sends SIGTERM to parent -- Verifies that parent forwards SIGTERM to all children -- Verifies that all processes exit cleanly with status 0 +The Boost.Test cases verify that: -### Test 2: Child Processes Not Killed Without SIGTERM -- Creates a parent with a child process -- Verifies that without receiving SIGTERM, the child continues running -- Sends SIGTERM to verify clean shutdown capability +1. child PIDs can be collected by the parent-side tracker, +2. sending `SIGTERM` to the tracked children terminates them cleanly, and +3. a child process continues running until an explicit termination signal is sent. -## How It Works - -The termination handling in the HTTP server follows this pattern: - -1. **Server.cpp**: Main server process - - Maintains a static vector `ChildPIDs` to track all child process IDs - - `Server::terminate()` handler sends SIGTERM to all tracked children when parent receives SIGTERM - -2. **ASProcessHandler.cpp**: Application Server child processes - - Each forked AS process PID is registered via `registerChildPID()` - - Child processes have their own SIGTERM handlers to exit gracefully - -3. **ResultProcessor.cpp**: Result processor child process - - Forked process PID is returned and registered with parent - - Has its own SIGTERM handler for clean shutdown - -## Running the Test +## 1.3. Running the Test ```bash cd build/test/integration/signal-termination ./test-signal-termination ``` - -## Expected Output - -All test cases should pass, indicating: -- ✓ Parent successfully tracks child PIDs -- ✓ SIGTERM is propagated from parent to all children -- ✓ All processes exit cleanly without requiring SIGKILL