├── .github ├── Dockerfile └── workflows │ ├── codeql.yml │ └── suite.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── benches ├── client.rs └── server.rs ├── build.rs ├── cbindgen.toml ├── examples └── config │ ├── pushpin.conf │ ├── routes │ └── runner │ └── certs │ └── README ├── header.APACHE2 ├── package.sh ├── postbuild └── postbuild.pro ├── src ├── bin │ ├── m2adapter.rs │ ├── pushpin-connmgr.rs │ ├── pushpin-handler.rs │ ├── pushpin-legacy.rs │ ├── pushpin-proxy.rs │ ├── pushpin-publish.rs │ └── pushpin.rs ├── connmgr │ ├── batch.rs │ ├── client.rs │ ├── connection.rs │ ├── counter.rs │ ├── listener.rs │ ├── mod.rs │ ├── pool.rs │ ├── resolver.rs │ ├── server.rs │ ├── tls.rs │ ├── track.rs │ ├── websocket.rs │ ├── zhttppacket.rs │ └── zhttpsocket.rs ├── core │ ├── arena.rs │ ├── buffer.rs │ ├── bufferlist.cpp │ ├── bufferlist.h │ ├── callback.h │ ├── channel.rs │ ├── config.cpp │ ├── config.h │ ├── config.rs │ ├── core.pri │ ├── cors.cpp │ ├── cors.h │ ├── defer.rs │ ├── defercall.cpp │ ├── defercall.h │ ├── defercalltest.cpp │ ├── event.cpp │ ├── event.h │ ├── event.rs │ ├── eventloop.cpp │ ├── eventloop.h │ ├── eventloop.rs │ ├── eventlooptest.cpp │ ├── executor.rs │ ├── filewatcher.cpp │ ├── filewatcher.h │ ├── fs.rs │ ├── http1 │ │ ├── client.rs │ │ ├── error.rs │ │ ├── mod.rs │ │ ├── protocol.rs │ │ ├── server.rs │ │ └── util.rs │ ├── httpheaders.cpp │ ├── httpheaders.h │ ├── httpheaderstest.cpp │ ├── httprequest.h │ ├── inspectdata.h │ ├── io.rs │ ├── jwt.cpp │ ├── jwt.h │ ├── jwt.rs │ ├── jwttest.cpp │ ├── layertracker.cpp │ ├── layertracker.h │ ├── list.rs │ ├── log.cpp │ ├── log.h │ ├── log.rs │ ├── logutil.cpp │ ├── logutil.h │ ├── mod.rs │ ├── net.rs │ ├── packet │ │ ├── httprequestdata.h │ │ ├── httpresponsedata.h │ │ ├── retryrequestpacket.cpp │ │ ├── retryrequestpacket.h │ │ ├── statspacket.cpp │ │ ├── statspacket.h │ │ ├── wscontrolpacket.cpp │ │ ├── wscontrolpacket.h │ │ ├── zrpcrequestpacket.cpp │ │ ├── zrpcrequestpacket.h │ │ ├── zrpcresponsepacket.cpp │ │ └── zrpcresponsepacket.h │ ├── processquit.cpp │ ├── processquit.h │ ├── qtcompat.h │ ├── qzmqcontext.cpp │ ├── qzmqcontext.h │ ├── qzmqreprouter.cpp │ ├── qzmqreprouter.h │ ├── qzmqreqmessage.h │ ├── qzmqsocket.cpp │ ├── qzmqsocket.h │ ├── qzmqvalve.cpp │ ├── qzmqvalve.h │ ├── reactor.rs │ ├── readwrite.h │ ├── select.rs │ ├── settings.cpp │ ├── settings.h │ ├── shuffle.rs │ ├── simplehttpserver.cpp │ ├── simplehttpserver.h │ ├── socketnotifier.cpp │ ├── socketnotifier.h │ ├── stats.cpp │ ├── stats.h │ ├── statsmanager.cpp │ ├── statsmanager.h │ ├── statusreasons.cpp │ ├── statusreasons.h │ ├── task.rs │ ├── tcplistener.cpp │ ├── tcplistener.h │ ├── tcpstream.cpp │ ├── tcpstream.h │ ├── tcpstreamtest.cpp │ ├── test.h │ ├── test.rs │ ├── tests.pri │ ├── time.rs │ ├── timer.cpp │ ├── timer.h │ ├── timer.rs │ ├── timertest.cpp │ ├── timerwheel.cpp │ ├── timerwheel.h │ ├── tnetstring.cpp │ ├── tnetstring.h │ ├── tnetstring.rs │ ├── unixlistener.cpp │ ├── unixlistener.h │ ├── unixstream.cpp │ ├── unixstream.h │ ├── unixstreamtest.cpp │ ├── uuidutil.cpp │ ├── uuidutil.h │ ├── waker.rs │ ├── websocket.h │ ├── wscontrol.h │ ├── zhttpmanager.cpp │ ├── zhttpmanager.h │ ├── zhttprequest.cpp │ ├── zhttprequest.h │ ├── zhttprequestpacket.cpp │ ├── zhttprequestpacket.h │ ├── zhttpresponsepacket.cpp │ ├── zhttpresponsepacket.h │ ├── zmq.rs │ ├── zrpcmanager.cpp │ ├── zrpcmanager.h │ ├── zrpcrequest.cpp │ ├── zrpcrequest.h │ ├── zutil.cpp │ ├── zutil.h │ ├── zwebsocket.cpp │ └── zwebsocket.h ├── cpp.pro ├── cpptests.pro ├── handler │ ├── cidset.h │ ├── clientsession.h │ ├── conncheckworker.cpp │ ├── conncheckworker.h │ ├── controlrequest.cpp │ ├── controlrequest.h │ ├── deferred.cpp │ ├── deferred.h │ ├── detectrule.h │ ├── filter.cpp │ ├── filter.h │ ├── filterstack.cpp │ ├── filterstack.h │ ├── filtertest.cpp │ ├── format.cpp │ ├── format.h │ ├── handler.pri │ ├── handlerapp.cpp │ ├── handlerapp.h │ ├── handlerengine.cpp │ ├── handlerengine.h │ ├── handlerenginetest.cpp │ ├── handlermain.cpp │ ├── httpsession.cpp │ ├── httpsession.h │ ├── httpsessionupdatemanager.cpp │ ├── httpsessionupdatemanager.h │ ├── idformat.cpp │ ├── idformat.h │ ├── idformattest.cpp │ ├── instruct.cpp │ ├── instruct.h │ ├── instructtest.cpp │ ├── jsonpatch.cpp │ ├── jsonpatch.h │ ├── jsonpatchtest.cpp │ ├── jsonpointer.cpp │ ├── jsonpointer.h │ ├── lastids.h │ ├── main.h │ ├── mod.rs │ ├── publishformat.cpp │ ├── publishformat.h │ ├── publishformattest.cpp │ ├── publishitem.cpp │ ├── publishitem.h │ ├── publishitemtest.cpp │ ├── publishlastids.cpp │ ├── publishlastids.h │ ├── ratelimiter.cpp │ ├── ratelimiter.h │ ├── refreshworker.cpp │ ├── refreshworker.h │ ├── requeststate.cpp │ ├── requeststate.h │ ├── sequencer.cpp │ ├── sequencer.h │ ├── sessionrequest.cpp │ ├── sessionrequest.h │ ├── tests.pri │ ├── variantutil.cpp │ ├── variantutil.h │ ├── wscontrolmessage.cpp │ ├── wscontrolmessage.h │ ├── wssession.cpp │ └── wssession.h ├── internal.conf ├── lib.rs ├── m2adapter │ ├── README │ ├── m2adapter.conf.example │ ├── m2adapter.pri │ ├── m2adapterapp.cpp │ ├── m2adapterapp.h │ ├── m2adaptermain.cpp │ ├── m2requestpacket.cpp │ ├── m2requestpacket.h │ ├── m2responsepacket.cpp │ ├── m2responsepacket.h │ ├── main.h │ └── tools │ │ ├── handoffhandler.py │ │ ├── hanghandler.py │ │ ├── hello.txt │ │ ├── keephandler.py │ │ ├── m2control.py │ │ ├── streamhandler.py │ │ ├── streamposthandler.py │ │ ├── testhandler.py │ │ └── wsechohandler.py ├── proxy │ ├── acceptdata.h │ ├── acceptrequest.cpp │ ├── acceptrequest.h │ ├── app.cpp │ ├── app.h │ ├── connectionmanager.cpp │ ├── connectionmanager.h │ ├── domainmap.cpp │ ├── domainmap.h │ ├── engine.cpp │ ├── engine.h │ ├── inspectrequest.cpp │ ├── inspectrequest.h │ ├── main.cpp │ ├── main.h │ ├── mod.rs │ ├── proxy.pri │ ├── proxyenginetest.cpp │ ├── proxysession.cpp │ ├── proxysession.h │ ├── proxyutil.cpp │ ├── proxyutil.h │ ├── requestsession.cpp │ ├── requestsession.h │ ├── routes.test │ ├── routesfile.cpp │ ├── routesfile.h │ ├── routesfiletest.cpp │ ├── sockjsmanager.cpp │ ├── sockjsmanager.h │ ├── sockjssession.cpp │ ├── sockjssession.h │ ├── testhttprequest.cpp │ ├── testhttprequest.h │ ├── tests.pri │ ├── testwebsocket.cpp │ ├── testwebsocket.h │ ├── updater.cpp │ ├── updater.h │ ├── websocketoverhttp.cpp │ ├── websocketoverhttp.h │ ├── websocketoverhttptest.cpp │ ├── wscontrolmanager.cpp │ ├── wscontrolmanager.h │ ├── wscontrolsession.cpp │ ├── wscontrolsession.h │ ├── wsproxysession.cpp │ ├── wsproxysession.h │ ├── xffrule.h │ ├── zroutes.cpp │ ├── zroutes.h │ ├── zrpcchecker.cpp │ └── zrpcchecker.h ├── publish │ └── mod.rs └── runner │ ├── connmgrservice.cpp │ ├── connmgrservice.h │ ├── listenport.h │ ├── m2adapter.conf.template │ ├── m2adapterservice.cpp │ ├── m2adapterservice.h │ ├── main.h │ ├── mod.rs │ ├── mongrel2.conf.template │ ├── mongrel2service.cpp │ ├── mongrel2service.h │ ├── pushpinhandlerservice.cpp │ ├── pushpinhandlerservice.h │ ├── pushpinproxyservice.cpp │ ├── pushpinproxyservice.h │ ├── runner.pri │ ├── runnerapp.cpp │ ├── runnerapp.h │ ├── runnermain.cpp │ ├── service.cpp │ ├── service.h │ ├── service.rs │ ├── template.cpp │ ├── template.h │ ├── templatetest.cpp │ ├── tests.pri │ ├── zurl.conf.template │ ├── zurlservice.cpp │ └── zurlservice.h └── tools ├── command.py ├── echo ├── echo.cpp └── echo.pro ├── edgebroker.py ├── getzmquris.py ├── gripstate.py ├── monitorstats.py ├── monitorsubs.py ├── monitorsubsock.py ├── mp3stream.php ├── mp3stream_publisher.py ├── publish.py ├── publish2.py ├── publish_curl.sh ├── recover.py ├── sourcebroker.py ├── testgripresponse.php ├── testgripresponse_json.php ├── testgripstream.php ├── testgripwebsocket.js ├── testgripwebsocket.php ├── testwebsocket.php ├── zhttp ├── basichandler.py ├── get.py ├── getstream.py ├── holdhandler.py ├── printreq.py ├── reqhandler.py ├── sendresp.py └── streamhandler.py └── zhttpreqhandler.py /.github/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 ubuntu:20.04 2 | 3 | ENV TZ=US \ 4 | DEBIAN_FRONTEND=noninteractive 5 | 6 | RUN apt-get -qq update && apt-get install -y zstd git pkg-config curl make g++ libssl-dev libzmq3-dev qtbase5-dev libboost-dev black 7 | 8 | # install toolchain 9 | RUN curl https://sh.rustup.rs -sSf | \ 10 | sh -s -- --default-toolchain stable-x86_64-unknown-linux-gnu -y 11 | 12 | ENV RUSTUP_HOME="/root/.rustup" \ 13 | CARGO_HOME="/root/.cargo" \ 14 | PATH=/root/.cargo/bin:$PATH 15 | 16 | # Keep in sync with minimum support Rust Version for Pushpin 17 | RUN rustup install 1.75.0-x86_64-unknown-linux-gnu 18 | 19 | RUN cargo install cargo-audit 20 | 21 | RUN rustup component add rustfmt 22 | 23 | RUN rustup component add clippy 24 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | schedule: 9 | - cron: '21 13 * * 6' 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze (${{ matrix.language }}) 14 | runs-on: 'ubuntu-latest' 15 | container: fanout/build-base:latest 16 | timeout-minutes: 15 17 | permissions: 18 | # required for all workflows 19 | security-events: write 20 | # required to fetch internal or private CodeQL packs 21 | packages: read 22 | # only required for workflows in private repositories 23 | actions: read 24 | contents: read 25 | 26 | strategy: 27 | fail-fast: true 28 | matrix: 29 | include: 30 | - language: c-cpp 31 | build-mode: manual 32 | - language: javascript-typescript 33 | build-mode: none 34 | - language: python 35 | build-mode: none 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v4 39 | - name: Cache 40 | uses: Swatinem/rust-cache@v2 41 | with: 42 | shared-key: "codeql" 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v3 46 | with: 47 | languages: ${{ matrix.language }} 48 | build-mode: ${{ matrix.build-mode }} 49 | - if: matrix.build-mode == 'manual' 50 | shell: bash 51 | run: make build 52 | - name: Perform CodeQL Analysis 53 | uses: github/codeql-action/analyze@v3 54 | with: 55 | category: "/language:${{matrix.language}}" 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | qrc_* 4 | *.moc 5 | *.o 6 | *.pdb 7 | ui_* 8 | moc_* 9 | *.pyc 10 | .qmake.stash 11 | target_wrapper.sh 12 | /target 13 | **/*.rs.bk 14 | .cargo 15 | vendor 16 | .vscode 17 | conf.pri 18 | 19 | /pushpin 20 | /pushpin-legacy 21 | /bin/* 22 | /src/runner/certs/*.crt 23 | /src/runner/certs/*.key 24 | /postbuild/Makefile 25 | /postbuild/*.inst 26 | /config 27 | /run 28 | /log 29 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # controlled leading whitespace, per the GNU make manual 2 | nullstring := 3 | space := $(nullstring) # end of the line 4 | 5 | ifdef RELEASE 6 | cargo_flags = $(space)--offline --locked --release 7 | endif 8 | 9 | ifdef TOOLCHAIN 10 | cargo_toolchain = $(space)+$(TOOLCHAIN) 11 | endif 12 | 13 | all: postbuild 14 | 15 | build: FORCE 16 | cargo$(cargo_toolchain) build$(cargo_flags) 17 | 18 | cargo-test: FORCE 19 | cargo$(cargo_toolchain) test$(cargo_flags) --all-features 20 | 21 | cargo-clean: FORCE 22 | cargo clean 23 | 24 | postbuild: build FORCE 25 | cd postbuild && $(MAKE) -f Makefile 26 | 27 | postbuild-install: FORCE 28 | cd postbuild && $(MAKE) -f Makefile install 29 | 30 | postbuild-clean: FORCE 31 | cd postbuild && $(MAKE) -f Makefile clean 32 | 33 | postbuild-distclean: FORCE 34 | cd postbuild && $(MAKE) -f Makefile distclean 35 | 36 | check: cargo-test 37 | 38 | install: postbuild-install 39 | 40 | clean: cargo-clean postbuild-clean 41 | 42 | distclean: cargo-clean postbuild-distclean 43 | 44 | FORCE: 45 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Report a security issue 2 | 3 | The project team welcomes security reports and is committed to providing prompt attention to security issues. Security issues should be reported privately via [Fastly’s security issue reporting process](https://www.fastly.com/security/report-security-issue). 4 | 5 | ## Security advisories 6 | 7 | Remediation of security vulnerabilities is prioritized by the project team. The project team endeavors to coordinate remediation with third-party stakeholders, and is committed to transparency in the disclosure process. The team announces security issues via [GitHub](https://github.com/fastly/pushpin/releases) as well as [RustSec](https://rustsec.org/advisories/) on a best-effort basis. 8 | 9 | Note that communications related to security issues in Fastly-maintained OSS as described here are distinct from [Fastly Security Advisories](https://www.fastly.com/security-advisories). 10 | -------------------------------------------------------------------------------- /cbindgen.toml: -------------------------------------------------------------------------------- 1 | include_guard = "RUST_BINDINGS_H" 2 | namespace = "ffi" 3 | 4 | after_includes = """ 5 | // zmq crate version 0.10 bundles zeromq 4.3 6 | #define WZMQ_VERSION_MAJOR 4 7 | #define WZMQ_VERSION_MINOR 3 8 | """ 9 | 10 | [parse] 11 | parse_deps = true 12 | include = ["jsonwebtoken", "zmq"] 13 | -------------------------------------------------------------------------------- /examples/config/routes: -------------------------------------------------------------------------------- 1 | * test 2 | -------------------------------------------------------------------------------- /examples/config/runner/certs/README: -------------------------------------------------------------------------------- 1 | Empty directory. 2 | -------------------------------------------------------------------------------- /header.APACHE2: -------------------------------------------------------------------------------- 1 | * 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | * 14 | -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ $# -lt 1 ]; then 5 | echo "usage: $0 [version]" 6 | exit 1 7 | fi 8 | 9 | VERSION=$1 10 | 11 | DESTDIR=build/pushpin-$VERSION 12 | 13 | mkdir -p $DESTDIR 14 | 15 | cp -a .gitignore benches build.rs Cargo.lock Cargo.toml cbindgen.toml CHANGELOG.md examples LICENSE Makefile postbuild SECURITY.md README.md src tools $DESTDIR 16 | 17 | sed -i.orig -e "s/^version = .*/version = \"$VERSION\"/g" $DESTDIR/Cargo.toml 18 | rm $DESTDIR/Cargo.toml.orig 19 | 20 | cd $DESTDIR 21 | mkdir -p .cargo 22 | cat >.cargo/config.toml < libc::c_int; 24 | } 25 | 26 | fn main() -> ExitCode { 27 | unsafe { ExitCode::from(call_c_main(m2adapter_main, env::args_os())) } 28 | } 29 | -------------------------------------------------------------------------------- /src/bin/pushpin-handler.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | use pushpin::core::call_c_main; 18 | use pushpin::import_cpp; 19 | use std::env; 20 | use std::process::ExitCode; 21 | 22 | import_cpp! { 23 | fn handler_main(argc: libc::c_int, argv: *const *const libc::c_char) -> libc::c_int; 24 | } 25 | 26 | fn main() -> ExitCode { 27 | unsafe { ExitCode::from(call_c_main(handler_main, env::args_os())) } 28 | } 29 | -------------------------------------------------------------------------------- /src/bin/pushpin-legacy.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | use pushpin::core::call_c_main; 18 | use pushpin::import_cpp; 19 | use std::env; 20 | use std::process::ExitCode; 21 | 22 | import_cpp! { 23 | fn runner_main(argc: libc::c_int, argv: *const *const libc::c_char) -> libc::c_int; 24 | } 25 | 26 | fn main() -> ExitCode { 27 | unsafe { ExitCode::from(call_c_main(runner_main, env::args_os())) } 28 | } 29 | -------------------------------------------------------------------------------- /src/bin/pushpin-proxy.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | use pushpin::core::call_c_main; 18 | use pushpin::import_cpp; 19 | use std::env; 20 | use std::process::ExitCode; 21 | 22 | import_cpp! { 23 | fn proxy_main(argc: libc::c_int, argv: *const *const libc::c_char) -> libc::c_int; 24 | } 25 | 26 | fn main() -> ExitCode { 27 | unsafe { ExitCode::from(call_c_main(proxy_main, env::args_os())) } 28 | } 29 | -------------------------------------------------------------------------------- /src/core/bufferlist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Fanout, Inc. 3 | * 4 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * $FANOUT_END_LICENSE$ 19 | */ 20 | 21 | #ifndef BUFFERLIST_H 22 | #define BUFFERLIST_H 23 | 24 | #include 25 | #include 26 | 27 | class BufferList 28 | { 29 | public: 30 | BufferList(); 31 | 32 | int size() const { return size_; } 33 | bool isEmpty() const { return size_ == 0; } 34 | 35 | QByteArray mid(int pos, int size = -1) const; 36 | 37 | void clear(); 38 | void append(const QByteArray &buf); 39 | QByteArray take(int size = -1); 40 | 41 | QByteArray toByteArray(); // non-const because we rewrite the list 42 | 43 | BufferList & operator+=(const QByteArray &buf) 44 | { 45 | append(buf); 46 | return *this; 47 | } 48 | 49 | private: 50 | QList bufs_; 51 | int size_; 52 | int offset_; 53 | 54 | void findPos(int pos, int *bufferIndex, int *offset) const; 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/core/config.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023-2024 Fastly, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include "config.h" 24 | 25 | #include "rust/bindings.h" 26 | 27 | namespace Config { 28 | 29 | static thread_local Config *g_config = 0; 30 | 31 | Config & get() 32 | { 33 | if(!g_config) 34 | { 35 | Config *c = new Config; 36 | 37 | ffi::BuildConfig *bc = ffi::build_config_new(); 38 | c->version = QString(bc->version); 39 | c->configDir = QString(bc->config_dir); 40 | c->libDir = QString(bc->lib_dir); 41 | ffi::build_config_destroy(bc); 42 | 43 | g_config = c; 44 | } 45 | 46 | return *g_config; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/core/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023-2024 Fastly, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef CONFIG_H 24 | #define CONFIG_H 25 | 26 | #include 27 | 28 | namespace Config { 29 | 30 | class Config 31 | { 32 | public: 33 | QString version; 34 | QString configDir; 35 | QString libDir; 36 | }; 37 | 38 | // value is thread local 39 | Config & get(); 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/core/cors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef CORS_H 24 | #define CORS_H 25 | 26 | class HttpHeaders; 27 | 28 | namespace Cors { 29 | 30 | void applyCorsHeaders(const HttpHeaders &requestHeaders, HttpHeaders *responseHeaders); 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/core/defer.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | pub struct Defer { 18 | f: Option, 19 | } 20 | 21 | impl Defer { 22 | pub fn new(f: T) -> Self { 23 | Self { f: Some(f) } 24 | } 25 | } 26 | 27 | impl Drop for Defer { 28 | fn drop(&mut self) { 29 | let f = self.f.take().unwrap(); 30 | 31 | f(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/core/event.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "event.h" 18 | 19 | namespace Event { 20 | 21 | SetReadiness::SetReadiness(ffi::SetReadiness *inner) : 22 | inner_(inner) 23 | { 24 | } 25 | 26 | SetReadiness::~SetReadiness() 27 | { 28 | ffi::set_readiness_destroy(inner_); 29 | } 30 | 31 | int SetReadiness::setReadiness(uint8_t readiness) 32 | { 33 | return ffi::set_readiness_set_readiness(inner_, readiness); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/core/event.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef EVENT_H 18 | #define EVENT_H 19 | 20 | #include "rust/bindings.h" 21 | 22 | class EventLoop; 23 | 24 | namespace Event { 25 | 26 | enum Interest 27 | { 28 | Readable = ffi::READABLE, 29 | Writable = ffi::WRITABLE, 30 | }; 31 | 32 | class SetReadiness 33 | { 34 | public: 35 | ~SetReadiness(); 36 | 37 | // disable copying 38 | SetReadiness(const SetReadiness &) = delete; 39 | SetReadiness & operator=(const SetReadiness &) = delete; 40 | 41 | // pass a non-zero set of Interest flags 42 | int setReadiness(uint8_t readiness); 43 | 44 | private: 45 | friend class ::EventLoop; 46 | 47 | SetReadiness(ffi::SetReadiness *inner); 48 | 49 | ffi::SetReadiness *inner_; 50 | }; 51 | 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/core/eventloop.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef EVENTLOOP_H 18 | #define EVENTLOOP_H 19 | 20 | #include 21 | #include 22 | #include "event.h" 23 | #include "rust/bindings.h" 24 | 25 | class EventLoop 26 | { 27 | public: 28 | EventLoop(int capacity); 29 | ~EventLoop(); 30 | 31 | // disable copying 32 | EventLoop(const EventLoop &) = delete; 33 | EventLoop & operator=(const EventLoop &) = delete; 34 | 35 | std::optional step(); 36 | int exec(); 37 | void exit(int code); 38 | 39 | int registerFd(int fd, uint8_t interest, void (*cb)(void *, uint8_t), void *ctx); 40 | int registerTimer(int timeout, void (*cb)(void *, uint8_t), void *ctx); 41 | std::tuple> registerCustom(void (*cb)(void *, uint8_t), void *ctx); 42 | void deregister(int id); 43 | 44 | static EventLoop *instance(); 45 | 46 | private: 47 | ffi::EventLoopRaw *inner_; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/core/filewatcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "filewatcher.h" 18 | 19 | #include 20 | #include 21 | 22 | FileWatcher::FileWatcher() : 23 | inner_(nullptr) 24 | { 25 | } 26 | 27 | FileWatcher::~FileWatcher() 28 | { 29 | sn_.reset(); 30 | 31 | if(inner_) 32 | ffi::file_watcher_destroy(inner_); 33 | } 34 | 35 | bool FileWatcher::start(const QString &filePath) 36 | { 37 | assert(!inner_); 38 | 39 | inner_ = ffi::file_watcher_create(filePath.toUtf8().data()); 40 | if(!inner_) 41 | return false; 42 | 43 | int fd = ffi::file_watcher_as_raw_fd(inner_); 44 | 45 | sn_ = std::make_unique(fd, SocketNotifier::Read); 46 | sn_->activated.connect(boost::bind(&FileWatcher::sn_activated, this, boost::placeholders::_1, boost::placeholders::_2)); 47 | sn_->clearReadiness(SocketNotifier::Read); 48 | sn_->setReadEnabled(true); 49 | 50 | // in case the socket was activated before registering the notifier 51 | if(ffi::file_watcher_file_changed(inner_)) 52 | deferCall_.defer([=] { fileChanged(); }); 53 | 54 | return true; 55 | } 56 | 57 | void FileWatcher::sn_activated(int socket, uint8_t readiness) 58 | { 59 | Q_UNUSED(socket); 60 | Q_UNUSED(readiness); 61 | 62 | sn_->clearReadiness(SocketNotifier::Read); 63 | 64 | if(ffi::file_watcher_file_changed(inner_)) 65 | fileChanged(); 66 | } 67 | -------------------------------------------------------------------------------- /src/core/filewatcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef FILEWATCHER_H 18 | #define FILEWATCHER_H 19 | 20 | #include 21 | #include "socketnotifier.h" 22 | #include "defercall.h" 23 | #include "rust/bindings.h" 24 | 25 | class QString; 26 | 27 | class FileWatcher 28 | { 29 | public: 30 | FileWatcher(); 31 | ~FileWatcher(); 32 | 33 | bool start(const QString &filePath); 34 | 35 | boost::signals2::signal fileChanged; 36 | 37 | private: 38 | ffi::FileWatcher *inner_; 39 | std::unique_ptr sn_; 40 | DeferCall deferCall_; 41 | 42 | void sn_activated(int socket, uint8_t readiness); 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/core/http1/error.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | use crate::core::http1::protocol; 18 | use std::io; 19 | 20 | #[derive(Debug)] 21 | pub enum Error { 22 | Io(io::Error), 23 | Protocol(protocol::Error), 24 | RequestTooLarge(usize), 25 | ResponseTooLarge(usize), 26 | ResponseDuringContinue, 27 | FurtherInputNotAllowed, 28 | BufferExceeded, 29 | Unusable, 30 | } 31 | 32 | impl From for Error { 33 | fn from(e: io::Error) -> Self { 34 | Self::Io(e) 35 | } 36 | } 37 | 38 | impl From for Error { 39 | fn from(e: protocol::Error) -> Self { 40 | Self::Protocol(e) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/core/http1/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | mod error; 18 | mod protocol; 19 | mod util; 20 | 21 | pub mod client; 22 | pub mod server; 23 | 24 | pub use error::*; 25 | pub use protocol::{ 26 | parse_header_value, BodySize, Header, HeaderParamsIterator, ParseScratch, Request, Response, 27 | EMPTY_HEADER, 28 | }; 29 | pub use util::{RecvStatus, SendStatus}; 30 | -------------------------------------------------------------------------------- /src/core/httpheaders.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Fanout, Inc. 3 | * 4 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * $FANOUT_END_LICENSE$ 19 | */ 20 | 21 | #ifndef HTTPHEADERS_H 22 | #define HTTPHEADERS_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | typedef QPair HttpHeaderParameter; 29 | 30 | class HttpHeaderParameters : public QList 31 | { 32 | public: 33 | bool contains(const QByteArray &key) const; 34 | QByteArray get(const QByteArray &key) const; 35 | }; 36 | 37 | typedef QPair HttpHeader; 38 | 39 | class HttpHeaders : public QList 40 | { 41 | public: 42 | enum ParseMode 43 | { 44 | NoParseFirstParameter, 45 | ParseAllParameters 46 | }; 47 | 48 | bool contains(const QByteArray &key) const; 49 | QByteArray get(const QByteArray &key) const; 50 | HttpHeaderParameters getAsParameters(const QByteArray &key, ParseMode mode = NoParseFirstParameter) const; 51 | QByteArray getAsFirstParameter(const QByteArray &key) const; 52 | QList getAll(const QByteArray &key, bool split = true) const; 53 | QList getAllAsParameters(const QByteArray &key, ParseMode mode = NoParseFirstParameter, bool split = true) const; 54 | QList takeAll(const QByteArray &key, bool split = true); 55 | void removeAll(const QByteArray &key); 56 | 57 | static QByteArray join(const QList &values); 58 | static HttpHeaderParameters parseParameters(const QByteArray &in, ParseMode mode = NoParseFirstParameter, bool *ok = 0); 59 | }; 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/core/inspectdata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef INSPECTDATA_H 24 | #define INSPECTDATA_H 25 | 26 | #include 27 | #include 28 | 29 | class InspectData 30 | { 31 | public: 32 | bool doProxy; 33 | QByteArray sharingKey; 34 | QByteArray sid; 35 | QHash lastIds; 36 | QVariant userData; 37 | 38 | InspectData() : 39 | doProxy(false) 40 | { 41 | } 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/core/layertracker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Fanout, Inc. 3 | * 4 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * $FANOUT_END_LICENSE$ 19 | */ 20 | 21 | #include "layertracker.h" 22 | 23 | #include 24 | 25 | LayerTracker::LayerTracker() : 26 | plain_(0) 27 | { 28 | } 29 | 30 | void LayerTracker::reset() 31 | { 32 | plain_ = 0; 33 | items_.clear(); 34 | } 35 | 36 | void LayerTracker::addPlain(int plain) 37 | { 38 | plain_ += plain; 39 | } 40 | 41 | void LayerTracker::specifyEncoded(int encoded, int plain) 42 | { 43 | // can't specify more bytes than we have 44 | assert(plain <= plain_); 45 | 46 | plain_ -= plain; 47 | Item i; 48 | i.plain = plain; 49 | i.encoded = encoded; 50 | items_ += i; 51 | } 52 | 53 | int LayerTracker::finished(int encoded) 54 | { 55 | int plain = 0; 56 | 57 | for(QList::Iterator it = items_.begin(); it != items_.end();) 58 | { 59 | Item &i = *it; 60 | 61 | // not enough? 62 | if(encoded < i.encoded) 63 | { 64 | i.encoded -= encoded; 65 | break; 66 | } 67 | 68 | encoded -= i.encoded; 69 | plain += i.plain; 70 | it = items_.erase(it); 71 | } 72 | 73 | return plain; 74 | } 75 | -------------------------------------------------------------------------------- /src/core/layertracker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Fanout, Inc. 3 | * 4 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * $FANOUT_END_LICENSE$ 19 | */ 20 | 21 | #ifndef LAYERTRACKER_H 22 | #define LAYERTRACKER_H 23 | 24 | #include 25 | 26 | class LayerTracker 27 | { 28 | public: 29 | LayerTracker(); 30 | 31 | void reset(); 32 | 33 | void addPlain(int plain); 34 | void specifyEncoded(int encoded, int plain); 35 | int finished(int encoded); 36 | 37 | private: 38 | class Item 39 | { 40 | public: 41 | int plain; 42 | int encoded; 43 | }; 44 | 45 | int plain_; 46 | QList items_; 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/core/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2016 Fanout, Inc. 3 | * 4 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * $FANOUT_END_LICENSE$ 19 | */ 20 | 21 | #ifndef LOG_H 22 | #define LOG_H 23 | 24 | #include 25 | 26 | // really simply logging stuff 27 | 28 | #define LOG_LEVEL_ERROR 0 29 | #define LOG_LEVEL_WARNING 1 30 | #define LOG_LEVEL_INFO 2 31 | #define LOG_LEVEL_DEBUG 3 32 | 33 | void log_startClock(); 34 | int log_outputLevel(); 35 | void log_setOutputLevel(int level); 36 | bool log_setFile(const QString &fname); 37 | bool log_rotate(); 38 | 39 | void log(int level, const char *fmt, ...); 40 | void log_error(const char *fmt, ...); 41 | void log_warning(const char *fmt, ...); 42 | void log_info(const char *fmt, ...); 43 | void log_debug(const char *fmt, ...); 44 | 45 | // log without prefixing or anything. useful for forwarding log data 46 | void log_raw(const char *line); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/core/packet/httprequestdata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef HTTPREQUESTDATA_H 24 | #define HTTPREQUESTDATA_H 25 | 26 | #include "../httpheaders.h" 27 | #include 28 | 29 | class HttpRequestData 30 | { 31 | public: 32 | QString method; 33 | QUrl uri; 34 | HttpHeaders headers; 35 | QByteArray body; 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/core/packet/httpresponsedata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef HTTPRESPONSEDATA_H 24 | #define HTTPRESPONSEDATA_H 25 | 26 | #include "../httpheaders.h" 27 | 28 | class HttpResponseData 29 | { 30 | public: 31 | int code; 32 | QByteArray reason; 33 | HttpHeaders headers; 34 | QByteArray body; 35 | 36 | HttpResponseData() : 37 | code(-1) 38 | { 39 | } 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/core/packet/wscontrolpacket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2022 Fanout, Inc. 3 | * Copyright (C) 2024-2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef WSCONTROLPACKET_H 25 | #define WSCONTROLPACKET_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | class WsControlPacket 33 | { 34 | public: 35 | class Item 36 | { 37 | public: 38 | enum Type 39 | { 40 | Here, 41 | KeepAlive, 42 | Gone, 43 | Grip, 44 | NeedKeepAlive, 45 | Subscribe, 46 | Cancel, 47 | Send, 48 | KeepAliveSetup, 49 | Refresh, 50 | Close, 51 | Detach, 52 | Ack 53 | }; 54 | 55 | QByteArray cid; 56 | Type type; 57 | QByteArray requestId; 58 | QUrl uri; 59 | QByteArray contentType; 60 | QByteArray message; 61 | bool queue; 62 | int code; 63 | QByteArray reason; 64 | bool debug; 65 | QByteArray route; 66 | bool separateStats; 67 | QByteArray channelPrefix; 68 | int logLevel; 69 | bool trusted; 70 | QByteArray channel; 71 | int ttl; 72 | int timeout; 73 | QByteArray keepAliveMode; 74 | 75 | Item() : 76 | type((Type)-1), 77 | queue(false), 78 | code(-1), 79 | debug(false), 80 | separateStats(false), 81 | logLevel(-1), 82 | trusted(false), 83 | ttl(-1), 84 | timeout(-1) 85 | { 86 | } 87 | }; 88 | 89 | QByteArray from; 90 | QList items; 91 | 92 | QVariant toVariant() const; 93 | bool fromVariant(const QVariant &in); 94 | }; 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/core/packet/zrpcrequestpacket.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Fanout, Inc. 3 | * Copyright (C) 2024 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #include "zrpcrequestpacket.h" 25 | 26 | #include "qtcompat.h" 27 | 28 | QVariant ZrpcRequestPacket::toVariant() const 29 | { 30 | QVariantHash obj; 31 | 32 | if(!from.isEmpty()) 33 | obj["from"] = from; 34 | 35 | if(!id.isEmpty()) 36 | obj["id"] = id; 37 | 38 | obj["method"] = method.toUtf8(); 39 | 40 | if(!args.isEmpty()) 41 | obj["args"] = args; 42 | 43 | return obj; 44 | } 45 | 46 | bool ZrpcRequestPacket::fromVariant(const QVariant &in) 47 | { 48 | if(typeId(in) != QMetaType::QVariantHash) 49 | return false; 50 | 51 | QVariantHash obj = in.toHash(); 52 | 53 | if(obj.contains("from")) 54 | { 55 | if(typeId(obj["from"]) != QMetaType::QByteArray) 56 | return false; 57 | 58 | from = obj["from"].toByteArray(); 59 | } 60 | 61 | if(obj.contains("id")) 62 | { 63 | if(typeId(obj["id"]) != QMetaType::QByteArray) 64 | return false; 65 | 66 | id = obj["id"].toByteArray(); 67 | } 68 | 69 | if(!obj.contains("method") || typeId(obj["method"]) != QMetaType::QByteArray) 70 | return false; 71 | method = QString::fromUtf8(obj["method"].toByteArray()); 72 | 73 | if(obj.contains("args")) 74 | { 75 | if(typeId(obj["args"]) != QMetaType::QVariantHash) 76 | return false; 77 | 78 | args = obj["args"].toHash(); 79 | } 80 | 81 | return true; 82 | } 83 | -------------------------------------------------------------------------------- /src/core/packet/zrpcrequestpacket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Fanout, Inc. 3 | * Copyright (C) 2024 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef ZRPCREQUESTPACKET_H 25 | #define ZRPCREQUESTPACKET_H 26 | 27 | #include 28 | #include 29 | 30 | class ZrpcRequestPacket 31 | { 32 | public: 33 | QByteArray from; 34 | QByteArray id; 35 | QString method; 36 | QVariantHash args; 37 | 38 | QVariant toVariant() const; 39 | bool fromVariant(const QVariant &in); 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/core/packet/zrpcresponsepacket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef ZRPCRESPONSEPACKET_H 24 | #define ZRPCRESPONSEPACKET_H 25 | 26 | #include 27 | #include 28 | 29 | class ZrpcResponsePacket 30 | { 31 | public: 32 | QByteArray id; 33 | bool success; 34 | QVariant value; 35 | QByteArray condition; 36 | 37 | ZrpcResponsePacket() : 38 | success(false) 39 | { 40 | } 41 | 42 | QVariant toVariant() const; 43 | bool fromVariant(const QVariant &in); 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/core/qtcompat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Fastly, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | inline QMetaType::Type typeId(const QVariant &v) 27 | { 28 | #if QT_VERSION >= 0x060000 29 | return (QMetaType::Type)v.typeId(); 30 | #else 31 | return (QMetaType::Type)v.type(); 32 | #endif 33 | } 34 | 35 | inline bool canConvert(const QVariant &v, QMetaType::Type type) 36 | { 37 | #if QT_VERSION >= 0x060000 38 | return v.canConvert(QMetaType(type)); 39 | #else 40 | return v.canConvert(type); 41 | #endif 42 | } 43 | -------------------------------------------------------------------------------- /src/core/qzmqcontext.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Justin Karneges 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include "qzmqcontext.h" 25 | 26 | #include 27 | #include "rust/bindings.h" 28 | 29 | using namespace ffi; 30 | 31 | namespace QZmq { 32 | 33 | Context::Context(int ioThreads) 34 | { 35 | context_ = wzmq_init(ioThreads); 36 | assert(context_); 37 | } 38 | 39 | Context::~Context() 40 | { 41 | wzmq_term(context_); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/core/qzmqcontext.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Justin Karneges 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef QZMQCONTEXT_H 25 | #define QZMQCONTEXT_H 26 | 27 | namespace QZmq { 28 | 29 | class Context 30 | { 31 | public: 32 | Context(int ioThreads = 1); 33 | ~Context(); 34 | 35 | // the zmq context 36 | void *context() { return context_; } 37 | 38 | private: 39 | void *context_; 40 | }; 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/core/qzmqreprouter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Justin Karneges 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef QZMQREPROUTER_H 25 | #define QZMQREPROUTER_H 26 | 27 | #include 28 | 29 | class QString; 30 | 31 | using Signal = boost::signals2::signal; 32 | using SignalInt = boost::signals2::signal; 33 | using Connection = boost::signals2::scoped_connection; 34 | 35 | namespace QZmq { 36 | 37 | class ReqMessage; 38 | 39 | class RepRouter 40 | { 41 | public: 42 | RepRouter(); 43 | ~RepRouter(); 44 | 45 | void setShutdownWaitTime(int msecs); 46 | 47 | void connectToAddress(const QString &addr); 48 | bool bind(const QString &addr); 49 | 50 | bool canRead() const; 51 | 52 | ReqMessage read(); 53 | void write(const ReqMessage &message); 54 | 55 | Signal readyRead; 56 | SignalInt messagesWritten; 57 | 58 | private: 59 | RepRouter(const RepRouter &) = delete; 60 | RepRouter &operator=(const RepRouter &) = delete; 61 | 62 | class Private; 63 | friend class Private; 64 | std::unique_ptr d; 65 | }; 66 | 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/core/qzmqvalve.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Justin Karneges 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a 6 | * copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included 14 | * in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #ifndef QZMQVALVE_H 26 | #define QZMQVALVE_H 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | using SignalList = boost::signals2::signal&)>; 33 | using Connection = boost::signals2::scoped_connection; 34 | 35 | namespace QZmq { 36 | 37 | class Socket; 38 | 39 | class Valve 40 | { 41 | public: 42 | Valve(QZmq::Socket *sock); 43 | ~Valve(); 44 | 45 | bool isOpen() const; 46 | 47 | void setMaxReadsPerEvent(int max); 48 | 49 | void open(); 50 | void close(); 51 | 52 | SignalList readyRead; 53 | 54 | private: 55 | class Private; 56 | friend class Private; 57 | std::shared_ptr d; 58 | }; 59 | 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/core/readwrite.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef READWRITE_H 18 | #define READWRITE_H 19 | 20 | #include 21 | #include 22 | 23 | class ReadWrite 24 | { 25 | public: 26 | virtual ~ReadWrite() = default; 27 | 28 | // size < 0 means default read size 29 | // returns buffer of bytes read. null buffer means error. empty means end 30 | virtual QByteArray read(int size = -1) = 0; 31 | 32 | // returns amount accepted, or -1 for error 33 | virtual int write(const QByteArray &buf) = 0; 34 | 35 | // returns errno of latest operation 36 | virtual int errorCondition() const = 0; 37 | 38 | boost::signals2::signal readReady; 39 | boost::signals2::signal writeReady; 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/core/settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2022 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef SETTINGS_H 24 | #define SETTINGS_H 25 | 26 | #include 27 | #include 28 | 29 | class QSettings; 30 | 31 | class Settings 32 | { 33 | public: 34 | Settings(const QString &fileName); 35 | ~Settings(); 36 | 37 | bool contains(const QString &key) const; 38 | QVariant valueRaw(const QString &key, const QVariant &defaultValue = QVariant()) const; 39 | QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; 40 | int adjustedPort(const QString &key, int defaultValue = -1) const; 41 | 42 | void setIpcPrefix(const QString &s); 43 | void setPortOffset(int x); 44 | 45 | private: 46 | QSettings *main_; 47 | QSettings *include_; 48 | QString libdir_; 49 | QString rundir_; 50 | QString ipcPrefix_; 51 | int portOffset_; 52 | 53 | QString resolveVars(const QString &in) const; 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/core/shuffle.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Alex Crichton 3 | * Copyright (c) 2017 The Tokio Authors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | use std::{ 19 | cell::Cell, 20 | collections::hash_map::DefaultHasher, 21 | hash::Hasher, 22 | num::Wrapping, 23 | sync::atomic::{AtomicUsize, Ordering}, 24 | }; 25 | 26 | // Based on [Fisher–Yates shuffle]. 27 | // 28 | // [Fisher–Yates shuffle]: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle 29 | pub fn shuffle(slice: &mut [T]) { 30 | for i in (1..slice.len()).rev() { 31 | slice.swap(i, gen_index(i + 1)); 32 | } 33 | } 34 | 35 | /// Return a value from `0..n`. 36 | fn gen_index(n: usize) -> usize { 37 | (random() % n as u64) as usize 38 | } 39 | 40 | /// Pseudorandom number generator based on [xorshift*]. 41 | /// 42 | /// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift* 43 | pub fn random() -> u64 { 44 | thread_local! { 45 | static RNG: Cell> = Cell::new(Wrapping(prng_seed())); 46 | } 47 | 48 | fn prng_seed() -> u64 { 49 | static COUNTER: AtomicUsize = AtomicUsize::new(0); 50 | 51 | // Any non-zero seed will do 52 | let mut seed = 0; 53 | while seed == 0 { 54 | let mut hasher = DefaultHasher::new(); 55 | hasher.write_usize(COUNTER.fetch_add(1, Ordering::Relaxed)); 56 | seed = hasher.finish(); 57 | } 58 | seed 59 | } 60 | 61 | RNG.with(|rng| { 62 | let mut x = rng.get(); 63 | debug_assert_ne!(x.0, 0); 64 | x ^= x >> 12; 65 | x ^= x << 25; 66 | x ^= x >> 27; 67 | rng.set(x); 68 | x.0.wrapping_mul(0x2545_f491_4f6c_dd1d) 69 | }) 70 | } 71 | -------------------------------------------------------------------------------- /src/core/stats.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include "stats.h" 24 | 25 | namespace Stats { 26 | 27 | void Counters::add(const Counters &other) 28 | { 29 | for(int n = 0; n < STATS_COUNTERS_MAX; ++n) 30 | inc((Counter)n, other._values[n]); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/core/statusreasons.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef STATUSREASONS_H 24 | #define STATUSREASONS_H 25 | 26 | class QByteArray; 27 | 28 | namespace StatusReasons { 29 | 30 | QByteArray getReason(int code); 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/core/tcplistener.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef TCPLISTENER_H 18 | #define TCPLISTENER_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include "rust/bindings.h" 24 | #include "tcpstream.h" 25 | 26 | class SocketNotifier; 27 | 28 | class TcpListener 29 | { 30 | public: 31 | TcpListener(); 32 | ~TcpListener(); 33 | 34 | // disable copying 35 | TcpListener(const TcpListener &) = delete; 36 | TcpListener & operator=(const TcpListener &) = delete; 37 | 38 | bool bind(const QHostAddress &addr, uint16_t port); 39 | std::tuple localAddress() const; 40 | std::unique_ptr accept(); 41 | int errorCondition() const { return errorCondition_; } 42 | 43 | boost::signals2::signal streamsReady; 44 | 45 | private: 46 | ffi::TcpListener *inner_; 47 | std::unique_ptr sn_; 48 | int errorCondition_; 49 | 50 | void reset(); 51 | void sn_activated(); 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/core/tcpstream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef TCPSTREAM_H 18 | #define TCPSTREAM_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "rust/bindings.h" 25 | #include "readwrite.h" 26 | 27 | class QHostAddress; 28 | 29 | class SocketNotifier; 30 | 31 | class TcpStream : public ReadWrite 32 | { 33 | public: 34 | TcpStream(); 35 | ~TcpStream(); 36 | 37 | // disable copying 38 | TcpStream(const TcpStream &) = delete; 39 | TcpStream & operator=(const TcpStream &) = delete; 40 | 41 | // returns true if connection starting, false on error 42 | bool connect(const QHostAddress &addr, uint16_t port); 43 | 44 | // returns true if connected, false on error. if errorCondition() returns 45 | // ENOTCONN, then it is not fatal and the socket is still connecting 46 | bool checkConnected(); 47 | 48 | // reimplemented 49 | virtual QByteArray read(int size = -1); 50 | virtual int write(const QByteArray &buf); 51 | virtual int errorCondition() const { return errorCondition_; } 52 | 53 | private: 54 | friend class TcpListener; 55 | 56 | ffi::TcpStream *inner_; 57 | std::unique_ptr sn_; 58 | int errorCondition_; 59 | std::shared_ptr alive_; 60 | 61 | TcpStream(ffi::TcpStream *inner); 62 | void reset(); 63 | void setupNotifier(); 64 | void sn_activated(int socket, uint8_t readiness); 65 | }; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/core/tests.pri: -------------------------------------------------------------------------------- 1 | SOURCES += \ 2 | $$PWD/httpheaderstest.cpp \ 3 | $$PWD/jwttest.cpp \ 4 | $$PWD/timertest.cpp \ 5 | $$PWD/defercalltest.cpp \ 6 | $$PWD/tcpstreamtest.cpp \ 7 | $$PWD/unixstreamtest.cpp \ 8 | $$PWD/eventlooptest.cpp 9 | -------------------------------------------------------------------------------- /src/core/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Fanout, Inc. 3 | * Copyright (C) 2024-2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef TIMER_H 25 | #define TIMER_H 26 | 27 | #include 28 | 29 | using Signal = boost::signals2::signal; 30 | 31 | class EventLoop; 32 | class TimerManager; 33 | 34 | class Timer 35 | { 36 | public: 37 | Timer(); 38 | ~Timer(); 39 | 40 | bool isActive() const; 41 | 42 | void setSingleShot(bool singleShot); 43 | void setInterval(int msec); 44 | void start(int msec); 45 | void start(); 46 | void stop(); 47 | 48 | // initialization is thread local 49 | static void init(int capacity); 50 | 51 | // only call if there are no active timers 52 | static void deinit(); 53 | 54 | Signal timeout; 55 | 56 | private: 57 | friend class TimerManager; 58 | 59 | EventLoop *loop_; 60 | bool singleShot_; 61 | int interval_; 62 | int timerId_; 63 | 64 | static void cb_timer_activated(void *ctx, uint8_t readiness); 65 | void timerReady(); 66 | }; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/core/timertest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include "test.h" 24 | #include "timer.h" 25 | #include "eventloop.h" 26 | 27 | // loop_advance should process enough events to cause the timers to 28 | // activate, without sleeping, in order to prove timeouts of zero are 29 | // processed immediately 30 | static int runZeroTimeout(std::function loop_advance) 31 | { 32 | Timer t; 33 | t.setSingleShot(true); 34 | 35 | int count = 0; 36 | 37 | t.timeout.connect([&] { 38 | ++count; 39 | if(count < 2) 40 | t.start(0); 41 | }); 42 | 43 | t.start(0); 44 | 45 | loop_advance(); 46 | 47 | return count; 48 | } 49 | 50 | static void zeroTimeout() 51 | { 52 | EventLoop loop(1); 53 | 54 | int count = runZeroTimeout([&] { 55 | // activate the first timer and queue the second 56 | loop.step(); 57 | 58 | // activate the second 59 | loop.step(); 60 | }); 61 | 62 | TEST_ASSERT_EQ(count, 2); 63 | } 64 | 65 | static void zeroTimeoutQt() 66 | { 67 | TestQCoreApplication qapp; 68 | Timer::init(1); 69 | 70 | int count = runZeroTimeout([] { 71 | // the timer's qt-based implementation will process both timeouts 72 | // during a single timer processing pass. therefore, both 73 | // timeouts should get processed within a single event loop pass 74 | QCoreApplication::processEvents(QEventLoop::AllEvents); 75 | }); 76 | 77 | TEST_ASSERT_EQ(count, 2); 78 | 79 | Timer::deinit(); 80 | } 81 | 82 | 83 | extern "C" int timer_test(ffi::TestException *out_ex) 84 | { 85 | TEST_CATCH(zeroTimeout()); 86 | TEST_CATCH(zeroTimeoutQt()); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /src/core/timerwheel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include "timerwheel.h" 24 | 25 | #include "rust/bindings.h" 26 | 27 | TimerWheel::TimerWheel(int capacity) 28 | { 29 | raw_ = ffi::timer_wheel_create(capacity); 30 | } 31 | 32 | TimerWheel::~TimerWheel() 33 | { 34 | ffi::timer_wheel_destroy(raw_); 35 | } 36 | 37 | int TimerWheel::add(quint64 expires, size_t userData) 38 | { 39 | return ffi::timer_add(raw_, expires, userData); 40 | } 41 | 42 | void TimerWheel::remove(int key) 43 | { 44 | ffi::timer_remove(raw_, key); 45 | } 46 | 47 | qint64 TimerWheel::timeout() const 48 | { 49 | return ffi::timer_wheel_timeout(raw_); 50 | } 51 | 52 | void TimerWheel::update(quint64 curtime) 53 | { 54 | ffi::timer_wheel_update(raw_, curtime); 55 | } 56 | 57 | TimerWheel::Expired TimerWheel::takeExpired() 58 | { 59 | ffi::ExpiredTimer ret = ffi::timer_wheel_take_expired(raw_); 60 | 61 | Expired expired; 62 | expired.key = ret.key; 63 | expired.userData = ret.user_data; 64 | 65 | return expired; 66 | } 67 | -------------------------------------------------------------------------------- /src/core/timerwheel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef TIMERWHEEL_H 24 | #define TIMERWHEEL_H 25 | 26 | #include 27 | 28 | namespace ffi { 29 | struct TimerWheel; 30 | } 31 | 32 | class TimerWheel 33 | { 34 | public: 35 | class Expired 36 | { 37 | public: 38 | int key; // <0 if invalid 39 | size_t userData; 40 | }; 41 | 42 | TimerWheel(int capacity); 43 | ~TimerWheel(); 44 | 45 | // disable copying 46 | TimerWheel(const TimerWheel &) = delete; 47 | TimerWheel & operator=(const TimerWheel &) = delete; 48 | 49 | // returns <0 if no capacity 50 | int add(quint64 expires, size_t userData); 51 | 52 | void remove(int key); 53 | 54 | // returns <0 if no timers 55 | qint64 timeout() const; 56 | 57 | void update(quint64 curtime); 58 | 59 | Expired takeExpired(); 60 | 61 | private: 62 | ffi::TimerWheel *raw_; 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/core/unixlistener.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "unixlistener.h" 18 | 19 | #include "socketnotifier.h" 20 | 21 | UnixListener::UnixListener() : 22 | inner_(nullptr) 23 | { 24 | } 25 | 26 | UnixListener::~UnixListener() 27 | { 28 | reset(); 29 | } 30 | 31 | bool UnixListener::bind(const QString &path) 32 | { 33 | reset(); 34 | 35 | QByteArray p = path.toUtf8(); 36 | errorCondition_ = 0; 37 | 38 | inner_ = ffi::unix_listener_bind(p.data(), &errorCondition_); 39 | if(!inner_) 40 | return false; 41 | 42 | int fd = ffi::unix_listener_as_raw_fd(inner_); 43 | 44 | sn_ = std::make_unique(fd, SocketNotifier::Read); 45 | sn_->activated.connect(boost::bind(&UnixListener::sn_activated, this)); 46 | sn_->setReadEnabled(true); 47 | 48 | return true; 49 | } 50 | 51 | std::unique_ptr UnixListener::accept() 52 | { 53 | assert(inner_); 54 | 55 | errorCondition_ = 0; 56 | 57 | ffi::UnixStream *s_inner = ffi::unix_listener_accept(inner_, &errorCondition_); 58 | if(!s_inner) 59 | { 60 | if(errorCondition_ == EAGAIN) 61 | sn_->clearReadiness(SocketNotifier::Read); 62 | 63 | return std::unique_ptr(); // null 64 | } 65 | 66 | UnixStream *s = new UnixStream(s_inner); 67 | 68 | return std::unique_ptr(s); 69 | } 70 | 71 | void UnixListener::reset() 72 | { 73 | sn_.reset(); 74 | 75 | if(inner_) 76 | { 77 | ffi::unix_listener_destroy(inner_); 78 | inner_ = nullptr; 79 | } 80 | } 81 | 82 | void UnixListener::sn_activated() 83 | { 84 | streamsReady(); 85 | } 86 | -------------------------------------------------------------------------------- /src/core/unixlistener.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UNIXLISTENER_H 18 | #define UNIXLISTENER_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include "rust/bindings.h" 24 | #include "unixstream.h" 25 | 26 | class SocketNotifier; 27 | 28 | class UnixListener 29 | { 30 | public: 31 | UnixListener(); 32 | ~UnixListener(); 33 | 34 | // disable copying 35 | UnixListener(const UnixListener &) = delete; 36 | UnixListener & operator=(const UnixListener &) = delete; 37 | 38 | bool bind(const QString &path); 39 | std::unique_ptr accept(); 40 | int errorCondition() const { return errorCondition_; } 41 | 42 | boost::signals2::signal streamsReady; 43 | 44 | private: 45 | ffi::UnixListener *inner_; 46 | std::unique_ptr sn_; 47 | int errorCondition_; 48 | 49 | void reset(); 50 | void sn_activated(); 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/core/unixstream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UNIXSTREAM_H 18 | #define UNIXSTREAM_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "rust/bindings.h" 25 | #include "readwrite.h" 26 | 27 | class SocketNotifier; 28 | 29 | class UnixStream : public ReadWrite 30 | { 31 | public: 32 | UnixStream(); 33 | ~UnixStream(); 34 | 35 | // disable copying 36 | UnixStream(const UnixStream &) = delete; 37 | UnixStream & operator=(const UnixStream &) = delete; 38 | 39 | // returns true if connection starting, false on error 40 | bool connect(const QString &path); 41 | 42 | // returns true if connected, false on error. if errorCondition() returns 43 | // ENOTCONN, then it is not fatal and the socket is still connecting 44 | bool checkConnected(); 45 | 46 | // reimplemented 47 | virtual QByteArray read(int size = -1); 48 | virtual int write(const QByteArray &buf); 49 | virtual int errorCondition() const { return errorCondition_; } 50 | 51 | private: 52 | friend class UnixListener; 53 | 54 | ffi::UnixStream *inner_; 55 | std::unique_ptr sn_; 56 | int errorCondition_; 57 | std::shared_ptr alive_; 58 | 59 | UnixStream(ffi::UnixStream *inner); 60 | void reset(); 61 | void setupNotifier(); 62 | void sn_activated(int socket, uint8_t readiness); 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/core/uuidutil.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include "uuidutil.h" 24 | 25 | #include 26 | 27 | namespace UuidUtil { 28 | 29 | QByteArray createUuid() 30 | { 31 | QByteArray out = QUuid::createUuid().toString().toLatin1(); 32 | if(out[0] == '{' && out[out.length() - 1] == '}') 33 | out = out.mid(1, out.length() - 2); 34 | return out; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/core/uuidutil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef UUIDUTIL_H 24 | #define UUIDUTIL_H 25 | 26 | class QByteArray; 27 | 28 | namespace UuidUtil { 29 | 30 | QByteArray createUuid(); 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/core/wscontrol.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef WSCONTROL_H 24 | #define WSCONTROL_H 25 | 26 | namespace WsControl { 27 | 28 | enum KeepAliveMode 29 | { 30 | NoKeepAlive, 31 | Idle, 32 | Interval 33 | }; 34 | 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/core/zhttpresponsepacket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2016 Fanout, Inc. 3 | * 4 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * $FANOUT_END_LICENSE$ 19 | */ 20 | 21 | #ifndef ZHTTPRESPONSEPACKET_H 22 | #define ZHTTPRESPONSEPACKET_H 23 | 24 | #include 25 | #include "httpheaders.h" 26 | 27 | class ZhttpResponsePacket 28 | { 29 | public: 30 | class Id 31 | { 32 | public: 33 | QByteArray id; 34 | int seq; 35 | 36 | Id() : 37 | seq(-1) 38 | { 39 | } 40 | 41 | Id(const QByteArray &_id, int _seq = -1) : 42 | id(_id), 43 | seq(_seq) 44 | { 45 | } 46 | }; 47 | 48 | enum Type 49 | { 50 | Data, 51 | Error, 52 | Credit, 53 | KeepAlive, 54 | Cancel, 55 | HandoffStart, 56 | HandoffProceed, 57 | Close, // WebSocket 58 | Ping, // WebSocket 59 | Pong // WebSocket 60 | }; 61 | 62 | QByteArray from; 63 | QList ids; 64 | 65 | Type type; 66 | QByteArray condition; 67 | 68 | int credits; 69 | bool more; 70 | 71 | int code; 72 | QByteArray reason; 73 | HttpHeaders headers; 74 | QByteArray body; 75 | 76 | QByteArray contentType; // WebSocket 77 | 78 | QVariant userData; 79 | 80 | bool multi; 81 | 82 | ZhttpResponsePacket() : 83 | type((Type)-1), 84 | credits(-1), 85 | more(false), 86 | code(-1), 87 | multi(false) 88 | { 89 | } 90 | 91 | QVariant toVariant() const; 92 | bool fromVariant(const QVariant &in); 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/core/zrpcmanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Fanout, Inc. 3 | * Copyright (C) 2023-2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef ZRPCMANAGER_H 25 | #define ZRPCMANAGER_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | using Signal = boost::signals2::signal; 32 | 33 | class ZrpcRequestPacket; 34 | class ZrpcResponsePacket; 35 | class ZrpcRequest; 36 | 37 | class ZrpcManager 38 | { 39 | public: 40 | ZrpcManager(); 41 | ~ZrpcManager(); 42 | 43 | int timeout() const; 44 | 45 | void setInstanceId(const QByteArray &instanceId); 46 | void setIpcFileMode(int mode); 47 | void setBind(bool enable); 48 | void setTimeout(int ms); 49 | void setUnavailableOnTimeout(bool enable); 50 | 51 | bool setClientSpecs(const QStringList &specs); 52 | bool setServerSpecs(const QStringList &specs); 53 | 54 | ZrpcRequest *takeNext(); 55 | 56 | bool canWriteImmediately() const; 57 | void write(const ZrpcRequestPacket &packet); 58 | 59 | Signal requestReady; 60 | 61 | private: 62 | class Private; 63 | Private *d; 64 | 65 | friend class ZrpcRequest; 66 | void link(ZrpcRequest *req); 67 | void unlink(ZrpcRequest *req); 68 | void write(const QList &headers, const ZrpcResponsePacket &packet); 69 | }; 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/core/zutil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef ZUTIL_H 24 | #define ZUTIL_H 25 | 26 | #include 27 | #include 28 | 29 | namespace QZmq { 30 | 31 | class Socket; 32 | 33 | } 34 | 35 | namespace ZUtil { 36 | 37 | bool bindSpec(QZmq::Socket *sock, const QString &spec, int ipcFileMode, QString *errorMessage = 0); 38 | 39 | bool setupSocket(QZmq::Socket *sock, const QStringList &specs, bool bind, int ipcFileMode, QString *errorMessage = 0); 40 | 41 | bool setupSocket(QZmq::Socket *sock, const QString &spec, bool bind, int ipcFileMode, QString *errorMessage = 0); 42 | 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/cpp.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | CONFIG -= app_bundle 3 | CONFIG += staticlib c++17 4 | QT -= gui 5 | QT += network 6 | TARGET = pushpin-cpp 7 | 8 | cpp_build_dir = $$OUT_PWD 9 | 10 | MOC_DIR = $$cpp_build_dir/moc 11 | OBJECTS_DIR = $$cpp_build_dir/obj 12 | 13 | include($$cpp_build_dir/conf.pri) 14 | 15 | QMAKE_CXXFLAGS += $$(CXXFLAGS) 16 | QMAKE_CFLAGS += $$(CFLAGS) 17 | QMAKE_LFLAGS += $$(LDFLAGS) 18 | 19 | SRC_DIR = $$PWD 20 | 21 | INCLUDEPATH += $$SRC_DIR/../target/include 22 | INCLUDEPATH += $$SRC_DIR/core 23 | 24 | include(core/core.pri) 25 | include(m2adapter/m2adapter.pri) 26 | include(proxy/proxy.pri) 27 | include(handler/handler.pri) 28 | include(runner/runner.pri) 29 | -------------------------------------------------------------------------------- /src/cpptests.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | CONFIG -= app_bundle 3 | CONFIG += staticlib c++17 4 | QT -= gui 5 | QT *= network testlib 6 | TARGET = pushpin-cpptest 7 | 8 | cpp_build_dir = $$OUT_PWD 9 | 10 | MOC_DIR = $$cpp_build_dir/test-moc 11 | OBJECTS_DIR = $$cpp_build_dir/test-obj 12 | 13 | include($$cpp_build_dir/conf.pri) 14 | 15 | SRC_DIR = $$PWD 16 | 17 | INCLUDEPATH += $$SRC_DIR/../target/include 18 | INCLUDEPATH += $$SRC_DIR/core 19 | 20 | include(core/tests.pri) 21 | include(proxy/tests.pri) 22 | include(handler/tests.pri) 23 | include(runner/tests.pri) 24 | -------------------------------------------------------------------------------- /src/handler/cidset.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef CIDSET_H 24 | #define CIDSET_H 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | typedef QSet CidSet; 31 | Q_DECLARE_METATYPE(CidSet); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/handler/clientsession.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Fastly, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef CLIENTSESSION_H 24 | #define CLIENTSESSION_H 25 | 26 | class ClientSession 27 | { 28 | public: 29 | virtual ~ClientSession() = default; 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/handler/conncheckworker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef CONNCHECKWORKER_H 25 | #define CONNCHECKWORKER_H 26 | 27 | #include 28 | #include 29 | #include "zrpcrequest.h" 30 | #include "deferred.h" 31 | #include "cidset.h" 32 | 33 | using Connection = boost::signals2::scoped_connection; 34 | 35 | class ZrpcManager; 36 | class StatsManager; 37 | 38 | class ConnCheckWorker : public Deferred 39 | { 40 | public: 41 | ConnCheckWorker(ZrpcRequest *req, ZrpcManager *proxyControlClient, StatsManager *stats); 42 | 43 | private: 44 | std::unique_ptr req_; 45 | CidSet cids_; 46 | CidSet missing_; 47 | std::unique_ptr connCheck_; 48 | Connection finishedConnection_; 49 | 50 | void respondError(const QByteArray &condition); 51 | void doFinish(); 52 | 53 | private: 54 | void proxyConnCheck_finished(const DeferredResult &result); 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/handler/controlrequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016-2017 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef CONTROLREQUEST_H 25 | #define CONTROLREQUEST_H 26 | 27 | #include 28 | #include "cidset.h" 29 | 30 | using Connection = boost::signals2::scoped_connection; 31 | 32 | class ZrpcManager; 33 | class StatsPacket; 34 | class Deferred; 35 | 36 | namespace ControlRequest { 37 | 38 | Deferred *connCheck(ZrpcManager *controlClient, const CidSet &cids); 39 | Deferred *refresh(ZrpcManager *controlClient, const QByteArray &cid); 40 | Deferred *report(ZrpcManager *controlClient, const StatsPacket &packet); 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/handler/deferred.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #include "deferred.h" 25 | 26 | Deferred::Deferred() 27 | { 28 | qRegisterMetaType(); 29 | } 30 | 31 | Deferred::~Deferred() 32 | { 33 | } 34 | 35 | void Deferred::setFinished(bool ok, const QVariant &value) 36 | { 37 | result_.success = ok; 38 | result_.value = value; 39 | 40 | deferCall_.defer([=] { doFinish(); }); 41 | } 42 | 43 | void Deferred::doFinish() 44 | { 45 | finished(result_); 46 | } 47 | -------------------------------------------------------------------------------- /src/handler/deferred.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef DEFERRED_H 25 | #define DEFERRED_H 26 | 27 | #include 28 | #include 29 | #include "defercall.h" 30 | 31 | class DeferredResult 32 | { 33 | public: 34 | bool success; 35 | QVariant value; 36 | 37 | DeferredResult() : 38 | success(false) 39 | { 40 | } 41 | 42 | DeferredResult(bool _success, const QVariant &_value = QVariant()) : 43 | success(_success), 44 | value(_value) 45 | { 46 | } 47 | }; 48 | 49 | Q_DECLARE_METATYPE(DeferredResult) 50 | 51 | class Deferred 52 | { 53 | public: 54 | virtual ~Deferred(); 55 | 56 | boost::signals2::signal finished; 57 | 58 | protected: 59 | Deferred(); 60 | 61 | void setFinished(bool ok, const QVariant &value = QVariant()); 62 | 63 | private: 64 | DeferredResult result_; 65 | DeferCall deferCall_; 66 | 67 | void doFinish(); 68 | }; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/handler/detectrule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef DETECTRULE_H 24 | #define DETECTRULE_H 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | class DetectRule 31 | { 32 | public: 33 | QString domain; 34 | QByteArray pathPrefix; 35 | QString sidPtr; 36 | QString jsonParam; 37 | }; 38 | 39 | typedef QList DetectRuleList; 40 | Q_DECLARE_METATYPE(DetectRuleList); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/handler/filterstack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef FILTERSTACK_H 24 | #define FILTERSTACK_H 25 | 26 | #include 27 | #include "filter.h" 28 | 29 | class FilterStack : public Filter 30 | { 31 | public: 32 | FilterStack(const Filter::Context &context, const QStringList &filters); 33 | 34 | // takes ownership of filters in list 35 | FilterStack(const Filter::Context &context, const QList &filters); 36 | 37 | ~FilterStack(); 38 | 39 | // reimplemented 40 | virtual SendAction sendAction() const; 41 | virtual QByteArray update(const QByteArray &data); 42 | virtual QByteArray finalize(); 43 | 44 | private: 45 | QList filters_; 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/handler/format.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef FORMAT_H 24 | #define FORMAT_H 25 | 26 | #include 27 | #include 28 | 29 | namespace Format { 30 | 31 | class Handler 32 | { 33 | public: 34 | virtual ~Handler() {} 35 | 36 | // returns null array on error 37 | virtual QByteArray handle(char type, const QByteArray &arg, QString *error) const = 0; 38 | }; 39 | 40 | QByteArray process(const QByteArray &format, Handler *handler, int *partialPos = 0, QString *error = 0); 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/handler/handler.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/deferred.h \ 3 | $$PWD/variantutil.h \ 4 | $$PWD/jsonpointer.h \ 5 | $$PWD/jsonpatch.h \ 6 | $$PWD/detectrule.h \ 7 | $$PWD/lastids.h \ 8 | $$PWD/cidset.h \ 9 | $$PWD/sessionrequest.h \ 10 | $$PWD/requeststate.h \ 11 | $$PWD/wscontrolmessage.h \ 12 | $$PWD/publishformat.h \ 13 | $$PWD/publishitem.h \ 14 | $$PWD/instruct.h \ 15 | $$PWD/format.h \ 16 | $$PWD/idformat.h \ 17 | $$PWD/clientsession.h \ 18 | $$PWD/httpsession.h \ 19 | $$PWD/httpsessionupdatemanager.h \ 20 | $$PWD/wssession.h \ 21 | $$PWD/publishlastids.h \ 22 | $$PWD/controlrequest.h \ 23 | $$PWD/conncheckworker.h \ 24 | $$PWD/refreshworker.h \ 25 | $$PWD/ratelimiter.h \ 26 | $$PWD/sequencer.h \ 27 | $$PWD/filter.h \ 28 | $$PWD/filterstack.h \ 29 | $$PWD/handlerengine.h \ 30 | $$PWD/handlerapp.h \ 31 | $$PWD/main.h 32 | 33 | SOURCES += \ 34 | $$PWD/deferred.cpp \ 35 | $$PWD/variantutil.cpp \ 36 | $$PWD/jsonpointer.cpp \ 37 | $$PWD/jsonpatch.cpp \ 38 | $$PWD/sessionrequest.cpp \ 39 | $$PWD/requeststate.cpp \ 40 | $$PWD/wscontrolmessage.cpp \ 41 | $$PWD/publishformat.cpp \ 42 | $$PWD/publishitem.cpp \ 43 | $$PWD/instruct.cpp \ 44 | $$PWD/format.cpp \ 45 | $$PWD/idformat.cpp \ 46 | $$PWD/httpsession.cpp \ 47 | $$PWD/httpsessionupdatemanager.cpp \ 48 | $$PWD/wssession.cpp \ 49 | $$PWD/publishlastids.cpp \ 50 | $$PWD/controlrequest.cpp \ 51 | $$PWD/conncheckworker.cpp \ 52 | $$PWD/refreshworker.cpp \ 53 | $$PWD/ratelimiter.cpp \ 54 | $$PWD/sequencer.cpp \ 55 | $$PWD/filter.cpp \ 56 | $$PWD/filterstack.cpp \ 57 | $$PWD/handlerengine.cpp \ 58 | $$PWD/handlerapp.cpp \ 59 | $$PWD/handlermain.cpp 60 | -------------------------------------------------------------------------------- /src/handler/handlerapp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef HANDLERAPP_H 25 | #define HANDLERAPP_H 26 | 27 | class HandlerApp 28 | { 29 | public: 30 | HandlerApp(); 31 | ~HandlerApp(); 32 | 33 | int run(); 34 | 35 | private: 36 | class Private; 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/handler/handlermain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * Copyright (C) 2024-2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #include 25 | #include "handlerapp.h" 26 | 27 | extern "C" { 28 | 29 | int handler_main(int argc, char **argv) 30 | { 31 | QCoreApplication qapp(argc, argv); 32 | 33 | HandlerApp app; 34 | return app.run(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/handler/httpsessionupdatemanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef HTTPSESSIONUPDATEMANAGER_H 25 | #define HTTPSESSIONUPDATEMANAGER_H 26 | 27 | #define TIMERS_PER_UNIQUE_UPDATE_REGISTRATION 1 28 | 29 | class QUrl; 30 | class HttpSession; 31 | 32 | class HttpSessionUpdateManager 33 | { 34 | public: 35 | HttpSessionUpdateManager(); 36 | ~HttpSessionUpdateManager(); 37 | 38 | // no-op if session already registered and resetTimeout=false 39 | void registerSession(HttpSession *hs, int timeout, const QUrl &uri, bool resetTimeout = false); 40 | 41 | void unregisterSession(HttpSession *hs); 42 | 43 | private: 44 | class Private; 45 | Private *d; 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/handler/idformat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef IDFORMAT_H 24 | #define IDFORMAT_H 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace IdFormat { 31 | 32 | class ContentRenderer 33 | { 34 | public: 35 | ContentRenderer(const QByteArray &defaultId, bool hex); 36 | 37 | // return null array on error 38 | QByteArray update(const QByteArray &data); 39 | QByteArray finalize(); 40 | 41 | QString errorMessage() { return errorMessage_; } 42 | 43 | QByteArray process(const QByteArray &data); 44 | 45 | private: 46 | QByteArray defaultId_; 47 | bool hex_; 48 | QByteArray buf_; 49 | QString errorMessage_; 50 | }; 51 | 52 | QByteArray renderId(const QByteArray &data, const QHash &vars, QString *error = 0); 53 | 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/handler/instruct.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016-2019 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef INSTRUCT_H 24 | #define INSTRUCT_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "packet/httpresponsedata.h" 33 | 34 | class Instruct 35 | { 36 | public: 37 | enum HoldMode 38 | { 39 | NoHold, 40 | ResponseHold, 41 | StreamHold 42 | }; 43 | 44 | enum KeepAliveMode 45 | { 46 | NoKeepAlive, 47 | Idle, 48 | Interval 49 | }; 50 | 51 | class Channel 52 | { 53 | public: 54 | QString name; 55 | QString prevId; 56 | QStringList filters; 57 | }; 58 | 59 | HoldMode holdMode; 60 | QList channels; 61 | int timeout; 62 | QList exposeHeaders; 63 | KeepAliveMode keepAliveMode; 64 | QByteArray keepAliveData; 65 | int keepAliveTimeout; 66 | QHash meta; 67 | HttpResponseData response; 68 | QUrl nextLink; 69 | int nextLinkTimeout; 70 | QUrl goneLink; 71 | 72 | Instruct() : 73 | holdMode(NoHold), 74 | timeout(-1), 75 | keepAliveMode(NoKeepAlive), 76 | keepAliveTimeout(-1), 77 | nextLinkTimeout(-1) 78 | { 79 | } 80 | 81 | static Instruct fromResponse(const HttpResponseData &response, bool *ok = 0, QString *errorMessage = 0); 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /src/handler/jsonpatch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef JSONPATCH_H 24 | #define JSONPATCH_H 25 | 26 | #include 27 | 28 | namespace JsonPatch { 29 | 30 | QVariant patch(const QVariant &data, const QVariantList &ops, QString *errorMessage = 0); 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/handler/lastids.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef LASTIDS_H 24 | #define LASTIDS_H 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | typedef QHash LastIds; 31 | Q_DECLARE_METATYPE(LastIds); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/handler/main.h: -------------------------------------------------------------------------------- 1 | #ifndef HANDLER_MAIN_H 2 | #define HANDLER_MAIN_H 3 | 4 | int handler_main(int argc, char **argv); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/handler/publishformat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016-2020 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef PUBLISHFORMAT_H 24 | #define PUBLISHFORMAT_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include "httpheaders.h" 30 | 31 | class PublishFormat 32 | { 33 | public: 34 | enum Type 35 | { 36 | HttpResponse, 37 | HttpStream, 38 | WebSocketMessage 39 | }; 40 | 41 | enum Action 42 | { 43 | Send, 44 | Hint, 45 | Refresh, 46 | Close 47 | }; 48 | 49 | enum MessageType 50 | { 51 | Text, 52 | Binary, 53 | Ping, 54 | Pong 55 | }; 56 | 57 | Type type; 58 | Action action; // response/stream/ws 59 | int code; // response/ws 60 | QByteArray reason; // response/ws 61 | HttpHeaders headers; // response 62 | QByteArray body; // response/stream/ws 63 | bool haveBodyPatch; // response 64 | QVariantList bodyPatch; // response 65 | MessageType messageType; // ws 66 | bool haveContentFilters; 67 | QStringList contentFilters; // response/stream/ws 68 | 69 | PublishFormat() : 70 | type((Type)-1), 71 | action(Send), 72 | code(-1), 73 | haveBodyPatch(false), 74 | messageType((MessageType)-1), 75 | haveContentFilters(false) 76 | { 77 | } 78 | 79 | PublishFormat(Type _type) : 80 | type(_type), 81 | action(Send), 82 | code(-1), 83 | haveBodyPatch(false), 84 | messageType((MessageType)-1), 85 | haveContentFilters(false) 86 | { 87 | } 88 | 89 | static PublishFormat fromVariant(Type type, const QVariant &in, bool *ok = 0, QString *errorMessage = 0); 90 | }; 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /src/handler/publishitem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef PUBLISHITEM_H 24 | #define PUBLISHITEM_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include "publishformat.h" 30 | 31 | class PublishItem 32 | { 33 | public: 34 | QString channel; 35 | QString id; 36 | QString prevId; 37 | QHash formats; 38 | QHash meta; 39 | int size; 40 | bool noSeq; 41 | 42 | PublishFormat format; // for single format items 43 | 44 | PublishItem() : 45 | size(-1), 46 | noSeq(false) 47 | { 48 | } 49 | 50 | static PublishItem fromVariant(const QVariant &vitem, const QString &channel = QString(), bool *ok = 0, QString *errorMessage = 0); 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/handler/publishlastids.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef PUBLISHLASTIDS_H 24 | #define PUBLISHLASTIDS_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | // cache with LRU expiration 32 | class PublishLastIds 33 | { 34 | public: 35 | PublishLastIds(int maxCapacity); 36 | void set(const QString &channel, const QString &id); 37 | void remove(const QString &channel); 38 | void clear(); 39 | QString value(const QString &channel); 40 | 41 | private: 42 | typedef QPair TimeStringPair; 43 | 44 | class Item 45 | { 46 | public: 47 | QString channel; 48 | QString id; 49 | QDateTime time; 50 | }; 51 | 52 | QHash table_; 53 | QMap recentlyUsed_; 54 | int maxCapacity_; 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/handler/ratelimiter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef RATELIMITER_H 25 | #define RATELIMITER_H 26 | 27 | #include 28 | 29 | class QString; 30 | 31 | class RateLimiter 32 | { 33 | public: 34 | class Action 35 | { 36 | public: 37 | virtual ~Action() {} 38 | 39 | virtual bool execute() = 0; 40 | }; 41 | 42 | RateLimiter(); 43 | ~RateLimiter(); 44 | 45 | void setRate(int actionsPerSecond); 46 | void setHwm(int hwm); 47 | void setBatchWaitEnabled(bool on); 48 | 49 | bool addAction(const QString &key, Action *action, int weight = 1); 50 | Action *lastAction(const QString &key) const; 51 | 52 | private: 53 | class Private; 54 | std::shared_ptr d; 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/handler/refreshworker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2020 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef REFRESHWORKER_H 25 | #define REFRESHWORKER_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "deferred.h" 32 | #include "zrpcrequest.h" 33 | 34 | using Connection = boost::signals2::scoped_connection; 35 | 36 | class ZrpcManager; 37 | class StatsManager; 38 | class WsSession; 39 | 40 | class RefreshWorker : public Deferred 41 | { 42 | public: 43 | RefreshWorker(ZrpcRequest *req, ZrpcManager *proxyControlClient, QHash > *wsSessionsByChannel); 44 | 45 | private: 46 | QStringList cids_; 47 | bool ignoreErrors_; 48 | ZrpcManager *proxyControlClient_; 49 | std::unique_ptr req_; 50 | std::unique_ptr refresh_; 51 | Connection finishedConnection_; 52 | 53 | void refreshNextCid(); 54 | void respondError(const QByteArray &condition); 55 | void proxyRefresh_finished(const DeferredResult &result); 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/handler/requeststate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016-2023 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef REQUESTSTATE_H 25 | #define REQUESTSTATE_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include "zhttprequest.h" 31 | 32 | class RequestState 33 | { 34 | public: 35 | ZhttpRequest::Rid rid; 36 | int responseCode; 37 | int inSeq; 38 | int outSeq; 39 | int outCredits; 40 | bool routerResp; 41 | QHostAddress peerAddress; 42 | QHostAddress logicalPeerAddress; 43 | bool isHttps; 44 | bool debug; 45 | bool isRetry; 46 | bool autoCrossOrigin; 47 | QByteArray jsonpCallback; 48 | bool jsonpExtendedResponse; 49 | int unreportedTime; 50 | QVariant userData; 51 | 52 | RequestState() : 53 | responseCode(-1), 54 | inSeq(0), 55 | outSeq(0), 56 | outCredits(0), 57 | routerResp(false), 58 | isHttps(false), 59 | debug(false), 60 | isRetry(false), 61 | autoCrossOrigin(false), 62 | jsonpExtendedResponse(false), 63 | unreportedTime(-1) 64 | { 65 | } 66 | 67 | static RequestState fromVariant(const QVariant &in); 68 | }; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/handler/sequencer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016-2021 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef SEQUENCER_H 25 | #define SEQUENCER_H 26 | 27 | #include 28 | 29 | class QString; 30 | 31 | class PublishLastIds; 32 | class PublishItem; 33 | 34 | class Sequencer 35 | { 36 | public: 37 | Sequencer(PublishLastIds *publishLastIds); 38 | ~Sequencer(); 39 | 40 | void setWaitMax(int msecs); 41 | void setIdCacheTtl(int secs); 42 | 43 | // seq = false means ID cache handling only 44 | // note: may emit signals 45 | void addItem(const PublishItem &item, bool seq = true); 46 | 47 | void clearPendingForChannel(const QString &channel); 48 | 49 | boost::signals2::signal itemReady; 50 | 51 | private: 52 | class Private; 53 | friend class Private; 54 | Private *d; 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/handler/sessionrequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef SESSIONREQUEST_H 25 | #define SESSIONREQUEST_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include "lastids.h" 31 | #include 32 | 33 | using Connection = boost::signals2::scoped_connection; 34 | 35 | class ZrpcManager; 36 | class Deferred; 37 | class DetectRule; 38 | 39 | namespace SessionRequest { 40 | 41 | Deferred *detectRulesSet(ZrpcManager *stateClient, const QList &rules); 42 | Deferred *detectRulesGet(ZrpcManager *stateClient, const QString &domain, const QByteArray &path); 43 | Deferred *createOrUpdate(ZrpcManager *stateClient, const QString &sid, const LastIds &lastIds); 44 | Deferred *updateMany(ZrpcManager *stateClient, const QHash &sidLastIds); 45 | Deferred *getLastIds(ZrpcManager *stateClient, const QString &sid); 46 | 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/handler/tests.pri: -------------------------------------------------------------------------------- 1 | SOURCES += \ 2 | $$PWD/filtertest.cpp \ 3 | $$PWD/jsonpatchtest.cpp \ 4 | $$PWD/instructtest.cpp \ 5 | $$PWD/idformattest.cpp \ 6 | $$PWD/publishformattest.cpp \ 7 | $$PWD/publishitemtest.cpp \ 8 | $$PWD/handlerenginetest.cpp 9 | -------------------------------------------------------------------------------- /src/handler/variantutil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef VARIANTUTIL_H 24 | #define VARIANTUTIL_H 25 | 26 | #include 27 | 28 | namespace VariantUtil { 29 | 30 | void setSuccess(bool *ok, QString *errorMessage); 31 | void setError(bool *ok, QString *errorMessage, const QString &msg); 32 | 33 | bool isKeyedObject(const QVariant &in); 34 | QVariant createSameKeyedObject(const QVariant &in); 35 | bool keyedObjectIsEmpty(const QVariant &in); 36 | bool keyedObjectContains(const QVariant &in, const QString &name); 37 | QVariant keyedObjectGetValue(const QVariant &in, const QString &name); 38 | void keyedObjectInsert(QVariant *in, const QString &name, const QVariant &value); 39 | 40 | QVariant getChild(const QVariant &in, const QString &parentName, const QString &childName, bool required, bool *ok = 0, QString *errorMessage = 0); 41 | QVariant getKeyedObject(const QVariant &in, const QString &parentName, const QString &childName, bool required, bool *ok = 0, QString *errorMessage = 0); 42 | QVariantList getList(const QVariant &in, const QString &parentName, const QString &childName, bool required, bool *ok = 0, QString *errorMessage = 0); 43 | QString getString(const QVariant &in, bool *ok = 0); 44 | QString getString(const QVariant &in, const QString &parentName, const QString &childName, bool required, bool *ok = 0, QString *errorMessage = 0); 45 | 46 | // return true if item modified 47 | bool convertToJsonStyleInPlace(QVariant *in); 48 | 49 | QVariant convertToJsonStyle(const QVariant &in); 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/handler/wscontrolmessage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016-2019 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef WSCONTROLMESSAGE_H 24 | #define WSCONTROLMESSAGE_H 25 | 26 | #include 27 | #include 28 | 29 | class QVariant; 30 | 31 | class WsControlMessage 32 | { 33 | public: 34 | enum Type 35 | { 36 | Subscribe, 37 | Unsubscribe, 38 | Detach, 39 | Session, 40 | SetMeta, 41 | KeepAlive, 42 | SendDelayed, 43 | FlushDelayed 44 | }; 45 | 46 | enum MessageType 47 | { 48 | Text, 49 | Binary, 50 | Ping, 51 | Pong 52 | }; 53 | 54 | Type type; 55 | QString channel; 56 | QStringList filters; 57 | QString sessionId; 58 | QString metaName; 59 | QString metaValue; 60 | MessageType messageType; 61 | QByteArray content; 62 | int timeout; 63 | QByteArray keepAliveMode; 64 | 65 | WsControlMessage() : 66 | type((Type)-1), 67 | messageType((MessageType)-1), 68 | timeout(-1) 69 | { 70 | } 71 | 72 | static WsControlMessage fromVariant(const QVariant &in, bool *ok = 0, QString *errorMessage = 0); 73 | }; 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /src/m2adapter/README: -------------------------------------------------------------------------------- 1 | M2Adapter 2 | --------- 3 | 4 | Put behind mongrel2 to convert its protocol to zmq-http. More than one 5 | mongrel2 can be linked to the same m2adapter. However, a mongrel2 may not be 6 | linked to more than one m2adapter! 7 | -------------------------------------------------------------------------------- /src/m2adapter/m2adapter.conf.example: -------------------------------------------------------------------------------- 1 | [General] 2 | # list of mongrel2 handler send_spec 3 | m2_in_specs= 4 | 5 | # list of mongrel2 handler recv_spec 6 | m2_out_specs= 7 | 8 | # list of mongrel2 send_ident (per send_spec) 9 | m2_send_idents= 10 | 11 | # list of mongrel2 control specs (per send_ident) 12 | m2_control_specs= 13 | 14 | # set to true if zhttp specs should connect. else, bind. 15 | #zhttp_connect=true 16 | 17 | # zhttp in specs 18 | zhttp_in_specs= 19 | 20 | # zhttp out specs 21 | zhttp_out_specs= 22 | 23 | # zhttp out stream specs 24 | zhttp_out_stream_specs= 25 | 26 | # set to true if zws specs should connect. else, bind. 27 | #zws_connect=true 28 | 29 | # zws in specs 30 | zws_in_specs= 31 | 32 | # zws out specs 33 | zws_out_specs= 34 | 35 | # zws out stream specs 36 | zws_out_stream_specs= 37 | 38 | # useful for testing with zurl 39 | #zhttp_connect_port=8080 40 | #zws_connect_port=8080 41 | #ignore_policies=true 42 | 43 | # don't send more than this to mongrel2 44 | m2_client_buffer=200000 45 | -------------------------------------------------------------------------------- /src/m2adapter/m2adapter.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/m2requestpacket.h \ 3 | $$PWD/m2responsepacket.h \ 4 | $$PWD/m2adapterapp.h \ 5 | $$PWD/main.h 6 | 7 | SOURCES += \ 8 | $$PWD/m2requestpacket.cpp \ 9 | $$PWD/m2responsepacket.cpp \ 10 | $$PWD/m2adapterapp.cpp \ 11 | $$PWD/m2adaptermain.cpp 12 | -------------------------------------------------------------------------------- /src/m2adapter/m2adapterapp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef M2ADAPTERAPP_H 24 | #define M2ADAPTERAPP_H 25 | 26 | #include 27 | #include 28 | 29 | using std::map; 30 | using SignalInt = boost::signals2::signal; 31 | using Connection = boost::signals2::scoped_connection; 32 | 33 | class M2AdapterApp : public QObject 34 | { 35 | Q_OBJECT 36 | 37 | public: 38 | M2AdapterApp(QObject *parent = 0); 39 | ~M2AdapterApp(); 40 | 41 | void start(); 42 | 43 | SignalInt quit; 44 | 45 | private: 46 | class Private; 47 | friend class Private; 48 | Private *d; 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/m2adapter/m2adaptermain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include 24 | #include 25 | #include "m2adapterapp.h" 26 | 27 | class M2AdapterAppMain 28 | { 29 | public: 30 | M2AdapterApp *app; 31 | 32 | void start() 33 | { 34 | app = new M2AdapterApp; 35 | app->quit.connect(boost::bind(&M2AdapterAppMain::app_quit, this, boost::placeholders::_1)); 36 | app->start(); 37 | } 38 | 39 | void app_quit(int returnCode) 40 | { 41 | delete app; 42 | QCoreApplication::exit(returnCode); 43 | } 44 | }; 45 | 46 | extern "C" { 47 | 48 | int m2adapter_main(int argc, char **argv) 49 | { 50 | QCoreApplication qapp(argc, argv); 51 | 52 | M2AdapterAppMain appMain; 53 | QTimer::singleShot(0, [&appMain]() {appMain.start();}); 54 | return qapp.exec(); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/m2adapter/m2requestpacket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef M2REQUESTPACKET_H 24 | #define M2REQUESTPACKET_H 25 | 26 | #include 27 | #include 28 | #include "httpheaders.h" 29 | 30 | class M2RequestPacket 31 | { 32 | public: 33 | enum Type 34 | { 35 | HttpRequest, 36 | WebSocketHandshake, // body will contain accept token 37 | WebSocketFrame, 38 | Disconnect, 39 | Credits 40 | }; 41 | 42 | QByteArray sender; 43 | QByteArray id; 44 | 45 | Type type; 46 | 47 | QHostAddress remoteAddress; 48 | QByteArray scheme; 49 | QByteArray version; 50 | QString method; 51 | QByteArray uri; 52 | HttpHeaders headers; 53 | QByteArray body; 54 | 55 | QString uploadFile; 56 | bool uploadDone; 57 | 58 | int uploadStreamOffset; 59 | bool uploadStreamDone; 60 | 61 | int downloadCredits; 62 | 63 | int frameFlags; 64 | 65 | M2RequestPacket(); 66 | 67 | bool fromByteArray(const QByteArray &in); 68 | }; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/m2adapter/m2responsepacket.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include "m2responsepacket.h" 24 | 25 | #include "tnetstring.h" 26 | 27 | M2ResponsePacket::M2ResponsePacket() 28 | { 29 | } 30 | 31 | QByteArray M2ResponsePacket::toByteArray() const 32 | { 33 | return sender + ' ' + TnetString::fromByteArray(id) + ' ' + data; 34 | } 35 | -------------------------------------------------------------------------------- /src/m2adapter/m2responsepacket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef M2RESPONSEPACKET_H 24 | #define M2RESPONSEPACKET_H 25 | 26 | #include 27 | 28 | class M2ResponsePacket 29 | { 30 | public: 31 | QByteArray sender; 32 | QByteArray id; 33 | QByteArray data; 34 | 35 | M2ResponsePacket(); 36 | 37 | QByteArray toByteArray() const; 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/m2adapter/main.h: -------------------------------------------------------------------------------- 1 | #ifndef M2ADAPTER_MAIN_H 2 | #define M2ADAPTER_MAIN_H 3 | 4 | int m2adapter_main(int argc, char **argv); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/m2adapter/tools/handoffhandler.py: -------------------------------------------------------------------------------- 1 | # this handler will start a handoff and then reclaim it 10 seconds later 2 | 3 | import time 4 | import tnetstring 5 | import zmq 6 | 7 | client_id = "zhttp-test" 8 | 9 | ctx = zmq.Context() 10 | in_sock = ctx.socket(zmq.PULL) 11 | in_sock.connect("ipc:///tmp/zhttp-test-out") 12 | in_stream_sock = ctx.socket(zmq.ROUTER) 13 | in_stream_sock.identity = client_id 14 | in_stream_sock.connect("ipc:///tmp/zhttp-test-out-stream") 15 | out_sock = ctx.socket(zmq.PUB) 16 | out_sock.connect("ipc:///tmp/zhttp-test-in") 17 | 18 | while True: 19 | m_raw = in_sock.recv() 20 | req = tnetstring.loads(m_raw[1:]) 21 | print("IN %s" % req) 22 | 23 | out_seq = 0 24 | 25 | resp = dict() 26 | resp["from"] = client_id 27 | resp["id"] = req["id"] 28 | resp["seq"] = out_seq 29 | out_seq += 1 30 | resp["type"] = "handoff-start" 31 | print("OUT %s" % resp) 32 | out_sock.send(req["from"] + " T" + tnetstring.dumps(resp)) 33 | 34 | m_raw = in_stream_sock.recv_multipart() 35 | req = tnetstring.loads(m_raw[2][1:]) 36 | print("IN %s" % req) 37 | 38 | assert req["type"] == "handoff-proceed" 39 | 40 | time.sleep(10) 41 | 42 | resp = dict() 43 | resp["from"] = client_id 44 | resp["id"] = req["id"] 45 | resp["seq"] = out_seq 46 | out_seq += 1 47 | resp["type"] = "keep-alive" 48 | print("OUT %s" % resp) 49 | out_sock.send(req["from"] + " T" + tnetstring.dumps(resp)) 50 | 51 | m_raw = in_stream_sock.recv_multipart() 52 | req = tnetstring.loads(m_raw[2][1:]) 53 | print("IN %s" % req) 54 | 55 | assert req["type"] == "error" 56 | print("error: %s" % req["condition"]) 57 | -------------------------------------------------------------------------------- /src/m2adapter/tools/hanghandler.py: -------------------------------------------------------------------------------- 1 | # this handler just eats requests and never responds. what a jerk! 2 | 3 | import tnetstring 4 | import zmq 5 | 6 | ctx = zmq.Context() 7 | in_sock = ctx.socket(zmq.PULL) 8 | in_sock.connect("ipc:///tmp/zhttp-test-out") 9 | 10 | while True: 11 | m_raw = in_sock.recv() 12 | req = tnetstring.loads(m_raw[1:]) 13 | print("IN %s" % req) 14 | -------------------------------------------------------------------------------- /src/m2adapter/tools/hello.txt: -------------------------------------------------------------------------------- 1 | hello world 2 | -------------------------------------------------------------------------------- /src/m2adapter/tools/keephandler.py: -------------------------------------------------------------------------------- 1 | # this handler doesn't respond to requests, but will send keep-alives forever 2 | 3 | import time 4 | import threading 5 | import tnetstring 6 | import zmq 7 | 8 | 9 | class Session(object): 10 | def __init__(self): 11 | self.to_address = None 12 | self.out_seq = 0 13 | 14 | 15 | sessions = dict() 16 | lock = threading.Lock() 17 | 18 | client_id = "zhttp-test" 19 | 20 | ctx = zmq.Context() 21 | in_sock = ctx.socket(zmq.PULL) 22 | in_sock.connect("ipc:///tmp/zhttp-test-out") 23 | out_sock = ctx.socket(zmq.PUB) 24 | out_sock.connect("ipc:///tmp/zhttp-test-in") 25 | 26 | 27 | def keepalive_worker(): 28 | lock.acquire() 29 | for id, s in sessions.iteritems(): 30 | resp = dict() 31 | resp["from"] = client_id 32 | resp["id"] = id 33 | resp["seq"] = s.out_seq 34 | s.out_seq += 1 35 | resp["type"] = "credit" 36 | resp["credits"] = 0 37 | 38 | print("OUT %s" % resp) 39 | out_sock.send(s.to_address + " T" + tnetstring.dumps(resp)) 40 | lock.release() 41 | 42 | 43 | class KeepAliveThread(threading.Thread): 44 | def run(self): 45 | while True: 46 | keepalive_worker() 47 | time.sleep(30) 48 | 49 | 50 | keepalive_thread = KeepAliveThread() 51 | keepalive_thread.daemon = True 52 | keepalive_thread.start() 53 | 54 | while True: 55 | m_raw = in_sock.recv() 56 | req = tnetstring.loads(m_raw[1:]) 57 | print("IN %s" % req) 58 | 59 | id = req["id"] 60 | if id in sessions: 61 | print("session already active") 62 | continue 63 | 64 | if "type" in req: 65 | print("wrong packet type") 66 | continue 67 | 68 | s = Session() 69 | s.to_address = req["from"] 70 | lock.acquire() 71 | sessions[id] = s 72 | lock.release() 73 | -------------------------------------------------------------------------------- /src/m2adapter/tools/m2control.py: -------------------------------------------------------------------------------- 1 | # adapted from mongrel2's manual 2 | 3 | import sys 4 | import zmq 5 | import tnetstring 6 | from pprint import pprint 7 | 8 | CTX = zmq.Context() 9 | addr = sys.argv[1] 10 | 11 | ctl = CTX.socket(zmq.REQ) 12 | 13 | print("CONNECTING") 14 | ctl.connect(addr) 15 | 16 | while True: 17 | cmd = raw_input("> ") 18 | # will only work with simple commands that have no arguments 19 | ctl.send(tnetstring.dumps([cmd, {}])) 20 | 21 | resp = ctl.recv() 22 | 23 | pprint(tnetstring.loads(resp)) 24 | 25 | ctl.close() 26 | -------------------------------------------------------------------------------- /src/m2adapter/tools/testhandler.py: -------------------------------------------------------------------------------- 1 | # this handler responds to every request with "hello world" 2 | 3 | import tnetstring 4 | import zmq 5 | 6 | ctx = zmq.Context() 7 | in_sock = ctx.socket(zmq.PULL) 8 | in_sock.connect("ipc:///tmp/zhttp-test-out") 9 | out_sock = ctx.socket(zmq.PUB) 10 | out_sock.connect("ipc:///tmp/zhttp-test-in") 11 | 12 | while True: 13 | m_raw = in_sock.recv() 14 | req = tnetstring.loads(m_raw[1:]) 15 | print("IN %s" % req) 16 | 17 | resp = dict() 18 | resp["id"] = req["id"] 19 | resp["code"] = 200 20 | resp["reason"] = "OK" 21 | resp["headers"] = [["Content-Type", "text/plain"]] 22 | resp["body"] = "hello world\n" 23 | 24 | print("OUT %s" % resp) 25 | out_sock.send(req["from"] + " T" + tnetstring.dumps(resp)) 26 | -------------------------------------------------------------------------------- /src/m2adapter/tools/wsechohandler.py: -------------------------------------------------------------------------------- 1 | # this handler echos every frame 2 | 3 | import tnetstring 4 | import zmq 5 | 6 | instance_id = "wsechohandler" 7 | 8 | ctx = zmq.Context() 9 | in_sock = ctx.socket(zmq.PULL) 10 | in_sock.connect("ipc:///tmp/zhttp-test-out") 11 | in_stream_sock = ctx.socket(zmq.ROUTER) 12 | in_stream_sock.setsockopt(zmq.IDENTITY, instance_id) 13 | in_stream_sock.connect("ipc:///tmp/zhttp-test-out-stream") 14 | out_sock = ctx.socket(zmq.PUB) 15 | out_sock.connect("ipc:///tmp/zhttp-test-in") 16 | 17 | poller = zmq.Poller() 18 | poller.register(in_sock, zmq.POLLIN) 19 | poller.register(in_stream_sock, zmq.POLLIN) 20 | 21 | sessions = set() 22 | 23 | while True: 24 | socks = dict(poller.poll()) 25 | if socks.get(in_sock) == zmq.POLLIN: 26 | m_raw = in_sock.recv() 27 | req = tnetstring.loads(m_raw[1:]) 28 | elif socks.get(in_stream_sock) == zmq.POLLIN: 29 | m_raw = in_stream_sock.recv_multipart() 30 | req = tnetstring.loads(m_raw[2][1:]) 31 | else: 32 | continue 33 | 34 | print("IN %s" % req) 35 | 36 | rid = (req["from"], req["id"]) 37 | 38 | resp = dict() 39 | if rid not in sessions: 40 | rtype = req.get("type") 41 | 42 | # first packet must be a data packet 43 | if rtype is not None: 44 | continue 45 | 46 | sessions.add(rid) 47 | resp["credits"] = 200000 48 | else: 49 | rtype = req.get("type") 50 | if rtype is None: 51 | if "content-type" in req: 52 | resp["content-type"] = req["content-type"] 53 | resp["body"] = req["body"] 54 | count = len(req["body"]) 55 | if req.get("more"): 56 | resp["more"] = True 57 | resp["credits"] = len(req["body"]) 58 | elif rtype == "close": 59 | sessions.remove(rid) 60 | resp["type"] = "close" 61 | if "code" in req: 62 | resp["code"] = req["code"] 63 | elif rtype == "keep-alive": 64 | resp["type"] = "keep-alive" 65 | else: 66 | continue 67 | 68 | resp["from"] = instance_id 69 | resp["id"] = req["id"] 70 | print("OUT %s" % resp) 71 | out_sock.send(req["from"] + " T" + tnetstring.dumps(resp)) 72 | -------------------------------------------------------------------------------- /src/proxy/acceptrequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef ACCEPTREQUEST_H 25 | #define ACCEPTREQUEST_H 26 | 27 | #include "packet/httpresponsedata.h" 28 | #include "zrpcrequest.h" 29 | 30 | class AcceptData; 31 | class ZrpcManager; 32 | 33 | class AcceptRequest : public ZrpcRequest 34 | { 35 | public: 36 | class ResponseData 37 | { 38 | public: 39 | bool accepted; 40 | HttpResponseData response; 41 | 42 | ResponseData() : 43 | accepted(false) 44 | { 45 | } 46 | }; 47 | 48 | AcceptRequest(ZrpcManager *manager); 49 | ~AcceptRequest(); 50 | 51 | ResponseData result() const; 52 | 53 | void start(const AcceptData &adata); 54 | 55 | protected: 56 | virtual void onSuccess(); 57 | 58 | private: 59 | class Private; 60 | std::unique_ptr d; 61 | }; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /src/proxy/app.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef APP_H 25 | #define APP_H 26 | 27 | class App 28 | { 29 | public: 30 | App(); 31 | ~App(); 32 | 33 | int run(); 34 | 35 | private: 36 | class Private; 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/proxy/connectionmanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015-2017 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef CONNECTIONMANAGER_H 24 | #define CONNECTIONMANAGER_H 25 | 26 | #include 27 | #include 28 | 29 | class WebSocket; 30 | class WsProxySession; 31 | 32 | class ConnectionManager 33 | { 34 | public: 35 | ConnectionManager(); 36 | ~ConnectionManager(); 37 | 38 | // returns cid 39 | QByteArray addConnection(WebSocket *sock); 40 | 41 | // returns cid or empty 42 | QByteArray getConnection(WebSocket *sock) const; 43 | 44 | void removeConnection(WebSocket *sock); 45 | 46 | WsProxySession *getProxyForConnection(const QByteArray &cid) const; 47 | 48 | void setProxyForConnection(WebSocket *sock, WsProxySession *proxy); 49 | 50 | private: 51 | class Private; 52 | Private *d; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/proxy/inspectrequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2015 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef INSPECTREQUEST_H 25 | #define INSPECTREQUEST_H 26 | 27 | #include "zrpcrequest.h" 28 | 29 | class HttpRequestData; 30 | class InspectData; 31 | class ZrpcManager; 32 | 33 | class InspectRequest : public ZrpcRequest 34 | { 35 | public: 36 | InspectRequest(ZrpcManager *manager); 37 | ~InspectRequest(); 38 | 39 | InspectData result() const; 40 | 41 | void start(const HttpRequestData &hdata, bool truncated, bool getSession, bool autoShare); 42 | 43 | protected: 44 | virtual void onSuccess(); 45 | 46 | private: 47 | class Private; 48 | Private *d; 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/proxy/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #include 25 | #include "app.h" 26 | 27 | extern "C" { 28 | 29 | int proxy_main(int argc, char **argv) 30 | { 31 | QCoreApplication qapp(argc, argv); 32 | 33 | App app; 34 | return app.run(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/proxy/main.h: -------------------------------------------------------------------------------- 1 | #ifndef PROXY_MAIN_H 2 | #define PROXY_MAIN_H 3 | 4 | int proxy_main(int argc, char **argv); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/proxy/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024-2025 Fastly, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #[cfg(test)] 18 | mod tests { 19 | use crate::core::test::{run_serial, TestException}; 20 | use crate::ffi; 21 | 22 | fn websocketoverhttp_test(out_ex: &mut TestException) -> bool { 23 | // SAFETY: safe to call 24 | unsafe { ffi::websocketoverhttp_test(out_ex) == 0 } 25 | } 26 | 27 | fn routesfile_test(out_ex: &mut TestException) -> bool { 28 | // SAFETY: safe to call 29 | unsafe { ffi::routesfile_test(out_ex) == 0 } 30 | } 31 | 32 | fn proxyengine_test(out_ex: &mut TestException) -> bool { 33 | // SAFETY: safe to call 34 | unsafe { ffi::proxyengine_test(out_ex) == 0 } 35 | } 36 | 37 | #[test] 38 | fn websocketoverhttp() { 39 | run_serial(websocketoverhttp_test); 40 | } 41 | 42 | #[test] 43 | fn routesfile() { 44 | run_serial(routesfile_test); 45 | } 46 | 47 | #[test] 48 | fn proxyengine() { 49 | run_serial(proxyengine_test); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/proxy/proxy.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/testhttprequest.h \ 3 | $$PWD/testwebsocket.h \ 4 | $$PWD/websocketoverhttp.h \ 5 | $$PWD/zrpcchecker.h \ 6 | $$PWD/sockjsmanager.h \ 7 | $$PWD/sockjssession.h \ 8 | $$PWD/inspectrequest.h \ 9 | $$PWD/acceptrequest.h \ 10 | $$PWD/connectionmanager.h \ 11 | $$PWD/wscontrolmanager.h \ 12 | $$PWD/wscontrolsession.h \ 13 | $$PWD/acceptdata.h \ 14 | $$PWD/routesfile.h \ 15 | $$PWD/domainmap.h \ 16 | $$PWD/zroutes.h \ 17 | $$PWD/xffrule.h \ 18 | $$PWD/requestsession.h \ 19 | $$PWD/proxyutil.h \ 20 | $$PWD/proxysession.h \ 21 | $$PWD/wsproxysession.h \ 22 | $$PWD/updater.h \ 23 | $$PWD/engine.h \ 24 | $$PWD/app.h \ 25 | $$PWD/main.h 26 | 27 | SOURCES += \ 28 | $$PWD/testhttprequest.cpp \ 29 | $$PWD/testwebsocket.cpp \ 30 | $$PWD/websocketoverhttp.cpp \ 31 | $$PWD/zrpcchecker.cpp \ 32 | $$PWD/sockjsmanager.cpp \ 33 | $$PWD/sockjssession.cpp \ 34 | $$PWD/inspectrequest.cpp \ 35 | $$PWD/acceptrequest.cpp \ 36 | $$PWD/connectionmanager.cpp \ 37 | $$PWD/wscontrolmanager.cpp \ 38 | $$PWD/wscontrolsession.cpp \ 39 | $$PWD/routesfile.cpp \ 40 | $$PWD/domainmap.cpp \ 41 | $$PWD/zroutes.cpp \ 42 | $$PWD/requestsession.cpp \ 43 | $$PWD/proxyutil.cpp \ 44 | $$PWD/proxysession.cpp \ 45 | $$PWD/wsproxysession.cpp \ 46 | $$PWD/updater.cpp \ 47 | $$PWD/engine.cpp \ 48 | $$PWD/app.cpp \ 49 | $$PWD/main.cpp 50 | -------------------------------------------------------------------------------- /src/proxy/routes.test: -------------------------------------------------------------------------------- 1 | *,debug origin:80 2 | *,path_beg=/jsonp,aco,debug origin:80 3 | *,path_beg=/jsonp-basic,aco,jsonp_mode=basic,jsonp_body=bparam,jsonp_defcb=jpcb,debug origin:80 4 | -------------------------------------------------------------------------------- /src/proxy/routesfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016-2022 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef ROUTESFILE_H 24 | #define ROUTESFILE_H 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace RoutesFile { 31 | 32 | class RouteSection 33 | { 34 | public: 35 | QString value; 36 | QMultiHash props; 37 | }; 38 | 39 | QList parseLine(const QString &line, bool *ok = 0, QString *errorMessage = 0); 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/proxy/tests.pri: -------------------------------------------------------------------------------- 1 | SOURCES += \ 2 | $$PWD/websocketoverhttptest.cpp \ 3 | $$PWD/routesfiletest.cpp \ 4 | $$PWD/proxyenginetest.cpp 5 | -------------------------------------------------------------------------------- /src/proxy/updater.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef UPDATER_H 25 | #define UPDATER_H 26 | 27 | #include 28 | 29 | using Connection = boost::signals2::scoped_connection; 30 | 31 | class QString; 32 | 33 | class ZhttpManager; 34 | 35 | class Updater 36 | { 37 | public: 38 | enum Mode 39 | { 40 | CheckMode, 41 | ReportMode 42 | }; 43 | 44 | class Report 45 | { 46 | public: 47 | int connectionsMax; 48 | int connectionsMinutes; 49 | int messagesReceived; 50 | int messagesSent; 51 | int ops; 52 | 53 | Report() : 54 | connectionsMax(0), 55 | connectionsMinutes(0), 56 | messagesReceived(0), 57 | messagesSent(0), 58 | ops(0) 59 | { 60 | } 61 | }; 62 | 63 | Updater(Mode mode, bool quiet, const QString ¤tVersion, const QString &org, ZhttpManager *zhttp); 64 | ~Updater(); 65 | 66 | void setReport(const Report &report); 67 | 68 | private: 69 | class Private; 70 | Private *d; 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/proxy/wscontrolmanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Fanout, Inc. 3 | * Copyright (C) 2024-2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef WSCONTROLMANAGER_H 25 | #define WSCONTROLMANAGER_H 26 | 27 | #include 28 | #include "packet/wscontrolpacket.h" 29 | 30 | class WsControlSession; 31 | 32 | class WsControlManager 33 | { 34 | public: 35 | WsControlManager(); 36 | ~WsControlManager(); 37 | 38 | void setIdentity(const QByteArray &id); 39 | void setIpcFileMode(int mode); 40 | 41 | bool setInitSpecs(const QStringList &specs); 42 | bool setStreamSpecs(const QStringList &specs); 43 | 44 | WsControlSession *createSession(const QByteArray &cid); 45 | 46 | private: 47 | class Private; 48 | std::shared_ptr d; 49 | 50 | friend class WsControlSession; 51 | void link(WsControlSession *s, const QByteArray &cid); 52 | void unlink(const QByteArray &cid); 53 | void writeInit(const WsControlPacket::Item &item); 54 | void writeStream(const WsControlPacket::Item &item, const QByteArray &instanceAddress); 55 | void registerKeepAlive(WsControlSession *s); 56 | void unregisterKeepAlive(WsControlSession *s); 57 | }; 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/proxy/xffrule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef XFFRULE_H 24 | #define XFFRULE_H 25 | 26 | class XffRule 27 | { 28 | public: 29 | int truncate; 30 | bool append; 31 | 32 | XffRule() : 33 | truncate(-1), 34 | append(false) 35 | { 36 | } 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/proxy/zroutes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef ZROUTES_H 25 | #define ZROUTES_H 26 | 27 | #include "zhttpmanager.h" 28 | #include "domainmap.h" 29 | 30 | class ZRoutes 31 | { 32 | public: 33 | ZRoutes(); 34 | ~ZRoutes(); 35 | 36 | void setInstanceId(const QByteArray &id); 37 | void setDefaultOutSpecs(const QStringList &specs); 38 | void setDefaultOutStreamSpecs(const QStringList &specs); 39 | void setDefaultInSpecs(const QStringList &specs); 40 | 41 | void setup(const QList &routes); 42 | 43 | ZhttpManager *defaultManager(); 44 | ZhttpManager *managerForRoute(const DomainMap::ZhttpRoute &route); 45 | 46 | void addRef(ZhttpManager *zhttpManager); 47 | void removeRef(ZhttpManager *zhttpManager); 48 | 49 | private: 50 | class Private; 51 | Private *d; 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/proxy/zrpcchecker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #ifndef ZRPCCHECKER_H 25 | #define ZRPCCHECKER_H 26 | 27 | #include 28 | 29 | using Connection = boost::signals2::scoped_connection; 30 | 31 | class ZrpcRequest; 32 | 33 | // all requests should be passed to this class for monitoring. use 34 | // watch() to have it monitor a request, but not own it. use give() to have 35 | // this class take ownership of an already-watched request. 36 | 37 | class ZrpcChecker 38 | { 39 | public: 40 | ZrpcChecker(); 41 | ~ZrpcChecker(); 42 | 43 | bool isInterfaceAvailable() const; 44 | void setInterfaceAvailable(bool available); 45 | 46 | void watch(ZrpcRequest *req); 47 | void give(ZrpcRequest *req); 48 | 49 | private: 50 | class Private; 51 | Private *d; 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/runner/connmgrservice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2023 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef CONNMGRSERVICE_H 24 | #define CONNMGRSERVICE_H 25 | 26 | #include "service.h" 27 | #include "listenport.h" 28 | 29 | class ConnmgrService : public Service 30 | { 31 | public: 32 | ConnmgrService( 33 | const QString &name, 34 | const QString &binFile, 35 | const QString &runDir, 36 | const QString &logDir, 37 | const QString &ipcPrefix, 38 | const QString &filePrefix, 39 | int logLevel, 40 | const QString &certsDir, 41 | int clientBufferSize, 42 | int maxconn, 43 | bool allowCompression, 44 | const QList &ports, 45 | bool enableClient); 46 | 47 | static bool hasClientMode(const QString &binFile); 48 | 49 | // reimplemented 50 | 51 | virtual QStringList arguments() const; 52 | 53 | private: 54 | QStringList args_; 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/runner/listenport.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2023 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef LISTENPORT_H 24 | #define LISTENPORT_H 25 | 26 | #include 27 | 28 | class ListenPort 29 | { 30 | public: 31 | QHostAddress addr; 32 | int port; 33 | bool ssl; 34 | QString localPath; 35 | int mode; 36 | QString user; 37 | QString group; 38 | 39 | ListenPort() : 40 | port(-1), 41 | ssl(false), 42 | mode(-1) 43 | { 44 | } 45 | 46 | ListenPort(const QHostAddress &_addr, int _port, bool _ssl, const QString &_localPath = QString(), int _mode = -1, const QString &_user = QString(), const QString &_group = QString()) : 47 | addr(_addr), 48 | port(_port), 49 | ssl(_ssl), 50 | localPath(_localPath), 51 | mode(_mode), 52 | user(_user), 53 | group(_group) 54 | { 55 | } 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/runner/m2adapter.conf.template: -------------------------------------------------------------------------------- 1 | [General] 2 | # list of mongrel2 handler send_spec 3 | m2_in_specs={% for p in ports %}{% if not loop.first %},{% endif %}ipc://{{ rundir }}/{{ ipc_prefix }}m2-out-{{ p }}{% endfor %} 4 | 5 | # list of mongrel2 handler recv_spec 6 | m2_out_specs={% for p in ports %}{% if not loop.first %},{% endif %}ipc://{{ rundir }}/{{ ipc_prefix }}m2-in-{{ p }}{% endfor %} 7 | 8 | # list of mongrel2 send_ident (per send_spec) 9 | m2_send_idents={% for p in ports %}{% if not loop.first %},{% endif %}pushpin-m2-{{ p }}{% endfor %} 10 | 11 | # list of mongrel2 control specs (per send_ident) 12 | m2_control_specs={% for p in ports %}{% if not loop.first %},{% endif %}ipc://{{ rundir }}/{{ ipc_prefix }}m2-control-{{ p }}{% endfor %} 13 | 14 | # zhttp in specs 15 | zhttp_in_specs=ipc://{{ rundir }}/{{ ipc_prefix }}m2zhttp-in 16 | 17 | # zhttp out specs 18 | zhttp_out_specs=ipc://{{ rundir }}/{{ ipc_prefix }}m2zhttp-out 19 | 20 | # zhttp out stream specs 21 | zhttp_out_stream_specs=ipc://{{ rundir }}/{{ ipc_prefix }}m2zhttp-out-stream 22 | 23 | # zws in specs 24 | zws_in_specs=ipc://{{ rundir }}/{{ ipc_prefix }}m2zws-in 25 | 26 | # zws out specs 27 | zws_out_specs=ipc://{{ rundir }}/{{ ipc_prefix }}m2zws-out 28 | 29 | # zws out stream specs 30 | zws_out_stream_specs=ipc://{{ rundir }}/{{ ipc_prefix }}m2zws-out-stream 31 | 32 | # don't send more than this to mongrel2 33 | m2_client_buffer=200000 34 | 35 | # don't allow more than this many connections at once 36 | max_open_requests=50000 37 | -------------------------------------------------------------------------------- /src/runner/m2adapterservice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef M2ADAPTERSERVICE_H 24 | #define M2ADAPTERSERVICE_H 25 | 26 | #include "service.h" 27 | 28 | class M2AdapterService : public Service 29 | { 30 | public: 31 | M2AdapterService( 32 | const QString &binFile, 33 | const QString &configTemplateFile, 34 | const QString &runDir, 35 | const QString &logDir, 36 | const QString &ipcPrefix, 37 | const QString &filePrefix, 38 | int logLevel, 39 | const QList &ports); 40 | 41 | // reimplemented 42 | 43 | virtual QStringList arguments() const; 44 | virtual bool acceptSighup() const; 45 | virtual bool preStart(); 46 | 47 | private: 48 | QStringList args_; 49 | QString configTemplateFile_; 50 | QString runDir_; 51 | QString ipcPrefix_; 52 | QString filePrefix_; 53 | QList ports_; 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/runner/main.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_MAIN_H 2 | #define RUNNER_MAIN_H 3 | 4 | int runner_main(int argc, char **argv); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/runner/mongrel2.conf.template: -------------------------------------------------------------------------------- 1 | {% for i in interfaces %}handler_{{ i.port }} = Handler( 2 | send_spec="ipc://{{ rundir }}/{{ ipc_prefix }}m2-out-{{ i.port }}", 3 | send_ident="pushpin-m2-{{ i.port }}", 4 | recv_spec="ipc://{{ rundir }}/{{ ipc_prefix }}m2-in-{{ i.port }}", 5 | recv_ident="pushpin-m2-{{ i.port }} " # trailing space needed 6 | ) 7 | 8 | {% endfor %}{% for i in interfaces %}host_{{ i.port }} = Host(name="default", routes={ "/": handler_{{ i.port }} }) 9 | 10 | {% endfor %}{% for i in interfaces %}server_{{ i.port }} = Server( 11 | uuid="default_{{ i.port }}",{% if i.ssl %} 12 | use_ssl=1,{% endif %}{%if logdir %} 13 | access_log="{{ logdir }}/{{ file_prefix }}access_{{ i.port }}.log", 14 | error_log="{{ logdir }}/{{ file_prefix }}error_{{ i.port }}.log",{% endif %}{%if not logdir %} 15 | access_log="/dev/stdout", 16 | error_log="/dev/stdout",{% endif %} 17 | error_log_level={{ loglevel }}, 18 | pid_file="{{ rundir }}/{{ file_prefix }}mongrel2_{{ i.port }}.pid", 19 | control_port="ipc://{{ rundir }}/{{ ipc_prefix }}m2-control-{{ i.port }}", 20 | default_host="default", 21 | name="server-{{ i.port }}", 22 | bind_addr="{{ i.addr }}", 23 | port={{ i.port }}, 24 | hosts=[host_{{ i.port }}] 25 | ) 26 | 27 | {% endfor %}settings = { 28 | "certdir": "{{ certdir }}/", 29 | "upload.stream": 1, 30 | "superpoll.max_fd": {{ superpoll_max_fd }}, 31 | "server.daemonize": 0, 32 | "no_clobber_xff": 1, 33 | "request.relaxed": 1, 34 | "download.flow_control": 1, 35 | "net.tcp_keepalive": 1, 36 | "limits.buffer_size": {{ limits_buffer_size }}, 37 | "disable.access_logging": {{ disable_access_logging}} 38 | } 39 | 40 | servers = [{% for i in interfaces %}server_{{ i.port }}{% if not loop.last %}, {% endif %}{% endfor %}] 41 | -------------------------------------------------------------------------------- /src/runner/mongrel2service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016-2020 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef MONGREL2SERVICE_H 24 | #define MONGREL2SERVICE_H 25 | 26 | #include "service.h" 27 | #include "listenport.h" 28 | 29 | class Mongrel2Service : public Service 30 | { 31 | Q_OBJECT 32 | 33 | public: 34 | Mongrel2Service( 35 | const QString &binFile, 36 | const QString &configFile, 37 | const QString &serverName, 38 | const QString &runDir, 39 | const QString &logDir, 40 | const QString &filePrefix, 41 | int port, 42 | bool ssl, 43 | int logLevel); 44 | 45 | static bool generateConfigFile(const QString &m2shBinFile, const QString &configTemplateFile, const QString &runDir, const QString &logDir, const QString &ipcPrefix, const QString &filePrefix, const QString &certsDir, int clientBufferSize, int maxconn, const QList &ports, int logLevel); 46 | 47 | // reimplemented 48 | 49 | virtual QStringList arguments() const; 50 | virtual bool acceptSighup() const; 51 | virtual bool alwaysLogStatus() const; 52 | virtual QString formatLogLine(const QString &line) const; 53 | 54 | private: 55 | QStringList args_; 56 | QString prefix_; 57 | int logLevel_; 58 | 59 | QString filterLogLine(int, const QString&) const; 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/runner/pushpinhandlerservice.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include "pushpinhandlerservice.h" 24 | 25 | #include 26 | #include 27 | 28 | PushpinHandlerService::PushpinHandlerService( 29 | const QString &binFile, 30 | const QString &configFile, 31 | const QString &runDir, 32 | const QString &logDir, 33 | const QString &ipcPrefix, 34 | const QString &filePrefix, 35 | int portOffset, 36 | int logLevel) 37 | { 38 | args_ += binFile; 39 | args_ += "--config=" + configFile; 40 | 41 | if(!ipcPrefix.isEmpty()) 42 | args_ += "--ipc-prefix=" + ipcPrefix; 43 | 44 | if(portOffset > 0) 45 | args_ += "--port-offset=" + QString::number(portOffset); 46 | 47 | if(!logDir.isEmpty()) 48 | { 49 | args_ += "--logfile=" + QDir(logDir).filePath(filePrefix + "pushpin-handler.log"); 50 | setStandardOutputFile(QProcess::nullDevice()); 51 | } 52 | 53 | if(logLevel >= 0) 54 | args_ += "--loglevel=" + QString::number(logLevel); 55 | 56 | setName("handler"); 57 | setPidFile(QDir(runDir).filePath(filePrefix + "pushpin-handler.pid")); 58 | } 59 | 60 | QStringList PushpinHandlerService::arguments() const 61 | { 62 | return args_; 63 | } 64 | 65 | bool PushpinHandlerService::acceptSighup() const 66 | { 67 | return true; 68 | } 69 | -------------------------------------------------------------------------------- /src/runner/pushpinhandlerservice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef PUSHPINHANDLERSERVICE_H 24 | #define PUSHPINHANDLERSERVICE_H 25 | 26 | #include "service.h" 27 | 28 | class PushpinHandlerService : public Service 29 | { 30 | public: 31 | PushpinHandlerService( 32 | const QString &binFile, 33 | const QString &configFile, 34 | const QString &runDir, 35 | const QString &logDir, 36 | const QString &ipcPrefix, 37 | const QString &filePrefix, 38 | int portOffset, 39 | int logLevel); 40 | 41 | // reimplemented 42 | 43 | virtual QStringList arguments() const; 44 | virtual bool acceptSighup() const; 45 | 46 | private: 47 | QStringList args_; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/runner/pushpinproxyservice.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include "pushpinproxyservice.h" 24 | 25 | #include 26 | #include 27 | 28 | PushpinProxyService::PushpinProxyService( 29 | const QString &binFile, 30 | const QString &configFile, 31 | const QString &runDir, 32 | const QString &logDir, 33 | const QString &ipcPrefix, 34 | const QString &filePrefix, 35 | int logLevel, 36 | const QStringList &routeLines, 37 | bool quietCheck) 38 | { 39 | args_ += binFile; 40 | args_ += "--config=" + configFile; 41 | 42 | if(!ipcPrefix.isEmpty()) 43 | args_ += "--ipc-prefix=" + ipcPrefix; 44 | 45 | if(!logDir.isEmpty()) 46 | { 47 | args_ += "--logfile=" + QDir(logDir).filePath(filePrefix + "pushpin-proxy.log"); 48 | setStandardOutputFile(QProcess::nullDevice()); 49 | } 50 | 51 | if(logLevel >= 0) 52 | args_ += "--loglevel=" + QString::number(logLevel); 53 | 54 | foreach(const QString &route, routeLines) 55 | args_ += "--route=" + route; 56 | 57 | if(quietCheck) 58 | args_ += "--quiet-check"; 59 | 60 | setName("proxy"); 61 | setPidFile(QDir(runDir).filePath(filePrefix + "pushpin-proxy.pid")); 62 | } 63 | 64 | QStringList PushpinProxyService::arguments() const 65 | { 66 | return args_; 67 | } 68 | 69 | bool PushpinProxyService::acceptSighup() const 70 | { 71 | return true; 72 | } 73 | -------------------------------------------------------------------------------- /src/runner/pushpinproxyservice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef PUSHPINPROXYSERVICE_H 24 | #define PUSHPINPROXYSERVICE_H 25 | 26 | #include "service.h" 27 | 28 | class PushpinProxyService : public Service 29 | { 30 | public: 31 | PushpinProxyService( 32 | const QString &binFile, 33 | const QString &configFile, 34 | const QString &runDir, 35 | const QString &logDir, 36 | const QString &ipcPrefix, 37 | const QString &filePrefix, 38 | int logLevel, 39 | const QStringList &routeLines, 40 | bool quietCheck); 41 | 42 | // reimplemented 43 | 44 | virtual QStringList arguments() const; 45 | virtual bool acceptSighup() const; 46 | 47 | private: 48 | QStringList args_; 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/runner/runner.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/template.h \ 3 | $$PWD/service.h \ 4 | $$PWD/listenport.h \ 5 | $$PWD/connmgrservice.h \ 6 | $$PWD/mongrel2service.h \ 7 | $$PWD/m2adapterservice.h \ 8 | $$PWD/zurlservice.h \ 9 | $$PWD/pushpinproxyservice.h \ 10 | $$PWD/pushpinhandlerservice.h \ 11 | $$PWD/runnerapp.h \ 12 | $$PWD/main.h 13 | 14 | SOURCES += \ 15 | $$PWD/template.cpp \ 16 | $$PWD/service.cpp \ 17 | $$PWD/connmgrservice.cpp \ 18 | $$PWD/mongrel2service.cpp \ 19 | $$PWD/m2adapterservice.cpp \ 20 | $$PWD/zurlservice.cpp \ 21 | $$PWD/pushpinproxyservice.cpp \ 22 | $$PWD/pushpinhandlerservice.cpp \ 23 | $$PWD/runnerapp.cpp \ 24 | $$PWD/runnermain.cpp 25 | -------------------------------------------------------------------------------- /src/runner/runnerapp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef RUNNERAPP_H 24 | #define RUNNERAPP_H 25 | 26 | #include 27 | #include 28 | 29 | using std::map; 30 | using SignalInt = boost::signals2::signal; 31 | using Connection = boost::signals2::scoped_connection; 32 | 33 | class RunnerApp 34 | { 35 | public: 36 | RunnerApp(); 37 | ~RunnerApp(); 38 | 39 | void start(); 40 | 41 | SignalInt quit; 42 | 43 | private: 44 | class Private; 45 | friend class Private; 46 | std::unique_ptr d; 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/runner/runnermain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #include 24 | #include 25 | #include "runnerapp.h" 26 | 27 | class RunnerAppMain 28 | { 29 | public: 30 | RunnerApp *app; 31 | 32 | void start() 33 | { 34 | app = new RunnerApp; 35 | app->quit.connect(boost::bind(&RunnerAppMain::app_quit, this, boost::placeholders::_1)); 36 | app->start(); 37 | } 38 | 39 | void app_quit(int returnCode) 40 | { 41 | delete app; 42 | QCoreApplication::exit(returnCode); 43 | } 44 | }; 45 | 46 | extern "C" { 47 | 48 | int runner_main(int argc, char **argv) 49 | { 50 | QCoreApplication qapp(argc, argv); 51 | 52 | RunnerAppMain appMain; 53 | QTimer::singleShot(0, [&appMain]() {appMain.start();}); 54 | return qapp.exec(); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/runner/service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef SERVICE_H 24 | #define SERVICE_H 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | using Signal = boost::signals2::signal; 31 | using SignalStr = boost::signals2::signal; 32 | using Connection = boost::signals2::scoped_connection; 33 | 34 | class Service : public QObject 35 | { 36 | Q_OBJECT 37 | 38 | public: 39 | Service(QObject *parent = 0); 40 | ~Service(); 41 | 42 | QString name() const; 43 | 44 | virtual QStringList arguments() const = 0; 45 | virtual bool acceptSighup() const; 46 | virtual bool alwaysLogStatus() const; 47 | virtual bool isStarted() const; 48 | 49 | virtual bool preStart(); 50 | virtual void start(); 51 | virtual void postStart(); 52 | virtual void stop(); 53 | virtual void postStop(); 54 | virtual QString formatLogLine(const QString &line) const; 55 | 56 | void sendSighup(); 57 | 58 | Signal started; 59 | Signal stopped; 60 | SignalStr logLine; 61 | SignalStr error; 62 | 63 | protected: 64 | void setName(const QString &name); 65 | void setStandardOutputFile(const QString &file); 66 | void setPidFile(const QString &file); 67 | 68 | private: 69 | class Private; 70 | Private *d; 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/runner/template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef TEMPLATE_H 24 | #define TEMPLATE_H 25 | 26 | #include 27 | #include 28 | 29 | namespace Template { 30 | 31 | QString render(const QString &content, const QVariantMap &context, QString *error = 0); 32 | bool renderFile(const QString &inFile, const QString &outFile, const QVariantMap &context, QString *error = 0); 33 | 34 | void dumpTemplate(const QString &content); 35 | 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/runner/templatetest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * Copyright (C) 2025 Fastly, Inc. 4 | * 5 | * This file is part of Pushpin. 6 | * 7 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * 21 | * $FANOUT_END_LICENSE$ 22 | */ 23 | 24 | #include "test.h" 25 | #include "template.h" 26 | 27 | static void render() 28 | { 29 | QVariantMap context; 30 | context["place"] = "world"; 31 | 32 | QVariantMap user; 33 | user["first"] = "john"; 34 | user["last"] = "smith"; 35 | context["user"] = user; 36 | 37 | QVariantList fruits; 38 | fruits.append("apple"); 39 | fruits.append("banana"); 40 | context["fruits"] = fruits; 41 | 42 | QString content("hello {{ place }}!"); 43 | QString output = Template::render(content, context); 44 | TEST_ASSERT_EQ(output, QString("hello world!")); 45 | 46 | content = QString("hello {% if formal %}{{ user.last }}{% endif %}{% if not formal %}{{ user.first }}{% endif %}!"); 47 | output = Template::render(content, context); 48 | TEST_ASSERT_EQ(output, QString("hello john!")); 49 | context["formal"] = true; 50 | output = Template::render(content, context); 51 | TEST_ASSERT_EQ(output, QString("hello smith!")); 52 | 53 | content = QString("please eat {% for f in fruits %}{% if not loop.first %} and {% endif %}fresh {{ f }}s{% endfor %}."); 54 | output = Template::render(content, context); 55 | TEST_ASSERT_EQ(output, QString("please eat fresh apples and fresh bananas.")); 56 | } 57 | 58 | extern "C" int template_test(ffi::TestException *out_ex) 59 | { 60 | TEST_CATCH(render()); 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/runner/tests.pri: -------------------------------------------------------------------------------- 1 | SOURCES += \ 2 | $$PWD/templatetest.cpp 3 | -------------------------------------------------------------------------------- /src/runner/zurl.conf.template: -------------------------------------------------------------------------------- 1 | [General] 2 | # instance routing id. keep blank for random. set for better error recovery 3 | instance_id= 4 | 5 | # bind PULL for initiating a request 6 | in_spec=ipc://{{ rundir }}/{{ ipc_prefix }}zurl-in 7 | 8 | # bind DEALER for continuing a request 9 | in_stream_spec=ipc://{{ rundir }}/{{ ipc_prefix }}zurl-in-stream 10 | 11 | # bind PUB for responding 12 | out_spec=ipc://{{ rundir }}/{{ ipc_prefix }}zurl-out 13 | 14 | # bind ROUTER for handling non-streamed requests/responses 15 | in_req_spec= 16 | 17 | # default policy, one of "allow" or "deny" 18 | defpolicy=allow 19 | 20 | # hosts to allow 21 | allow= 22 | 23 | # hosts to deny 24 | deny=127.*,10.*,192.168.*,*.local 25 | 26 | # worker count 27 | max_open_requests=2000 28 | 29 | # input buffer size per request 30 | buffer_size=200000 31 | 32 | # expiration time (in seconds) for inactive requests 33 | timeout=600 34 | 35 | # advanced 36 | in_hwm=1000 37 | out_hwm=1000 38 | -------------------------------------------------------------------------------- /src/runner/zurlservice.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Fanout, Inc. 3 | * 4 | * This file is part of Pushpin. 5 | * 6 | * $FANOUT_BEGIN_LICENSE:APACHE2$ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * $FANOUT_END_LICENSE$ 21 | */ 22 | 23 | #ifndef ZURLSERVICE_H 24 | #define ZURLSERVICE_H 25 | 26 | #include "service.h" 27 | 28 | class ZurlService : public Service 29 | { 30 | public: 31 | ZurlService( 32 | const QString &binFile, 33 | const QString &configTemplateFile, 34 | const QString &runDir, 35 | const QString &logDir, 36 | const QString &ipcPrefix, 37 | const QString &filePrefix, 38 | int logLevel); 39 | 40 | // reimplemented 41 | 42 | virtual QStringList arguments() const; 43 | virtual bool acceptSighup() const; 44 | virtual bool preStart(); 45 | 46 | private: 47 | QString configTemplateFile_; 48 | QString runDir_; 49 | QString ipcPrefix_; 50 | QString filePrefix_; 51 | QStringList args_; 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /tools/command.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import uuid 3 | import json 4 | import tnetstring 5 | import zmq 6 | 7 | 8 | def make_tnet_compat(obj): 9 | if isinstance(obj, dict): 10 | out = {} 11 | for k, v in obj.items(): 12 | out[make_tnet_compat(k)] = make_tnet_compat(v) 13 | return out 14 | elif isinstance(obj, list): 15 | out = list() 16 | for v in obj: 17 | out.append(make_tnet_compat(v)) 18 | return out 19 | elif isinstance(obj, str): 20 | return obj.encode("utf-8") 21 | else: 22 | return obj 23 | 24 | 25 | ctx = zmq.Context() 26 | sock = ctx.socket(zmq.REQ) 27 | sock.connect(sys.argv[1]) 28 | 29 | method = sys.argv[2] 30 | 31 | if len(sys.argv) > 3: 32 | args = json.loads(sys.argv[3]) 33 | assert isinstance(args, dict) 34 | else: 35 | args = {} 36 | 37 | print("calling {}: args={}".format(method, repr(args))) 38 | 39 | req = { 40 | b"id": str(uuid.uuid4()).encode("utf-8"), 41 | b"method": method.encode("utf-8"), 42 | b"args": make_tnet_compat(args), 43 | } 44 | 45 | sock.send(tnetstring.dumps(req)) 46 | 47 | resp = tnetstring.loads(sock.recv()) 48 | 49 | if resp[b"success"]: 50 | value = resp[b"value"] 51 | print("success: {}".format(repr(value))) 52 | else: 53 | condition = resp[b"condition"].decode("utf-8") 54 | value = resp.get(b"value") 55 | print("error: {} {}".format(condition, repr(value))) 56 | -------------------------------------------------------------------------------- /tools/echo/echo.pro: -------------------------------------------------------------------------------- 1 | CONFIG += console 2 | CONFIG -= app_bundle 3 | QT -= gui 4 | QT += network 5 | 6 | SOURCES += echo.cpp 7 | -------------------------------------------------------------------------------- /tools/edgebroker.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import zmq 3 | 4 | if len(sys.argv) < 3: 5 | print(f"usage: {sys.argv[0]} [pub_spec] [sub_spec,sub_spec,...]") 6 | sys.exit(1) 7 | 8 | pub_spec = sys.argv[1] 9 | sub_specs = sys.argv[2:] 10 | 11 | zmq_context = zmq.Context() 12 | 13 | sub_sock = zmq_context.socket(zmq.SUB) 14 | for spec in sub_specs: 15 | sub_sock.connect(spec) 16 | 17 | pub_sock = zmq_context.socket(zmq.XPUB) 18 | pub_sock.connect(pub_spec) 19 | 20 | poller = zmq.Poller() 21 | poller.register(sub_sock, zmq.POLLIN) 22 | poller.register(pub_sock, zmq.POLLIN) 23 | 24 | while True: 25 | socks = dict(poller.poll()) 26 | if socks.get(sub_sock) == zmq.POLLIN: 27 | m = sub_sock.recv_multipart() 28 | pub_sock.send_multipart(m) 29 | elif socks.get(pub_sock) == zmq.POLLIN: 30 | m = pub_sock.recv() 31 | mtype = m[0] 32 | topic = m[1:] 33 | topicstr = topic.decode("utf-8") 34 | if mtype == 1: 35 | print(f"subscribing [{topic}]") 36 | sub_sock.setsockopt(zmq.SUBSCRIBE, topic) 37 | elif mtype == 0: 38 | print(f"unsubscribing [{topic}]") 39 | sub_sock.setsockopt(zmq.UNSUBSCRIBE, topic) 40 | -------------------------------------------------------------------------------- /tools/getzmquris.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import zmq 3 | import tnetstring 4 | 5 | command_host = None 6 | 7 | 8 | def resolve(uri): 9 | if uri.startswith("tcp://"): 10 | at = uri.find(":", 6) 11 | addr = uri[6:at] 12 | if addr == "*": 13 | if command_host: 14 | return uri[0:6] + command_host + uri[at:] 15 | else: 16 | return uri[0:6] + "localhost" + uri[at:] 17 | return uri 18 | 19 | 20 | command_uri = sys.argv[1] 21 | if command_uri.startswith("tcp://"): 22 | at = command_uri.find(":", 6) 23 | command_host = command_uri[6:at] 24 | 25 | sock = zmq.Context.instance().socket(zmq.REQ) 26 | sock.connect(command_uri) 27 | 28 | req = {"method": "get-zmq-uris"} 29 | sock.send(tnetstring.dumps(req)) 30 | 31 | resp = tnetstring.loads(sock.recv()) 32 | if not resp.get("success"): 33 | raise ValueError("request failed: %s" % resp) 34 | 35 | v = resp["value"] 36 | 37 | if "command" in v: 38 | print("command: %s" % resolve(v["command"])) 39 | if "publish-pull" in v: 40 | print("publish-pull: %s" % resolve(v["publish-pull"])) 41 | if "publish-sub" in v: 42 | print("publish-sub: %s" % resolve(v["publish-sub"])) 43 | -------------------------------------------------------------------------------- /tools/monitorstats.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import tnetstring 4 | import zmq 5 | 6 | 7 | def ensure_str(i): 8 | if isinstance(i, dict): 9 | out = {} 10 | for k, v in i.items(): 11 | out[ensure_str(k)] = ensure_str(v) 12 | return out 13 | elif isinstance(i, list): 14 | out = [] 15 | for v in i: 16 | out.append(ensure_str(v)) 17 | return out 18 | elif isinstance(i, bytes): 19 | return i.decode("utf-8") 20 | else: 21 | return i 22 | 23 | 24 | ctx = zmq.Context() 25 | sock = ctx.socket(zmq.SUB) 26 | sock.connect(sys.argv[1]) 27 | 28 | if len(sys.argv) >= 3: 29 | for mtype in sys.argv[2].split(","): 30 | sock.setsockopt(zmq.SUBSCRIBE, "{} ".format(mtype).encode("utf-8")) 31 | else: 32 | sock.setsockopt(zmq.SUBSCRIBE, b"") 33 | 34 | while True: 35 | m_raw = sock.recv() 36 | at = m_raw.find(b" ") 37 | mtype = ensure_str(m_raw[:at]) 38 | mdata = m_raw[at + 1 :] 39 | if mdata[0] == ord(b"T"): 40 | m = ensure_str(tnetstring.loads(mdata[1:])) 41 | elif mdata[0] == ord(b"J"): 42 | m = json.loads(mdata[1:]) 43 | else: 44 | m = mdata 45 | print("{} {}".format(mtype, m)) 46 | -------------------------------------------------------------------------------- /tools/monitorsubs.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import tnetstring 4 | import zmq 5 | 6 | 7 | class Subscription(object): 8 | def __init__(self): 9 | self.ttl = None 10 | self.last_refresh = None 11 | 12 | 13 | # key=(mode, channel) 14 | subs = dict() 15 | 16 | ctx = zmq.Context() 17 | sock = ctx.socket(zmq.SUB) 18 | sock.connect(sys.argv[1]) 19 | sock.setsockopt(zmq.SUBSCRIBE, "sub ") 20 | 21 | poller = zmq.Poller() 22 | poller.register(sock, zmq.POLLIN) 23 | 24 | while True: 25 | socks = dict(poller.poll(1000)) 26 | if socks.get(sock) == zmq.POLLIN: 27 | m_raw = sock.recv() 28 | if not m_raw.startswith("sub T"): 29 | continue 30 | m = tnetstring.loads(m_raw[5:]) 31 | 32 | now = int(time.time()) 33 | sub_key = (m["mode"], m["channel"]) 34 | sub = subs.get(sub_key) 35 | if m.get("unavailable"): 36 | if sub: 37 | del subs[sub_key] 38 | print("UNSUB mode=%s channel=%s" % (m["mode"], m["channel"])) 39 | else: 40 | if not sub: 41 | sub = Subscription() 42 | subs[sub_key] = sub 43 | print("SUB mode=%s channel=%s" % (m["mode"], m["channel"])) 44 | sub.ttl = m["ttl"] 45 | sub.last_refresh = now 46 | 47 | unsubs = set() 48 | for sub_key, sub in subs.iteritems(): 49 | if sub.last_refresh + sub.ttl <= now: 50 | unsubs.add(sub_key) 51 | for sub_key in unsubs: 52 | del subs[sub_key] 53 | print("UNSUB mode=%s channel=%s" % (sub_key[0], sub_key[1])) 54 | -------------------------------------------------------------------------------- /tools/monitorsubsock.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import zmq 3 | 4 | if len(sys.argv) < 2: 5 | print("usage: {} [pub_spec]".format(sys.argv[0])) 6 | sys.exit(1) 7 | 8 | spec = sys.argv[1] 9 | 10 | zmq_context = zmq.Context.instance() 11 | sock = zmq_context.socket(zmq.XPUB) 12 | sock.rcvhwm = 0 13 | if hasattr(sock, "immediate"): 14 | sock.immediate = 1 15 | sock.connect(spec) 16 | 17 | while True: 18 | m = sock.recv() 19 | mtype = int(m[0]) 20 | topic = m[1:].decode("utf-8") 21 | if mtype == 1: 22 | print("SUB {}".format(topic)) 23 | elif mtype == 0: 24 | print("UNSUB {}".format(topic)) 25 | -------------------------------------------------------------------------------- /tools/mp3stream.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /tools/mp3stream_publisher.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import socket 3 | import threading 4 | import subprocess 5 | from pubcontrol import Item 6 | from gripcontrol import GripPubControl, HttpStreamFormat 7 | 8 | pub = GripPubControl({"control_uri": "http://localhost:5561"}) 9 | 10 | 11 | def publish_worker(): 12 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 13 | sock.bind(("127.0.0.1", 5004)) 14 | while True: 15 | data, addr = sock.recvfrom(65536) 16 | pub.publish("music", Item(HttpStreamFormat(data))) 17 | 18 | 19 | thread = threading.Thread(target=publish_worker) 20 | thread.daemon = True 21 | thread.start() 22 | 23 | subprocess.check_call( 24 | [ 25 | "gst-launch-1.0", 26 | "filesrc", 27 | "location=%s" % sys.argv[1], 28 | "!", 29 | "decodebin", 30 | "!", 31 | "queue", 32 | "!", 33 | "lamemp3enc", 34 | "!", 35 | "udpsink", 36 | "clients=localhost:5004", 37 | ] 38 | ) 39 | -------------------------------------------------------------------------------- /tools/publish2.py: -------------------------------------------------------------------------------- 1 | # this program uses pushpin's SUB socket to publish 2 | 3 | import sys 4 | import time 5 | import tnetstring 6 | import zmq 7 | 8 | if len(sys.argv) < 3: 9 | print("usage: {} [channel] [content]".format(sys.argv[0])) 10 | sys.exit(1) 11 | 12 | channel = sys.argv[1] 13 | content = sys.argv[2] 14 | 15 | ctx = zmq.Context() 16 | 17 | # note: in a typical long-running program you'd use a normal PUB socket and 18 | # send messages when needed: 19 | # 20 | # sock = ctx.socket(zmq.PUB) 21 | # sock.connect(...) 22 | # ... 23 | # sock.send_multipart([channel, {item}]) 24 | # 25 | # however, since this is a short-running program, we'll use XPUB and wait a 26 | # moment for the subscription to arrive. this is bad practice, though. if you 27 | # need to publish from a short-running program in real life, use pushpin's 28 | # PULL socket, or create a long-running broker that uses PUB to pushpin and 29 | # a PULL socket for input. 30 | 31 | sock = ctx.socket(zmq.XPUB) 32 | sock.connect("tcp://localhost:5562") 33 | 34 | poller = zmq.Poller() 35 | poller.register(sock, zmq.POLLIN) 36 | start = int(time.time() * 1000) 37 | while True: 38 | elapsed = int(time.time() * 1000) - start 39 | if elapsed >= 500: 40 | # give up 41 | break 42 | socks = dict(poller.poll(500 - elapsed)) 43 | if socks.get(sock) == zmq.POLLIN: 44 | m = sock.recv() 45 | if m[0] == 1 and m[1:].decode("utf-8") == channel: 46 | # subscription ready 47 | break 48 | 49 | content = content.encode("utf-8") 50 | 51 | hr = {b"body": content + b"\n"} 52 | hs = {b"content": content + b"\n"} 53 | ws = {b"content": content} 54 | formats = {b"http-response": hr, b"http-stream": hs, b"ws-message": ws} 55 | item = {b"formats": formats} 56 | 57 | sock.send_multipart([channel.encode("utf-8"), tnetstring.dumps(item)]) 58 | 59 | print("Published") 60 | -------------------------------------------------------------------------------- /tools/publish_curl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ $# -lt 2 ]; then 5 | echo "usage: $0 [channel] [content]" 6 | exit 1 7 | fi 8 | 9 | channel=$1 10 | content=$2 11 | 12 | curl -d "{ \"items\": [ { \"channel\": \"$channel\", \"formats\": { \"http-response\": { \"body\": \"$content\\n\" }, \"http-stream\": {\"content\": \"$content\\n\" }, \"ws-message\": {\"content\": \"$content\" } } } ] }" http://localhost:5561/publish/ 13 | -------------------------------------------------------------------------------- /tools/recover.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import zmq 3 | import tnetstring 4 | 5 | command_uri = sys.argv[1] 6 | 7 | sock = zmq.Context.instance().socket(zmq.REQ) 8 | sock.connect(command_uri) 9 | 10 | req = {"method": "recover"} 11 | sock.send(tnetstring.dumps(req)) 12 | 13 | resp = tnetstring.loads(sock.recv()) 14 | if not resp.get("success"): 15 | raise ValueError("request failed: %s" % resp) 16 | -------------------------------------------------------------------------------- /tools/sourcebroker.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import tnetstring 3 | import zmq 4 | 5 | if len(sys.argv) < 3: 6 | print(f"usage: {sys.argv[0]} [pub_spec] [pull_spec]") 7 | sys.exit(1) 8 | 9 | pub_spec = sys.argv[1] 10 | pull_spec = sys.argv[2] 11 | 12 | zmq_context = zmq.Context() 13 | 14 | pull_sock = zmq_context.socket(zmq.PULL) 15 | pull_sock.bind(pull_spec) 16 | 17 | pub_sock = zmq_context.socket(zmq.XPUB) 18 | pub_sock.bind(pub_spec) 19 | 20 | poller = zmq.Poller() 21 | poller.register(pull_sock, zmq.POLLIN) 22 | poller.register(pub_sock, zmq.POLLIN) 23 | 24 | subs = set() 25 | 26 | while True: 27 | socks = dict(poller.poll()) 28 | if socks.get(pull_sock) == zmq.POLLIN: 29 | m = tnetstring.loads(pull_sock.recv()) 30 | channel = m[b"channel"] 31 | if channel in subs: 32 | del m[b"channel"] 33 | pub_sock.send_multipart([channel, tnetstring.dumps(m)]) 34 | elif socks.get(pub_sock) == zmq.POLLIN: 35 | m = pub_sock.recv() 36 | mtype = m[0] 37 | topic = m[1:] 38 | topicstr = topic.decode("utf-8") 39 | if mtype == 1: 40 | assert topic not in subs 41 | print(f"subscribing [{topicstr}]") 42 | subs.add(topic) 43 | elif mtype == 0: 44 | assert topic in subs 45 | print(f"unsubscribing [{topicstr}]") 46 | subs.remove(topic) 47 | -------------------------------------------------------------------------------- /tools/testgripresponse.php: -------------------------------------------------------------------------------- 1 | 5 | nothing for now 6 | -------------------------------------------------------------------------------- /tools/testgripresponse_json.php: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "hold": { 4 | "mode": "response", 5 | "channels": [ 6 | { 7 | "name": "test" 8 | } 9 | ], 10 | "timeout": 55 11 | }, 12 | "response": { 13 | "headers": { 14 | "Content-Type": "text/plain" 15 | }, 16 | "body": "nothing for now\n" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tools/testgripstream.php: -------------------------------------------------------------------------------- 1 | 4 | [stream open] 5 | -------------------------------------------------------------------------------- /tools/testgripwebsocket.js: -------------------------------------------------------------------------------- 1 | const http = require('node:http'); 2 | 3 | const hostname = '127.0.0.1'; 4 | const port = 3000; 5 | 6 | const server = http.createServer(); 7 | 8 | server.on('request', (req, res) => { 9 | console.log('Got request: ' + req.toString()); 10 | var sub = false; 11 | var body = ''; 12 | req.on('readable', () => { 13 | var bodyPart = req.read(); 14 | if (bodyPart) { 15 | body += bodyPart; 16 | } 17 | }).on('end', () => { 18 | if (body && body.substring(0,6) === 'OPEN\r\n') { 19 | sub = true; 20 | res.setHeader('Sec-WebSocket-Extensions', 'grip; message-prefix=""'); 21 | } 22 | 23 | res.statusCode = 200; 24 | res.setHeader('Content-Type', 'application/websocket-events'); 25 | 26 | if (body !== null) { 27 | res.write(body); 28 | } 29 | 30 | if (sub) { 31 | var msg = 'c:{"type": "subscribe", "channel": "test"}'; 32 | var out = 'TEXT ' + msg.length.toString(16) + '\r\n' + msg + '\r\n'; 33 | res.write(out); 34 | } 35 | 36 | res.end(); 37 | }); 38 | }); 39 | 40 | server.listen(port, hostname, () => { 41 | console.log(`Server running at http://${hostname}:${port}/`); 42 | }); 43 | -------------------------------------------------------------------------------- /tools/testgripwebsocket.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /tools/testwebsocket.php: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /tools/zhttp/basichandler.py: -------------------------------------------------------------------------------- 1 | # this handler responds to every request with "hello world" 2 | 3 | import os 4 | import time 5 | import tnetstring 6 | import zmq 7 | 8 | instance_id = "basichandler.{}".format(os.getpid()).encode() 9 | 10 | ctx = zmq.Context() 11 | in_sock = ctx.socket(zmq.PULL) 12 | in_sock.connect("ipc://client-out") 13 | out_sock = ctx.socket(zmq.PUB) 14 | out_sock.connect("ipc://client-in") 15 | 16 | # await subscription 17 | time.sleep(0.01) 18 | 19 | while True: 20 | m_raw = in_sock.recv() 21 | req = tnetstring.loads(m_raw[1:]) 22 | print("IN {}".format(req)) 23 | 24 | resp = {} 25 | resp[b"from"] = instance_id 26 | resp[b"id"] = req[b"id"] 27 | resp[b"code"] = 200 28 | resp[b"reason"] = b"OK" 29 | resp[b"headers"] = [[b"Content-Type", b"text/plain"]] 30 | resp[b"body"] = b"hello world\n" 31 | 32 | print("OUT {}".format(resp)) 33 | out_sock.send(req[b"from"] + b" T" + tnetstring.dumps(resp)) 34 | -------------------------------------------------------------------------------- /tools/zhttp/get.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import uuid 3 | import tnetstring 4 | import zmq 5 | 6 | if len(sys.argv) < 2: 7 | print("usage: {} [url]".format(sys.argv[0])) 8 | sys.exit(1) 9 | 10 | ctx = zmq.Context() 11 | sock = ctx.socket(zmq.REQ) 12 | sock.connect("ipc://server") 13 | 14 | req = { 15 | b"method": b"GET", 16 | b"uri": sys.argv[1].encode("utf-8"), 17 | # b'follow-redirects': True, 18 | # b'ignore-tls-errors': True, 19 | } 20 | 21 | sock.send(b"T" + tnetstring.dumps(req)) 22 | 23 | resp = tnetstring.loads(sock.recv()[1:]) 24 | if b"type" in resp and resp[b"type"] == b"error": 25 | print("error: {}".format(resp[b"condition"])) 26 | sys.exit(1) 27 | 28 | print("code={} reason=[{}]".format(resp[b"code"], resp[b"reason"])) 29 | for h in resp[b"headers"]: 30 | print("{}: {}".format(h[0], h[1])) 31 | 32 | if b"body" in resp: 33 | print("\n{}".format(resp[b"body"])) 34 | else: 35 | print("\n") 36 | -------------------------------------------------------------------------------- /tools/zhttp/getstream.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import uuid 4 | import tnetstring 5 | import zmq 6 | 7 | client_id = b"getstream.py" 8 | 9 | ctx = zmq.Context() 10 | out_sock = ctx.socket(zmq.PUSH) 11 | out_sock.connect("ipc://server-in") 12 | out_stream_sock = ctx.socket(zmq.ROUTER) 13 | out_stream_sock.connect("ipc://server-in-stream") 14 | in_sock = ctx.socket(zmq.SUB) 15 | in_sock.setsockopt(zmq.SUBSCRIBE, client_id) 16 | in_sock.connect("ipc://server-out") 17 | 18 | time.sleep(0.5) 19 | 20 | rid = str(uuid.uuid4()).encode("utf-8") 21 | inseq = 0 22 | outseq = 0 23 | out_sock.send( 24 | b"T" 25 | + tnetstring.dumps( 26 | { 27 | b"from": client_id, 28 | b"id": rid, 29 | b"seq": outseq, 30 | b"method": b"GET", 31 | b"uri": sys.argv[1].encode("utf-8"), 32 | b"stream": True, 33 | b"credits": 8192, 34 | } 35 | ) 36 | ) 37 | outseq += 1 38 | 39 | while True: 40 | buf = in_sock.recv() 41 | at = buf.find(b" ") 42 | receiver = buf[:at] 43 | indata = tnetstring.loads(buf[at + 2 :]) 44 | if indata[b"id"] != rid: 45 | continue 46 | print("IN: {}".format(indata)) 47 | assert indata[b"seq"] == inseq 48 | inseq += 1 49 | if ( 50 | b"type" in indata 51 | and (indata[b"type"] == b"error" or indata[b"type"] == b"cancel") 52 | ) or (b"type" not in indata and b"more" not in indata): 53 | break 54 | raddr = indata[b"from"] 55 | if b"body" in indata and len(indata[b"body"]) > 0: 56 | outdata = { 57 | b"id": rid, 58 | b"from": client_id, 59 | b"seq": outseq, 60 | b"type": b"credit", 61 | b"credits": len(indata[b"body"]), 62 | } 63 | print("OUT: {}".format(outdata)) 64 | out_stream_sock.send_multipart([raddr, b"", b"T" + tnetstring.dumps(outdata)]) 65 | outseq += 1 66 | -------------------------------------------------------------------------------- /tools/zhttp/printreq.py: -------------------------------------------------------------------------------- 1 | # this handler just outputs the request ID 2 | 3 | import tnetstring 4 | import zmq 5 | 6 | ctx = zmq.Context() 7 | sock = ctx.socket(zmq.PULL) 8 | sock.connect("ipc://client-out") 9 | 10 | while True: 11 | m = sock.recv_multipart() 12 | req = tnetstring.loads(m[0][1:]) 13 | print("{} {}".format(req[b"from"].decode(), req[b"id"].decode())) 14 | -------------------------------------------------------------------------------- /tools/zhttp/reqhandler.py: -------------------------------------------------------------------------------- 1 | # this handler responds to every request with "hello world" 2 | 3 | import tnetstring 4 | import zmq 5 | 6 | ctx = zmq.Context() 7 | sock = ctx.socket(zmq.REP) 8 | sock.connect("ipc://client") 9 | 10 | while True: 11 | m_raw = sock.recv() 12 | req = tnetstring.loads(m_raw[1:]) 13 | print("IN {}".format(req)) 14 | 15 | resp = {} 16 | resp[b"id"] = req[b"id"] 17 | resp[b"code"] = 200 18 | resp[b"reason"] = b"OK" 19 | resp[b"headers"] = [[b"Content-Type", b"text/plain"]] 20 | resp[b"body"] = b"hello world\n" 21 | 22 | print("OUT {}".format(resp)) 23 | sock.send(b"T" + tnetstring.dumps(resp)) 24 | -------------------------------------------------------------------------------- /tools/zhttp/sendresp.py: -------------------------------------------------------------------------------- 1 | # this program sends a response to a certain request ID 2 | 3 | import sys 4 | import time 5 | import tnetstring 6 | import zmq 7 | 8 | body = sys.argv[1] 9 | addr = sys.argv[2].encode() 10 | rid = sys.argv[3].encode() 11 | 12 | ctx = zmq.Context() 13 | sock = ctx.socket(zmq.PUB) 14 | sock.connect("ipc://client-in") 15 | 16 | # await subscription 17 | time.sleep(0.01) 18 | 19 | resp = {} 20 | resp[b"from"] = b"sendresp" 21 | resp[b"id"] = rid 22 | resp[b"code"] = 200 23 | resp[b"reason"] = b"OK" 24 | resp[b"headers"] = [[b"Content-Type", b"text/plain"]] 25 | resp[b"body"] = "{}\n".format(body).encode() 26 | 27 | m = [addr + b" T" + tnetstring.dumps(resp)] 28 | 29 | sock.send_multipart(m) 30 | -------------------------------------------------------------------------------- /tools/zhttpreqhandler.py: -------------------------------------------------------------------------------- 1 | # use route target zhttpreq/ipc:///tmp/zhttpreqhandler 2 | 3 | import zmq 4 | import tnetstring 5 | 6 | zmq_context = zmq.Context() 7 | sock = zmq_context.socket(zmq.REP) 8 | sock.connect("ipc:///tmp/zhttpreqhandler") 9 | 10 | while True: 11 | req = tnetstring.loads(sock.recv()[1:]) 12 | 13 | resp = { 14 | "id": req["id"], 15 | "code": 200, 16 | "reason": "OK", 17 | "headers": [["Content-Type", "text/plain"]], 18 | "body": "hello there\n", 19 | } 20 | 21 | sock.send("T" + tnetstring.dumps(resp)) 22 | --------------------------------------------------------------------------------