From 1be88e1973b09261bbfde3eeb1e60060fdcd9660 Mon Sep 17 00:00:00 2001 From: Eugene Morozov Date: Sat, 20 Jul 2024 10:48:03 +0300 Subject: [PATCH] Removed unit project; use matrix to build --- .gitattributes | 7 - .gitea/workflows/build.yml | 27 +- .github/workflows/ci.yml | 339 - .gitignore | 5 +- .hgignore | 6 - .hgtags | 43 - .mailmap | 20 - .rustfmt.toml | 1 - CHANGES | 1135 --- CODE_OF_CONDUCT.md | 74 - CONTRIBUTING.md | 90 - ...erfile.python3.10 => Dockerfile.python3.10 | 0 ...erfile.python3.11 => Dockerfile.python3.11 | 0 ...erfile.python3.12 => Dockerfile.python3.12 | 0 LICENSE | 178 - NOTICE | 37 - README.md | 198 - SECURITY.txt | 30 - auto/atomic | 122 - auto/capability | 19 - auto/cc/deps | 25 - auto/cc/test | 209 - auto/cgroup | 22 - auto/clang | 196 - auto/echo/Makefile | 3 - auto/echo/build | 27 - auto/echo/echo.c | 43 - auto/endian | 31 - auto/events | 196 - auto/feature | 116 - auto/files | 83 - auto/have | 12 - auto/help | 87 - auto/isolation | 200 - auto/make | 475 -- auto/malloc | 175 - auto/mmap | 87 - auto/modules/conf | 51 - auto/modules/go | 141 - auto/modules/java | 641 -- auto/modules/java_chk_sha512 | 49 - auto/modules/java_get_jar | 46 - auto/modules/java_jar.sha512 | 14 - auto/modules/nodejs | 216 - auto/modules/perl | 208 - auto/modules/php | 289 - auto/modules/python | 237 - auto/modules/ruby | 274 - auto/modules/wasm | 207 - auto/modules/wasm-wasi-component | 120 - auto/njs | 53 - auto/options | 172 - auto/os/conf | 278 - auto/os/test | 101 - auto/pcre | 77 - auto/save | 34 - auto/sendfile | 164 - auto/shmem | 139 - auto/sockets | 280 - auto/sources | 313 - auto/ssltls | 215 - auto/summary | 39 - auto/test_build | 76 - auto/threads | 258 - auto/time | 224 - auto/types | 118 - auto/unix | 211 - configure | 182 - ...cker-entrypoint.sh => docker-entrypoint.sh | 0 docs/Makefile | 69 - docs/change_log_conf.dtd | 26 - docs/change_log_conf.xml | 56 - docs/changes.dtd | 25 - docs/changes.xml | 4138 ---------- docs/changes.xsls | 289 - docs/changes.xslt | 281 - docs/man/man8/unitd.8.in | 129 - docs/unit-openapi.yaml | 6389 ---------------- docs/unitlogo.svg | 305 - go/go.mod | 1 - go/ldflags-darwin.go | 15 - go/ldflags-lrt.go | 14 - go/ldflags.go | 10 - go/nxt_cgo_lib.c | 95 - go/nxt_cgo_lib.h | 32 - go/observable.go | 32 - go/port.go | 205 - go/request.go | 136 - go/response.go | 107 - go/unit.go | 157 - pkg/Makefile | 45 - pkg/contrib/Makefile | 140 - pkg/contrib/src/libunit-wasm/Makefile | 23 - pkg/contrib/src/libunit-wasm/version | 2 - pkg/contrib/src/njs/Makefile | 22 - pkg/contrib/src/njs/SHA512SUMS | 1 - pkg/contrib/src/njs/version | 1 - pkg/contrib/src/wasi-sysroot/Makefile | 17 - pkg/contrib/src/wasi-sysroot/SHA512SUMS | 1 - pkg/contrib/src/wasi-sysroot/version | 2 - pkg/contrib/src/wasmtime/Makefile | 30 - pkg/contrib/src/wasmtime/SHA512SUMS | 1 - pkg/contrib/src/wasmtime/version | 1 - pkg/contrib/tarballs/.hgignore | 3 - pkg/deb/Makefile | 370 - pkg/deb/Makefile.go | 50 - pkg/deb/Makefile.jsc-common | 38 - pkg/deb/Makefile.jsc10 | 71 - pkg/deb/Makefile.jsc11 | 71 - pkg/deb/Makefile.jsc16 | 71 - pkg/deb/Makefile.jsc17 | 71 - pkg/deb/Makefile.jsc18 | 71 - pkg/deb/Makefile.jsc19 | 71 - pkg/deb/Makefile.jsc20 | 71 - pkg/deb/Makefile.jsc21 | 71 - pkg/deb/Makefile.jsc8 | 71 - pkg/deb/Makefile.perl | 46 - pkg/deb/Makefile.php | 53 - pkg/deb/Makefile.python27 | 46 - pkg/deb/Makefile.python310 | 46 - pkg/deb/Makefile.python311 | 46 - pkg/deb/Makefile.python312 | 46 - pkg/deb/Makefile.python36 | 46 - pkg/deb/Makefile.python37 | 46 - pkg/deb/Makefile.python38 | 46 - pkg/deb/Makefile.python39 | 46 - pkg/deb/Makefile.ruby | 48 - pkg/deb/Makefile.wasm | 47 - pkg/deb/debian.module/control-noarch.in | 23 - pkg/deb/debian.module/control.in | 34 - .../debian.module/copyright.unit-jsc-common | 872 --- pkg/deb/debian.module/copyright.unit-jsc11 | 42 - pkg/deb/debian.module/copyright.unit-jsc8 | 42 - pkg/deb/debian.module/preinst.in | 21 - pkg/deb/debian.module/rules-noarch.in | 109 - pkg/deb/debian.module/rules.in | 112 - pkg/deb/debian.module/unit.example-go-app | 20 - pkg/deb/debian.module/unit.example-go-config | 14 - pkg/deb/debian.module/unit.example-jsc-app | 12 - .../debian.module/unit.example-jsc11-config | 15 - .../debian.module/unit.example-jsc16-config | 15 - .../debian.module/unit.example-jsc17-config | 15 - .../debian.module/unit.example-jsc18-config | 15 - .../debian.module/unit.example-jsc19-config | 15 - .../debian.module/unit.example-jsc20-config | 15 - .../debian.module/unit.example-jsc21-config | 15 - .../debian.module/unit.example-jsc8-config | 15 - pkg/deb/debian.module/unit.example-perl-app | 12 - .../debian.module/unit.example-perl-config | 16 - pkg/deb/debian.module/unit.example-php-app | 1 - pkg/deb/debian.module/unit.example-php-config | 16 - pkg/deb/debian.module/unit.example-python-app | 16 - .../unit.example-python2.7-config | 16 - .../unit.example-python3.10-config | 16 - .../unit.example-python3.11-config | 16 - .../unit.example-python3.12-config | 16 - .../unit.example-python3.6-config | 16 - .../unit.example-python3.7-config | 16 - .../unit.example-python3.8-config | 16 - .../unit.example-python3.9-config | 16 - pkg/deb/debian.module/unit.example-ruby-app | 7 - .../debian.module/unit.example-ruby-config | 15 - pkg/deb/debian/control.in | 45 - pkg/deb/debian/copyright | 38 - pkg/deb/debian/dirs | 5 - pkg/deb/debian/rules.in | 155 - pkg/deb/debian/unit-debug.service | 14 - pkg/deb/debian/unit.default | 1 - pkg/deb/debian/unit.example-go-app | 20 - pkg/deb/debian/unit.example-php-app | 1 - pkg/deb/debian/unit.example-python-app | 16 - pkg/deb/debian/unit.example.config | 47 - pkg/deb/debian/unit.init | 74 - pkg/deb/debian/unit.logrotate | 15 - pkg/deb/debian/unit.postinst | 44 - pkg/deb/debian/unit.preinst | 35 - pkg/deb/debian/unit.service | 14 - pkg/docker/Dockerfile.go1.21 | 89 - pkg/docker/Dockerfile.go1.22 | 89 - pkg/docker/Dockerfile.jsc11 | 89 - pkg/docker/Dockerfile.minimal | 89 - pkg/docker/Dockerfile.node20 | 89 - pkg/docker/Dockerfile.node21 | 89 - pkg/docker/Dockerfile.perl5.36 | 89 - pkg/docker/Dockerfile.perl5.38 | 89 - pkg/docker/Dockerfile.php8.2 | 89 - pkg/docker/Dockerfile.php8.3 | 89 - pkg/docker/Dockerfile.ruby3.2 | 89 - pkg/docker/Dockerfile.ruby3.3 | 89 - pkg/docker/Dockerfile.wasm | 110 - pkg/docker/Makefile | 174 - pkg/docker/template.Dockerfile | 89 - pkg/npm/Makefile | 28 - pkg/rpm/Makefile | 307 - pkg/rpm/Makefile.go | 68 - pkg/rpm/Makefile.jsc-common | 54 - pkg/rpm/Makefile.jsc11 | 70 - pkg/rpm/Makefile.jsc17 | 83 - pkg/rpm/Makefile.jsc8 | 72 - pkg/rpm/Makefile.perl | 58 - pkg/rpm/Makefile.php | 53 - pkg/rpm/Makefile.python27 | 66 - pkg/rpm/Makefile.python310 | 57 - pkg/rpm/Makefile.python311 | 57 - pkg/rpm/Makefile.python312 | 53 - pkg/rpm/Makefile.python36 | 57 - pkg/rpm/Makefile.python37 | 57 - pkg/rpm/Makefile.python38 | 53 - pkg/rpm/Makefile.python39 | 57 - pkg/rpm/Makefile.ruby | 60 - pkg/rpm/Makefile.wasm | 51 - .../SOURCES/COPYRIGHT.unit-jsc-common | 872 --- pkg/rpm/rpmbuild/SOURCES/COPYRIGHT.unit-jsc11 | 41 - pkg/rpm/rpmbuild/SOURCES/COPYRIGHT.unit-jsc8 | 41 - pkg/rpm/rpmbuild/SOURCES/unit-debug.service | 26 - pkg/rpm/rpmbuild/SOURCES/unit.example-go-app | 20 - .../rpmbuild/SOURCES/unit.example-go-config | 14 - pkg/rpm/rpmbuild/SOURCES/unit.example-jsc-app | 12 - .../SOURCES/unit.example-jsc11-config | 15 - .../SOURCES/unit.example-jsc17-config | 15 - .../rpmbuild/SOURCES/unit.example-jsc8-config | 15 - .../rpmbuild/SOURCES/unit.example-perl-app | 12 - .../rpmbuild/SOURCES/unit.example-perl-config | 16 - pkg/rpm/rpmbuild/SOURCES/unit.example-php-app | 1 - .../rpmbuild/SOURCES/unit.example-php-config | 16 - .../rpmbuild/SOURCES/unit.example-python-app | 16 - .../SOURCES/unit.example-python-config | 16 - .../SOURCES/unit.example-python27-config | 16 - .../SOURCES/unit.example-python310-config | 16 - .../SOURCES/unit.example-python311-config | 16 - .../SOURCES/unit.example-python312-config | 16 - .../SOURCES/unit.example-python34-config | 16 - .../SOURCES/unit.example-python36-config | 16 - .../SOURCES/unit.example-python37-config | 16 - .../SOURCES/unit.example-python38-config | 16 - .../SOURCES/unit.example-python39-config | 16 - .../rpmbuild/SOURCES/unit.example-ruby-app | 7 - .../rpmbuild/SOURCES/unit.example-ruby-config | 15 - pkg/rpm/rpmbuild/SOURCES/unit.example.config | 47 - pkg/rpm/rpmbuild/SOURCES/unit.logrotate | 14 - pkg/rpm/rpmbuild/SOURCES/unit.service | 26 - pkg/rpm/unit.module.spec.in | 117 - pkg/rpm/unit.spec.in | 244 - pkg/shasum.mak | 9 - src/java/README.JSR-340 | 16 - src/java/javax/websocket/ClientEndpoint.java | 34 - .../javax/websocket/ClientEndpointConfig.java | 138 - src/java/javax/websocket/CloseReason.java | 122 - .../javax/websocket/ContainerProvider.java | 63 - src/java/javax/websocket/DecodeException.java | 56 - src/java/javax/websocket/Decoder.java | 53 - .../DefaultClientEndpointConfig.java | 80 - .../javax/websocket/DeploymentException.java | 30 - src/java/javax/websocket/EncodeException.java | 38 - src/java/javax/websocket/Encoder.java | 51 - src/java/javax/websocket/Endpoint.java | 49 - src/java/javax/websocket/EndpointConfig.java | 29 - src/java/javax/websocket/Extension.java | 29 - .../javax/websocket/HandshakeResponse.java | 30 - src/java/javax/websocket/MessageHandler.java | 42 - src/java/javax/websocket/OnClose.java | 27 - src/java/javax/websocket/OnError.java | 27 - src/java/javax/websocket/OnMessage.java | 28 - src/java/javax/websocket/OnOpen.java | 27 - src/java/javax/websocket/PongMessage.java | 32 - src/java/javax/websocket/RemoteEndpoint.java | 229 - src/java/javax/websocket/SendHandler.java | 22 - src/java/javax/websocket/SendResult.java | 39 - src/java/javax/websocket/Session.java | 193 - .../javax/websocket/SessionException.java | 35 - .../javax/websocket/WebSocketContainer.java | 131 - .../server/DefaultServerEndpointConfig.java | 95 - .../websocket/server/HandshakeRequest.java | 53 - .../javax/websocket/server/PathParam.java | 33 - .../server/ServerApplicationConfig.java | 51 - .../websocket/server/ServerContainer.java | 30 - .../websocket/server/ServerEndpoint.java | 46 - .../server/ServerEndpointConfig.java | 218 - src/java/nginx/unit/Context.java | 3638 --------- .../nginx/unit/DynamicDispatcherRequest.java | 8 - src/java/nginx/unit/DynamicPathRequest.java | 15 - .../nginx/unit/ForwardRequestWrapper.java | 162 - .../nginx/unit/HeaderNamesEnumeration.java | 42 - src/java/nginx/unit/HeadersEnumeration.java | 40 - .../nginx/unit/IncludeRequestWrapper.java | 100 - .../nginx/unit/IncludeResponseWrapper.java | 117 - src/java/nginx/unit/InitParams.java | 7 - src/java/nginx/unit/InputStream.java | 90 - src/java/nginx/unit/JspPropertyGroup.java | 169 - src/java/nginx/unit/OutputStream.java | 68 - src/java/nginx/unit/Request.java | 1338 ---- src/java/nginx/unit/RequestAttrProxy.java | 40 - src/java/nginx/unit/Response.java | 832 -- src/java/nginx/unit/Session.java | 251 - src/java/nginx/unit/SessionAttrProxy.java | 40 - src/java/nginx/unit/Taglib.java | 44 - .../nginx/unit/UnitSessionCookieConfig.java | 110 - .../unit/websocket/AsyncChannelGroupUtil.java | 151 - .../unit/websocket/AsyncChannelWrapper.java | 47 - .../AsyncChannelWrapperNonSecure.java | 112 - .../websocket/AsyncChannelWrapperSecure.java | 578 -- .../websocket/AuthenticationException.java | 35 - .../nginx/unit/websocket/Authenticator.java | 71 - .../unit/websocket/AuthenticatorFactory.java | 68 - .../unit/websocket/BackgroundProcess.java | 26 - .../websocket/BackgroundProcessManager.java | 149 - .../unit/websocket/BasicAuthenticator.java | 66 - src/java/nginx/unit/websocket/Constants.java | 158 - .../nginx/unit/websocket/DecoderEntry.java | 39 - .../unit/websocket/DigestAuthenticator.java | 150 - .../unit/websocket/FutureToSendHandler.java | 112 - .../unit/websocket/LocalStrings.properties | 147 - .../unit/websocket/MessageHandlerResult.java | 42 - .../websocket/MessageHandlerResultType.java | 23 - .../nginx/unit/websocket/MessagePart.java | 83 - .../unit/websocket/PerMessageDeflate.java | 476 -- .../ReadBufferOverflowException.java | 34 - .../nginx/unit/websocket/Transformation.java | 111 - .../unit/websocket/TransformationFactory.java | 51 - .../unit/websocket/TransformationResult.java | 37 - src/java/nginx/unit/websocket/Util.java | 666 -- .../unit/websocket/WrappedMessageHandler.java | 25 - .../unit/websocket/WsContainerProvider.java | 28 - .../nginx/unit/websocket/WsExtension.java | 46 - .../unit/websocket/WsExtensionParameter.java | 40 - .../nginx/unit/websocket/WsFrameBase.java | 1010 --- .../nginx/unit/websocket/WsFrameClient.java | 228 - .../unit/websocket/WsHandshakeResponse.java | 56 - .../nginx/unit/websocket/WsIOException.java | 41 - .../nginx/unit/websocket/WsPongMessage.java | 39 - .../unit/websocket/WsRemoteEndpointAsync.java | 79 - .../unit/websocket/WsRemoteEndpointBase.java | 64 - .../unit/websocket/WsRemoteEndpointBasic.java | 76 - .../websocket/WsRemoteEndpointImplBase.java | 1234 --- .../websocket/WsRemoteEndpointImplClient.java | 75 - src/java/nginx/unit/websocket/WsSession.java | 1070 --- .../unit/websocket/WsWebSocketContainer.java | 1123 --- .../nginx/unit/websocket/pojo/Constants.java | 32 - .../websocket/pojo/LocalStrings.properties | 40 - .../unit/websocket/pojo/PojoEndpointBase.java | 156 - .../websocket/pojo/PojoEndpointClient.java | 47 - .../websocket/pojo/PojoEndpointServer.java | 66 - .../pojo/PojoMessageHandlerBase.java | 122 - .../pojo/PojoMessageHandlerPartialBase.java | 77 - .../pojo/PojoMessageHandlerPartialBinary.java | 36 - .../pojo/PojoMessageHandlerPartialText.java | 35 - .../pojo/PojoMessageHandlerWholeBase.java | 94 - .../pojo/PojoMessageHandlerWholeBinary.java | 131 - .../pojo/PojoMessageHandlerWholePong.java | 48 - .../pojo/PojoMessageHandlerWholeText.java | 136 - .../websocket/pojo/PojoMethodMapping.java | 731 -- .../unit/websocket/pojo/PojoPathParam.java | 47 - .../unit/websocket/pojo/package-info.java | 21 - .../unit/websocket/server/Constants.java | 38 - .../DefaultServerEndpointConfigurator.java | 88 - .../websocket/server/LocalStrings.properties | 43 - .../unit/websocket/server/UpgradeUtil.java | 285 - .../unit/websocket/server/UriTemplate.java | 177 - .../websocket/server/WsContextListener.java | 51 - .../nginx/unit/websocket/server/WsFilter.java | 81 - .../websocket/server/WsHandshakeRequest.java | 196 - .../server/WsHttpUpgradeHandler.java | 172 - .../websocket/server/WsMappingResult.java | 44 - .../WsPerSessionServerEndpointConfig.java | 84 - .../server/WsRemoteEndpointImplServer.java | 158 - .../nginx/unit/websocket/server/WsSci.java | 145 - .../websocket/server/WsServerContainer.java | 470 -- .../websocket/server/WsSessionListener.java | 36 - .../unit/websocket/server/WsWriteTimeout.java | 128 - .../unit/websocket/server/package-info.java | 21 - src/java/nxt_jni.c | 175 - src/java/nxt_jni.h | 55 - src/java/nxt_jni_Context.c | 164 - src/java/nxt_jni_Context.h | 23 - src/java/nxt_jni_HeaderNamesEnumeration.c | 153 - src/java/nxt_jni_HeaderNamesEnumeration.h | 19 - src/java/nxt_jni_HeadersEnumeration.c | 148 - src/java/nxt_jni_HeadersEnumeration.h | 19 - src/java/nxt_jni_InputStream.c | 210 - src/java/nxt_jni_InputStream.h | 15 - src/java/nxt_jni_OutputStream.c | 236 - src/java/nxt_jni_OutputStream.h | 17 - src/java/nxt_jni_Request.c | 823 -- src/java/nxt_jni_Request.h | 23 - src/java/nxt_jni_Response.c | 1106 --- src/java/nxt_jni_Response.h | 18 - src/java/nxt_jni_Thread.c | 94 - src/java/nxt_jni_Thread.h | 20 - src/java/nxt_jni_URLClassLoader.c | 187 - src/java/nxt_jni_URLClassLoader.h | 27 - src/nodejs/unit-http/README.md | 5 - src/nodejs/unit-http/addon.cpp | 15 - src/nodejs/unit-http/binding.gyp | 21 - src/nodejs/unit-http/binding_pub.gyp | 35 - src/nodejs/unit-http/http.js | 26 - src/nodejs/unit-http/http_server.js | 573 -- src/nodejs/unit-http/loader.js | 29 - src/nodejs/unit-http/loader.mjs | 22 - src/nodejs/unit-http/nxt_napi.h | 839 -- src/nodejs/unit-http/package.json | 15 - src/nodejs/unit-http/socket.js | 104 - src/nodejs/unit-http/unit.cpp | 1168 --- src/nodejs/unit-http/unit.h | 87 - src/nodejs/unit-http/utils.js | 73 - src/nodejs/unit-http/websocket.js | 14 - src/nodejs/unit-http/websocket_connection.js | 683 -- src/nodejs/unit-http/websocket_frame.js | 11 - src/nodejs/unit-http/websocket_request.js | 509 -- src/nodejs/unit-http/websocket_router.js | 157 - .../unit-http/websocket_router_request.js | 54 - src/nodejs/unit-http/websocket_server.js | 213 - src/nxt_aix_send_file.c | 126 - src/nxt_app_log.c | 139 - src/nxt_app_nncq.h | 165 - src/nxt_app_queue.h | 125 - src/nxt_application.c | 1287 ---- src/nxt_application.h | 177 - src/nxt_array.c | 150 - src/nxt_array.h | 58 - src/nxt_atomic.h | 269 - src/nxt_buf.c | 329 - src/nxt_buf.h | 269 - src/nxt_buf_pool.c | 185 - src/nxt_buf_pool.h | 75 - src/nxt_capability.c | 119 - src/nxt_capability.h | 18 - src/nxt_cert.c | 1254 --- src/nxt_cert.h | 32 - src/nxt_cgroup.c | 174 - src/nxt_cgroup.h | 14 - src/nxt_clang.h | 258 - src/nxt_clone.c | 434 -- src/nxt_clone.h | 54 - src/nxt_conf.c | 2658 ------- src/nxt_conf.h | 156 - src/nxt_conf_validation.c | 3437 --------- src/nxt_conn.c | 185 - src/nxt_conn.h | 364 - src/nxt_conn_accept.c | 386 - src/nxt_conn_close.c | 174 - src/nxt_conn_connect.c | 203 - src/nxt_conn_proxy.c | 987 --- src/nxt_conn_read.c | 252 - src/nxt_conn_write.c | 544 -- src/nxt_controller.c | 2665 ------- src/nxt_credential.c | 353 - src/nxt_credential.h | 30 - src/nxt_cyassl.c | 621 -- src/nxt_devpoll_engine.c | 661 -- src/nxt_djb_hash.c | 45 - src/nxt_djb_hash.h | 25 - src/nxt_dyld.c | 86 - src/nxt_dyld.h | 29 - src/nxt_epoll_engine.c | 1174 --- src/nxt_errno.c | 152 - src/nxt_errno.h | 88 - src/nxt_event_conn_job_sendfile.c | 259 - src/nxt_event_engine.c | 759 -- src/nxt_event_engine.h | 542 -- src/nxt_eventport_engine.c | 613 -- src/nxt_external.c | 208 - src/nxt_fd_event.c | 112 - src/nxt_fd_event.h | 118 - src/nxt_fiber.c | 465 -- src/nxt_fiber.h | 57 - src/nxt_file.c | 777 -- src/nxt_file.h | 219 - src/nxt_file_event.h | 18 - src/nxt_file_name.c | 201 - src/nxt_file_name.h | 15 - src/nxt_freebsd_sendfile.c | 143 - src/nxt_fs.c | 84 - src/nxt_fs.h | 13 - src/nxt_fs_mount.c | 230 - src/nxt_fs_mount.h | 48 - src/nxt_gmtime.c | 79 - src/nxt_gnutls.c | 742 -- src/nxt_h1proto.c | 2887 ------- src/nxt_h1proto.h | 57 - src/nxt_h1proto_websocket.c | 702 -- src/nxt_hash.h | 47 - src/nxt_hpux_sendfile.c | 137 - src/nxt_http.h | 441 -- src/nxt_http_chunk_parse.c | 272 - src/nxt_http_error.c | 104 - src/nxt_http_js.c | 389 - src/nxt_http_parse.c | 1275 --- src/nxt_http_parse.h | 159 - src/nxt_http_proxy.c | 432 -- src/nxt_http_request.c | 1318 ---- src/nxt_http_response.c | 87 - src/nxt_http_return.c | 234 - src/nxt_http_rewrite.c | 111 - src/nxt_http_route.c | 2209 ------ src/nxt_http_route_addr.c | 346 - src/nxt_http_route_addr.h | 74 - src/nxt_http_set_headers.c | 176 - src/nxt_http_static.c | 1102 --- src/nxt_http_variables.c | 778 -- src/nxt_http_websocket.c | 155 - src/nxt_isolation.c | 1123 --- src/nxt_isolation.h | 18 - src/nxt_java.c | 760 -- src/nxt_job.c | 199 - src/nxt_job.h | 86 - src/nxt_job_cache_file.c | 24 - src/nxt_js.c | 489 -- src/nxt_js.h | 45 - src/nxt_kqueue_engine.c | 1028 --- src/nxt_lib.c | 157 - src/nxt_linux_sendfile.c | 239 - src/nxt_list.c | 108 - src/nxt_list.h | 127 - src/nxt_listen_socket.c | 394 - src/nxt_listen_socket.h | 65 - src/nxt_log.c | 119 - src/nxt_log.h | 168 - src/nxt_log_moderation.c | 97 - src/nxt_log_moderation.h | 49 - src/nxt_lvlhsh.c | 994 --- src/nxt_lvlhsh.h | 200 - src/nxt_macosx_sendfile.c | 153 - src/nxt_main.c | 39 - src/nxt_main.h | 173 - src/nxt_main_process.c | 1730 ----- src/nxt_main_process.h | 37 - src/nxt_malloc.c | 229 - src/nxt_malloc.h | 126 - src/nxt_mem_map.c | 40 - src/nxt_mem_map.h | 62 - src/nxt_mem_zone.c | 948 --- src/nxt_mem_zone.h | 28 - src/nxt_mp.c | 1075 --- src/nxt_mp.h | 119 - src/nxt_murmur_hash.c | 86 - src/nxt_murmur_hash.h | 15 - src/nxt_nncq.h | 162 - src/nxt_nvbcq.h | 146 - src/nxt_openssl.c | 1817 ----- src/nxt_parse.c | 348 - src/nxt_parse.h | 25 - src/nxt_pcre.c | 135 - src/nxt_pcre2.c | 161 - src/nxt_php_sapi.c | 1641 ---- src/nxt_polarssl.c | 118 - src/nxt_poll_engine.c | 694 -- src/nxt_pollset_engine.c | 645 -- src/nxt_port.c | 631 -- src/nxt_port.h | 376 - src/nxt_port_hash.c | 142 - src/nxt_port_hash.h | 24 - src/nxt_port_memory.c | 882 --- src/nxt_port_memory.h | 55 - src/nxt_port_memory_int.h | 196 - src/nxt_port_queue.h | 102 - src/nxt_port_rpc.c | 521 -- src/nxt_port_rpc.h | 35 - src/nxt_port_socket.c | 1386 ---- src/nxt_process.c | 1280 ---- src/nxt_process.h | 241 - src/nxt_process_title.c | 256 - src/nxt_process_type.h | 23 - src/nxt_queue.c | 85 - src/nxt_queue.h | 219 - src/nxt_random.c | 216 - src/nxt_random.h | 27 - src/nxt_rbtree.c | 533 -- src/nxt_rbtree.h | 131 - src/nxt_recvbuf.c | 82 - src/nxt_recvbuf.h | 24 - src/nxt_regex.h | 41 - src/nxt_router.c | 5878 -------------- src/nxt_router.h | 271 - src/nxt_router_access_log.c | 470 -- src/nxt_router_request.h | 40 - src/nxt_runtime.c | 1841 ----- src/nxt_runtime.h | 171 - src/nxt_script.c | 709 -- src/nxt_script.h | 37 - src/nxt_select_engine.c | 370 - src/nxt_semaphore.c | 244 - src/nxt_semaphore.h | 32 - src/nxt_sendbuf.c | 445 -- src/nxt_sendbuf.h | 131 - src/nxt_service.c | 165 - src/nxt_service.h | 29 - src/nxt_sha1.c | 295 - src/nxt_sha1.h | 24 - src/nxt_signal.c | 192 - src/nxt_signal.h | 50 - src/nxt_signal_handlers.c | 67 - src/nxt_sockaddr.c | 975 --- src/nxt_sockaddr.h | 108 - src/nxt_socket.c | 360 - src/nxt_socket.h | 128 - src/nxt_socket_msg.c | 57 - src/nxt_socket_msg.h | 234 - src/nxt_socketpair.c | 187 - src/nxt_solaris_sendfilev.c | 169 - src/nxt_sort.h | 14 - src/nxt_source.h | 42 - src/nxt_spinlock.c | 112 - src/nxt_spinlock.h | 19 - src/nxt_sprintf.c | 724 -- src/nxt_sprintf.h | 21 - src/nxt_status.c | 105 - src/nxt_status.h | 33 - src/nxt_string.c | 844 -- src/nxt_string.h | 167 - src/nxt_test_build.c | 153 - src/nxt_test_build.h | 274 - src/nxt_thread.c | 267 - src/nxt_thread.h | 163 - src/nxt_thread_cond.c | 107 - src/nxt_thread_id.h | 189 - src/nxt_thread_log.h | 61 - src/nxt_thread_mutex.c | 192 - src/nxt_thread_pool.c | 310 - src/nxt_thread_pool.h | 44 - src/nxt_thread_time.c | 432 -- src/nxt_thread_time.h | 92 - src/nxt_time.c | 365 - src/nxt_time.h | 107 - src/nxt_time_parse.c | 489 -- src/nxt_timer.c | 344 - src/nxt_timer.h | 113 - src/nxt_tls.h | 116 - src/nxt_tstr.c | 343 - src/nxt_tstr.h | 82 - src/nxt_types.h | 151 - src/nxt_unicode_lowcase.h | 1043 --- src/nxt_unicode_lowcase.pl | 88 - src/nxt_unicode_macosx_lowcase.h | 816 -- src/nxt_unit.c | 6802 ----------------- src/nxt_unit.h | 400 - src/nxt_unit_field.h | 34 - src/nxt_unit_request.h | 55 - src/nxt_unit_response.h | 27 - src/nxt_unit_sptr.h | 38 - src/nxt_unit_typedefs.h | 26 - src/nxt_unit_websocket.h | 27 - src/nxt_unix.h | 292 - src/nxt_upstream.c | 151 - src/nxt_upstream.h | 81 - src/nxt_upstream_round_robin.c | 205 - src/nxt_utf8.c | 273 - src/nxt_utf8.h | 60 - src/nxt_var.c | 588 -- src/nxt_var.h | 69 - src/nxt_vector.c | 156 - src/nxt_vector.h | 65 - src/nxt_websocket.c | 122 - src/nxt_websocket.h | 21 - src/nxt_websocket_accept.c | 68 - src/nxt_websocket_header.h | 68 - src/nxt_work_queue.c | 311 - src/nxt_work_queue.h | 127 - src/perl/nxt_perl_psgi.c | 1435 ---- src/perl/nxt_perl_psgi_layer.c | 382 - src/perl/nxt_perl_psgi_layer.h | 48 - src/python/nxt_python.c | 848 -- src/python/nxt_python.h | 84 - src/python/nxt_python_asgi.c | 1570 ---- src/python/nxt_python_asgi.h | 71 - src/python/nxt_python_asgi_http.c | 689 -- src/python/nxt_python_asgi_lifespan.c | 659 -- src/python/nxt_python_asgi_str.c | 143 - src/python/nxt_python_asgi_str.h | 70 - src/python/nxt_python_asgi_websocket.c | 1091 --- src/python/nxt_python_wsgi.c | 1414 ---- src/ruby/nxt_ruby.c | 1510 ---- src/ruby/nxt_ruby.h | 36 - src/ruby/nxt_ruby_stream_io.c | 269 - src/test/nxt_base64_test.c | 98 - src/test/nxt_clone_test.c | 601 -- src/test/nxt_cq_test.c | 578 -- src/test/nxt_gmtime_test.c | 84 - src/test/nxt_http_parse_test.c | 819 -- src/test/nxt_lvlhsh_test.c | 263 - src/test/nxt_malloc_test.c | 123 - src/test/nxt_mem_zone_test.c | 74 - src/test/nxt_mp_test.c | 90 - src/test/nxt_msec_diff_test.c | 46 - src/test/nxt_rbtree1.c | 382 - src/test/nxt_rbtree1.h | 73 - src/test/nxt_rbtree1_test.c | 341 - src/test/nxt_rbtree_test.c | 279 - src/test/nxt_sprintf_test.c | 71 - src/test/nxt_strverscmp_test.c | 94 - src/test/nxt_term_parse_test.c | 60 - src/test/nxt_tests.c | 176 - src/test/nxt_tests.h | 71 - src/test/nxt_unit_app_test.c | 281 - src/test/nxt_unit_websocket_chat.c | 348 - src/test/nxt_unit_websocket_echo.c | 105 - src/test/nxt_utf8_file_name_test.c | 148 - src/test/nxt_utf8_test.c | 191 - src/unit.pc.in | 11 - src/wasm-wasi-component/.gitignore | 1 - src/wasm-wasi-component/Cargo.lock | 2293 ------ src/wasm-wasi-component/Cargo.toml | 30 - src/wasm-wasi-component/build.rs | 33 - src/wasm-wasi-component/src/lib.rs | 620 -- src/wasm-wasi-component/wrapper.h | 5 - src/wasm/nxt_rt_wasmtime.c | 433 -- src/wasm/nxt_wasm.c | 315 - src/wasm/nxt_wasm.h | 142 - test/conftest.py | 709 -- test/go/404/404.html | 6 - test/go/404/app.go | 22 - test/go/command_line_arguments/app.go | 23 - test/go/cookies/app.go | 19 - test/go/empty/app.go | 13 - test/go/get_variables/app.go | 17 - test/go/mirror/app.go | 21 - test/go/ns_inspect/app.go | 101 - test/go/post_variables/app.go | 19 - test/go/variables/app.go | 30 - test/java/content_type/app.java | 89 - test/java/cookies/app.java | 30 - test/java/empty/app.java | 18 - test/java/empty_war/empty.war | Bin 484 -> 0 bytes test/java/filter/app.java | 54 - test/java/forward/app.java | 138 - test/java/forward/index.html | 1 - test/java/forward/web.xml | 38 - test/java/get_header/app.java | 21 - test/java/get_header_names/app.java | 27 - test/java/get_headers/app.java | 27 - test/java/get_params/app.java | 50 - test/java/header/app.java | 34 - test/java/header_date/app.java | 22 - test/java/header_int/app.java | 22 - test/java/include/app.java | 136 - test/java/include/index.html | 1 - test/java/include/web.xml | 37 - test/java/jsp/index.jsp | 2 - test/java/mirror/app.java | 37 - test/java/multipart/app.java | 93 - test/java/path_translation/app.java | 56 - test/java/path_translation/index.html | 1 - test/java/post_params/app.java | 22 - test/java/query_string/app.java | 20 - test/java/request_listeners/app.java | 79 - test/java/session/app.java | 30 - test/java/session_inactive/app.java | 33 - test/java/session_invalidate/app.java | 23 - test/java/session_listeners/app.java | 80 - test/java/session_listeners/web.xml | 14 - test/java/threads/app.java | 32 - test/java/url_pattern/app.java | 39 - test/java/url_pattern/web.xml | 75 - test/java/websockets_mirror/app.java | 57 - test/java/welcome_files/app.java | 67 - test/java/welcome_files/dir1/index.txt | 1 - test/java/welcome_files/dir2/default.jsp | 3 - test/java/welcome_files/dir2/index.html | 1 - test/java/welcome_files/dir3/index.txt | 1 - test/java/welcome_files/dir4/index.html | 1 - test/java/welcome_files/index.htm | 1 - test/java/welcome_files/web.xml | 27 - test/njs/global_this/script.js | 3 - test/njs/import_from/script.js | 5 - test/njs/invalid/script.js | 3 - test/njs/next/script.js | 3 - test/node/404/404.html | 6 - test/node/404/app.js | 6 - test/node/basic/app.js | 5 - test/node/double_end/app.js | 4 - test/node/flush_headers/app.js | 7 - test/node/get_header_names/app.js | 7 - test/node/get_header_type/app.js | 6 - test/node/get_variables/app.js | 8 - test/node/has_header/app.js | 5 - test/node/header_name_case/app.js | 7 - test/node/header_name_valid/app.js | 6 - test/node/header_value_object/app.js | 5 - test/node/loader/es_modules_http/app.mjs | 6 - .../loader/es_modules_http_indirect/app.js | 1 - .../es_modules_http_indirect/module.mjs | 6 - test/node/loader/es_modules_websocket/app.mjs | 30 - .../es_modules_websocket_indirect/app.js | 1 - .../es_modules_websocket_indirect/module.mjs | 30 - test/node/loader/transitive_dependency/app.js | 1 - .../transitive_dependency/transitive_http.js | 8 - test/node/loader/unit_http/app.js | 4 - test/node/mirror/app.js | 11 - test/node/options/app.js | 4 - test/node/post_variables/app.js | 14 - test/node/promise_end/app.js | 15 - test/node/promise_handler/app.js | 16 - test/node/remove_header/app.js | 10 - test/node/set_header_array/app.js | 5 - test/node/status_message/app.js | 4 - test/node/update_header/app.js | 6 - test/node/variables/app.js | 18 - test/node/websockets/mirror/app.js | 28 - .../websockets/mirror_fragmentation/app.js | 23 - test/node/write_array/app.js | 4 - test/node/write_before_write_head/app.js | 5 - test/node/write_buffer/app.js | 5 - test/node/write_callback/app.js | 12 - test/node/write_multiple/app.js | 7 - test/node/write_return/app.js | 5 - test/perl/body_array/psgi.pl | 5 - test/perl/body_empty/psgi.pl | 5 - test/perl/body_io_empty/psgi.pl | 9 - test/perl/body_io_fake/IOFake.pm | 33 - test/perl/body_io_fake/psgi.pl | 11 - test/perl/body_io_file/file | 1 - test/perl/body_io_file/psgi.pl | 7 - test/perl/delayed_response/psgi.pl | 10 - test/perl/errors_print/psgi.pl | 7 - test/perl/header_equal_names/psgi.pl | 9 - test/perl/header_pairs/psgi.pl | 5 - test/perl/input_buffered_read/psgi.pl | 17 - test/perl/input_close/psgi.pl | 8 - test/perl/input_copy/psgi.pl | 10 - test/perl/input_read_empty/psgi.pl | 7 - test/perl/input_read_offset/psgi.pl | 7 - test/perl/input_read_parts/psgi.pl | 10 - test/perl/query_string/psgi.pl | 8 - test/perl/server_port/psgi.pl | 8 - test/perl/streaming_body/psgi.pl | 13 - .../streaming_body_multiple_responses/psgi.pl | 11 - test/perl/syntax_error/psgi.pl | 5 - test/perl/threads/psgi.pl | 11 - test/perl/variables/psgi.pl | 26 - test/php/404/404.html | 6 - test/php/404/index.php | 10 - test/php/auth/index.php | 7 - test/php/conditional/index.php | 5 - test/php/cookies/index.php | 4 - test/php/cwd/index.php | 20 - test/php/cwd/subdir/index.php | 1 - test/php/date_time/index.php | 5 - test/php/error_log/index.php | 3 - test/php/fastcgi_finish_request/index.php | 13 - test/php/fastcgi_finish_request/server.php | 4 - test/php/get_variables/index.php | 7 - test/php/header/index.php | 4 - test/php/ini_precision/index.php | 8 - test/php/ini_precision/ini/php.ini | 1 - test/php/list-extensions/index.php | 11 - test/php/list-extensions/php.ini | 1 - test/php/mirror/index.php | 5 - test/php/opcache/index.php | 18 - test/php/opcache/preload/chdir.php | 7 - .../preload/fastcgi_finish_request.php | 5 - test/php/opcache/test.php | 1 - test/php/open/index.php | 7 - test/php/open/test.txt | 1 - test/php/phpinfo/index.php | 3 - test/php/phpinfo/index.wrong | 3 - test/php/post_variables/index.php | 6 - test/php/query_string/index.php | 4 - test/php/script/phpinfo.php | 3 - test/php/targets/1.php | 4 - test/php/targets/2/2.php | 4 - test/php/targets/index.php | 4 - test/php/time_exec/index.php | 4 - test/php/variables/index.php | 14 - test/pytest.ini | 3 - test/python/204_no_content/asgi.py | 10 - test/python/204_no_content/wsgi.py | 4 - test/python/atexit/wsgi.py | 12 - test/python/body_array/wsgi.py | 3 - test/python/body_bytearray/asgi.py | 20 - test/python/body_generate/wsgi.py | 6 - test/python/body_io/wsgi.py | 7 - test/python/body_io_file/file | 1 - test/python/body_io_file/wsgi.py | 4 - test/python/callable/wsgi.py | 8 - test/python/chunked/wsgi.py | 18 - test/python/client_ip/wsgi.py | 4 - test/python/close/wsgi.py | 12 - test/python/close_error/wsgi.py | 12 - test/python/ctx_iter_atexit/wsgi.py | 24 - test/python/custom_header/wsgi.py | 10 - test/python/delayed/asgi.py | 56 - test/python/delayed/wsgi.py | 26 - test/python/empty/asgi.py | 10 - test/python/empty/wsgi.py | 3 - test/python/encoding/wsgi.py | 12 - test/python/environment/wsgi.py | 13 - test/python/errors_write/wsgi.py | 6 - test/python/forwarded_header/wsgi.py | 10 - test/python/header_fields/wsgi.py | 8 - test/python/host/wsgi.py | 10 - test/python/input_iter/wsgi.py | 16 - test/python/input_read_length/wsgi.py | 7 - test/python/input_readline/wsgi.py | 20 - test/python/input_readline_size/wsgi.py | 16 - test/python/input_readlines/wsgi.py | 5 - test/python/iter_exception/wsgi.py | 45 - test/python/legacy/asgi.py | 16 - test/python/legacy_force/asgi.py | 19 - test/python/lifespan/empty/asgi.py | 37 - test/python/lifespan/error/asgi.py | 3 - test/python/lifespan/error_auto/asgi.py | 2 - test/python/lifespan/failed/asgi.py | 11 - test/python/log_body/wsgi.py | 9 - test/python/mirror/asgi.py | 19 - test/python/mirror/wsgi.py | 7 - test/python/not_iterable/wsgi.py | 7 - test/python/ns_inspect/wsgi.py | 31 - test/python/path/wsgi.py | 9 - test/python/prefix/asgi.py | 15 - test/python/prefix/wsgi.py | 10 - test/python/query_string/asgi.py | 13 - test/python/query_string/wsgi.py | 10 - test/python/restart/longstart.py | 11 - test/python/restart/v1.py | 5 - test/python/restart/v2.py | 5 - test/python/server_port/asgi.py | 13 - test/python/server_port/wsgi.py | 7 - test/python/start_response_exit/wsgi.py | 4 - test/python/syntax_error/wsgi.py | 3 - test/python/targets/asgi.py | 71 - test/python/targets/wsgi.py | 14 - test/python/threading/asgi.py | 39 - test/python/threading/wsgi.py | 31 - test/python/threads/asgi.py | 29 - test/python/threads/wsgi.py | 19 - test/python/unicode/wsgi.py | 8 - test/python/upload/wsgi.py | 29 - test/python/user_group/wsgi.py | 24 - test/python/variables/asgi.py | 39 - test/python/variables/wsgi.py | 24 - test/python/websockets/mirror/asgi.py | 18 - test/python/websockets/subprotocol/asgi.py | 29 - test/python/write/wsgi.py | 5 - test/requirements.txt | 2 - test/ruby/at_exit/config.ru | 8 - test/ruby/body_array/config.ru | 5 - test/ruby/body_each_error/config.ru | 6 - test/ruby/body_empty/config.ru | 5 - test/ruby/body_file/config.ru | 6 - test/ruby/body_file/file | 1 - test/ruby/constants/config.ru | 15 - test/ruby/empty/config.ru | 9 - test/ruby/encoding/config.ru | 8 - test/ruby/errors_puts/config.ru | 6 - test/ruby/errors_puts_int/config.ru | 6 - test/ruby/errors_write/config.ru | 8 - test/ruby/errors_write_int/config.ru | 6 - test/ruby/errors_write_to_s_custom/config.ru | 15 - test/ruby/header_array/config.ru | 7 - test/ruby/header_array_empty/config.ru | 7 - test/ruby/header_array_nil/config.ru | 7 - test/ruby/header_custom/config.ru | 8 - test/ruby/header_rack/config.ru | 8 - test/ruby/header_status/config.ru | 8 - test/ruby/hooks/config.ru | 7 - test/ruby/hooks/eval.rb | 3 - test/ruby/hooks/multiple.rb | 13 - test/ruby/hooks/on_thread_boot.rb | 9 - test/ruby/hooks/on_thread_shutdown.rb | 9 - test/ruby/hooks/on_worker_boot.rb | 5 - test/ruby/hooks/on_worker_shutdown.rb | 5 - test/ruby/input_each/config.ru | 11 - test/ruby/input_gets/config.ru | 9 - test/ruby/input_gets_all/config.ru | 14 - test/ruby/input_read_buffer/config.ru | 9 - .../input_read_buffer_not_empty/config.ru | 9 - test/ruby/input_read_empty/config.ru | 6 - test/ruby/input_read_parts/config.ru | 10 - test/ruby/mirror/config.ru | 8 - test/ruby/multipart/config.ru | 7 - test/ruby/query_string/config.ru | 8 - test/ruby/server_port/config.ru | 8 - test/ruby/session/config.ru | 6 - test/ruby/status_int/config.ru | 5 - test/ruby/syntax_error/config.ru | 5 - test/ruby/threads/config.ru | 13 - test/ruby/variables/config.ru | 26 - test/test_access_log.py | 387 - test/test_asgi_application.py | 485 -- test/test_asgi_application_unix_abstract.py | 22 - test/test_asgi_lifespan.py | 122 - test/test_asgi_targets.py | 143 - test/test_asgi_websockets.py | 1505 ---- test/test_client_ip.py | 187 - test/test_configuration.py | 466 -- test/test_forwarded_header.py | 271 - test/test_go_application.py | 168 - test/test_go_isolation.py | 368 - test/test_go_isolation_rootfs.py | 19 - test/test_http_header.py | 501 -- test/test_java_application.py | 1034 --- test/test_java_isolation_rootfs.py | 69 - test/test_java_websockets.py | 1415 ---- test/test_njs.py | 154 - test/test_njs_modules.py | 104 - test/test_node_application.py | 351 - test/test_node_es_modules.py | 49 - test/test_node_websockets.py | 1435 ---- test/test_perl_application.py | 319 - test/test_php_application.py | 890 --- test/test_php_basic.py | 130 - test/test_php_isolation.py | 85 - test/test_php_targets.py | 100 - test/test_procman.py | 303 - test/test_proxy.py | 508 -- test/test_proxy_chunked.py | 229 - test/test_python_application.py | 934 --- test/test_python_basic.py | 134 - test/test_python_environment.py | 162 - test/test_python_isolation.py | 214 - test/test_python_isolation_chroot.py | 29 - test/test_python_targets.py | 105 - test/test_reconfigure.py | 55 - test/test_reconfigure_tls.py | 122 - test/test_respawn.py | 109 - test/test_response_headers.py | 174 - test/test_return.py | 221 - test/test_rewrite.py | 222 - test/test_routing.py | 2011 ----- test/test_routing_tls.py | 29 - test/test_ruby_application.py | 471 -- test/test_ruby_hooks.py | 102 - test/test_ruby_isolation.py | 43 - test/test_settings.py | 588 -- test/test_static.py | 350 - test/test_static_chroot.py | 165 - test/test_static_fallback.py | 158 - test/test_static_mount.py | 139 - test/test_static_share.py | 74 - test/test_static_symlink.py | 98 - test/test_static_types.py | 174 - test/test_static_variables.py | 86 - test/test_status.py | 242 - test/test_status_tls.py | 31 - test/test_tls.py | 703 -- test/test_tls_conf_command.py | 119 - test/test_tls_session.py | 140 - test/test_tls_sni.py | 301 - test/test_tls_tickets.py | 202 - test/test_unix_abstract.py | 105 - test/test_upstreams_rr.py | 493 -- test/test_usr1.py | 85 - test/test_variables.py | 540 -- test/unit/__init__.py | 0 test/unit/applications/__init__.py | 0 test/unit/applications/lang/__init__.py | 0 test/unit/applications/lang/go.py | 105 - test/unit/applications/lang/java.py | 112 - test/unit/applications/lang/node.py | 60 - test/unit/applications/lang/perl.py | 25 - test/unit/applications/lang/php.py | 48 - test/unit/applications/lang/python.py | 66 - test/unit/applications/lang/ruby.py | 44 - test/unit/applications/proto.py | 32 - test/unit/applications/tls.py | 111 - test/unit/applications/websockets.py | 237 - test/unit/check/check_prerequisites.py | 64 - test/unit/check/chroot.py | 30 - test/unit/check/discover_available.py | 49 - test/unit/check/go.py | 5 - test/unit/check/isolation.py | 160 - test/unit/check/njs.py | 5 - test/unit/check/node.py | 17 - test/unit/check/regex.py | 5 - test/unit/check/tls.py | 11 - test/unit/check/unix_abstract.py | 25 - test/unit/control.py | 59 - test/unit/http.py | 359 - test/unit/log.py | 113 - test/unit/option.py | 26 - test/unit/status.py | 45 - test/unit/utils.py | 123 - tools/README.md | 106 - tools/setup-unit | 1673 ---- tools/unitc | 330 - version | 5 - pkg/docker/welcome.html => welcome.html | 0 pkg/docker/welcome.json => welcome.json | 0 pkg/docker/welcome.md => welcome.md | 0 1078 files changed, 16 insertions(+), 208337 deletions(-) delete mode 100644 .gitattributes delete mode 100644 .github/workflows/ci.yml delete mode 100644 .hgignore delete mode 100644 .hgtags delete mode 100644 .mailmap delete mode 100644 .rustfmt.toml delete mode 100644 CHANGES delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 CONTRIBUTING.md rename pkg/docker/Dockerfile.python3.10 => Dockerfile.python3.10 (100%) rename pkg/docker/Dockerfile.python3.11 => Dockerfile.python3.11 (100%) rename pkg/docker/Dockerfile.python3.12 => Dockerfile.python3.12 (100%) delete mode 100644 LICENSE delete mode 100644 NOTICE delete mode 100644 README.md delete mode 100644 SECURITY.txt delete mode 100644 auto/atomic delete mode 100644 auto/capability delete mode 100644 auto/cc/deps delete mode 100644 auto/cc/test delete mode 100644 auto/cgroup delete mode 100644 auto/clang delete mode 100644 auto/echo/Makefile delete mode 100644 auto/echo/build delete mode 100644 auto/echo/echo.c delete mode 100644 auto/endian delete mode 100644 auto/events delete mode 100644 auto/feature delete mode 100644 auto/files delete mode 100644 auto/have delete mode 100644 auto/help delete mode 100644 auto/isolation delete mode 100644 auto/make delete mode 100644 auto/malloc delete mode 100644 auto/mmap delete mode 100644 auto/modules/conf delete mode 100644 auto/modules/go delete mode 100644 auto/modules/java delete mode 100644 auto/modules/java_chk_sha512 delete mode 100644 auto/modules/java_get_jar delete mode 100644 auto/modules/java_jar.sha512 delete mode 100644 auto/modules/nodejs delete mode 100644 auto/modules/perl delete mode 100644 auto/modules/php delete mode 100644 auto/modules/python delete mode 100644 auto/modules/ruby delete mode 100644 auto/modules/wasm delete mode 100644 auto/modules/wasm-wasi-component delete mode 100644 auto/njs delete mode 100644 auto/options delete mode 100644 auto/os/conf delete mode 100644 auto/os/test delete mode 100644 auto/pcre delete mode 100644 auto/save delete mode 100644 auto/sendfile delete mode 100644 auto/shmem delete mode 100644 auto/sockets delete mode 100644 auto/sources delete mode 100644 auto/ssltls delete mode 100644 auto/summary delete mode 100644 auto/test_build delete mode 100644 auto/threads delete mode 100644 auto/time delete mode 100644 auto/types delete mode 100644 auto/unix delete mode 100755 configure rename pkg/docker/docker-entrypoint.sh => docker-entrypoint.sh (100%) delete mode 100644 docs/Makefile delete mode 100644 docs/change_log_conf.dtd delete mode 100644 docs/change_log_conf.xml delete mode 100644 docs/changes.dtd delete mode 100644 docs/changes.xml delete mode 100644 docs/changes.xsls delete mode 100644 docs/changes.xslt delete mode 100644 docs/man/man8/unitd.8.in delete mode 100644 docs/unit-openapi.yaml delete mode 100644 docs/unitlogo.svg delete mode 100644 go/go.mod delete mode 100644 go/ldflags-darwin.go delete mode 100644 go/ldflags-lrt.go delete mode 100644 go/ldflags.go delete mode 100644 go/nxt_cgo_lib.c delete mode 100644 go/nxt_cgo_lib.h delete mode 100644 go/observable.go delete mode 100644 go/port.go delete mode 100644 go/request.go delete mode 100644 go/response.go delete mode 100644 go/unit.go delete mode 100644 pkg/Makefile delete mode 100644 pkg/contrib/Makefile delete mode 100644 pkg/contrib/src/libunit-wasm/Makefile delete mode 100644 pkg/contrib/src/libunit-wasm/version delete mode 100644 pkg/contrib/src/njs/Makefile delete mode 100644 pkg/contrib/src/njs/SHA512SUMS delete mode 100644 pkg/contrib/src/njs/version delete mode 100644 pkg/contrib/src/wasi-sysroot/Makefile delete mode 100644 pkg/contrib/src/wasi-sysroot/SHA512SUMS delete mode 100644 pkg/contrib/src/wasi-sysroot/version delete mode 100644 pkg/contrib/src/wasmtime/Makefile delete mode 100644 pkg/contrib/src/wasmtime/SHA512SUMS delete mode 100644 pkg/contrib/src/wasmtime/version delete mode 100644 pkg/contrib/tarballs/.hgignore delete mode 100644 pkg/deb/Makefile delete mode 100644 pkg/deb/Makefile.go delete mode 100644 pkg/deb/Makefile.jsc-common delete mode 100644 pkg/deb/Makefile.jsc10 delete mode 100644 pkg/deb/Makefile.jsc11 delete mode 100644 pkg/deb/Makefile.jsc16 delete mode 100644 pkg/deb/Makefile.jsc17 delete mode 100644 pkg/deb/Makefile.jsc18 delete mode 100644 pkg/deb/Makefile.jsc19 delete mode 100644 pkg/deb/Makefile.jsc20 delete mode 100644 pkg/deb/Makefile.jsc21 delete mode 100644 pkg/deb/Makefile.jsc8 delete mode 100644 pkg/deb/Makefile.perl delete mode 100644 pkg/deb/Makefile.php delete mode 100644 pkg/deb/Makefile.python27 delete mode 100644 pkg/deb/Makefile.python310 delete mode 100644 pkg/deb/Makefile.python311 delete mode 100644 pkg/deb/Makefile.python312 delete mode 100644 pkg/deb/Makefile.python36 delete mode 100644 pkg/deb/Makefile.python37 delete mode 100644 pkg/deb/Makefile.python38 delete mode 100644 pkg/deb/Makefile.python39 delete mode 100644 pkg/deb/Makefile.ruby delete mode 100644 pkg/deb/Makefile.wasm delete mode 100644 pkg/deb/debian.module/control-noarch.in delete mode 100644 pkg/deb/debian.module/control.in delete mode 100644 pkg/deb/debian.module/copyright.unit-jsc-common delete mode 100644 pkg/deb/debian.module/copyright.unit-jsc11 delete mode 100644 pkg/deb/debian.module/copyright.unit-jsc8 delete mode 100644 pkg/deb/debian.module/preinst.in delete mode 100644 pkg/deb/debian.module/rules-noarch.in delete mode 100755 pkg/deb/debian.module/rules.in delete mode 100644 pkg/deb/debian.module/unit.example-go-app delete mode 100644 pkg/deb/debian.module/unit.example-go-config delete mode 100644 pkg/deb/debian.module/unit.example-jsc-app delete mode 100644 pkg/deb/debian.module/unit.example-jsc11-config delete mode 100644 pkg/deb/debian.module/unit.example-jsc16-config delete mode 100644 pkg/deb/debian.module/unit.example-jsc17-config delete mode 100644 pkg/deb/debian.module/unit.example-jsc18-config delete mode 100644 pkg/deb/debian.module/unit.example-jsc19-config delete mode 100644 pkg/deb/debian.module/unit.example-jsc20-config delete mode 100644 pkg/deb/debian.module/unit.example-jsc21-config delete mode 100644 pkg/deb/debian.module/unit.example-jsc8-config delete mode 100644 pkg/deb/debian.module/unit.example-perl-app delete mode 100644 pkg/deb/debian.module/unit.example-perl-config delete mode 100644 pkg/deb/debian.module/unit.example-php-app delete mode 100644 pkg/deb/debian.module/unit.example-php-config delete mode 100644 pkg/deb/debian.module/unit.example-python-app delete mode 100644 pkg/deb/debian.module/unit.example-python2.7-config delete mode 100644 pkg/deb/debian.module/unit.example-python3.10-config delete mode 100644 pkg/deb/debian.module/unit.example-python3.11-config delete mode 100644 pkg/deb/debian.module/unit.example-python3.12-config delete mode 100644 pkg/deb/debian.module/unit.example-python3.6-config delete mode 100644 pkg/deb/debian.module/unit.example-python3.7-config delete mode 100644 pkg/deb/debian.module/unit.example-python3.8-config delete mode 100644 pkg/deb/debian.module/unit.example-python3.9-config delete mode 100644 pkg/deb/debian.module/unit.example-ruby-app delete mode 100644 pkg/deb/debian.module/unit.example-ruby-config delete mode 100644 pkg/deb/debian/control.in delete mode 100644 pkg/deb/debian/copyright delete mode 100644 pkg/deb/debian/dirs delete mode 100644 pkg/deb/debian/rules.in delete mode 100644 pkg/deb/debian/unit-debug.service delete mode 100644 pkg/deb/debian/unit.default delete mode 100644 pkg/deb/debian/unit.example-go-app delete mode 100644 pkg/deb/debian/unit.example-php-app delete mode 100644 pkg/deb/debian/unit.example-python-app delete mode 100644 pkg/deb/debian/unit.example.config delete mode 100644 pkg/deb/debian/unit.init delete mode 100644 pkg/deb/debian/unit.logrotate delete mode 100755 pkg/deb/debian/unit.postinst delete mode 100644 pkg/deb/debian/unit.preinst delete mode 100644 pkg/deb/debian/unit.service delete mode 100644 pkg/docker/Dockerfile.go1.21 delete mode 100644 pkg/docker/Dockerfile.go1.22 delete mode 100644 pkg/docker/Dockerfile.jsc11 delete mode 100644 pkg/docker/Dockerfile.minimal delete mode 100644 pkg/docker/Dockerfile.node20 delete mode 100644 pkg/docker/Dockerfile.node21 delete mode 100644 pkg/docker/Dockerfile.perl5.36 delete mode 100644 pkg/docker/Dockerfile.perl5.38 delete mode 100644 pkg/docker/Dockerfile.php8.2 delete mode 100644 pkg/docker/Dockerfile.php8.3 delete mode 100644 pkg/docker/Dockerfile.ruby3.2 delete mode 100644 pkg/docker/Dockerfile.ruby3.3 delete mode 100644 pkg/docker/Dockerfile.wasm delete mode 100644 pkg/docker/Makefile delete mode 100644 pkg/docker/template.Dockerfile delete mode 100644 pkg/npm/Makefile delete mode 100644 pkg/rpm/Makefile delete mode 100644 pkg/rpm/Makefile.go delete mode 100644 pkg/rpm/Makefile.jsc-common delete mode 100644 pkg/rpm/Makefile.jsc11 delete mode 100644 pkg/rpm/Makefile.jsc17 delete mode 100644 pkg/rpm/Makefile.jsc8 delete mode 100644 pkg/rpm/Makefile.perl delete mode 100644 pkg/rpm/Makefile.php delete mode 100644 pkg/rpm/Makefile.python27 delete mode 100644 pkg/rpm/Makefile.python310 delete mode 100644 pkg/rpm/Makefile.python311 delete mode 100644 pkg/rpm/Makefile.python312 delete mode 100644 pkg/rpm/Makefile.python36 delete mode 100644 pkg/rpm/Makefile.python37 delete mode 100644 pkg/rpm/Makefile.python38 delete mode 100644 pkg/rpm/Makefile.python39 delete mode 100644 pkg/rpm/Makefile.ruby delete mode 100644 pkg/rpm/Makefile.wasm delete mode 100644 pkg/rpm/rpmbuild/SOURCES/COPYRIGHT.unit-jsc-common delete mode 100644 pkg/rpm/rpmbuild/SOURCES/COPYRIGHT.unit-jsc11 delete mode 100644 pkg/rpm/rpmbuild/SOURCES/COPYRIGHT.unit-jsc8 delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit-debug.service delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-go-app delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-go-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-jsc-app delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-jsc11-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-jsc17-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-jsc8-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-perl-app delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-perl-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-php-app delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-php-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python-app delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python27-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python310-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python311-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python312-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python34-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python36-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python37-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python38-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-python39-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-ruby-app delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example-ruby-config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.example.config delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.logrotate delete mode 100644 pkg/rpm/rpmbuild/SOURCES/unit.service delete mode 100644 pkg/rpm/unit.module.spec.in delete mode 100644 pkg/rpm/unit.spec.in delete mode 100644 pkg/shasum.mak delete mode 100644 src/java/README.JSR-340 delete mode 100644 src/java/javax/websocket/ClientEndpoint.java delete mode 100644 src/java/javax/websocket/ClientEndpointConfig.java delete mode 100644 src/java/javax/websocket/CloseReason.java delete mode 100644 src/java/javax/websocket/ContainerProvider.java delete mode 100644 src/java/javax/websocket/DecodeException.java delete mode 100644 src/java/javax/websocket/Decoder.java delete mode 100644 src/java/javax/websocket/DefaultClientEndpointConfig.java delete mode 100644 src/java/javax/websocket/DeploymentException.java delete mode 100644 src/java/javax/websocket/EncodeException.java delete mode 100644 src/java/javax/websocket/Encoder.java delete mode 100644 src/java/javax/websocket/Endpoint.java delete mode 100644 src/java/javax/websocket/EndpointConfig.java delete mode 100644 src/java/javax/websocket/Extension.java delete mode 100644 src/java/javax/websocket/HandshakeResponse.java delete mode 100644 src/java/javax/websocket/MessageHandler.java delete mode 100644 src/java/javax/websocket/OnClose.java delete mode 100644 src/java/javax/websocket/OnError.java delete mode 100644 src/java/javax/websocket/OnMessage.java delete mode 100644 src/java/javax/websocket/OnOpen.java delete mode 100644 src/java/javax/websocket/PongMessage.java delete mode 100644 src/java/javax/websocket/RemoteEndpoint.java delete mode 100644 src/java/javax/websocket/SendHandler.java delete mode 100644 src/java/javax/websocket/SendResult.java delete mode 100644 src/java/javax/websocket/Session.java delete mode 100644 src/java/javax/websocket/SessionException.java delete mode 100644 src/java/javax/websocket/WebSocketContainer.java delete mode 100644 src/java/javax/websocket/server/DefaultServerEndpointConfig.java delete mode 100644 src/java/javax/websocket/server/HandshakeRequest.java delete mode 100644 src/java/javax/websocket/server/PathParam.java delete mode 100644 src/java/javax/websocket/server/ServerApplicationConfig.java delete mode 100644 src/java/javax/websocket/server/ServerContainer.java delete mode 100644 src/java/javax/websocket/server/ServerEndpoint.java delete mode 100644 src/java/javax/websocket/server/ServerEndpointConfig.java delete mode 100644 src/java/nginx/unit/Context.java delete mode 100644 src/java/nginx/unit/DynamicDispatcherRequest.java delete mode 100644 src/java/nginx/unit/DynamicPathRequest.java delete mode 100644 src/java/nginx/unit/ForwardRequestWrapper.java delete mode 100644 src/java/nginx/unit/HeaderNamesEnumeration.java delete mode 100644 src/java/nginx/unit/HeadersEnumeration.java delete mode 100644 src/java/nginx/unit/IncludeRequestWrapper.java delete mode 100644 src/java/nginx/unit/IncludeResponseWrapper.java delete mode 100644 src/java/nginx/unit/InitParams.java delete mode 100644 src/java/nginx/unit/InputStream.java delete mode 100644 src/java/nginx/unit/JspPropertyGroup.java delete mode 100644 src/java/nginx/unit/OutputStream.java delete mode 100644 src/java/nginx/unit/Request.java delete mode 100644 src/java/nginx/unit/RequestAttrProxy.java delete mode 100644 src/java/nginx/unit/Response.java delete mode 100644 src/java/nginx/unit/Session.java delete mode 100644 src/java/nginx/unit/SessionAttrProxy.java delete mode 100644 src/java/nginx/unit/Taglib.java delete mode 100644 src/java/nginx/unit/UnitSessionCookieConfig.java delete mode 100644 src/java/nginx/unit/websocket/AsyncChannelGroupUtil.java delete mode 100644 src/java/nginx/unit/websocket/AsyncChannelWrapper.java delete mode 100644 src/java/nginx/unit/websocket/AsyncChannelWrapperNonSecure.java delete mode 100644 src/java/nginx/unit/websocket/AsyncChannelWrapperSecure.java delete mode 100644 src/java/nginx/unit/websocket/AuthenticationException.java delete mode 100644 src/java/nginx/unit/websocket/Authenticator.java delete mode 100644 src/java/nginx/unit/websocket/AuthenticatorFactory.java delete mode 100644 src/java/nginx/unit/websocket/BackgroundProcess.java delete mode 100644 src/java/nginx/unit/websocket/BackgroundProcessManager.java delete mode 100644 src/java/nginx/unit/websocket/BasicAuthenticator.java delete mode 100644 src/java/nginx/unit/websocket/Constants.java delete mode 100644 src/java/nginx/unit/websocket/DecoderEntry.java delete mode 100644 src/java/nginx/unit/websocket/DigestAuthenticator.java delete mode 100644 src/java/nginx/unit/websocket/FutureToSendHandler.java delete mode 100644 src/java/nginx/unit/websocket/LocalStrings.properties delete mode 100644 src/java/nginx/unit/websocket/MessageHandlerResult.java delete mode 100644 src/java/nginx/unit/websocket/MessageHandlerResultType.java delete mode 100644 src/java/nginx/unit/websocket/MessagePart.java delete mode 100644 src/java/nginx/unit/websocket/PerMessageDeflate.java delete mode 100644 src/java/nginx/unit/websocket/ReadBufferOverflowException.java delete mode 100644 src/java/nginx/unit/websocket/Transformation.java delete mode 100644 src/java/nginx/unit/websocket/TransformationFactory.java delete mode 100644 src/java/nginx/unit/websocket/TransformationResult.java delete mode 100644 src/java/nginx/unit/websocket/Util.java delete mode 100644 src/java/nginx/unit/websocket/WrappedMessageHandler.java delete mode 100644 src/java/nginx/unit/websocket/WsContainerProvider.java delete mode 100644 src/java/nginx/unit/websocket/WsExtension.java delete mode 100644 src/java/nginx/unit/websocket/WsExtensionParameter.java delete mode 100644 src/java/nginx/unit/websocket/WsFrameBase.java delete mode 100644 src/java/nginx/unit/websocket/WsFrameClient.java delete mode 100644 src/java/nginx/unit/websocket/WsHandshakeResponse.java delete mode 100644 src/java/nginx/unit/websocket/WsIOException.java delete mode 100644 src/java/nginx/unit/websocket/WsPongMessage.java delete mode 100644 src/java/nginx/unit/websocket/WsRemoteEndpointAsync.java delete mode 100644 src/java/nginx/unit/websocket/WsRemoteEndpointBase.java delete mode 100644 src/java/nginx/unit/websocket/WsRemoteEndpointBasic.java delete mode 100644 src/java/nginx/unit/websocket/WsRemoteEndpointImplBase.java delete mode 100644 src/java/nginx/unit/websocket/WsRemoteEndpointImplClient.java delete mode 100644 src/java/nginx/unit/websocket/WsSession.java delete mode 100644 src/java/nginx/unit/websocket/WsWebSocketContainer.java delete mode 100644 src/java/nginx/unit/websocket/pojo/Constants.java delete mode 100644 src/java/nginx/unit/websocket/pojo/LocalStrings.properties delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoEndpointClient.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoEndpointServer.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoMessageHandlerBase.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialBase.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialBinary.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialText.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeBase.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeBinary.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholePong.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeText.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoMethodMapping.java delete mode 100644 src/java/nginx/unit/websocket/pojo/PojoPathParam.java delete mode 100644 src/java/nginx/unit/websocket/pojo/package-info.java delete mode 100644 src/java/nginx/unit/websocket/server/Constants.java delete mode 100644 src/java/nginx/unit/websocket/server/DefaultServerEndpointConfigurator.java delete mode 100644 src/java/nginx/unit/websocket/server/LocalStrings.properties delete mode 100644 src/java/nginx/unit/websocket/server/UpgradeUtil.java delete mode 100644 src/java/nginx/unit/websocket/server/UriTemplate.java delete mode 100644 src/java/nginx/unit/websocket/server/WsContextListener.java delete mode 100644 src/java/nginx/unit/websocket/server/WsFilter.java delete mode 100644 src/java/nginx/unit/websocket/server/WsHandshakeRequest.java delete mode 100644 src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java delete mode 100644 src/java/nginx/unit/websocket/server/WsMappingResult.java delete mode 100644 src/java/nginx/unit/websocket/server/WsPerSessionServerEndpointConfig.java delete mode 100644 src/java/nginx/unit/websocket/server/WsRemoteEndpointImplServer.java delete mode 100644 src/java/nginx/unit/websocket/server/WsSci.java delete mode 100644 src/java/nginx/unit/websocket/server/WsServerContainer.java delete mode 100644 src/java/nginx/unit/websocket/server/WsSessionListener.java delete mode 100644 src/java/nginx/unit/websocket/server/WsWriteTimeout.java delete mode 100644 src/java/nginx/unit/websocket/server/package-info.java delete mode 100644 src/java/nxt_jni.c delete mode 100644 src/java/nxt_jni.h delete mode 100644 src/java/nxt_jni_Context.c delete mode 100644 src/java/nxt_jni_Context.h delete mode 100644 src/java/nxt_jni_HeaderNamesEnumeration.c delete mode 100644 src/java/nxt_jni_HeaderNamesEnumeration.h delete mode 100644 src/java/nxt_jni_HeadersEnumeration.c delete mode 100644 src/java/nxt_jni_HeadersEnumeration.h delete mode 100644 src/java/nxt_jni_InputStream.c delete mode 100644 src/java/nxt_jni_InputStream.h delete mode 100644 src/java/nxt_jni_OutputStream.c delete mode 100644 src/java/nxt_jni_OutputStream.h delete mode 100644 src/java/nxt_jni_Request.c delete mode 100644 src/java/nxt_jni_Request.h delete mode 100644 src/java/nxt_jni_Response.c delete mode 100644 src/java/nxt_jni_Response.h delete mode 100644 src/java/nxt_jni_Thread.c delete mode 100644 src/java/nxt_jni_Thread.h delete mode 100644 src/java/nxt_jni_URLClassLoader.c delete mode 100644 src/java/nxt_jni_URLClassLoader.h delete mode 100644 src/nodejs/unit-http/README.md delete mode 100644 src/nodejs/unit-http/addon.cpp delete mode 100644 src/nodejs/unit-http/binding.gyp delete mode 100644 src/nodejs/unit-http/binding_pub.gyp delete mode 100644 src/nodejs/unit-http/http.js delete mode 100644 src/nodejs/unit-http/http_server.js delete mode 100644 src/nodejs/unit-http/loader.js delete mode 100644 src/nodejs/unit-http/loader.mjs delete mode 100644 src/nodejs/unit-http/nxt_napi.h delete mode 100644 src/nodejs/unit-http/package.json delete mode 100644 src/nodejs/unit-http/socket.js delete mode 100644 src/nodejs/unit-http/unit.cpp delete mode 100644 src/nodejs/unit-http/unit.h delete mode 100644 src/nodejs/unit-http/utils.js delete mode 100644 src/nodejs/unit-http/websocket.js delete mode 100644 src/nodejs/unit-http/websocket_connection.js delete mode 100644 src/nodejs/unit-http/websocket_frame.js delete mode 100644 src/nodejs/unit-http/websocket_request.js delete mode 100644 src/nodejs/unit-http/websocket_router.js delete mode 100644 src/nodejs/unit-http/websocket_router_request.js delete mode 100644 src/nodejs/unit-http/websocket_server.js delete mode 100644 src/nxt_aix_send_file.c delete mode 100644 src/nxt_app_log.c delete mode 100644 src/nxt_app_nncq.h delete mode 100644 src/nxt_app_queue.h delete mode 100644 src/nxt_application.c delete mode 100644 src/nxt_application.h delete mode 100644 src/nxt_array.c delete mode 100644 src/nxt_array.h delete mode 100644 src/nxt_atomic.h delete mode 100644 src/nxt_buf.c delete mode 100644 src/nxt_buf.h delete mode 100644 src/nxt_buf_pool.c delete mode 100644 src/nxt_buf_pool.h delete mode 100644 src/nxt_capability.c delete mode 100644 src/nxt_capability.h delete mode 100644 src/nxt_cert.c delete mode 100644 src/nxt_cert.h delete mode 100644 src/nxt_cgroup.c delete mode 100644 src/nxt_cgroup.h delete mode 100644 src/nxt_clang.h delete mode 100644 src/nxt_clone.c delete mode 100644 src/nxt_clone.h delete mode 100644 src/nxt_conf.c delete mode 100644 src/nxt_conf.h delete mode 100644 src/nxt_conf_validation.c delete mode 100644 src/nxt_conn.c delete mode 100644 src/nxt_conn.h delete mode 100644 src/nxt_conn_accept.c delete mode 100644 src/nxt_conn_close.c delete mode 100644 src/nxt_conn_connect.c delete mode 100644 src/nxt_conn_proxy.c delete mode 100644 src/nxt_conn_read.c delete mode 100644 src/nxt_conn_write.c delete mode 100644 src/nxt_controller.c delete mode 100644 src/nxt_credential.c delete mode 100644 src/nxt_credential.h delete mode 100644 src/nxt_cyassl.c delete mode 100644 src/nxt_devpoll_engine.c delete mode 100644 src/nxt_djb_hash.c delete mode 100644 src/nxt_djb_hash.h delete mode 100644 src/nxt_dyld.c delete mode 100644 src/nxt_dyld.h delete mode 100644 src/nxt_epoll_engine.c delete mode 100644 src/nxt_errno.c delete mode 100644 src/nxt_errno.h delete mode 100644 src/nxt_event_conn_job_sendfile.c delete mode 100644 src/nxt_event_engine.c delete mode 100644 src/nxt_event_engine.h delete mode 100644 src/nxt_eventport_engine.c delete mode 100644 src/nxt_external.c delete mode 100644 src/nxt_fd_event.c delete mode 100644 src/nxt_fd_event.h delete mode 100644 src/nxt_fiber.c delete mode 100644 src/nxt_fiber.h delete mode 100644 src/nxt_file.c delete mode 100644 src/nxt_file.h delete mode 100644 src/nxt_file_event.h delete mode 100644 src/nxt_file_name.c delete mode 100644 src/nxt_file_name.h delete mode 100644 src/nxt_freebsd_sendfile.c delete mode 100644 src/nxt_fs.c delete mode 100644 src/nxt_fs.h delete mode 100644 src/nxt_fs_mount.c delete mode 100644 src/nxt_fs_mount.h delete mode 100644 src/nxt_gmtime.c delete mode 100644 src/nxt_gnutls.c delete mode 100644 src/nxt_h1proto.c delete mode 100644 src/nxt_h1proto.h delete mode 100644 src/nxt_h1proto_websocket.c delete mode 100644 src/nxt_hash.h delete mode 100644 src/nxt_hpux_sendfile.c delete mode 100644 src/nxt_http.h delete mode 100644 src/nxt_http_chunk_parse.c delete mode 100644 src/nxt_http_error.c delete mode 100644 src/nxt_http_js.c delete mode 100644 src/nxt_http_parse.c delete mode 100644 src/nxt_http_parse.h delete mode 100644 src/nxt_http_proxy.c delete mode 100644 src/nxt_http_request.c delete mode 100644 src/nxt_http_response.c delete mode 100644 src/nxt_http_return.c delete mode 100644 src/nxt_http_rewrite.c delete mode 100644 src/nxt_http_route.c delete mode 100644 src/nxt_http_route_addr.c delete mode 100644 src/nxt_http_route_addr.h delete mode 100644 src/nxt_http_set_headers.c delete mode 100644 src/nxt_http_static.c delete mode 100644 src/nxt_http_variables.c delete mode 100644 src/nxt_http_websocket.c delete mode 100644 src/nxt_isolation.c delete mode 100644 src/nxt_isolation.h delete mode 100644 src/nxt_java.c delete mode 100644 src/nxt_job.c delete mode 100644 src/nxt_job.h delete mode 100644 src/nxt_job_cache_file.c delete mode 100644 src/nxt_js.c delete mode 100644 src/nxt_js.h delete mode 100644 src/nxt_kqueue_engine.c delete mode 100644 src/nxt_lib.c delete mode 100644 src/nxt_linux_sendfile.c delete mode 100644 src/nxt_list.c delete mode 100644 src/nxt_list.h delete mode 100644 src/nxt_listen_socket.c delete mode 100644 src/nxt_listen_socket.h delete mode 100644 src/nxt_log.c delete mode 100644 src/nxt_log.h delete mode 100644 src/nxt_log_moderation.c delete mode 100644 src/nxt_log_moderation.h delete mode 100644 src/nxt_lvlhsh.c delete mode 100644 src/nxt_lvlhsh.h delete mode 100644 src/nxt_macosx_sendfile.c delete mode 100644 src/nxt_main.c delete mode 100644 src/nxt_main.h delete mode 100644 src/nxt_main_process.c delete mode 100644 src/nxt_main_process.h delete mode 100644 src/nxt_malloc.c delete mode 100644 src/nxt_malloc.h delete mode 100644 src/nxt_mem_map.c delete mode 100644 src/nxt_mem_map.h delete mode 100644 src/nxt_mem_zone.c delete mode 100644 src/nxt_mem_zone.h delete mode 100644 src/nxt_mp.c delete mode 100644 src/nxt_mp.h delete mode 100644 src/nxt_murmur_hash.c delete mode 100644 src/nxt_murmur_hash.h delete mode 100644 src/nxt_nncq.h delete mode 100644 src/nxt_nvbcq.h delete mode 100644 src/nxt_openssl.c delete mode 100644 src/nxt_parse.c delete mode 100644 src/nxt_parse.h delete mode 100644 src/nxt_pcre.c delete mode 100644 src/nxt_pcre2.c delete mode 100644 src/nxt_php_sapi.c delete mode 100644 src/nxt_polarssl.c delete mode 100644 src/nxt_poll_engine.c delete mode 100644 src/nxt_pollset_engine.c delete mode 100644 src/nxt_port.c delete mode 100644 src/nxt_port.h delete mode 100644 src/nxt_port_hash.c delete mode 100644 src/nxt_port_hash.h delete mode 100644 src/nxt_port_memory.c delete mode 100644 src/nxt_port_memory.h delete mode 100644 src/nxt_port_memory_int.h delete mode 100644 src/nxt_port_queue.h delete mode 100644 src/nxt_port_rpc.c delete mode 100644 src/nxt_port_rpc.h delete mode 100644 src/nxt_port_socket.c delete mode 100644 src/nxt_process.c delete mode 100644 src/nxt_process.h delete mode 100644 src/nxt_process_title.c delete mode 100644 src/nxt_process_type.h delete mode 100644 src/nxt_queue.c delete mode 100644 src/nxt_queue.h delete mode 100644 src/nxt_random.c delete mode 100644 src/nxt_random.h delete mode 100644 src/nxt_rbtree.c delete mode 100644 src/nxt_rbtree.h delete mode 100644 src/nxt_recvbuf.c delete mode 100644 src/nxt_recvbuf.h delete mode 100644 src/nxt_regex.h delete mode 100644 src/nxt_router.c delete mode 100644 src/nxt_router.h delete mode 100644 src/nxt_router_access_log.c delete mode 100644 src/nxt_router_request.h delete mode 100644 src/nxt_runtime.c delete mode 100644 src/nxt_runtime.h delete mode 100644 src/nxt_script.c delete mode 100644 src/nxt_script.h delete mode 100644 src/nxt_select_engine.c delete mode 100644 src/nxt_semaphore.c delete mode 100644 src/nxt_semaphore.h delete mode 100644 src/nxt_sendbuf.c delete mode 100644 src/nxt_sendbuf.h delete mode 100644 src/nxt_service.c delete mode 100644 src/nxt_service.h delete mode 100644 src/nxt_sha1.c delete mode 100644 src/nxt_sha1.h delete mode 100644 src/nxt_signal.c delete mode 100644 src/nxt_signal.h delete mode 100644 src/nxt_signal_handlers.c delete mode 100644 src/nxt_sockaddr.c delete mode 100644 src/nxt_sockaddr.h delete mode 100644 src/nxt_socket.c delete mode 100644 src/nxt_socket.h delete mode 100644 src/nxt_socket_msg.c delete mode 100644 src/nxt_socket_msg.h delete mode 100644 src/nxt_socketpair.c delete mode 100644 src/nxt_solaris_sendfilev.c delete mode 100644 src/nxt_sort.h delete mode 100644 src/nxt_source.h delete mode 100644 src/nxt_spinlock.c delete mode 100644 src/nxt_spinlock.h delete mode 100644 src/nxt_sprintf.c delete mode 100644 src/nxt_sprintf.h delete mode 100644 src/nxt_status.c delete mode 100644 src/nxt_status.h delete mode 100644 src/nxt_string.c delete mode 100644 src/nxt_string.h delete mode 100644 src/nxt_test_build.c delete mode 100644 src/nxt_test_build.h delete mode 100644 src/nxt_thread.c delete mode 100644 src/nxt_thread.h delete mode 100644 src/nxt_thread_cond.c delete mode 100644 src/nxt_thread_id.h delete mode 100644 src/nxt_thread_log.h delete mode 100644 src/nxt_thread_mutex.c delete mode 100644 src/nxt_thread_pool.c delete mode 100644 src/nxt_thread_pool.h delete mode 100644 src/nxt_thread_time.c delete mode 100644 src/nxt_thread_time.h delete mode 100644 src/nxt_time.c delete mode 100644 src/nxt_time.h delete mode 100644 src/nxt_time_parse.c delete mode 100644 src/nxt_timer.c delete mode 100644 src/nxt_timer.h delete mode 100644 src/nxt_tls.h delete mode 100644 src/nxt_tstr.c delete mode 100644 src/nxt_tstr.h delete mode 100644 src/nxt_types.h delete mode 100644 src/nxt_unicode_lowcase.h delete mode 100644 src/nxt_unicode_lowcase.pl delete mode 100644 src/nxt_unicode_macosx_lowcase.h delete mode 100644 src/nxt_unit.c delete mode 100644 src/nxt_unit.h delete mode 100644 src/nxt_unit_field.h delete mode 100644 src/nxt_unit_request.h delete mode 100644 src/nxt_unit_response.h delete mode 100644 src/nxt_unit_sptr.h delete mode 100644 src/nxt_unit_typedefs.h delete mode 100644 src/nxt_unit_websocket.h delete mode 100644 src/nxt_unix.h delete mode 100644 src/nxt_upstream.c delete mode 100644 src/nxt_upstream.h delete mode 100644 src/nxt_upstream_round_robin.c delete mode 100644 src/nxt_utf8.c delete mode 100644 src/nxt_utf8.h delete mode 100644 src/nxt_var.c delete mode 100644 src/nxt_var.h delete mode 100644 src/nxt_vector.c delete mode 100644 src/nxt_vector.h delete mode 100644 src/nxt_websocket.c delete mode 100644 src/nxt_websocket.h delete mode 100644 src/nxt_websocket_accept.c delete mode 100644 src/nxt_websocket_header.h delete mode 100644 src/nxt_work_queue.c delete mode 100644 src/nxt_work_queue.h delete mode 100644 src/perl/nxt_perl_psgi.c delete mode 100644 src/perl/nxt_perl_psgi_layer.c delete mode 100644 src/perl/nxt_perl_psgi_layer.h delete mode 100644 src/python/nxt_python.c delete mode 100644 src/python/nxt_python.h delete mode 100644 src/python/nxt_python_asgi.c delete mode 100644 src/python/nxt_python_asgi.h delete mode 100644 src/python/nxt_python_asgi_http.c delete mode 100644 src/python/nxt_python_asgi_lifespan.c delete mode 100644 src/python/nxt_python_asgi_str.c delete mode 100644 src/python/nxt_python_asgi_str.h delete mode 100644 src/python/nxt_python_asgi_websocket.c delete mode 100644 src/python/nxt_python_wsgi.c delete mode 100644 src/ruby/nxt_ruby.c delete mode 100644 src/ruby/nxt_ruby.h delete mode 100644 src/ruby/nxt_ruby_stream_io.c delete mode 100644 src/test/nxt_base64_test.c delete mode 100644 src/test/nxt_clone_test.c delete mode 100644 src/test/nxt_cq_test.c delete mode 100644 src/test/nxt_gmtime_test.c delete mode 100644 src/test/nxt_http_parse_test.c delete mode 100644 src/test/nxt_lvlhsh_test.c delete mode 100644 src/test/nxt_malloc_test.c delete mode 100644 src/test/nxt_mem_zone_test.c delete mode 100644 src/test/nxt_mp_test.c delete mode 100644 src/test/nxt_msec_diff_test.c delete mode 100644 src/test/nxt_rbtree1.c delete mode 100644 src/test/nxt_rbtree1.h delete mode 100644 src/test/nxt_rbtree1_test.c delete mode 100644 src/test/nxt_rbtree_test.c delete mode 100644 src/test/nxt_sprintf_test.c delete mode 100644 src/test/nxt_strverscmp_test.c delete mode 100644 src/test/nxt_term_parse_test.c delete mode 100644 src/test/nxt_tests.c delete mode 100644 src/test/nxt_tests.h delete mode 100644 src/test/nxt_unit_app_test.c delete mode 100644 src/test/nxt_unit_websocket_chat.c delete mode 100644 src/test/nxt_unit_websocket_echo.c delete mode 100644 src/test/nxt_utf8_file_name_test.c delete mode 100644 src/test/nxt_utf8_test.c delete mode 100644 src/unit.pc.in delete mode 100644 src/wasm-wasi-component/.gitignore delete mode 100644 src/wasm-wasi-component/Cargo.lock delete mode 100644 src/wasm-wasi-component/Cargo.toml delete mode 100644 src/wasm-wasi-component/build.rs delete mode 100644 src/wasm-wasi-component/src/lib.rs delete mode 100644 src/wasm-wasi-component/wrapper.h delete mode 100644 src/wasm/nxt_rt_wasmtime.c delete mode 100644 src/wasm/nxt_wasm.c delete mode 100644 src/wasm/nxt_wasm.h delete mode 100644 test/conftest.py delete mode 100644 test/go/404/404.html delete mode 100644 test/go/404/app.go delete mode 100644 test/go/command_line_arguments/app.go delete mode 100644 test/go/cookies/app.go delete mode 100644 test/go/empty/app.go delete mode 100644 test/go/get_variables/app.go delete mode 100644 test/go/mirror/app.go delete mode 100644 test/go/ns_inspect/app.go delete mode 100644 test/go/post_variables/app.go delete mode 100644 test/go/variables/app.go delete mode 100644 test/java/content_type/app.java delete mode 100644 test/java/cookies/app.java delete mode 100644 test/java/empty/app.java delete mode 100644 test/java/empty_war/empty.war delete mode 100644 test/java/filter/app.java delete mode 100644 test/java/forward/app.java delete mode 100644 test/java/forward/index.html delete mode 100644 test/java/forward/web.xml delete mode 100644 test/java/get_header/app.java delete mode 100644 test/java/get_header_names/app.java delete mode 100644 test/java/get_headers/app.java delete mode 100644 test/java/get_params/app.java delete mode 100644 test/java/header/app.java delete mode 100644 test/java/header_date/app.java delete mode 100644 test/java/header_int/app.java delete mode 100644 test/java/include/app.java delete mode 100644 test/java/include/index.html delete mode 100644 test/java/include/web.xml delete mode 100644 test/java/jsp/index.jsp delete mode 100644 test/java/mirror/app.java delete mode 100644 test/java/multipart/app.java delete mode 100644 test/java/path_translation/app.java delete mode 100644 test/java/path_translation/index.html delete mode 100644 test/java/post_params/app.java delete mode 100644 test/java/query_string/app.java delete mode 100644 test/java/request_listeners/app.java delete mode 100644 test/java/session/app.java delete mode 100644 test/java/session_inactive/app.java delete mode 100644 test/java/session_invalidate/app.java delete mode 100644 test/java/session_listeners/app.java delete mode 100644 test/java/session_listeners/web.xml delete mode 100644 test/java/threads/app.java delete mode 100644 test/java/url_pattern/app.java delete mode 100644 test/java/url_pattern/web.xml delete mode 100644 test/java/websockets_mirror/app.java delete mode 100644 test/java/welcome_files/app.java delete mode 100644 test/java/welcome_files/dir1/index.txt delete mode 100644 test/java/welcome_files/dir2/default.jsp delete mode 100644 test/java/welcome_files/dir2/index.html delete mode 100644 test/java/welcome_files/dir3/index.txt delete mode 100644 test/java/welcome_files/dir4/index.html delete mode 100644 test/java/welcome_files/index.htm delete mode 100644 test/java/welcome_files/web.xml delete mode 100644 test/njs/global_this/script.js delete mode 100644 test/njs/import_from/script.js delete mode 100644 test/njs/invalid/script.js delete mode 100644 test/njs/next/script.js delete mode 100644 test/node/404/404.html delete mode 100644 test/node/404/app.js delete mode 100644 test/node/basic/app.js delete mode 100644 test/node/double_end/app.js delete mode 100644 test/node/flush_headers/app.js delete mode 100644 test/node/get_header_names/app.js delete mode 100644 test/node/get_header_type/app.js delete mode 100644 test/node/get_variables/app.js delete mode 100644 test/node/has_header/app.js delete mode 100644 test/node/header_name_case/app.js delete mode 100644 test/node/header_name_valid/app.js delete mode 100644 test/node/header_value_object/app.js delete mode 100644 test/node/loader/es_modules_http/app.mjs delete mode 100644 test/node/loader/es_modules_http_indirect/app.js delete mode 100644 test/node/loader/es_modules_http_indirect/module.mjs delete mode 100644 test/node/loader/es_modules_websocket/app.mjs delete mode 100644 test/node/loader/es_modules_websocket_indirect/app.js delete mode 100644 test/node/loader/es_modules_websocket_indirect/module.mjs delete mode 100644 test/node/loader/transitive_dependency/app.js delete mode 100644 test/node/loader/transitive_dependency/transitive_http.js delete mode 100644 test/node/loader/unit_http/app.js delete mode 100644 test/node/mirror/app.js delete mode 100644 test/node/options/app.js delete mode 100644 test/node/post_variables/app.js delete mode 100644 test/node/promise_end/app.js delete mode 100644 test/node/promise_handler/app.js delete mode 100644 test/node/remove_header/app.js delete mode 100644 test/node/set_header_array/app.js delete mode 100644 test/node/status_message/app.js delete mode 100644 test/node/update_header/app.js delete mode 100644 test/node/variables/app.js delete mode 100644 test/node/websockets/mirror/app.js delete mode 100644 test/node/websockets/mirror_fragmentation/app.js delete mode 100644 test/node/write_array/app.js delete mode 100644 test/node/write_before_write_head/app.js delete mode 100644 test/node/write_buffer/app.js delete mode 100644 test/node/write_callback/app.js delete mode 100644 test/node/write_multiple/app.js delete mode 100644 test/node/write_return/app.js delete mode 100644 test/perl/body_array/psgi.pl delete mode 100644 test/perl/body_empty/psgi.pl delete mode 100644 test/perl/body_io_empty/psgi.pl delete mode 100644 test/perl/body_io_fake/IOFake.pm delete mode 100644 test/perl/body_io_fake/psgi.pl delete mode 100644 test/perl/body_io_file/file delete mode 100644 test/perl/body_io_file/psgi.pl delete mode 100644 test/perl/delayed_response/psgi.pl delete mode 100644 test/perl/errors_print/psgi.pl delete mode 100644 test/perl/header_equal_names/psgi.pl delete mode 100644 test/perl/header_pairs/psgi.pl delete mode 100644 test/perl/input_buffered_read/psgi.pl delete mode 100644 test/perl/input_close/psgi.pl delete mode 100644 test/perl/input_copy/psgi.pl delete mode 100644 test/perl/input_read_empty/psgi.pl delete mode 100644 test/perl/input_read_offset/psgi.pl delete mode 100644 test/perl/input_read_parts/psgi.pl delete mode 100644 test/perl/query_string/psgi.pl delete mode 100644 test/perl/server_port/psgi.pl delete mode 100644 test/perl/streaming_body/psgi.pl delete mode 100644 test/perl/streaming_body_multiple_responses/psgi.pl delete mode 100644 test/perl/syntax_error/psgi.pl delete mode 100644 test/perl/threads/psgi.pl delete mode 100644 test/perl/variables/psgi.pl delete mode 100644 test/php/404/404.html delete mode 100644 test/php/404/index.php delete mode 100644 test/php/auth/index.php delete mode 100644 test/php/conditional/index.php delete mode 100644 test/php/cookies/index.php delete mode 100644 test/php/cwd/index.php delete mode 100644 test/php/cwd/subdir/index.php delete mode 100644 test/php/date_time/index.php delete mode 100644 test/php/error_log/index.php delete mode 100644 test/php/fastcgi_finish_request/index.php delete mode 100644 test/php/fastcgi_finish_request/server.php delete mode 100644 test/php/get_variables/index.php delete mode 100644 test/php/header/index.php delete mode 100644 test/php/ini_precision/index.php delete mode 100644 test/php/ini_precision/ini/php.ini delete mode 100644 test/php/list-extensions/index.php delete mode 100644 test/php/list-extensions/php.ini delete mode 100644 test/php/mirror/index.php delete mode 100644 test/php/opcache/index.php delete mode 100644 test/php/opcache/preload/chdir.php delete mode 100644 test/php/opcache/preload/fastcgi_finish_request.php delete mode 100644 test/php/opcache/test.php delete mode 100644 test/php/open/index.php delete mode 100644 test/php/open/test.txt delete mode 100644 test/php/phpinfo/index.php delete mode 100644 test/php/phpinfo/index.wrong delete mode 100644 test/php/post_variables/index.php delete mode 100644 test/php/query_string/index.php delete mode 100644 test/php/script/phpinfo.php delete mode 100644 test/php/targets/1.php delete mode 100644 test/php/targets/2/2.php delete mode 100644 test/php/targets/index.php delete mode 100644 test/php/time_exec/index.php delete mode 100644 test/php/variables/index.php delete mode 100644 test/pytest.ini delete mode 100644 test/python/204_no_content/asgi.py delete mode 100644 test/python/204_no_content/wsgi.py delete mode 100644 test/python/atexit/wsgi.py delete mode 100644 test/python/body_array/wsgi.py delete mode 100644 test/python/body_bytearray/asgi.py delete mode 100644 test/python/body_generate/wsgi.py delete mode 100644 test/python/body_io/wsgi.py delete mode 100644 test/python/body_io_file/file delete mode 100644 test/python/body_io_file/wsgi.py delete mode 100644 test/python/callable/wsgi.py delete mode 100644 test/python/chunked/wsgi.py delete mode 100644 test/python/client_ip/wsgi.py delete mode 100644 test/python/close/wsgi.py delete mode 100644 test/python/close_error/wsgi.py delete mode 100644 test/python/ctx_iter_atexit/wsgi.py delete mode 100644 test/python/custom_header/wsgi.py delete mode 100644 test/python/delayed/asgi.py delete mode 100644 test/python/delayed/wsgi.py delete mode 100644 test/python/empty/asgi.py delete mode 100644 test/python/empty/wsgi.py delete mode 100644 test/python/encoding/wsgi.py delete mode 100644 test/python/environment/wsgi.py delete mode 100644 test/python/errors_write/wsgi.py delete mode 100644 test/python/forwarded_header/wsgi.py delete mode 100644 test/python/header_fields/wsgi.py delete mode 100644 test/python/host/wsgi.py delete mode 100644 test/python/input_iter/wsgi.py delete mode 100644 test/python/input_read_length/wsgi.py delete mode 100644 test/python/input_readline/wsgi.py delete mode 100644 test/python/input_readline_size/wsgi.py delete mode 100644 test/python/input_readlines/wsgi.py delete mode 100644 test/python/iter_exception/wsgi.py delete mode 100644 test/python/legacy/asgi.py delete mode 100644 test/python/legacy_force/asgi.py delete mode 100644 test/python/lifespan/empty/asgi.py delete mode 100644 test/python/lifespan/error/asgi.py delete mode 100644 test/python/lifespan/error_auto/asgi.py delete mode 100644 test/python/lifespan/failed/asgi.py delete mode 100644 test/python/log_body/wsgi.py delete mode 100644 test/python/mirror/asgi.py delete mode 100644 test/python/mirror/wsgi.py delete mode 100644 test/python/not_iterable/wsgi.py delete mode 100644 test/python/ns_inspect/wsgi.py delete mode 100644 test/python/path/wsgi.py delete mode 100644 test/python/prefix/asgi.py delete mode 100644 test/python/prefix/wsgi.py delete mode 100644 test/python/query_string/asgi.py delete mode 100644 test/python/query_string/wsgi.py delete mode 100644 test/python/restart/longstart.py delete mode 100644 test/python/restart/v1.py delete mode 100644 test/python/restart/v2.py delete mode 100644 test/python/server_port/asgi.py delete mode 100644 test/python/server_port/wsgi.py delete mode 100644 test/python/start_response_exit/wsgi.py delete mode 100644 test/python/syntax_error/wsgi.py delete mode 100644 test/python/targets/asgi.py delete mode 100644 test/python/targets/wsgi.py delete mode 100644 test/python/threading/asgi.py delete mode 100644 test/python/threading/wsgi.py delete mode 100644 test/python/threads/asgi.py delete mode 100644 test/python/threads/wsgi.py delete mode 100644 test/python/unicode/wsgi.py delete mode 100644 test/python/upload/wsgi.py delete mode 100644 test/python/user_group/wsgi.py delete mode 100644 test/python/variables/asgi.py delete mode 100644 test/python/variables/wsgi.py delete mode 100644 test/python/websockets/mirror/asgi.py delete mode 100644 test/python/websockets/subprotocol/asgi.py delete mode 100644 test/python/write/wsgi.py delete mode 100644 test/requirements.txt delete mode 100644 test/ruby/at_exit/config.ru delete mode 100644 test/ruby/body_array/config.ru delete mode 100644 test/ruby/body_each_error/config.ru delete mode 100644 test/ruby/body_empty/config.ru delete mode 100644 test/ruby/body_file/config.ru delete mode 100644 test/ruby/body_file/file delete mode 100644 test/ruby/constants/config.ru delete mode 100644 test/ruby/empty/config.ru delete mode 100644 test/ruby/encoding/config.ru delete mode 100644 test/ruby/errors_puts/config.ru delete mode 100644 test/ruby/errors_puts_int/config.ru delete mode 100644 test/ruby/errors_write/config.ru delete mode 100644 test/ruby/errors_write_int/config.ru delete mode 100644 test/ruby/errors_write_to_s_custom/config.ru delete mode 100644 test/ruby/header_array/config.ru delete mode 100644 test/ruby/header_array_empty/config.ru delete mode 100644 test/ruby/header_array_nil/config.ru delete mode 100644 test/ruby/header_custom/config.ru delete mode 100644 test/ruby/header_rack/config.ru delete mode 100644 test/ruby/header_status/config.ru delete mode 100644 test/ruby/hooks/config.ru delete mode 100644 test/ruby/hooks/eval.rb delete mode 100644 test/ruby/hooks/multiple.rb delete mode 100644 test/ruby/hooks/on_thread_boot.rb delete mode 100644 test/ruby/hooks/on_thread_shutdown.rb delete mode 100644 test/ruby/hooks/on_worker_boot.rb delete mode 100644 test/ruby/hooks/on_worker_shutdown.rb delete mode 100644 test/ruby/input_each/config.ru delete mode 100644 test/ruby/input_gets/config.ru delete mode 100644 test/ruby/input_gets_all/config.ru delete mode 100644 test/ruby/input_read_buffer/config.ru delete mode 100644 test/ruby/input_read_buffer_not_empty/config.ru delete mode 100644 test/ruby/input_read_empty/config.ru delete mode 100644 test/ruby/input_read_parts/config.ru delete mode 100644 test/ruby/mirror/config.ru delete mode 100644 test/ruby/multipart/config.ru delete mode 100644 test/ruby/query_string/config.ru delete mode 100644 test/ruby/server_port/config.ru delete mode 100644 test/ruby/session/config.ru delete mode 100644 test/ruby/status_int/config.ru delete mode 100644 test/ruby/syntax_error/config.ru delete mode 100644 test/ruby/threads/config.ru delete mode 100644 test/ruby/variables/config.ru delete mode 100644 test/test_access_log.py delete mode 100644 test/test_asgi_application.py delete mode 100644 test/test_asgi_application_unix_abstract.py delete mode 100644 test/test_asgi_lifespan.py delete mode 100644 test/test_asgi_targets.py delete mode 100644 test/test_asgi_websockets.py delete mode 100644 test/test_client_ip.py delete mode 100644 test/test_configuration.py delete mode 100644 test/test_forwarded_header.py delete mode 100644 test/test_go_application.py delete mode 100644 test/test_go_isolation.py delete mode 100644 test/test_go_isolation_rootfs.py delete mode 100644 test/test_http_header.py delete mode 100644 test/test_java_application.py delete mode 100644 test/test_java_isolation_rootfs.py delete mode 100644 test/test_java_websockets.py delete mode 100644 test/test_njs.py delete mode 100644 test/test_njs_modules.py delete mode 100644 test/test_node_application.py delete mode 100644 test/test_node_es_modules.py delete mode 100644 test/test_node_websockets.py delete mode 100644 test/test_perl_application.py delete mode 100644 test/test_php_application.py delete mode 100644 test/test_php_basic.py delete mode 100644 test/test_php_isolation.py delete mode 100644 test/test_php_targets.py delete mode 100644 test/test_procman.py delete mode 100644 test/test_proxy.py delete mode 100644 test/test_proxy_chunked.py delete mode 100644 test/test_python_application.py delete mode 100644 test/test_python_basic.py delete mode 100644 test/test_python_environment.py delete mode 100644 test/test_python_isolation.py delete mode 100644 test/test_python_isolation_chroot.py delete mode 100644 test/test_python_targets.py delete mode 100644 test/test_reconfigure.py delete mode 100644 test/test_reconfigure_tls.py delete mode 100644 test/test_respawn.py delete mode 100644 test/test_response_headers.py delete mode 100644 test/test_return.py delete mode 100644 test/test_rewrite.py delete mode 100644 test/test_routing.py delete mode 100644 test/test_routing_tls.py delete mode 100644 test/test_ruby_application.py delete mode 100644 test/test_ruby_hooks.py delete mode 100644 test/test_ruby_isolation.py delete mode 100644 test/test_settings.py delete mode 100644 test/test_static.py delete mode 100644 test/test_static_chroot.py delete mode 100644 test/test_static_fallback.py delete mode 100644 test/test_static_mount.py delete mode 100644 test/test_static_share.py delete mode 100644 test/test_static_symlink.py delete mode 100644 test/test_static_types.py delete mode 100644 test/test_static_variables.py delete mode 100644 test/test_status.py delete mode 100644 test/test_status_tls.py delete mode 100644 test/test_tls.py delete mode 100644 test/test_tls_conf_command.py delete mode 100644 test/test_tls_session.py delete mode 100644 test/test_tls_sni.py delete mode 100644 test/test_tls_tickets.py delete mode 100644 test/test_unix_abstract.py delete mode 100644 test/test_upstreams_rr.py delete mode 100644 test/test_usr1.py delete mode 100644 test/test_variables.py delete mode 100644 test/unit/__init__.py delete mode 100644 test/unit/applications/__init__.py delete mode 100644 test/unit/applications/lang/__init__.py delete mode 100644 test/unit/applications/lang/go.py delete mode 100644 test/unit/applications/lang/java.py delete mode 100644 test/unit/applications/lang/node.py delete mode 100644 test/unit/applications/lang/perl.py delete mode 100644 test/unit/applications/lang/php.py delete mode 100644 test/unit/applications/lang/python.py delete mode 100644 test/unit/applications/lang/ruby.py delete mode 100644 test/unit/applications/proto.py delete mode 100644 test/unit/applications/tls.py delete mode 100644 test/unit/applications/websockets.py delete mode 100644 test/unit/check/check_prerequisites.py delete mode 100644 test/unit/check/chroot.py delete mode 100644 test/unit/check/discover_available.py delete mode 100644 test/unit/check/go.py delete mode 100644 test/unit/check/isolation.py delete mode 100644 test/unit/check/njs.py delete mode 100644 test/unit/check/node.py delete mode 100644 test/unit/check/regex.py delete mode 100644 test/unit/check/tls.py delete mode 100644 test/unit/check/unix_abstract.py delete mode 100644 test/unit/control.py delete mode 100644 test/unit/http.py delete mode 100644 test/unit/log.py delete mode 100644 test/unit/option.py delete mode 100644 test/unit/status.py delete mode 100644 test/unit/utils.py delete mode 100644 tools/README.md delete mode 100755 tools/setup-unit delete mode 100755 tools/unitc delete mode 100644 version rename pkg/docker/welcome.html => welcome.html (100%) rename pkg/docker/welcome.json => welcome.json (100%) rename pkg/docker/welcome.md => welcome.md (100%) diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 16af3a06..00000000 --- a/.gitattributes +++ /dev/null @@ -1,7 +0,0 @@ -*.c diff=cpp -*.h diff=cpp - -.hg* export-ignore -pkg/** export-ignore -docs/*.* export-ignore -docs/Makefile export-ignore diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 59d59104..d905fc58 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -15,6 +15,9 @@ jobs: env: DOCKER_ORG: technocloud-public RUNNER_TOOL_CACHE: /toolcache + strategy: + matrix: + python-version: ['3.10', '3.11', '3.12'] steps: - name: Checkout uses: actions/checkout@v4 @@ -41,29 +44,29 @@ jobs: run: | echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT - - name: Build and push Python 3.10 + - name: Build and push Python ${{ matrix.python-version }} uses: docker/build-push-action@v5 with: - context: pkg/docker - file: pkg/docker/Dockerfile.python3.10 + context: . + file: Dockerfile.python${{ matrix.python-version }} platforms: linux/amd64,linux/arm64 push: true - tags: gitea.technocloud.ee/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:python3.10 + tags: gitea.technocloud.ee/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:python${{ matrix.python-version }} - - name: Build and push Python 3.11 + - name: Build and push Python ${{ matrix.python-version }} uses: docker/build-push-action@v5 with: - context: pkg/docker - file: pkg/docker/Dockerfile.python3.11 + context: . + file: Dockerfile.python${{ matrix.python-version }} platforms: linux/amd64,linux/arm64 push: true - tags: gitea.technocloud.ee/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:python3.11 + tags: gitea.technocloud.ee/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:python${{ matrix.python-version }} - - name: Build and push Python 3.12 + - name: Build and push Python ${{ matrix.python-version }} uses: docker/build-push-action@v5 with: - context: pkg/docker - file: pkg/docker/Dockerfile.python3.12 + context: . + file: Dockerfile.python${{ matrix.python-version }} platforms: linux/amd64,linux/arm64 push: true - tags: gitea.technocloud.ee/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:python3.12 + tags: gitea.technocloud.ee/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:python${{ matrix.python-version }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index b5368ae9..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,339 +0,0 @@ -name: ci - -on: - pull_request: - push: - branches: - - master - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - # Core - - build: unit - os: ubuntu-latest - # Modules - - build: go-1.21 - os: ubuntu-latest - - build: go-1.22 - os: ubuntu-latest - - build: java-17 - os: ubuntu-latest - - build: java-18 - os: ubuntu-latest - - build: java-21 - os: ubuntu-latest - - build: node-20 - os: ubuntu-latest - - build: node-21 - os: ubuntu-latest - - build: perl - os: ubuntu-latest - - build: php-8.1 - os: ubuntu-latest - - build: php-8.2 - os: ubuntu-latest - - build: php-8.3 - os: ubuntu-latest - - build: python-3.11 - os: ubuntu-latest - - build: python-3.12 - os: ubuntu-latest - - build: ruby-3.2 - os: ubuntu-latest - - build: ruby-3.3 - os: ubuntu-latest - - build: wasm - os: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - # Creates and outputs directories used by tests (/usr/local is unfriendly) - - name: Configure directories - id: dir - run: | - PREFIX=${HOME}/.unit - BIN=${PREFIX}/bin - VAR=${PREFIX}/var - mkdir -p $BIN - mkdir -p $VAR - - echo "prefix=${PREFIX}" >> "$GITHUB_OUTPUT" - echo "bin=${BIN}" >> "$GITHUB_OUTPUT" - echo "bin=${BIN}" >> "$GITHUB_PATH" - echo "var=${VAR}" >> "$GITHUB_OUTPUT" - cat "$GITHUB_OUTPUT" - - # Provides module, language version and testpath from build name - - name: Output build metadata - id: metadata - run: | - # Split the build name by '-' into module and version - IFS='-' read -r module version <<< "${{ matrix.build }}" - - testpath="test/test_${module}*" - - # Run all tests for "unit" and "python" - # Python is the default module for tests - if [ "$module" = "unit" ] || [ "$module" = "python" ]; then - testpath="test" - fi - - echo "module=${module}" >> "$GITHUB_OUTPUT" - echo "version=${version}" >> "$GITHUB_OUTPUT" - echo "testpath=${testpath}" >> "$GITHUB_OUTPUT" - - NJS_VERSION=$(sed -n "s/NJS_VERSION := \(.*\)/\1/p" pkg/contrib/src/njs/version) - echo "njs_version=${NJS_VERSION}" >> "$GITHUB_OUTPUT" - - cat "$GITHUB_OUTPUT" - - # https://github.com/actions/runner-images/issues/2821 - - name: Kill mono process - run: | - sudo systemctl stop mono-xsp4.service - sudo systemctl mask mono-xsp4.service - sudo systemctl status mono-xsp4.service || true - PID=$(sudo lsof -t -i :8084) - echo "Killing PID $PID" - sudo kill -9 $PID - - ## - ## njs - ## - - - name: Clone njs repository - uses: actions/checkout@v4 - with: - repository: nginx/njs - ref: '${{ steps.metadata.outputs.njs_version }}' - path: njs - - - name: Make njs - run: | - ./configure --no-libxml2 --no-zlib - make -j4 -k - working-directory: njs - - ## - ## Unit - ## - - - name: Configure unit - run: | - ./configure \ - --prefix=${{ steps.dir.outputs.prefix }} \ - --sbindir=${{ steps.dir.outputs.bin }} \ - --logdir=${{ steps.dir.outputs.var }}/log \ - --log=${{ steps.dir.outputs.var }}/log/unit/unit.log \ - --runstatedir=${{ steps.dir.outputs.var }}/run \ - --pid=${{ steps.dir.outputs.var }}/run/unit/unit.pid \ - --control=unix:${{ steps.dir.outputs.var }}/run/unit/control.sock \ - --modules=${{ steps.dir.outputs.prefix }}/lib/unit/modules \ - --statedir=${{ steps.dir.outputs.var }}/state/unit \ - --tests \ - --openssl \ - --njs \ - --cc-opt="-I njs/src/ -I njs/build" \ - --ld-opt="-L njs/build" - - - name: Make unit - run: | - make -j4 -k || make - - ## - ## Go - ## - - - uses: actions/setup-go@v5 - with: - go-version: '${{ steps.metadata.outputs.version }}' - cache: false - if: steps.metadata.outputs.module == 'go' - - - name: Configure go - run: | - ./configure go --go-path= - if: steps.metadata.outputs.module == 'go' - - - name: Make go - run: | - make go - make go-install - if: steps.metadata.outputs.module == 'go' - - ## - ## Java - ## - - - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: '${{ steps.metadata.outputs.version }}' - if: steps.metadata.outputs.module == 'java' - - - name: Configure java - run: | - ./configure java - if: steps.metadata.outputs.module == 'java' - - - name: Make java - run: | - make java - if: steps.metadata.outputs.module == 'java' - - ## - ## Node - ## - - - uses: actions/setup-node@v4 - with: - node-version: '${{ steps.metadata.outputs.version }}' - if: steps.metadata.outputs.module == 'node' - - - name: Install node-gyp - run: | - npm install -g node-gyp - if: steps.metadata.outputs.module == 'node' - - - name: Configure node - run: | - ./configure nodejs - if: steps.metadata.outputs.module == 'node' - - - name: Make node - run: | - make node-local-install DESTDIR=node - if: steps.metadata.outputs.module == 'node' - - ## - ## Perl - ## - - # Uses default Actions VM Perl - # https://github.com/actions/runner-images#available-images - - - name: Install libperl-dev - run: | - sudo apt-get install libperl-dev - if: steps.metadata.outputs.module == 'perl' - - - name: Configure perl - run: | - ./configure perl - if: steps.metadata.outputs.module == 'perl' - - - name: Make perl - run: | - make perl - if: steps.metadata.outputs.module == 'perl' - - ## - ## PHP - ## - - - uses: shivammathur/setup-php@v2 - with: - php-version: '${{ steps.metadata.outputs.version }}' - extensions: none - env: - update: true - if: steps.metadata.outputs.module == 'php' - - - name: Configure php - run: | - ./configure php - if: steps.metadata.outputs.module == 'php' - - - name: Make php - run: | - make php - if: steps.metadata.outputs.module == 'php' - - ## - ## Python 3 - ## - - - uses: actions/setup-python@v5 - with: - python-version: '${{ steps.metadata.outputs.version }}' - if: steps.metadata.outputs.module == 'python' - - - name: Configure python3 - run: | - ./configure python --config=python3-config - if: steps.metadata.outputs.module == 'python' - - - name: Make python3 - run: | - make python3 - if: steps.metadata.outputs.module == 'python' - - ## - ## Ruby - ## - - - uses: ruby/setup-ruby@v1 - with: - ruby-version: '${{ steps.metadata.outputs.version }}' - if: steps.metadata.outputs.module == 'ruby' - - - name: Install rack - run: | - gem install rack - if: steps.metadata.outputs.module == 'ruby' - - - name: Configure ruby - run: | - ./configure ruby - if: steps.metadata.outputs.module == 'ruby' - - - name: Make ruby - run: | - make ruby - if: steps.metadata.outputs.module == 'ruby' - - ## - ## Wasm - ## - - - name: Make wasmtime - run: | - make -C pkg/contrib .wasmtime - if: steps.metadata.outputs.module == 'wasm' - - - name: Configure wasm - run: | - ./configure wasm --include-path=pkg/contrib/wasmtime/crates/c-api/include --lib-path=pkg/contrib/wasmtime/target/release - if: steps.metadata.outputs.module == 'wasm' - - - name: Make wasm - run: | - make wasm - if: steps.metadata.outputs.module == 'wasm' - - ## - ## Tests - ## - - # Install python3 if not present - - uses: actions/setup-python@v5 - with: - python-version: '3' - if: steps.metadata.outputs.module != 'wasm' - - - name: Install pytest - run: | - pip install pytest - if: steps.metadata.outputs.module != 'wasm' - - - name: Run ${{ steps.metadata.outputs.module }} tests - run: | - pytest --print-log ${{ steps.metadata.outputs.testpath }} - # Skip pytest if wasm build, as there are no tests yet - if: steps.metadata.outputs.module != 'wasm' diff --git a/.gitignore b/.gitignore index 91875722..723ef36f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ -/build/ -Makefile -*.pyc -__pycache__/ +.idea \ No newline at end of file diff --git a/.hgignore b/.hgignore deleted file mode 100644 index d4f37fde..00000000 --- a/.hgignore +++ /dev/null @@ -1,6 +0,0 @@ -^build/ -^Makefile$ -\.pyc$ -\.cache$ -\.pytest_cache$ -__pycache__/ diff --git a/.hgtags b/.hgtags deleted file mode 100644 index 8e6743d1..00000000 --- a/.hgtags +++ /dev/null @@ -1,43 +0,0 @@ -f9d308f3fceba164f2326fb2ad242339157cb162 0.1 -b09757e4984e70439168af3501ac1787d0276368 0.2 -b8400e8feb36f29a6b3f5f58b1473b040720490c 0.3 -6071f4300f76e2b879e9cc7fd431e5e119077f16 0.4 -1ba4d13d222bc62caa5b1b42cf5ad50a9cf47f64 0.5 -88831b81e384982223fa01f2f29cbb8642846a80 0.6 -d2fcec5b0fa3b0e8da1945aa240d23be3bf94309 0.7 -5870dd420309fe2584abc4ca8d63168ad9141274 1.0 -3f710b55c226c7579d4e737198c2d8a9b7d67518 1.1 -fbe7f5a3867e9559ef0884786fe5150aa60414e6 1.2 -b3cf22b8a17e0e35ca80decb03ed2cceb662c3de 1.3 -8f4524a9cf87fbddf626302da071f5055cf33f28 1.4 -b3dee0cc5a4edd046345511769b5cfec49044f1c 1.5 -d411e7fdee9e03036adb652f8d9f4c45a420bdd5 1.6 -784b45adb0fe8bdd707510f59ed18309087e5c21 1.7 -0f04ef991fbc1dadbc590ab7fb229d4f3d6357bc 1.7.1 -0a18a14d169f156f8e2daca35aa86d5a6dd9b1ae 1.8.0 -dda6319de785dc2d225d818349aba56fc48d47f6 1.9.0 -cdbba3c3e3762eacc308a5407877c3665a05058d 1.10.0 -3b1601ac0f2f53fed4cae01b9db0e4e070665cae 1.11.0 -b391df5f0102aa6afe660cfc863729c1b1111c9e 1.12.0 -3313bf222e6e0a91213946dfcbd70bb5079f4cef 1.13.0 -6e28966ed1f26e119bf333229ea5e6686c60a469 1.14.0 -801ac82f80fb2b2333f2c03ac9c3df6b7cec130a 1.15.0 -8bab088952dd9d7caa3d04fd4b3026cef26fcf7d 1.16.0 -4b13438632bc37ca599113be90af64f6e2f09d83 1.17.0 -9e14c63773be52613dd47dea9fd113037f15a3eb 1.18.0 -86cdf66f82745d8db35345368dcdb38c79a4f03a 1.19.0 -0e985b30067380782125f1c479eda4ef909418df 1.20.0 -f804aaf7eee10a7d8116820840d6312dd4914a41 1.21.0 -331bdadeca30a49dd11b86af99124c2ffeb22d05 1.22.0 -49ee24c03f5749f8a1b69dc1c600ad48517d9d7a 1.23.0 -847c88d10f26765b45149c14f88c2274adfc3f42 1.24.0 -54ffe5ce4fb3c4304faf6d342d9b17dee2c745ac 1.25.0 -2be7b623fbfafdb470d832a28abb1cd55c76e04f 1.26.0 -1a08f884b24effa8b843d6aeeaf016b6354d1256 1.26.1 -8a9055cbe4ffd450fac4d7a849c00e0db5485ad3 1.27.0 -ea073fb3cb75abfb4be5dc12402de73e0c20da60 1.28.0 -37cac7fec92e5656d8a03a8594ade131c3391f45 1.29.0 -fa0227b7f62691a186d752ace475868de49e9fce 1.29.1 -2692a5823c403a4e209681943e32a4907317d14b 1.30.0 -3a9046dca2a6c51ee2df2cabdf69cb9a83e7a1e6 1.31.0 -25aafe2ff61e0424b3245f4e3d40eb1fa7611063 1.31.1 diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 23a492fa..00000000 --- a/.mailmap +++ /dev/null @@ -1,20 +0,0 @@ -Alejandro Colomar -Alejandro Colomar -Alejandro Colomar -Andrei Zeliankou -Andrei Zeliankou -Andrew Clayton -Andrew Clayton -Artem Konev <41629299+artemkonev@users.noreply.github.com> -Dan Callahan -Danielle De Leo -Dylan Arbour -Konstantin Pavlov -Konstantin Pavlov -Max Romanov -OutOfFocus4 -Sergey A. Osokin -Taryn Musgrave <34845739+tarynmusgrave@users.noreply.github.com> -Tiago Natel de Moura -Timo Stark -Zhidao HONG diff --git a/.rustfmt.toml b/.rustfmt.toml deleted file mode 100644 index df99c691..00000000 --- a/.rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -max_width = 80 diff --git a/CHANGES b/CHANGES deleted file mode 100644 index a1a4a418..00000000 --- a/CHANGES +++ /dev/null @@ -1,1135 +0,0 @@ - -Changes with Unit 1.32.1 26 Mar 2024 - - *) Bugfix: NJS variables in templates may have incorrect values due to - improper caching. - - *) Bugfix: Wasm application process hangs after receiving restart signal - from the control. - - -Changes with Unit 1.32.0 27 Feb 2024 - - *) Feature: WebAssembly Components using WASI interfaces defined in - wasi:http/proxy@0.2.0. - - *) Feature: conditional access logging. - - *) Feature: NJS variables access. - - *) Feature: $request_id variable contains a string that is formed using - random data and can be used as a unique request identifier. - - *) Feature: options to set control socket permissions. - - *) Feature: Ruby arrays in response headers, improving compatibility - with Rack v3.0. - - *) Feature: Python bytearray response bodies for ASGI applications. - - *) Bugfix: router could crash while sending large files. Thanks to - rustedsword. - - *) Bugfix: serving static files from a network filesystem could lead to - error. - - *) Bugfix: "uidmap" and "gidmap" isolation options validation. - - *) Bugfix: abstract UNIX socket name could be corrupted during - configuration validation. Thanks to Alejandro Colomar. - - *) Bugfix: HTTP header field value encoding could be misinterpreted in - Python module. - - *) Bugfix: Node.js http.createServer() accepts and ignores the "options" - argument, improving compatibility with strapi applications, among - others. - - *) Bugfix: ServerRequest.flushHeaders() implemented in Node.js module to - make it compatible with Next.js. - - *) Bugfix: ServerRequest.httpVersion variable format in Node.js module. - - *) Bugfix: Node.js module handles standard library imports prefixed with - "node:", making it possible to run newer Nuxt applications, among - others. - - *) Bugfix: Node.js tarball location changed to avoid build/install - errors. - - *) Bugfix: Go module sets environment variables necessary for building - on macOS/arm64 systems. - - -Changes with Unit 1.31.1 19 Oct 2023 - - *) Feature: allow to set the HTTP response status in Wasm module. - - *) Feature: allow uploads larger than 4GiB in Wasm module. - - *) Bugfix: application process could crash while rewriting URLs with - query strings. - - *) Bugfix: requests larger than about 64MiB could cause error in Wasm - module. - - *) Bugfix: when using many headers in Java module some of them could be - corrupted due to memory realocation issue. - - *) Bugfix: ServerRequest.destroy() implemented in Node.js module to make - it compatible with some frameworks that might use it. - - *) Bugfix: chunk argument of ServerResponse.write() can now be a - Uint8Array to improve compatibility with Node.js 15.0.0 and above. - - *) Bugfix: Node.JS unit-http NPM module now has appropriate default - paths for macOS/arm64 systems. - - *) Bugfix: build on musl libc with clang. - - -Changes with Unit 1.31.0 31 Aug 2023 - - *) Change: if building with njs, version 0.8.0 or later is now required. - - *) Feature: technology preview of WebAssembly application module. - - *) Feature: "response_headers" option to manage headers in the action - and fallback. - - *) Feature: HTTP response header variables. - - *) Feature: ASGI lifespan state support. Thanks to synodriver. - - *) Bugfix: ensure that $uri variable is not cached. - - *) Bugfix: deprecated options were unavailable. - - *) Bugfix: ASGI applications inaccessible over IPv6. - - -Changes with Unit 1.30.0 10 May 2023 - - *) Change: remove Unix domain listen sockets upon reconfiguration. - - *) Feature: basic URI rewrite support. - - *) Feature: NJS loadable modules support. - - *) Feature: per-application logging. - - *) Feature: conditional logging of route selection. - - *) Feature: support the keys API on the request objects in NJS. - - *) Feature: default values for 'make install' pathnames such as prefix; - this allows to './configure && make && sudo make install'. - - *) Feature: "server_version" setting to omit the version token from - "Server" header field. - - *) Bugfix: request header field values could be corrupted in some cases; - the bug had appeared in 1.29.0. - - *) Bugfix: PHP error handling (added missing 403 and 404 errors). - - *) Bugfix: Perl applications crash on second responder call. - - -Changes with Unit 1.29.1 28 Feb 2023 - - *) Bugfix: stop creating world-writeable directories. - - *) Bugfix: memory leak related to NJS. - - *) Bugfix: path parsing in PHP applications. - - *) Bugfix: enabled UTF-8 for Python config by default to avoid - applications failing in some cases. - - *) Bugfix: using asyncio.get_running_loop() instead of - asyncio.get_event_loop() when it's available to prevent errors in - some Python ASGI applications. - - *) Bugfix: applications that make use of various low level APIs such as - pthreads could fail to work correctly. - - *) Bugfix: websocket endianness detection for obscure operating systems. - - -Changes with Unit 1.29.0 15 Dec 2022 - - *) Change: removed $uri auto-append for "share" when loading - configuration. - - *) Change: prefer system crypto policy instead of hardcoding a default. - - *) Feature: njs support with the basic syntax of JS template literals. - - *) Feature: support per-application cgroups on Linux. - - *) Feature: the $request_time variable contains the request processing - time. - - *) Feature: "prefix" option in Python applications to set WSGI - "SCRIPT_NAME" and ASGI root-path variables. - - *) Feature: compatibility with Python 3.11. - - *) Feature: compatibility with OpenSSL 3. - - *) Feature: compatibility with PHP 8.2. - - *) Feature: compatibility with Node.js 19.0. - - *) Feature: Ruby Rack v3 support. - - *) Bugfix: fix error in connection statistics when using proxy. - - *) Bugfix: fix HTTP cookie parsing when the value contains an equals - sign. - - *) Bugfix: PHP directory URLs without a trailing '/' would give a 503 - error (fixed with a 301 re-direct). - - *) Bugfix: missing error checks in the C API. - - *) Bugfix: report the regex status in configure summary. - - -Changes with Unit 1.28.0 13 Sep 2022 - - *) Change: increased the applications' startup timeout. - - *) Change: disallowed abstract Unix domain socket syntax in non-Linux - systems. - - *) Feature: basic statistics API. - - *) Feature: customizable access log format. - - *) Feature: more HTTP variables support. - - *) Feature: forwarded header to replace client address and protocol. - - *) Feature: ability to get dynamic variables. - - *) Feature: support for abstract Unix sockets. - - *) Feature: support for Unix sockets in address matching. - - *) Feature: the $dollar variable translates to a literal "$" during - variable substitution. - - *) Bugfix: router process could crash if index file didn't contain an - extension. - - *) Bugfix: force SCRIPT_NAME in Ruby to always be an empty string. - - *) Bugfix: when isolated PID numbers reach the prototype process host - PID, the prototype crashed. - - *) Bugfix: the Ruby application process could crash on SIGTERM. - - *) Bugfix: the Ruby application process could crash on SIGINT. - - *) Bugfix: mutex leak in the C API. - - -Changes with Unit 1.27.0 02 Jun 2022 - - *) Feature: ability to specify a custom index file name when serving - static files. - - *) Feature: variables support in the "location" option of the "return" - action. - - *) Feature: support empty strings in the "location" option of the - "return" action. - - *) Feature: added a new variable, $request_uri, that includes both the - path and the query parts as per RFC 3986, sections 3-4. - - *) Feature: Ruby Rack environment parameter "SCRIPT_NAME" support. - - *) Feature: compatibility with GCC 12. - - *) Bugfix: Ruby Sinatra applications don't work without custom logging. - - *) Bugfix: the controller process could crash when a chain of more than - four certificates was uploaded. - - *) Bugfix: some Perl applications failed to process the request body, - notably with Plack. - - *) Bugfix: some Spring Boot applications failed to start, notably with - Grails. - - *) Bugfix: incorrect Python protocol auto detection (ASGI or WSGI) for - native callable object, notably with Falcon. - - *) Bugfix: ECMAScript modules did not work with the recent Node.js - versions. - - -Changes with Unit 1.26.1 02 Dec 2021 - - *) Bugfix: occasionally, the Unit daemon was unable to fully terminate; - the bug had appeared in 1.26.0. - - *) Bugfix: a prototype process could crash on an application process - exit; the bug had appeared in 1.26.0. - - *) Bugfix: the router process crashed on reconfiguration if "access_log" - was configured without listeners. - - *) Bugfix: a segmentation fault occurred in the PHP module if chdir() or - fastcgi_finish_request() was called in the OPcache preloading script. - - *) Bugfix: fatal errors on DragonFly BSD; the bug had appeared in - 1.26.0. - - -Changes with Unit 1.26.0 18 Nov 2021 - - *) Change: the "share" option now specifies the entire path to the files - it serves, rather than a document root directory to be prepended to - the request URI. - - *) Feature: automatic adjustment of existing configurations to the new - "share" behavior when updating from previous versions. - - *) Feature: variables support in the "share" option. - - *) Feature: multiple paths in the "share" option. - - *) Feature: variables support in the "chroot" option. - - *) Feature: PHP opcache is shared between application processes. - - *) Feature: request routing by the query string. - - *) Bugfix: the router and app processes could crash when the requests - limit was reached by asynchronous or multithreaded apps. - - *) Bugfix: established WebSocket connections could stop reading frames - from the client after the corresponding listener had been - reconfigured. - - *) Bugfix: fixed building with glibc 2.34, notably Fedora 35. - - -Changes with Unit 1.25.0 19 Aug 2021 - - *) Feature: client IP address replacement from a specified HTTP header - field. - - *) Feature: TLS sessions cache. - - *) Feature: TLS session tickets. - - *) Feature: application restart control. - - *) Feature: process and thread lifecycle hooks in Ruby. - - *) Bugfix: the router process could crash on TLS connection open when - multiple listeners with TLS certificates were configured; the bug had - appeared in 1.23.0. - - *) Bugfix: TLS connections were rejected for configurations with - multiple certificate bundles in a listener if the client did not use - SNI. - - *) Bugfix: the router process could crash with frequent multithreaded - application reconfiguration. - - *) Bugfix: compatibility issues with some Python ASGI apps, notably - based on the Starlette framework. - - *) Bugfix: a descriptor and memory leak occurred in the router process - when an app process stopped or crashed. - - *) Bugfix: the controller or router process could crash if the - configuration contained a full-form IPv6 in a listener address. - - *) Bugfix: the router process crashed when a request was passed to an - empty "routes" or "upstreams" using a variable "pass" option. - - *) Bugfix: the router process crashed while matching a request to an - empty array of source or destination address patterns. - - -Changes with Unit 1.24.0 27 May 2021 - - *) Change: PHP added to the default MIME type list. - - *) Feature: arbitrary configuration of TLS connections via OpenSSL - commands. - - *) Feature: the ability to limit static file serving by MIME types. - - *) Feature: support for chrooting, rejecting symlinks, and rejecting - mount point traversal on a per-request basis when serving static - files. - - *) Feature: a loader for automatically overriding the "http" and - "websocket" modules in Node.js. - - *) Feature: multiple "targets" in Python applications. - - *) Feature: compatibility with Ruby 3.0. - - *) Bugfix: the router process could crash while closing a TLS - connection. - - *) Bugfix: a segmentation fault might have occurred in the PHP module if - fastcgi_finish_request() was used with the "auto_globals_jit" option - enabled. - - -Changes with Unit 1.23.0 25 Mar 2021 - - *) Feature: support for multiple certificate bundles on a listener via - the Server Name Indication (SNI) TLS extension. - - *) Feature: "--mandir" ./configure option to specify the directory for - man page installation. - - *) Bugfix: the router process could crash on premature TLS connection - close; the bug had appeared in 1.17.0. - - *) Bugfix: a connection leak occurred on premature TLS connection close; - the bug had appeared in 1.6. - - *) Bugfix: a descriptor and memory leak occurred in the router process - when processing small WebSocket frames from a client; the bug had - appeared in 1.19.0. - - *) Bugfix: a descriptor leak occurred in the router process when - removing or reconfiguring an application; the bug had appeared in - 1.19.0. - - *) Bugfix: persistent storage of certificates might've not worked with - some filesystems in Linux, and all uploaded certificate bundles were - forgotten after restart. - - *) Bugfix: the controller process could crash while requesting - information about a certificate with a non-DNS SAN entry. - - *) Bugfix: the controller process could crash on manipulations with a - certificate containing a SAN and no standard name attributes in - subject or issuer. - - *) Bugfix: the Ruby module didn't respect the user locale for defaults - in the Encoding class. - - *) Bugfix: the PHP 5 module failed to build with thread safety enabled; - the bug had appeared in 1.22.0. - - -Changes with Unit 1.22.0 04 Feb 2021 - - *) Feature: the ServerRequest and ServerResponse objects of Node.js - module are now compliant with Stream API. - - *) Feature: support for specifying multiple directories in the "path" - option of Python apps. - - *) Bugfix: a memory leak occurred in the router process when serving - files larger than 128K; the bug had appeared in 1.13.0. - - *) Bugfix: apps could stop processing new requests under high load; the - bug had appeared in 1.19.0. - - *) Bugfix: app processes could terminate unexpectedly under high load; - the bug had appeared in 1.19.0. - - *) Bugfix: invalid HTTP responses were generated for some unusual status - codes. - - *) Bugfix: the PHP_AUTH_USER, PHP_AUTH_PW, and PHP_AUTH_DIGEST server - variables were missing in the PHP module. - - *) Bugfix: the router process could crash with multithreaded apps under - high load. - - *) Bugfix: Ruby apps with multithreading configured could crash on start - under load. - - *) Bugfix: mount points weren't unmounted when the "mount" namespace - isolation was used; the bug had appeared in 1.21.0. - - *) Bugfix: the router process could crash while removing or - reconfiguring an app that used WebSocket. - - *) Bugfix: a memory leak occurring in the router process when removing - or reconfiguring an application; the bug had appeared in 1.19.0. - - -Changes with Unit 1.21.0 19 Nov 2020 - - *) Change: procfs is mounted by default for all languages when "rootfs" - isolation is used. - - *) Change: any characters valid according to RFC 7230 are now allowed in - HTTP header field names. - - *) Change: HTTP header fields with underscores ("_") are now discarded - from requests by default. - - *) Feature: optional multithreaded request processing for Java, Python, - Perl, and Ruby apps. - - *) Feature: regular expressions in route matching patterns. - - *) Feature: compatibility with Python 3.9. - - *) Feature: the Python module now supports ASGI 2.0 legacy applications. - - *) Feature: the "protocol" option in Python applications aids choice - between ASGI and WSGI. - - *) Feature: the fastcgi_finish_request() PHP function that finalizes - request processing and continues code execution without holding onto - the client connection. - - *) Feature: the "discard_unsafe_fields" HTTP option that enables - discarding request header fields with irregular (but still valid) - characters in the field name. - - *) Feature: the "procfs" and "tmpfs" automount isolation options to - disable automatic mounting of eponymous filesystems. - - *) Bugfix: the router process could crash when running Go applications - under high load; the bug had appeared in 1.19.0. - - *) Bugfix: some language dependencies could remain mounted after using - "rootfs" isolation. - - *) Bugfix: various compatibility issues in Java applications. - - *) Bugfix: the Java module built with the musl C library couldn't run - applications that use "rootfs" isolation. - - -Changes with Unit 1.20.0 08 Oct 2020 - - *) Change: the PHP module is now initialized before chrooting; this - enables loading all extensions from the host system. - - *) Change: AVIF and APNG image formats added to the default MIME type - list. - - *) Change: functional tests migrated to the pytest framework. - - *) Feature: the Python module now fully supports applications that use - the ASGI 3.0 server interface. - - *) Feature: the Python module now has a built-in WebSocket server - implementation for applications, compatible with the HTTP & WebSocket - ASGI Message Format 2.1 specification. - - *) Feature: automatic mounting of an isolated "/tmp" file system into - chrooted application environments. - - *) Feature: the $host variable contains a normalized "Host" request - value. - - *) Feature: the "callable" option sets Python application callable - names. - - *) Feature: compatibility with PHP 8 RC 1. Thanks to Remi Collet. - - *) Feature: the "automount" option in the "isolation" object allows to - turn off the automatic mounting of language module dependencies. - - *) Bugfix: "pass"-ing requests to upstreams from a route was broken; the - bug had appeared in 1.19.0. Thanks to 洪志道 (Hong Zhi Dao) for - discovering and fixing it. - - *) Bugfix: the router process could crash during reconfiguration. - - *) Bugfix: a memory leak occurring in the router process; the bug had - appeared in 1.18.0. - - *) Bugfix: the "!" (non-empty) pattern was matched incorrectly; the bug - had appeared in 1.19.0. - - *) Bugfix: fixed building on platforms without sendfile() support, - notably NetBSD; the bug had appeared in 1.16.0. - - -Changes with Unit 1.19.0 13 Aug 2020 - - *) Feature: reworked IPC between the router process and the applications - to lower latencies, increase performance, and improve scalability. - - *) Feature: support for an arbitrary number of wildcards in route - matching patterns. - - *) Feature: chunked transfer encoding in proxy responses. - - *) Feature: basic variables support in the "pass" option. - - *) Feature: compatibility with PHP 8 Beta 1. Thanks to Remi Collet. - - *) Bugfix: the router process could crash while passing requests to an - application under high load. - - *) Bugfix: a number of language modules failed to build on some systems; - the bug had appeared in 1.18.0. - - *) Bugfix: time in error log messages from PHP applications could lag. - - *) Bugfix: reconfiguration requests could hang if an application had - failed to start; the bug had appeared in 1.18.0. - - *) Bugfix: memory leak during reconfiguration. - - *) Bugfix: the daemon didn't start without language modules; the bug had - appeared in 1.18.0. - - *) Bugfix: the router process could crash at exit. - - *) Bugfix: Node.js applications could crash at exit. - - *) Bugfix: the Ruby module could be linked against a wrong library - version. - - -Changes with Unit 1.18.0 28 May 2020 - - *) Feature: the "rootfs" isolation option for changing root filesystem - for an application. - - *) Feature: multiple "targets" in PHP applications. - - *) Feature: support for percent-encoding in the "uri" and "arguments" - matching options and in the "pass" option. - - -Changes with Unit 1.17.0 16 Apr 2020 - - *) Feature: a "return" action with optional "location" for immediate - responses and external redirection. - - *) Feature: fractional weights support for upstream servers. - - *) Bugfix: accidental 502 "Bad Gateway" errors might have occurred in - applications under high load. - - *) Bugfix: memory leak in the router; the bug had appeared in 1.13.0. - - *) Bugfix: segmentation fault might have occurred in the router process - when reaching open connections limit. - - *) Bugfix: "close() failed (9: Bad file descriptor)" alerts might have - appeared in the log while processing large request bodies; the bug - had appeared in 1.16.0. - - *) Bugfix: existing application processes didn't reopen the log file. - - *) Bugfix: incompatibility with some Node.js applications. - - *) Bugfix: broken build on DragonFly BSD; the bug had appeared in - 1.16.0. - - -Changes with Unit 1.16.0 12 Mar 2020 - - *) Feature: basic load-balancing support with round-robin. - - *) Feature: a "fallback" option that performs an alternative action if a - request can't be served from the "share" directory. - - *) Feature: reduced memory consumption by dumping large request bodies - to disk. - - *) Feature: stripping UTF-8 BOM and JavaScript-style comments from - uploaded JSON. - - *) Bugfix: negative address matching in router might work improperly in - combination with non-negative patterns. - - *) Bugfix: Java Spring applications failed to run; the bug had appeared - in 1.10.0. - - *) Bugfix: PHP 7.4 was broken if it was built with thread safety - enabled. - - *) Bugfix: compatibility issues with some Python applications. - - -Changes with Unit 1.15.0 06 Feb 2020 - - *) Change: extensions of dynamically requested PHP scripts were - restricted to ".php". - - *) Feature: compatibility with Ruby 2.7. - - *) Bugfix: segmentation fault might have occurred in the router process - with multiple application processes under load; the bug had appeared - in 1.14.0. - - *) Bugfix: receiving request body over TLS connection might have - stalled. - - -Changes with Unit 1.14.0 26 Dec 2019 - - *) Change: the Go package import name changed to "unit.nginx.org/go". - - *) Change: Go package now links to libunit instead of including library - sources. - - *) Feature: ability to change user and group for isolated applications - when Unit daemon runs as an unprivileged user. - - *) Feature: request routing by source and destination addresses and - ports. - - *) Bugfix: memory bloat on large responses. - - -Changes with Unit 1.13.0 14 Nov 2019 - - *) Feature: basic support for HTTP reverse proxying. - - *) Feature: compatibility with Python 3.8. - - *) Bugfix: memory leak in Python application processes when the close - handler was used. - - *) Bugfix: threads in Python applications might not work correctly. - - *) Bugfix: Ruby on Rails applications might not work on Ruby 2.6. - - *) Bugfix: backtraces for uncaught exceptions in Python 3 might be - logged with significant delays. - - *) Bugfix: explicit setting a namespaces isolation option to false might - have enabled it. - - -Changes with Unit 1.12.0 03 Oct 2019 - - *) Feature: compatibility with PHP 7.4. - - *) Bugfix: descriptors leak on process creation; the bug had appeared in - 1.11.0. - - *) Bugfix: TLS connection might be closed prematurely while sending - response. - - *) Bugfix: segmentation fault might have occurred if an irregular file - was requested. - - -Changes with Unit 1.11.0 19 Sep 2019 - - *) Feature: basic support for serving static files. - - *) Feature: isolation of application processes with Linux namespaces. - - *) Feature: built-in WebSocket server implementation for Java Servlet - Containers. - - *) Feature: direct addressing of API configuration options containing - slashes "/" using URI encoding (%2F). - - *) Bugfix: segmentation fault might have occurred in Go applications - under high load. - - *) Bugfix: WebSocket support was broken if Unit was built with some - linkers other than GNU ld (e.g. gold or LLD). - - -Changes with Unit 1.10.0 22 Aug 2019 - - *) Change: matching of cookies in routes made case sensitive. - - *) Change: decreased log level of common errors when clients close - connections. - - *) Change: removed the Perl module's "--include=" ./configure option. - - *) Feature: built-in WebSocket server implementation for Node.js module. - - *) Feature: splitting PATH_INFO from request URI in PHP module. - - *) Feature: request routing by scheme (HTTP or HTTPS). - - *) Feature: support for multipart requests body in Java module. - - *) Feature: improved API compatibility with Node.js 11.10 or later. - - *) Bugfix: reconfiguration failed if "listeners" or "applications" - objects were missing. - - *) Bugfix: applying a large configuration might have failed. - - -Changes with Unit 1.9.0 30 May 2019 - - *) Feature: request routing by arguments, headers, and cookies. - - *) Feature: route matching patterns allow a wildcard in the middle. - - *) Feature: POST operation for appending elements to arrays in - configuration. - - *) Feature: support for changing credentials using CAP_SETUID and - CAP_SETGID capabilities on Linux without running main process as - privileged user. - - *) Bugfix: memory leak in the router process might have happened when a - client prematurely closed the connection. - - *) Bugfix: applying a large configuration might have failed. - - *) Bugfix: PUT and DELETE operations on array elements in configuration - did not work. - - *) Bugfix: request schema in applications did not reflect TLS - connections. - - *) Bugfix: restored compatibility with Node.js applications that use - ServerResponse._implicitHeader() function; the bug had appeared in - 1.7. - - *) Bugfix: various compatibility issues with Node.js applications. - - -Changes with Unit 1.8.0 01 Mar 2019 - - *) Change: now three numbers are always used for versioning: major, - minor, and patch versions. - - *) Change: now QUERY_STRING is always defined even if the request does - not include the query component. - - *) Feature: basic internal request routing by Host, URI, and method. - - *) Feature: experimental support for Java Servlet Containers. - - *) Bugfix: segmentation fault might have occurred in the router process. - - *) Bugfix: various potential memory leaks. - - *) Bugfix: TLS connections might have stalled. - - *) Bugfix: some Perl applications might have failed to send the response - body. - - *) Bugfix: some compilers with specific flags might have produced - non-functioning builds; the bug had appeared in 1.5. - - *) Bugfix: Node.js package had wrong version number when installed from - sources. - - -Changes with Unit 1.7.1 07 Feb 2019 - - *) Security: a heap memory buffer overflow might have been caused in the - router process by a specially crafted request, potentially resulting - in a segmentation fault or other unspecified behavior - (CVE-2019-7401). - - *) Bugfix: install of Go module failed without prior building of Unit - daemon; the bug had appeared in 1.7. - - -Changes with Unit 1.7 20 Dec 2018 - - *) Change: now rpath is set in Ruby module only if the library was not - found in default search paths; this allows to meet packaging - restrictions on some systems. - - *) Bugfix: "disable_functions" and "disable_classes" PHP options set via - Control API did not work. - - *) Bugfix: Promises on request data in Node.js were not triggered. - - *) Bugfix: various compatibility issues with Node.js applications. - - *) Bugfix: a segmentation fault occurred in Node.js module if - application tried to read request body after request.end() was - called. - - *) Bugfix: a segmentation fault occurred in Node.js module if - application attempted to send header twice. - - *) Bugfix: names of response header fields in Node.js module were - erroneously treated as case-sensitive. - - *) Bugfix: uncatched exceptions in Node.js were not logged. - - *) Bugfix: global install of Node.js module from sources was broken on - some systems; the bug had appeared in 1.6. - - *) Bugfix: traceback for exceptions during initialization of Python - applications might not be logged. - - *) Bugfix: PHP module build failed if PHP interpreter was built with - thread safety enabled. - - -Changes with Unit 1.6 15 Nov 2018 - - *) Change: "make install" now installs Node.js module as well if it was - configured. - - *) Feature: "--local" ./configure option to install Node.js module - locally. - - *) Bugfix: Node.js module might have crashed due to broken reference - counting. - - *) Bugfix: asynchronous operations in Node.js might not have worked. - - *) Bugfix: various compatibility issues with Node.js applications. - - *) Bugfix: "freed pointer is out of pool" alerts might have appeared in - log. - - *) Bugfix: module discovery did not work on 64-bit big-endian systems - like IBM/S390x. - - -Changes with Unit 1.5 25 Oct 2018 - - *) Change: the "type" of application object for Go was changed to - "external". - - *) Feature: initial version of Node.js package with basic HTTP - request-response support. - - *) Feature: compatibility with LibreSSL. - - *) Feature: --libdir and --incdir ./configure options to install libunit - headers and static library. - - *) Bugfix: connection might be closed prematurely while sending - response; the bug had appeared in 1.3. - - *) Bugfix: application processes might have stopped handling requests, - producing "last message send failed: Resource temporarily - unavailable" alerts in log; the bug had appeared in 1.4. - - *) Bugfix: Go applications did not work when Unit was built with musl C - library. - - -Changes with Unit 1.4 20 Sep 2018 - - *) Change: the control API maps the configuration object only at - "/config/". - - *) Feature: TLS support for client connections. - - *) Feature: TLS certificates storage control API. - - *) Feature: Unit library (libunit) to streamline language module - integration. - - *) Feature: "408 Request Timeout" responses while closing HTTP - keep-alive connections. - - *) Feature: improvements in OpenBSD support. Thanks to David Carlier. - - *) Bugfix: a segmentation fault might have occurred after - reconfiguration. - - *) Bugfix: building on systems with non-default locale might be broken. - - *) Bugfix: "header_read_timeout" might not work properly. - - *) Bugfix: header fields values with non-ASCII bytes might be handled - incorrectly in Python 3 module. - - -Changes with Unit 1.3 13 Jul 2018 - - *) Change: UTF-8 characters are now allowed in request header field - values. - - *) Feature: configuration of the request body size limit. - - *) Feature: configuration of various HTTP connection timeouts. - - *) Feature: Ruby module now automatically uses Bundler where possible. - - *) Feature: http.Flusher interface in Go module. - - *) Bugfix: various issues in HTTP connection errors handling. - - *) Bugfix: requests with body data might be handled incorrectly in PHP - module. - - *) Bugfix: individual PHP configuration options specified via control - API were reset to previous values after the first request in - application process. - - -Changes with Unit 1.2 07 Jun 2018 - - *) Feature: configuration of environment variables for application - processes. - - *) Feature: customization of php.ini path. - - *) Feature: setting of individual PHP configuration options. - - *) Feature: configuration of execution arguments for Go applications. - - *) Bugfix: keep-alive connections might hang after reconfiguration. - - -Changes with Unit 1.1 26 Apr 2018 - - *) Bugfix: Python applications that use the write() callable did not - work. - - *) Bugfix: virtual environments created with Python 3.3 or above might - not have worked. - - *) Bugfix: the request.Read() function in Go applications did not - produce EOF when the whole body was read. - - *) Bugfix: a segmentation fault might have occurred while access log - reopening. - - *) Bugfix: in parsing of IPv6 control socket addresses. - - *) Bugfix: loading of application modules was broken on OpenBSD. - - *) Bugfix: a segmentation fault might have occurred when there were two - modules with the same type and version; the bug had appeared in 1.0. - - *) Bugfix: alerts "freed pointer points to non-freeble page" might have - appeared in log on 32-bit platforms. - - -Changes with Unit 1.0 12 Apr 2018 - - *) Change: configuration object moved into "/config/" path. - - *) Feature: basic access logging. - - *) Bugfix: 503 error occurred if Go application did not write response - header or body. - - *) Bugfix: Ruby applications that use encoding conversions might not - have worked. - - *) Bugfix: various stability issues. - - -Changes with Unit 0.7 22 Mar 2018 - - *) Feature: Ruby application module. - - *) Bugfix: in discovering modules. - - *) Bugfix: various race conditions on reconfiguration and during - shutting down. - - *) Bugfix: tabs and trailing spaces were not allowed in header fields - values. - - *) Bugfix: a segmentation fault occurred in Python module if - start_response() was called outside of WSGI callable. - - *) Bugfix: a segmentation fault might have occurred in PHP module if - there was an error while initialization. - - -Changes with Unit 0.6 09 Feb 2018 - - *) Bugfix: the main process died when the "type" application option - contained version; the bug had appeared in 0.5. - - -Changes with Unit 0.5 08 Feb 2018 - - *) Change: the "workers" application option was removed, the "processes" - application option should be used instead. - - *) Feature: the "processes" application option with prefork and dynamic - process management support. - - *) Feature: Perl application module. - - *) Bugfix: in reading client request body; the bug had appeared in 0.3. - - *) Bugfix: some Python applications might not have worked due to missing - "wsgi.errors" environ variable. - - *) Bugfix: HTTP chunked responses might be encoded incorrectly on 32-bit - platforms. - - *) Bugfix: infinite looping in HTTP parser. - - *) Bugfix: segmentation fault in router. - - -Changes with Unit 0.4 15 Jan 2018 - - *) Feature: compatibility with DragonFly BSD. - - *) Feature: "configure php --lib-static" option. - - *) Bugfix: HTTP request body was not passed to application; the bug had - appeared in 0.3. - - *) Bugfix: HTTP large header buffers allocation and deallocation fixed; - the bug had appeared in 0.3. - - *) Bugfix: some PHP applications might not have worked with relative - "root" path. - - -Changes with Unit 0.3 28 Dec 2017 - - *) Change: the Go package name changed to "nginx/unit". - - *) Change: in the "limits.timeout" application option: application start - time and time in queue now are not accounted. - - *) Feature: the "limits.requests" application option. - - *) Feature: application request processing latency optimization. - - *) Feature: HTTP keep-alive connections support. - - *) Feature: the "home" Python virtual environment configuration option. - - *) Feature: Python atexit hook support. - - *) Feature: various Go package improvements. - - *) Bugfix: various crashes fixed. - - -Changes with Unit 0.2 19 Oct 2017 - - *) Feature: configuration persistence. - - *) Feature: improved handling of configuration errors. - - *) Feature: application "timeout" property. - - *) Bugfix: POST request for PHP were handled incorrectly. - - *) Bugfix: the router exited abnormally if all listeners had been - deleted. - - *) Bugfix: the router crashed under load. - - *) Bugfix: memory leak in the router. - - -Changes with Unit 0.1 06 Sep 2017 - - *) First public release. - diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index aea287f6..00000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,74 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or - advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic - address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the moderation team at nginx-oss-community@f5.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4, -available at - -For answers to common questions about this code of conduct, see - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 77343271..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,90 +0,0 @@ -# Contributing Guidelines - -The following is a set of guidelines for contributing to NGINX Unit. We do -appreciate that you are considering contributing! - -## Table Of Contents - -- [Getting Started](#getting-started) -- [Ask a Question](#ask-a-question) -- [Contributing](#contributing) -- [Git Style Guide](#git-style-guide) - - -## Getting Started - -Check out the [Quick Installation](README.md#quick-installation) and -[Howto](https://unit.nginx.org/howto/) guides to get NGINX Unit up and running. - - -## Ask a Question - -Please open an [issue](https://github.com/nginx/unit/issues/new) on GitHub with -the label `question`. You can also ask a question on -[GitHub Discussions](https://github.com/nginx/unit/discussions) or the NGINX Unit mailing list, -unit@nginx.org (subscribe -[here](https://mailman.nginx.org/mailman3/lists/unit.nginx.org/)). - - -## Contributing - -### Report a Bug - -Ensure the bug was not already reported by searching on GitHub under -[Issues](https://github.com/nginx/unit/issues). - -If the bug is a potential security vulnerability, please report using our -[security policy](https://unit.nginx.org/troubleshooting/#getting-support). - -To report a non-security bug, open an -[issue](https://github.com/nginx/unit/issues/new) on GitHub with the label -`bug`. Be sure to include a title and clear description, as much relevant -information as possible, and a code sample or an executable test case showing -the expected behavior that doesn't occur. - - -### Suggest an Enhancement - -To suggest an enhancement, open an -[issue](https://github.com/nginx/unit/issues/new) on GitHub with the label -`enhancement`. Please do this before implementing a new feature to discuss the -feature first. - - -### Open a Pull Request - -Before submitting a PR, please read the NGINX Unit code guidelines to know more -about coding conventions and benchmarks. Fork the repo, create a branch, and -submit a PR when your changes are tested and ready for review. Again, if you'd -like to implement a new feature, please consider creating a feature request -issue first to start a discussion about the feature. - - -## Git Style Guide - -- Keep a clean, concise and meaningful `git commit` history on your branch, - rebasing locally and squashing before submitting a PR - -- For any user-visible changes, updates, and bugfixes, add a note to - `docs/changes.xml` under the section for the upcoming release, using `` for new functionality, `` for changed - behavior, and `` for bug fixes. - -- In the subject line, use the past tense ("Added feature", not "Add feature"); - also, use past tense to describe past scenarios, and present tense for - current behavior - -- Limit the subject line to 67 characters, and the rest of the commit message - to 80 characters - -- Use subject line prefixes for commits that affect a specific portion of the - code; examples include "Tests:", "Packages:", or "Docker:", and also - individual languages such as "Java:" or "Ruby:" - -- Reference issues and PRs liberally after the subject line; if the commit - remedies a GitHub issue, [name - it](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) - accordingly - -- Don't rely on command-line commit messages with `-m`; use the editor instead - diff --git a/pkg/docker/Dockerfile.python3.10 b/Dockerfile.python3.10 similarity index 100% rename from pkg/docker/Dockerfile.python3.10 rename to Dockerfile.python3.10 diff --git a/pkg/docker/Dockerfile.python3.11 b/Dockerfile.python3.11 similarity index 100% rename from pkg/docker/Dockerfile.python3.11 rename to Dockerfile.python3.11 diff --git a/pkg/docker/Dockerfile.python3.12 b/Dockerfile.python3.12 similarity index 100% rename from pkg/docker/Dockerfile.python3.12 rename to Dockerfile.python3.12 diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e454a525..00000000 --- a/LICENSE +++ /dev/null @@ -1,178 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - diff --git a/NOTICE b/NOTICE deleted file mode 100644 index 257f478c..00000000 --- a/NOTICE +++ /dev/null @@ -1,37 +0,0 @@ - - NGINX Unit. - - Copyright 2017-2024 NGINX, Inc. - Copyright 2017-2024 Andrei Zeliankou - Copyright 2018-2024 Konstantin Pavlov - Copyright 2021-2024 Zhidao Hong - Copyright 2022-2024 Andrew Clayton - Copyright 2022-2024 Liam Crilly - Copyright 2023-2024 Dan Callahan - Copyright 2023-2024 Danielle De Leo - Copyright 2023-2024 Dylan Arbour - Copyright 2023-2024 Gabor Javorszky - Copyright 2023-2024 Igor Ippolitov - Copyright 2023-2024 Taryn Musgrave - Copyright 2021-2023 Alejandro Colomar - Copyright 2017-2022 Valentin V. Bartenev - Copyright 2017-2022 Max Romanov - Copyright 2021-2022 Oisín Canty - Copyright 2017-2021 Igor Sysoev - Copyright 2017-2021 Andrei Belov - Copyright 2019-2021 Tiago Natel de Moura - Copyright 2019-2020 Axel Duch - Copyright 2018-2019 Alexander Borisov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/README.md b/README.md deleted file mode 100644 index 4e230767..00000000 --- a/README.md +++ /dev/null @@ -1,198 +0,0 @@ -# NGINX Unit - -## Universal Web App Server - -![NGINX Unit Logo](docs/unitlogo.svg) - -NGINX Unit is a lightweight and versatile open-source server that has -two primary capabilities: - -- serves static media assets, -- runs application code in seven languages. - -Unit compresses several layers of the modern application stack into a potent, -coherent solution with a focus on performance, low latency, and scalability. It -is intended as a universal building block for any web architecture regardless -of its complexity, from enterprise-scale deployments to your pet's homepage. - -Its native [RESTful JSON API](#openapi-specification) enables dynamic -updates with zero interruptions and flexible configuration, while its -out-of-the-box productivity reliably scales to production-grade workloads. We -achieve that with a complex, asynchronous, multithreading architecture -comprising multiple processes to ensure security and robustness while getting -the most out of today's computing platforms. - - -## Quick Installation - -### macOS - -``` console -$ brew install nginx/unit/unit -``` - -For details and available language packages, see the -[docs](https://unit.nginx.org/installation/#homebrew). - - -### Docker - -``` console -$ docker pull unit -``` - -For a description of image tags, see the -[docs](https://unit.nginx.org/installation/#docker-images). - - -### Amazon Linux, Fedora, Red Hat - -``` console -$ wget https://raw.githubusercontent.com/nginx/unit/master/tools/setup-unit && chmod +x setup-unit -# ./setup-unit repo-config && yum install unit -# ./setup-unit welcome -``` - -For details and available language packages, see the -[docs](https://unit.nginx.org/installation/#official-packages). - - -### Debian, Ubuntu - -``` console -$ wget https://raw.githubusercontent.com/nginx/unit/master/tools/setup-unit && chmod +x setup-unit -# ./setup-unit repo-config && apt install unit -# ./setup-unit welcome -``` - -For details and available language packages, see the -[docs](https://unit.nginx.org/installation/#official-packages). - - -## Running a Hello World App - -Unit runs apps in a -[variety of languages](https://unit.nginx.org/howto/samples/). -Let's consider a basic example, -choosing PHP for no particular reason. - -Suppose you saved a PHP script as `/www/helloworld/index.php`: -``` php - -``` - -To run it on Unit with the `unit-php` module installed, first set up an -application object. Let's store our first config snippet in a file called -`config.json`: - -``` json -{ - "helloworld": { - "type": "php", - "root": "/www/helloworld/" - } -} -``` - -Saving it as a file isn't necessary, but can come in handy with larger objects. - -Now, `PUT` it into the `/config/applications` section of Unit's control API, -usually available by default via a Unix domain socket: - -``` console -# curl -X PUT --data-binary @config.json --unix-socket \ - /path/to/control.unit.sock http://localhost/config/applications -``` -``` json - -{ - "success": "Reconfiguration done." -} -``` - -Next, reference the app from a listener object in the `/config/listeners` -section of the API. This time, we pass the config snippet straight from the -command line: - -``` console -# curl -X PUT -d '{"127.0.0.1:8080": {"pass": "applications/helloworld"}}' \ - --unix-socket /path/to/control.unit.sock http://localhost/config/listeners -``` -``` json -{ - "success": "Reconfiguration done." -} -``` - -Now Unit accepts requests at the specified IP and port, passing them to the -application process. Your app works! - -``` console -$ curl 127.0.0.1:8080 - - Hello, PHP on Unit! -``` - -Finally, query the entire `/config` section of the control API: - -``` console -# curl --unix-socket /path/to/control.unit.sock http://localhost/config/ -``` - -Unit's output should contain both snippets, neatly organized: - -``` json -{ - "listeners": { - "127.0.0.1:8080": { - "pass": "applications/helloworld" - } - }, - - "applications": { - "helloworld": { - "type": "php", - "root": "/www/helloworld/" - } - } -} -``` - -For full details of configuration management, see the -[docs](https://unit.nginx.org/configuration/#configuration-management). - -## OpenAPI Specification - -Our [OpenAPI specification](docs/unit-openapi.yaml) aims to simplify -configuring and integrating NGINX Unit deployments and provide an authoritative -source of knowledge about the control API. - -Although the specification is still in the early beta stage, it is a promising -step forward for the NGINX Unit community. While working on it, we kindly ask -you to experiment and provide feedback to help improve its functionality and -usability. - -## Community - -- The go-to place to start asking questions and share your thoughts is - [GitHub Discussions](https://github.com/nginx/unit/discussions). - -- Our [GitHub issues page](https://github.com/nginx/unit/issues) offers - space for a more technical discussion at your own pace. - -- The [project map](https://github.com/orgs/nginx/projects/1) on - GitHub sheds some light on our current work and plans for the future. - -- Our [official website](https://unit.nginx.org/) may provide answers - not easily found otherwise. - -- Get involved with the project by contributing! See the - [contributing guide](CONTRIBUTING.md) for details. - -- To reach the team directly, subscribe to the - [mailing list](https://mailman.nginx.org/mailman/listinfo/unit). - -- For security issues, [email us](security-alert@nginx.org), mentioning - NGINX Unit in the subject and following the [CVSS - v3.1](https://www.first.org/cvss/v3.1/specification-document) spec. - diff --git a/SECURITY.txt b/SECURITY.txt deleted file mode 100644 index 2d2ad2b1..00000000 --- a/SECURITY.txt +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN PGP SIGNED MESSAGE----- -Hash: SHA256 - -# -# Please report security issues as below, specifically -# mentioning NGINX Unit in the subject. -# -Canonical: https://unit.nginx.org/.well-known/security.txt -Contact: mailto:security-alert@nginx.org -Encryption: https://nginx.org/keys/maxim.key -Encryption: https://nginx.org/keys/sb.key -Encryption: https://nginx.org/keys/thresh.key -Expires: 2025-01-01T00:00:00.000Z -Policy: https://www.first.org/cvss/v3.1/specification-document -Preferred-Languages: en - ------BEGIN PGP SIGNATURE----- - -iQGzBAEBCAAdFiEEE8gqY7YDV2FW4wpOoOqYG2aw2WcFAmWdrbkACgkQoOqYG2aw -2WdAIQv/UpQXSYWboNMq9DnXZsMNdeCdAg8nv1PdNYfDzr21YavHsdP3upEg2NUX -M/9WiyO5HwV7FAWKQ8J6T0vg8EZITij5Dxhia4Z/h9QE6bXTH4rD/UViJ+/RTtwF -3WvaMNGUSlTQUNCRQ0QGTAb/jXUQCE8OwFz2UM0ZgqyUmIdkuxMEhsNd4AfAUS4A -OOhM6qfXXAulPNVFZ65Lx7NIner37OyNuzhyuQxIFsnbGagMEIvptkevNIMEy8WO -BeseYx/fp1gHdLTIUKl+nvKR7as5O+fFZSm/eG3VpkS6Fall54WX6zzalhZN7Pie -pze8YdbUukdMUV6wQ/pQH4e/QyEEI8RCk95cZE9mSfxygpbIfBypj66GTaOUC/2z -iTv2tX/DXiGQbSpkNLzwntVvuN5P9BebxmSKdspwfszccPzNhhCVQMkkhzvNVeQ6 -UTorp2O3xvi5fBIUWQU5xkrKqwAmZBYHMPDA97H9hiTmHkytd7YYkvPmJKNDksSa -ui3gNrJe -=yDJD ------END PGP SIGNATURE----- diff --git a/auto/atomic b/auto/atomic deleted file mode 100644 index f99adf7e..00000000 --- a/auto/atomic +++ /dev/null @@ -1,122 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# GCC 4.1+ builtin atomic operations. - -nxt_feature="GCC builtin atomic operations" -nxt_feature_name=NXT_HAVE_GCC_ATOMIC -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="int main(void) { - long n = 0; - - if (!__sync_bool_compare_and_swap(&n, 0, 3)) - return 1; - if (__sync_fetch_and_add(&n, 1) != 3) - return 1; - if (__sync_lock_test_and_set(&n, 5) != 4) - return 1; - if (n != 5) - return 1; - if (__sync_or_and_fetch(&n, 2) != 7) - return 1; - if (__sync_and_and_fetch(&n, 5) != 5) - return 1; - __sync_lock_release(&n); - if (n != 0) - return 1; - return 0; - }" -. auto/feature - - -# Solaris 10 builtin atomic operations. - -if [ $nxt_found = no ]; then - - nxt_feature="Solaris builtin atomic operations" - nxt_feature_name=NXT_HAVE_SOLARIS_ATOMIC - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - - int main(void) { - ulong_t n = 0; - - if (atomic_cas_ulong(&n, 0, 3) != 0) - return 1; - if (atomic_add_long_nv(&n, 1) != 4) - return 1; - if (atomic_swap_ulong(&n, 5) != 4) - return 1; - if (n != 5) - return 1; - if (atomic_or_ulong_nv(&n, 2) != 7) - return 1; - if (atomic_and_ulong_nv(&n, 5) != 5) - return 1; - return 0; - }" - . auto/feature -fi - - -# AIX xlC builtin atomic operations. - -if [ $nxt_found = no ]; then - - if [ $NXT_64BIT = 1 ]; then - nxt_feature_test="int main(void) { - long n = 0; - long o = 0; - - if (!__compare_and_swaplp(&n, &o, 3)) - return 1; - if (__fetch_and_addlp(&n, 1) != 3) - return 1; - if (__fetch_and_swaplp(&n, 5) != 4) - return 1; - if (n != 5) - return 1; - __isync(); - __lwsync(); - return 0; - }" - else - nxt_feature_test="int main(void) { - int n = 0; - int o = 0; - - if (!__compare_and_swap(&n, &o, 3)) - return 1; - if (__fetch_and_add(&n, 1) != 3) - return 1; - if (__fetch_and_swap(&n, 5) != 4) - return 1; - if (n != 5) - return 1; - __isync(); - __lwsync(); - return 0; - }" - fi - - nxt_feature="xlC builtin atomic operations" - nxt_feature_name=NXT_HAVE_XLC_ATOMIC - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs= - . auto/feature -fi - - -if [ $nxt_found = no ]; then - $echo - $echo $0: error: no atomic operations found. - $echo - exit 1; -fi diff --git a/auto/capability b/auto/capability deleted file mode 100644 index c0410b34..00000000 --- a/auto/capability +++ /dev/null @@ -1,19 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - -# Linux capability - -nxt_feature="Linux capability" -nxt_feature_name=NXT_HAVE_LINUX_CAPABILITY -nxt_feature_test="#include - #include - #include - - int main(void) { - struct __user_cap_header_struct hdr; - hdr.version = _LINUX_CAPABILITY_VERSION; - syscall(SYS_capget, &hdr, 0); - return 0; - }" -. auto/feature diff --git a/auto/cc/deps b/auto/cc/deps deleted file mode 100644 index 11429788..00000000 --- a/auto/cc/deps +++ /dev/null @@ -1,25 +0,0 @@ - -case "$NXT_CC_NAME" in - - SunC): - nxt_gen_dep_flags() { - $echo "-xMMD -xMF $NXT_BUILD_DIR/$nxt_dep.tmp" - } - - nxt_gen_dep_post() { - $echo -n "@sed -e 's#^.*:#$NXT_BUILD_DIR/$nxt_obj:#' " - $echo -n "$NXT_BUILD_DIR/$nxt_dep.tmp > $NXT_BUILD_DIR/$nxt_dep" - $echo " && rm -f $NXT_BUILD_DIR/$nxt_dep.tmp" - } - ;; - - *) - nxt_gen_dep_flags() { - $echo "-MMD -MF $NXT_BUILD_DIR/$nxt_dep -MT $NXT_BUILD_DIR/$nxt_obj" - } - - nxt_gen_dep_post() { - $echo "" - } - ;; -esac diff --git a/auto/cc/test b/auto/cc/test deleted file mode 100644 index 9c9602db..00000000 --- a/auto/cc/test +++ /dev/null @@ -1,209 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -$echo checking for C compiler: $CC -cat << END >> $NXT_AUTOCONF_ERR ----------------------------------------- -checking for C compiler: $CC -END - - -# Allow error exit status. -set +e - -if [ -z `which $CC` ]; then - $echo - $echo $0: error: $CC not found. - $echo - exit 1; -fi - - -if `/bin/sh -c "($CC -v)" 2>&1 | grep "gcc version" >> $NXT_AUTOCONF_ERR 2>&1` -then - NXT_CC_NAME=gcc - $echo " + using GNU C compiler" - NXT_CC_VERSION=`/bin/sh -c "($CC -v)" 2>&1 | grep "gcc version" 2>&1` - $echo " + $NXT_CC_VERSION" - -else -if `/bin/sh -c "($CC -v)" 2>&1 | grep "clang version" >> $NXT_AUTOCONF_ERR 2>&1` -then - NXT_CC_NAME=clang - $echo " + using Clang C compiler" - NXT_CC_VERSION=`/bin/sh -c "($CC -v)" 2>&1 | grep "clang version" 2>&1` - $echo " + $NXT_CC_VERSION" - -else -if `/bin/sh -c "($CC -v)" 2>&1 \ - | grep "Apple LLVM version" >> $NXT_AUTOCONF_ERR 2>&1` -then - NXT_CC_NAME=clang - $echo " + using Clang C compiler" - NXT_CC_VERSION=`/bin/sh -c "($CC -v)" 2>&1 | grep "Apple LLVM version" 2>&1` - $echo " + $NXT_CC_VERSION" - -else -if `/bin/sh -c "($CC -V)" 2>&1 | grep "Sun C" >> $NXT_AUTOCONF_ERR 2>&1` -then - NXT_CC_NAME=SunC - $echo " + using Sun C compiler" - NXT_CC_VERSION=`/bin/sh -c "($CC -V)" 2>&1 | grep "Sun C" 2>&1` - $echo " + $NXT_CC_VERSION" - -else -if `/bin/sh -c "($CC -qversion)" 2>&1 \ - | grep "^IBM XL" >> $NXT_AUTOCONF_ERR 2>&1` -then - NXT_CC_NAME=xlC - $echo " + using AIX xlC compiler" - NXT_CC_VERSION=`/bin/sh -c "($CC -qversion)" 2>&1 | grep "IBM XL" 2>&1` - $echo " + $NXT_CC_VERSION" - -else -if `/bin/sh -c "($CC -V)" 2>&1 | grep "Intel(R) C" >> $NXT_AUTOCONF_ERR 2>&1` -then - NXT_CC_NAME=ICC - $echo " + using Intel C++ compiler" - NXT_CC_VERSION=ICC - -else -if `/bin/sh -c "($CC -v)" 2>&1 \ - | grep "Microsoft (R) 32-bit C/C" >> $NXT_AUTOCONF_ERR 2>&1` -then - NXT_CC_NAME=MSVC - $echo " + using MS Visual C++ compiler" - NXT_CC_VERSION=MSVC - -else - NXT_CC_NAME=cc - NXT_CC_VERSION=cc - -fi # MSVC -fi # ICC -fi # xlC -fi # SunC -fi # Apple LLVM clang -fi # clang -fi # gcc - - -case $NXT_CC_NAME in - - gcc) - nxt_have=NXT_GCC . auto/have - - NXT_CFLAGS="$NXT_CFLAGS -pipe" - NXT_CFLAGS="$NXT_CFLAGS -fPIC" - - # Do not export symbols except explicitly marked with NXT_EXPORT. - NXT_CFLAGS="$NXT_CFLAGS -fvisibility=hidden" - - # c99/gnu99 conflict with Solaris XOPEN. - #NXT_CFLAGS="$NXT_CFLAGS -std=gnu99" - - NXT_CFLAGS="$NXT_CFLAGS -O" - #NXT_CFLAGS="$NXT_CFLAGS -O0" - NXT_CFLAGS="$NXT_CFLAGS -W -Wall -Wextra" - - #NXT_CFLAGS="$NXT_CFLAGS -Wunused-result" - NXT_CFLAGS="$NXT_CFLAGS -Wno-unused-parameter" - #NXT_CFLAGS="$NXT_CFLAGS -Wshorten-64-to-32" - NXT_CFLAGS="$NXT_CFLAGS -Wwrite-strings" - - # -O2 enables -fstrict-aliasing and -fstrict-overflow. - #NXT_CFLAGS="$NXT_CFLAGS -O2" - #NXT_CFLAGS="$NXT_CFLAGS -Wno-strict-aliasing" - - #NXT_CFLAGS="$NXT_CFLAGS -fomit-frame-pointer" - #NXT_CFLAGS="$NXT_CFLAGS -momit-leaf-frame-pointer" - - # -Wstrict-overflow is supported by GCC 4.2+. - #NXT_CFLAGS="$NXT_CFLAGS -Wstrict-overflow=5" - - NXT_CFLAGS="$NXT_CFLAGS -Wmissing-prototypes" - - # Stop on warning. - NXT_CFLAGS="$NXT_CFLAGS -Werror" - - # Debug. - NXT_CFLAGS="$NXT_CFLAGS -g" - ;; - - clang) - nxt_have=NXT_CLANG . auto/have - - NXT_CFLAGS="$NXT_CFLAGS -pipe" - NXT_CFLAGS="$NXT_CFLAGS -fPIC" - - # Do not export symbols except explicitly marked with NXT_EXPORT. - NXT_CFLAGS="$NXT_CFLAGS -fvisibility=hidden" - - NXT_CFLAGS="$NXT_CFLAGS -O" - #NXT_CFLAGS="$NXT_CFLAGS -O0" - NXT_CFLAGS="$NXT_CFLAGS -W -Wall -Wextra" - - #NXT_CFLAGS="$NXT_CFLAGS -Wunused-result" - NXT_CFLAGS="$NXT_CFLAGS -Wno-unused-parameter" - #NXT_CFLAGS="$NXT_CFLAGS -Wshorten-64-to-32" - NXT_CFLAGS="$NXT_CFLAGS -Wwrite-strings" - #NXT_CFLAGS="$NXT_CFLAGS -O2" - #NXT_CFLAGS="$NXT_CFLAGS -fomit-frame-pointer" - NXT_CFLAGS="$NXT_CFLAGS -fstrict-aliasing" - NXT_CFLAGS="$NXT_CFLAGS -Wstrict-overflow=5" - - NXT_CFLAGS="$NXT_CFLAGS -Wmissing-prototypes" - - # Stop on warning. - NXT_CFLAGS="$NXT_CFLAGS -Werror" - - # Debug. - - if [ "$NXT_SYSTEM_PLATFORM" != "powerpc" ]; then - # "-g" flag causes the "unknown pseudo-op: `.cfi_sections'" - # error on PowerPC Clang. - NXT_CFLAGS="$NXT_CFLAGS -g" - fi - ;; - - SunC) - nxt_have=NXT_SUNC . auto/have - - NXT_CFLAGS="$NXT_CFLAGS -fPIC" - # Optimization. - NXT_CFLAGS="$NXT_CFLAGS -O -fast" - # Stop on warning. - NXT_CFLAGS="$NXT_CFLAGS -errwarn=%all" - # Debug. - NXT_CFLAGS="$NXT_CFLAGS -g" - ;; - - xlC) - nxt_have=NXT_XLC . auto/have - - #NXT_CFLAGS="$NXT_CFLAGS -qalloca" - # alloca support. - NXT_CFLAGS="$NXT_CFLAGS -qlanglvl=extc99" - # __thread support. - NXT_CFLAGS="$NXT_CFLAGS -qtls" - # Suppress warning - # 1506-159 (E) Bit field type specified for XXX is not valid. - # Type unsigned assumed. - NXT_CFLAGS="$NXT_CFLAGS -qsuppress=1506-159" - ;; - - ICC) - ;; - - MSVC) - ;; - - *) - ;; - -esac - -# Stop on error exit status again. -set -e diff --git a/auto/cgroup b/auto/cgroup deleted file mode 100644 index 2262b2ef..00000000 --- a/auto/cgroup +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) Andrew Clayton -# Copyright (C) F5, Inc. - -NXT_HAVE_CGROUP=NO - -if [ -f "/proc/mounts" ]; then - CGROUP=$(grep cgroup2 /proc/mounts | head -n 1 | cut -d " " -f 2) - - if [ "$CGROUP" ]; then - NXT_HAVE_CGROUP=YES - - cat << END >> $NXT_AUTO_CONFIG_H - -#ifndef NXT_HAVE_CGROUP -#define NXT_HAVE_CGROUP 1 -#define NXT_CGROUP_ROOT "$CGROUP" -#endif - -END - - fi -fi diff --git a/auto/clang b/auto/clang deleted file mode 100644 index 975a6468..00000000 --- a/auto/clang +++ /dev/null @@ -1,196 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# C language features. - - -nxt_feature="C99 variadic macro" -nxt_feature_name=NXT_HAVE_C99_VARIADIC_MACRO -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #define set(dummy, ...) sprintf(__VA_ARGS__) - - int main(void) { - char buf[4]; - - buf[0] = '0'; - set(0, buf, \"%d\", 1); - - if (buf[0] == '1') - return 0; - return 1; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - nxt_feature="GCC variadic macro" - nxt_feature_name=NXT_HAVE_GCC_VARIADIC_MACRO - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - #define set(dummy, args...) sprintf(args) - - int main(void) { - char buf[4]; - - buf[0] = '0'; - set(0, buf, \"%d\", 1); - - if (buf[0] == '1') - return 0; - return 1; - }" - . auto/feature -fi - - -nxt_feature="GCC __builtin_expect()" -nxt_feature_name=NXT_HAVE_BUILTIN_EXPECT -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="int main(int argc, char *const *argv) { - if ((__typeof__(argc == 0)) - __builtin_expect((argc == 0), 0)) - return 0; - return 1; - }" -. auto/feature - - -nxt_feature="GCC __builtin_unreachable()" -nxt_feature_name=NXT_HAVE_BUILTIN_UNREACHABLE -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="int main(void) { - __builtin_unreachable(); - }" -. auto/feature - - -nxt_feature="GCC __builtin_prefetch()" -nxt_feature_name=NXT_HAVE_BUILTIN_PREFETCH -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="int main(void) { - __builtin_prefetch(0); - return 0; - }" -. auto/feature - - -nxt_feature="GCC __builtin_clz()" -nxt_feature_name=NXT_HAVE_BUILTIN_CLZ -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="int main(void) { - if (__builtin_clz(1) == 31) - return 0; - return 1; - }" -. auto/feature - - -nxt_feature="GCC __builtin_popcount()" -nxt_feature_name=NXT_HAVE_BUILTIN_POPCOUNT -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="int main(void) { - if (__builtin_popcount(5) == 2) - return 0; - return 1; - }" -. auto/feature - - -nxt_feature="GCC __attribute__ visibility" -nxt_feature_name=NXT_HAVE_GCC_ATTRIBUTE_VISIBILITY -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="int n __attribute__ ((visibility(\"default\"))); - - int main(void) { - return 1; - }" -. auto/feature - - -nxt_feature="GCC __attribute__ aligned" -nxt_feature_name=NXT_HAVE_GCC_ATTRIBUTE_ALIGNED -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="int n __attribute__ ((aligned(64))); - - int main(void) { - return 1; - }" -. auto/feature - - -nxt_feature="GCC __attribute__ malloc" -nxt_feature_name=NXT_HAVE_GCC_ATTRIBUTE_MALLOC -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - void *f(void) __attribute__ ((__malloc__)); - - void *f(void) { - return malloc(1); - } - - int main(void) { - if (f() != NULL) { - return 1; - } - return 0; - }" -. auto/feature - - -nxt_feature="GCC __attribute__ packed" -nxt_feature_name=NXT_HAVE_GCC_ATTRIBUTE_PACKED -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="struct s { - char c; - int i; - } __attribute__ ((__packed__)); - - int main(void) { - return 1; - }" -. auto/feature - - -nxt_feature="GCC __attribute__ unused" -nxt_feature_name=NXT_HAVE_GCC_ATTRIBUTE_UNUSED -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="static void f(void) __attribute__ ((__unused__)); - - static void f(void) - { - return; - } - - int main(void) { - return 0; - }" -. auto/feature diff --git a/auto/echo/Makefile b/auto/echo/Makefile deleted file mode 100644 index 28a519c3..00000000 --- a/auto/echo/Makefile +++ /dev/null @@ -1,3 +0,0 @@ - -echo.exe: echo.c - mingw32-gcc -o echo.exe -O2 echo.c diff --git a/auto/echo/build b/auto/echo/build deleted file mode 100644 index b2396cd0..00000000 --- a/auto/echo/build +++ /dev/null @@ -1,27 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -$echo 'building an "echo" program' - -rm -f $NXT_BUILD_DIR/bin/echo - -nxt_echo_test="$CC -o $NXT_BUILD_DIR/bin/echo -O $NXT_CC_OPT - auto/echo/echo.c $NXT_LD_OPT" - -# "|| true" is to bypass "set -e" setting. -nxt_echo_err=`$nxt_echo_test 2>&1 || true` - -if [ ! -x $NXT_BUILD_DIR/bin/echo ]; then - $echo - $echo $0: error: cannot build an \"echo\" program: - $echo - $echo $nxt_echo_test - $echo - $echo $nxt_echo_err - $echo - exit 1 -fi - -echo=$NXT_BUILD_DIR/bin/echo diff --git a/auto/echo/echo.c b/auto/echo/echo.c deleted file mode 100644 index 937483af..00000000 --- a/auto/echo/echo.c +++ /dev/null @@ -1,43 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - * - * A portable "echo" program that supports "-n" option: - * echo Hello world! - * echo "Hello world!" - * echo -n Hello world! - * echo - * - * It also passes "\c" characters as is. - */ - - -#include -#include - - -int -main(int argc, char *const *argv) -{ - int i = 1; - int nl = 1; - - if (argc > 1) { - if (strcmp(argv[1], "-n") == 0) { - nl = 0; - i++; - } - - while (i < argc) { - printf("%s%s", argv[i], (i == argc - 1) ? "" : " "); - i++; - } - } - - if (nl) { - printf("\n"); - } - - return 0; -} diff --git a/auto/endian b/auto/endian deleted file mode 100644 index 40b5ad28..00000000 --- a/auto/endian +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (C) Igor Sysoev -# Copyright (C) Andrew Clayton -# Copyright (C) NGINX, Inc. - - -nxt_feature="endianness" -nxt_feature_name= -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - int i = 0x11223344; - uint8_t *p; - - p = (uint8_t *)&i; - if (*p == 0x44) - printf(\"little endian\"); - else - printf(\"big endian\"); - return 0; - }" -. auto/feature - -if [ "$nxt_feature_value" = "little endian" ]; then - nxt_have=NXT_HAVE_LITTLE_ENDIAN . auto/have -else - nxt_have=NXT_HAVE_BIG_ENDIAN . auto/have -fi diff --git a/auto/events b/auto/events deleted file mode 100644 index 1ca6e7cd..00000000 --- a/auto/events +++ /dev/null @@ -1,196 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# Linux epoll. - -nxt_feature="Linux epoll" -nxt_feature_name=NXT_HAVE_EPOLL -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - int n; - - n = epoll_create(1); - close(n); - return 0; - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_HAVE_EPOLL=YES - - nxt_feature="Linux signalfd()" - nxt_feature_name=NXT_HAVE_SIGNALFD - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - #include - #include - - int main(void) { - int n; - sigset_t mask; - - sigemptyset(&mask); - n = signalfd(-1, &mask, 0); - close(n); - return 0; - }" - . auto/feature - - - nxt_feature="Linux eventfd()" - nxt_feature_name=NXT_HAVE_EVENTFD - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - #include - - int main(void) { - int n; - - n = eventfd(0, 0); - close(n); - return 0; - }" - . auto/feature - -else - NXT_HAVE_EPOLL=NO -fi - - -# FreeBSD, MacOSX, NetBSD, OpenBSD kqueue. - -nxt_feature="kqueue" -nxt_feature_name=NXT_HAVE_KQUEUE -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - - int main(void) { - int n; - - n = kqueue(); - close(n); - return 0; - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_HAVE_KQUEUE=YES - - nxt_feature="kqueue EVFILT_USER" - nxt_feature_name=NXT_HAVE_EVFILT_USER - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - #include - #include - - int main(void) { - struct kevent kev; - - kev.filter = EVFILT_USER; - kevent(0, &kev, 1, NULL, 0, NULL); - return 0; - }" - . auto/feature - -else - NXT_HAVE_KQUEUE=NO -fi - - -# Solaris event port. - -nxt_feature="Solaris event port" -nxt_feature_name=NXT_HAVE_EVENTPORT -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - int n; - - n = port_create(); - close(n); - return 0; - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_HAVE_EVENTPORT=YES -else - NXT_HAVE_EVENTPORT=NO -fi - - -# Solaris, HP-UX, IRIX, Tru64 UNIX /dev/poll. - -nxt_feature="/dev/poll" -nxt_feature_name=NXT_HAVE_DEVPOLL -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - #include - - int main(void) { - int n; - - n = open(\"/dev/poll\", O_RDWR); - close(n); - return 0; - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_HAVE_DEVPOLL=YES -else - NXT_HAVE_DEVPOLL=NO -fi - - -# AIX pollset. - -nxt_feature="AIX pollset" -nxt_feature_name=NXT_HAVE_POLLSET -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - #include - - int main(void) { - pollset_t n; - - n = pollset_create(-1); - pollset_destroy(n); - return 0; - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_HAVE_POLLSET=YES -else - NXT_HAVE_POLLSET=NO -fi diff --git a/auto/feature b/auto/feature deleted file mode 100644 index dc58054c..00000000 --- a/auto/feature +++ /dev/null @@ -1,116 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -$echo -n "checking for $nxt_feature ..." - -cat << END >> $NXT_AUTOCONF_ERR ----------------------------------------- -checking for $nxt_feature -END - - -nxt_found=no -nxt_feature_value= -nxt_feature_inc_path= - -if test -n "$nxt_feature_incs"; then - case "$nxt_feature_incs" in - -*) - nxt_feature_inc_path="$nxt_feature_incs" - ;; - - *) - for nxt_temp in $nxt_feature_incs; do - nxt_feature_inc_path="$nxt_feature_inc_path -I $nxt_temp" - done - ;; - esac -fi - - -cat << END > $NXT_AUTOTEST.c -$nxt_feature_test -END - - -nxt_test="$CC $CFLAGS $NXT_CFLAGS $NXT_CC_OPT $NXT_TEST_CFLAGS \ - $nxt_feature_inc_path -o $NXT_AUTOTEST $NXT_AUTOTEST.c \ - $nxt_feature_libs $NXT_LD_OPT $NXT_TEST_LIBS" - -# /bin/sh -c "(...)" is to intercept "Killed", "Abort trap", -# "Segmentation fault", or other shell messages. -# "|| true" is to bypass "set -e" setting. - -/bin/sh -c "($nxt_test || true)" >> $NXT_AUTOCONF_ERR 2>&1 - - -if [ -x $NXT_AUTOTEST ]; then - - case "$nxt_feature_run" in - - value) - if /bin/sh -c "($NXT_AUTOTEST)" >> $NXT_AUTOCONF_ERR 2>&1; then - $echo >> $NXT_AUTOCONF_ERR - nxt_found=yes - nxt_feature_value=`$NXT_AUTOTEST` - $echo " $nxt_feature_value" - if [ -n "$nxt_feature_name" ]; then - cat << END >> $NXT_AUTO_CONFIG_H - -#ifndef $nxt_feature_name -#define $nxt_feature_name $nxt_feature_value -#endif - -END - fi - else - $echo " not found" - fi - ;; - - yes) - if /bin/sh -c "($NXT_AUTOTEST)" >> $NXT_AUTOCONF_ERR 2>&1; then - $echo " found" - nxt_found=yes - if [ -n "$nxt_feature_name" ]; then - cat << END >> $NXT_AUTO_CONFIG_H - -#ifndef $nxt_feature_name -#define $nxt_feature_name 1 -#endif - -END - fi - else - $echo " found but is not working" - fi - ;; - - *) - $echo " found" - nxt_found=yes - if [ -n "$nxt_feature_name" ]; then - cat << END >> $NXT_AUTO_CONFIG_H - -#ifndef $nxt_feature_name -#define $nxt_feature_name 1 -#endif - -END - fi - ;; - esac - -else - $echo " not found" - - $echo "----------" >> $NXT_AUTOCONF_ERR - cat $NXT_AUTOTEST.c >> $NXT_AUTOCONF_ERR - $echo "----------" >> $NXT_AUTOCONF_ERR - $echo $nxt_test >> $NXT_AUTOCONF_ERR - $echo "----------" >> $NXT_AUTOCONF_ERR -fi - -rm -rf $NXT_AUTOTEST* diff --git a/auto/files b/auto/files deleted file mode 100644 index 1fa6ca28..00000000 --- a/auto/files +++ /dev/null @@ -1,83 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# Linux 2.6, FreeBSD 8.2, 9.1, Solaris 11. - -nxt_feature="posix_fadvise()" -nxt_feature_name=NXT_HAVE_POSIX_FADVISE -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - (void) posix_fadvise(0, 0, 0, POSIX_FADV_WILLNEED); - return 0; - }" -. auto/feature - - -# FreeBSD 8.0. - -nxt_feature="fcntl(F_READAHEAD)" -nxt_feature_name=NXT_HAVE_READAHEAD -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - (void) fcntl(0, F_READAHEAD, 1024); - return 0; - }" -. auto/feature - - -# MacOSX, FreeBSD 8.0. - -nxt_feature="fcntl(F_RDAHEAD)" -nxt_feature_name=NXT_HAVE_RDAHEAD -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - (void) fcntl(0, F_RDAHEAD, 1); - return 0; - }" -. auto/feature - - -nxt_feature="openat2()" -nxt_feature_name=NXT_HAVE_OPENAT2 -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - #include - #include - - int main(void) { - struct open_how how; - - memset(&how, 0, sizeof(how)); - - how.flags = O_RDONLY; - how.mode = O_NONBLOCK; - how.resolve = RESOLVE_IN_ROOT - | RESOLVE_NO_SYMLINKS - | RESOLVE_NO_XDEV; - - int fd = syscall(SYS_openat2, AT_FDCWD, \".\", - &how, sizeof(how)); - if (fd == -1) - return 1; - - return 0; - }" -. auto/feature diff --git a/auto/have b/auto/have deleted file mode 100644 index b10b8394..00000000 --- a/auto/have +++ /dev/null @@ -1,12 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -cat << END >> $NXT_AUTO_CONFIG_H - -#ifndef $nxt_have -#define $nxt_have 1 -#endif - -END diff --git a/auto/help b/auto/help deleted file mode 100644 index d23c67ed..00000000 --- a/auto/help +++ /dev/null @@ -1,87 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -cat << END - -./configure options: - - --cc=FILE set C compiler filename, default: "$CC" - --cc-opt=OPTIONS set additional C compiler options - --ld-opt=OPTIONS set additional linker options - - --prefix=DIR default: "/usr/local" - --exec-prefix=DIR default: "\$prefix" - --bindir=DIR default: "\$exec_prefix/bin" - --sbindir=DIR default: "\$exec_prefix/sbin" - --includedir=DIR default: "\$prefix/include" - --libdir=DIR default: "\$exec_prefix/lib" - --modulesdir=DIR default: "\$libdir/unit/modules" - --datarootdir=DIR default: "\$prefix/share" - --mandir=DIR default: "\$datarootdir/man" - --pkgconfigdir=DIR default: "\$datarootdir/pkgconfig" - --localstatedir=DIR default: "\$prefix/var" - --statedir=DIR default: "\$localstatedir/lib/unit" - --runstatedir=DIR default: "\$localstatedir/run/unit" - --logdir=DIR default: "\$localstatedir/log/unit" - --tmpdir=DIR default: "/tmp" - - --incdir=DIR [deprecated] synonym for --includedir - --modules=DIR [deprecated] synonym for --modulesdir - --state=DIR [deprecated] synonym for --statedir - --tmp=DIR [deprecated] synonym for --tmpdir - - --pid=FILE set pid filename, default: "\$runstatedir/unit.pid" - --log=FILE set log filename, default: "\$logdir/unit.log" - - --control=ADDRESS set address of control API socket - default: "unix:\$runstatedir/control.unit.sock" - - --user=USER set non-privileged processes to run as specified user - default: "$NXT_USER" - --group=GROUP set non-privileged processes to run as specified group - default: user's primary group - - --no-ipv6 disable IPv6 support - --no-unix-sockets disable Unix domain sockets support - --no-regex disable regular expression support - --no-pcre2 force using PCRE library - - --openssl enable OpenSSL library usage - - --njs enable NJS library usage - - --debug enable debug logging - - - python OPTIONS configure Python module - run "./configure python --help" to see available options - - php OPTIONS configure PHP module - run "./configure php --help" to see available options - - go OPTIONS configure Go module - run "./configure go --help" to see available options - - perl OPTIONS configure Perl module - run "./configure perl --help" to see available options - - ruby OPTIONS configure Ruby module - run "./configure ruby --help" to see available options - - nodejs OPTIONS configure Node.js module - run "./configure nodejs --help" to see available options - - java OPTIONS configure Java module - run "./configure java --help" to see available options - - wasm OPTIONS configure WebAssembly module - run "./configure wasm --help" to see available options - - wasm-wasi-component OPTIONS - configure WebAssembly Component Model module - run "./configure wasm-wasi-component --help" to see - available options - -END diff --git a/auto/isolation b/auto/isolation deleted file mode 100644 index c535e80a..00000000 --- a/auto/isolation +++ /dev/null @@ -1,200 +0,0 @@ -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - -# Linux clone syscall. - -NXT_ISOLATION=NO -NXT_HAVE_LINUX_NS=NO -NXT_HAVE_CLONE_NEWUSER=NO -NXT_HAVE_MOUNT=NO -NXT_HAVE_UNMOUNT=NO -NXT_HAVE_ROOTFS=NO - -nsflags="USER NS PID NET UTS CGROUP" - -nxt_feature="Linux unshare()" -nxt_feature_name=NXT_HAVE_LINUX_NS -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#define _GNU_SOURCE - #include - - int main(void) { - return unshare(0); - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_HAVE_LINUX_NS=YES - - # Test all isolation flags - for flag in $nsflags; do - nxt_feature="CLONE_NEW${flag}" - nxt_feature_name=NXT_HAVE_CLONE_NEW${flag} - nxt_feature_run=no - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#define _GNU_SOURCE - #include - #include - #include - - int main(void) { - return CLONE_NEW$flag; - }" - . auto/feature - - if [ $nxt_found = yes ]; then - if [ $flag = "USER" ]; then - NXT_HAVE_CLONE_NEWUSER=YES - fi - - if [ "$NXT_ISOLATION" = "NO" ]; then - NXT_ISOLATION=$flag - else - NXT_ISOLATION="$NXT_ISOLATION $flag" - fi - fi - done -fi - - -nxt_feature="Linux pivot_root()" -nxt_feature_name=NXT_HAVE_LINUX_PIVOT_ROOT -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #if !defined(__linux__) - # error - #endif - - int main(void) { - return SYS_pivot_root; - }" -. auto/feature - - -nxt_feature="" -nxt_feature_name=NXT_HAVE_MNTENT_H -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - return 0; - }" -. auto/feature - - -nxt_feature="prctl(PR_SET_NO_NEW_PRIVS)" -nxt_feature_name=NXT_HAVE_PR_SET_NO_NEW_PRIVS -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - return PR_SET_NO_NEW_PRIVS; - }" -. auto/feature - - -nxt_feature="prctl(PR_SET_CHILD_SUBREAPER)" -nxt_feature_name=NXT_HAVE_PR_SET_CHILD_SUBREAPER -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - return PR_SET_CHILD_SUBREAPER; - }" -. auto/feature - - -nxt_feature="Linux mount()" -nxt_feature_name=NXT_HAVE_LINUX_MOUNT -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - return mount(\"/\", \"/\", \"bind\", - MS_BIND | MS_REC, \"\"); - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_HAVE_MOUNT=YES -fi - - -if [ $nxt_found = no ]; then - nxt_feature="FreeBSD nmount()" - nxt_feature_name=NXT_HAVE_FREEBSD_NMOUNT - nxt_feature_run=no - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - - int main(void) { - return nmount((void *)0, 0, 0); - }" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_HAVE_MOUNT=YES - fi -fi - - -nxt_feature="Linux umount2()" -nxt_feature_name=NXT_HAVE_LINUX_UMOUNT2 -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - return umount2((void *)0, 0); - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_HAVE_UNMOUNT=YES -fi - -if [ $nxt_found = no ]; then - nxt_feature="unmount()" - nxt_feature_name=NXT_HAVE_UNMOUNT - nxt_feature_run=no - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - - int main(void) { - return unmount((void *)0, 0); - }" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_HAVE_UNMOUNT=YES - fi -fi - -if [ $NXT_HAVE_MOUNT = YES -a $NXT_HAVE_UNMOUNT = YES ]; then - NXT_HAVE_ROOTFS=YES - - cat << END >> $NXT_AUTO_CONFIG_H - -#ifndef NXT_HAVE_ISOLATION_ROOTFS -#define NXT_HAVE_ISOLATION_ROOTFS 1 -#endif - -END - -fi diff --git a/auto/make b/auto/make deleted file mode 100644 index abfd41ad..00000000 --- a/auto/make +++ /dev/null @@ -1,475 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Valentin V. Bartenev -# Copyright (C) NGINX, Inc. - -. auto/cc/deps - -$echo "creating $NXT_MAKEFILE" - - -cat << END > $NXT_MAKEFILE - -CC = $CC -AR = $AR - -CFLAGS = $NXT_CFLAGS $NXT_CC_OPT $CFLAGS - -NXT_EXEC_LINK = $NXT_EXEC_LINK $NXT_LD_OPT -NXT_SHARED_LOCAL_LINK = $NXT_SHARED_LOCAL_LINK $NXT_LD_OPT -NXT_MODULE_LINK = $NXT_MODULE_LINK - -all: $NXT_DAEMON manpage - -.PHONY: $NXT_DAEMON manpage -$NXT_DAEMON: $NXT_BUILD_DIR/sbin/$NXT_DAEMON -manpage: $NXT_BUILD_DIR/share/man/man8/unitd.8 - -END - - -# The include paths list. - -$echo -n "NXT_LIB_INCS =" >> $NXT_MAKEFILE - -for nxt_inc in src $NXT_BUILD_DIR/include -do - $echo -n " -I $nxt_inc" >> $NXT_MAKEFILE -done - -$echo >> $NXT_MAKEFILE -$echo >> $NXT_MAKEFILE - - -# Library object files list. - -$echo "NXT_LIB_OBJS = \\" >> $NXT_MAKEFILE - -for nxt_src in $NXT_LIB_SRCS -do - nxt_obj=${nxt_src%.c}.o - $echo " $NXT_BUILD_DIR/$nxt_obj \\" >> $NXT_MAKEFILE -done - -$echo >> $NXT_MAKEFILE - -$echo "NXT_LIB_UNIT_OBJS = \\" >> $NXT_MAKEFILE -$echo " $NXT_BUILD_DIR/src/nxt_lvlhsh.o \\" >> $NXT_MAKEFILE -$echo " $NXT_BUILD_DIR/src/nxt_murmur_hash.o \\" >> $NXT_MAKEFILE -$echo " $NXT_BUILD_DIR/src/nxt_socket_msg.o \\" >> $NXT_MAKEFILE -$echo " $NXT_BUILD_DIR/src/nxt_websocket.o \\" >> $NXT_MAKEFILE - -for nxt_src in $NXT_LIB_UNIT_SRCS -do - nxt_obj=${nxt_src%.c}.o - $echo " $NXT_BUILD_DIR/$nxt_obj \\" >> $NXT_MAKEFILE -done - -$echo >> $NXT_MAKEFILE - - -# The version file. - -cat << END >> $NXT_MAKEFILE - -include version - -$NXT_VERSION_H: version - $echo '#define NXT_VERSION "\$(NXT_VERSION)"' > $NXT_VERSION_H - $echo '#define NXT_VERNUM \$(NXT_VERNUM)' >> $NXT_VERSION_H - -END - - -# Shared and static library. - -cat << END >> $NXT_MAKEFILE - -libnxt: $NXT_BUILD_DIR/lib/$NXT_LIB_SHARED $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC - -$NXT_BUILD_DIR/lib/$NXT_LIB_SHARED: \$(NXT_LIB_OBJS) - \$(NXT_SHARED_LOCAL_LINK) -o \$@ \$(NXT_LIB_OBJS) \\ - $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS - -$NXT_BUILD_DIR/lib/$NXT_LIB_STATIC: \$(NXT_LIB_OBJS) - $NXT_STATIC_LINK \$@ \$(NXT_LIB_OBJS) - -$NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC: \$(NXT_LIB_UNIT_OBJS) \\ - $NXT_BUILD_DIR/share/pkgconfig/unit.pc \\ - $NXT_BUILD_DIR/share/pkgconfig/unit-uninstalled.pc - $NXT_STATIC_LINK \$@ \$(NXT_LIB_UNIT_OBJS) - -END - - -# Object files. - -for nxt_src in $NXT_LIB_SRCS $NXT_TEST_SRCS $NXT_LIB_UNIT_SRCS \ - src/test/nxt_unit_app_test.c \ - src/test/nxt_unit_websocket_chat.c \ - src/test/nxt_unit_websocket_echo.c -do - nxt_obj=${nxt_src%.c}.o - nxt_dep=${nxt_src%.c}.dep - nxt_dep_flags=`nxt_gen_dep_flags` - nxt_dep_post=`nxt_gen_dep_post` - cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/$nxt_obj: $nxt_src $NXT_VERSION_H - \$(CC) -c \$(CFLAGS) \$(NXT_LIB_INCS) $NXT_LIB_AUX_CFLAGS \\ - -o $NXT_BUILD_DIR/$nxt_obj \\ - $nxt_dep_flags \\ - $nxt_src - $nxt_dep_post - --include $NXT_BUILD_DIR/$nxt_dep - -END - -done - -nxt_src=src/test/nxt_cq_test.c -nxt_obj=src/test/nxt_ncq_test.o -nxt_dep=src/test/nxt_ncq_test.dep -nxt_dep_flags=`nxt_gen_dep_flags` -nxt_dep_post=`nxt_gen_dep_post` -cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/$nxt_obj: $nxt_src $NXT_VERSION_H - \$(CC) -c \$(CFLAGS) -DNXT_NCQ_TEST=1 \$(NXT_LIB_INCS) $NXT_LIB_AUX_CFLAGS \\ - -o $NXT_BUILD_DIR/$nxt_obj \\ - $nxt_dep_flags \\ - $nxt_src - $nxt_dep_post - --include $NXT_BUILD_DIR/$nxt_dep - -END - -nxt_src=src/test/nxt_cq_test.c -nxt_obj=src/test/nxt_vbcq_test.o -nxt_dep=src/test/nxt_vbcq_test.dep -nxt_dep_flags=`nxt_gen_dep_flags` -nxt_dep_post=`nxt_gen_dep_post` -cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/$nxt_obj: $nxt_src $NXT_VERSION_H - \$(CC) -c \$(CFLAGS) -DNXT_NCQ_TEST=0 \$(NXT_LIB_INCS) $NXT_LIB_AUX_CFLAGS \\ - -o $NXT_BUILD_DIR/$nxt_obj \\ - $nxt_dep_flags \\ - $nxt_src - $nxt_dep_post - --include $NXT_BUILD_DIR/$nxt_dep - -END - -$echo >> $NXT_MAKEFILE - - -if [ $NXT_TESTS = YES ]; then - - # Test object files list. - - $echo "NXT_TEST_OBJS = \\" >> $NXT_MAKEFILE - - for nxt_src in $NXT_TEST_SRCS - do - nxt_obj=${nxt_src%.c}.o - $echo " $NXT_BUILD_DIR/$nxt_obj \\" >> $NXT_MAKEFILE - done - - # Test executables. - - cat << END >> $NXT_MAKEFILE - -.PHONY: tests -tests: $NXT_BUILD_DIR/tests $NXT_BUILD_DIR/utf8_file_name_test \\ - $NXT_BUILD_DIR/ncq_test \\ - $NXT_BUILD_DIR/vbcq_test \\ - $NXT_BUILD_DIR/unit_app_test $NXT_BUILD_DIR/unit_websocket_chat \\ - $NXT_BUILD_DIR/unit_websocket_echo - -$NXT_BUILD_DIR/tests: \$(NXT_TEST_OBJS) \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC - \$(NXT_EXEC_LINK) -o $NXT_BUILD_DIR/tests \\ - \$(CFLAGS) \$(NXT_TEST_OBJS) \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC \\ - $NXT_LD_OPT $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS - -$NXT_BUILD_DIR/utf8_file_name_test: $NXT_LIB_UTF8_FILE_NAME_TEST_SRCS \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC - \$(CC) \$(CFLAGS) \$(NXT_LIB_INCS) $NXT_LIB_AUX_CFLAGS \\ - -o $NXT_BUILD_DIR/utf8_file_name_test \\ - $NXT_LIB_UTF8_FILE_NAME_TEST_SRCS \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC \\ - $NXT_LD_OPT $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS - -$NXT_BUILD_DIR/ncq_test: $NXT_BUILD_DIR/src/test/nxt_ncq_test.o \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC - \$(NXT_EXEC_LINK) -o $NXT_BUILD_DIR/ncq_test \\ - \$(CFLAGS) $NXT_BUILD_DIR/src/test/nxt_ncq_test.o \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC \\ - $NXT_LD_OPT $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS - -$NXT_BUILD_DIR/vbcq_test: $NXT_BUILD_DIR/src/test/nxt_vbcq_test.o \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC - \$(NXT_EXEC_LINK) -o $NXT_BUILD_DIR/vbcq_test \\ - \$(CFLAGS) $NXT_BUILD_DIR/src/test/nxt_vbcq_test.o \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC \\ - $NXT_LD_OPT $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS - -$NXT_BUILD_DIR/unit_app_test: $NXT_BUILD_DIR/src/test/nxt_unit_app_test.o \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC - \$(NXT_EXEC_LINK) -o $NXT_BUILD_DIR/unit_app_test \\ - \$(CFLAGS) $NXT_BUILD_DIR/src/test/nxt_unit_app_test.o \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC \\ - $NXT_LD_OPT $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS - -$NXT_BUILD_DIR/unit_websocket_chat: \\ - $NXT_BUILD_DIR/src/test/nxt_unit_websocket_chat.o \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC - \$(NXT_EXEC_LINK) -o $NXT_BUILD_DIR/unit_websocket_chat \\ - \$(CFLAGS) $NXT_BUILD_DIR/src/test/nxt_unit_websocket_chat.o \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC \\ - $NXT_LD_OPT $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS - -$NXT_BUILD_DIR/unit_websocket_echo: \\ - $NXT_BUILD_DIR/src/test/nxt_unit_websocket_echo.o \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC - \$(NXT_EXEC_LINK) -o $NXT_BUILD_DIR/unit_websocket_echo \\ - \$(CFLAGS) $NXT_BUILD_DIR/src/test/nxt_unit_websocket_echo.o \\ - $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC \\ - $NXT_LD_OPT $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS - -END - -else - - cat << END >> $NXT_MAKEFILE - -.PHONY: tests -tests: - @(echo; \\ - echo "error: to make tests you need to configure --tests option."; \\ - echo; \\ - exit 1) - -END - -fi - - -NXT_MAKE_INCS="src $NXT_BUILD_DIR/include" -NXT_MAKE_SRCS="$NXT_SRCS" - - -# The include paths list. - -$echo -n "NXT_INCS =" >> $NXT_MAKEFILE - -for nxt_inc in $NXT_MAKE_INCS -do - $echo -n " -I $nxt_inc" >> $NXT_MAKEFILE -done - -$echo >> $NXT_MAKEFILE -$echo >> $NXT_MAKEFILE - - -# Object files list. - -$echo "NXT_OBJS = \\" >> $NXT_MAKEFILE - -for nxt_src in $NXT_MAKE_SRCS -do - nxt_obj=${nxt_src%.c}.o - $echo " $NXT_BUILD_DIR/$nxt_obj \\" >> $NXT_MAKEFILE -done - -$echo >> $NXT_MAKEFILE - - -# unit executable. - -cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/sbin/$NXT_DAEMON: $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC \\ - \$(NXT_OBJS) - \$(NXT_EXEC_LINK) -o \$@ \$(CFLAGS) \\ - \$(NXT_OBJS) $NXT_BUILD_DIR/lib/$NXT_LIB_STATIC \\ - $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS - -END - - -# unitd man page - -cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/share/man/man8/unitd.8: docs/man/man8/unitd.8.in \\ - $NXT_BUILD_DIR/include/nxt_auto_config.h - sed -e "s|%%ERROR_LOG_PATH%%|$NXT_LOG|" \\ - -e "s|%%PID_PATH%%|$NXT_PID|" \\ - -e "s|%%SOCKET_PATH%%|$NXT_CONTROL|" \\ - < docs/man/man8/unitd.8.in > \$@ - -END - - -# unit object files. - -for nxt_src in $NXT_MAKE_SRCS -do - nxt_obj=${nxt_src%.c}.o - nxt_dep=${nxt_src%.c}.dep - nxt_dep_flags=`nxt_gen_dep_flags` - nxt_dep_post=`nxt_gen_dep_post` - cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/$nxt_obj: $nxt_src $NXT_VERSION_H - \$(CC) -c \$(CFLAGS) \$(NXT_INCS) \\ - $NXT_LIB_AUX_CFLAGS \\ - -o $NXT_BUILD_DIR/$nxt_obj \\ - $nxt_dep_flags \\ - $nxt_src - $nxt_dep_post - --include $NXT_BUILD_DIR/$nxt_dep - -END - -done - - -# install - -cat << END >> $NXT_MAKEFILE - -.PHONY: install ${NXT_DAEMON}-install install-check manpage-install - -install: ${NXT_DAEMON}-install manpage-install - -install-check: - @test -n "\$(DESTDIR)$NXT_PREFIX" \\ - || (echo; \\ - echo "error: to make install you need either"; \\ - echo " to configure --prefix option"; \\ - echo " or to set DESTDIR environment variable."; \\ - echo; \\ - exit 1) - -${NXT_DAEMON}-install: $NXT_DAEMON install-check - test -d \$(DESTDIR)$NXT_SBINDIR \ - || install -d \$(DESTDIR)$NXT_SBINDIR - install -p $NXT_BUILD_DIR/sbin/$NXT_DAEMON \$(DESTDIR)$NXT_SBINDIR/ - test -d \$(DESTDIR)$NXT_STATEDIR \ - || install -d \$(DESTDIR)$NXT_STATEDIR - test -d \$(DESTDIR)$NXT_LOGDIR \ - || install -d \$(DESTDIR)$NXT_LOGDIR - test -d \$(DESTDIR)$NXT_RUNSTATEDIR \ - || install -d \$(DESTDIR)$NXT_RUNSTATEDIR - -manpage-install: manpage install-check - test -d \$(DESTDIR)$NXT_MANDIR/man8 \ - || install -d \$(DESTDIR)$NXT_MANDIR/man8 - install -p -m644 $NXT_BUILD_DIR/share/man/man8/unitd.8 \ - \$(DESTDIR)$NXT_MANDIR/man8/ - -.PHONY: uninstall ${NXT_DAEMON}-uninstall manpage-uninstall - -uninstall: ${NXT_DAEMON}-uninstall manpage-uninstall - -${NXT_DAEMON}-uninstall: - rm -f \$(DESTDIR)$NXT_SBINDIR/$NXT_DAEMON - @rmdir -p \$(DESTDIR)$NXT_SBINDIR 2>/dev/null || true - -manpage-uninstall: - rm -f \$(DESTDIR)$NXT_MANDIR/man8/unitd.8 - @rmdir -p \$(DESTDIR)$NXT_MANDIR/man8 2>/dev/null || true - -END - -cat << END >> $NXT_MAKEFILE - -.PHONY: libunit-install libunit-uninstall - -libunit-install: $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC - test -d \$(DESTDIR)$NXT_LIBDIR \ - || install -d \$(DESTDIR)$NXT_LIBDIR - install -p -m u=rw,go=r $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC \ - \$(DESTDIR)$NXT_LIBDIR/ - test -d \$(DESTDIR)$NXT_PKGCONFIGDIR \ - || install -d \$(DESTDIR)$NXT_PKGCONFIGDIR - install -p -m u=rw,go=r $NXT_BUILD_DIR/share/pkgconfig/unit.pc \ - \$(DESTDIR)$NXT_PKGCONFIGDIR/ - test -d \$(DESTDIR)$NXT_INCLUDEDIR \ - || install -d \$(DESTDIR)$NXT_INCLUDEDIR - install -p -m u=rw,go=r src/nxt_unit.h \ - src/nxt_unit_field.h \ - src/nxt_unit_request.h \ - src/nxt_unit_response.h \ - src/nxt_unit_sptr.h \ - src/nxt_unit_typedefs.h \ - src/nxt_unit_websocket.h \ - $NXT_BUILD_DIR/include/nxt_auto_config.h \ - $NXT_BUILD_DIR/include/nxt_version.h \ - src/nxt_websocket_header.h \ - \$(DESTDIR)$NXT_INCLUDEDIR/ - -libunit-uninstall: - rm -f \$(DESTDIR)$NXT_LIBDIR/$NXT_LIB_UNIT_STATIC - @rmdir -p \$(DESTDIR)$NXT_LIBDIR 2>/dev/null || true - rm -f \$(DESTDIR)$NXT_PKGCONFIGDIR/unit.pc - @rmdir -p \$(DESTDIR)$NXT_PKGCONFIGDIR 2>/dev/null || true - rm -f \$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit.h \ - \$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit_field.h \ - \$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit_request.h \ - \$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit_response.h \ - \$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit_sptr.h \ - \$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit_typedefs.h \ - \$(DESTDIR)$NXT_INCLUDEDIR/nxt_unit_websocket.h \ - \$(DESTDIR)$NXT_INCLUDEDIR/nxt_auto_config.h \ - \$(DESTDIR)$NXT_INCLUDEDIR/nxt_version.h \ - \$(DESTDIR)$NXT_INCLUDEDIR/nxt_websocket_header.h - @rmdir -p \$(DESTDIR)$NXT_INCLUDEDIR 2>/dev/null || true - -END - -# pkg-config files - -cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/share/pkgconfig/unit.pc: src/unit.pc.in - sed -e "s|@PREFIX@|$NXT_PREFIX|" \\ - -e "s|@LIBDIR@|$NXT_LIBDIR|" \\ - -e "s|@CFLAGS@|-I$NXT_INCLUDEDIR|" \\ - -e "s|@VERSION@|\$(NXT_VERSION)|" \\ - -e "s|@EXTRA_LIBS@|$NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS|" \\ - -e "s|@CONFARGS@|$(echo $NXT_CONFIGURE_OPTIONS | sed -e 's| -pie||' -e 's| --njs||')|" \\ - -e "s|@MODULESDIR@|$NXT_MODULESDIR|" \\ - < src/unit.pc.in > \$@ - -$NXT_BUILD_DIR/share/pkgconfig/unit-uninstalled.pc: src/unit.pc.in - sed -e "s|@PREFIX@|$(pwd)/$NXT_BUILD_DIR|" \\ - -e "s|@LIBDIR@|$(pwd)/$NXT_BUILD_DIR/lib|" \\ - -e "s|@CFLAGS@|-I$(pwd)/src -I$(pwd)$NXT_BUILD_DIR/include|" \\ - -e "s|@VERSION@|\$(NXT_VERSION)|" \\ - -e "s|@EXTRA_LIBS@|$NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS|" \\ - -e "s|@CONFARGS@|$(echo $NXT_CONFIGURE_OPTIONS | sed -e 's| -pie||' -e 's| --njs||')|" \\ - < src/unit.pc.in > \$@ - -END - -# Makefile. -# *.dSYM is MacOSX Clang debug information. - -cat << END > Makefile - -include $NXT_MAKEFILE - -.PHONY: clean -clean: - rm -rf $NXT_BUILD_DIR *.dSYM Makefile - -END diff --git a/auto/malloc b/auto/malloc deleted file mode 100644 index cf6fc59e..00000000 --- a/auto/malloc +++ /dev/null @@ -1,175 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# Linux glibc 2.1.91, FreeBSD 7.0, Solaris 11, -# MacOSX 10.6 (Snow Leopard), NetBSD 5.0. - -nxt_feature="posix_memalign()" -nxt_feature_name=NXT_HAVE_POSIX_MEMALIGN -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - void *p; - - if (posix_memalign(&p, 4096, 4096) != 0) - return 1; - - free(p); - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # Solaris, HP-UX. - - nxt_feature="memalign()" - nxt_feature_name=NXT_HAVE_MEMALIGN - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - - int main(void) { - void *p; - - p = memalign(4096, 4096); - if (p == NULL) - return 1; - - free(p); - return 0; - }" - . auto/feature -fi - - -# Linux malloc_usable_size(). - -nxt_feature="Linux malloc_usable_size()" -nxt_feature_name=NXT_HAVE_MALLOC_USABLE_SIZE -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - void *p; - - p = malloc(4096); - if (malloc_usable_size(p) < 4096) - return 1; - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # FreeBSD malloc_usable_size(). - - nxt_feature="FreeBSD malloc_usable_size()" - nxt_feature_name=NXT_HAVE_MALLOC_USABLE_SIZE - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - #include - - int main(void) { - void *p; - - p = malloc(4096); - if (malloc_usable_size(p) < 4096) - return 1; - return 0; - }" - . auto/feature -fi - - -if [ $nxt_found = no ]; then - - # MacOSX malloc_good_size(). - - nxt_feature="MacOSX malloc_good_size()" - nxt_feature_name=NXT_HAVE_MALLOC_GOOD_SIZE - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - - int main(void) { - if (malloc_good_size(4096) < 4096) - return 1; - return 0; - }" - . auto/feature -fi - - -# alloca(). - -# Linux, FreeBSD, MacOSX. - -nxt_feature="alloca()" -nxt_feature_name=NXT_HAVE_ALLOCA -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - void *p; - - p = alloca(256); - if (p == 0) - return 1; - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # Linux, Solaris, MacOSX. - - nxt_feature="alloca() in alloca.h" - nxt_feature_name=NXT_HAVE_ALLOCA_H - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - - int main(void) { - void *p; - - p = alloca(256); - if (p == 0) - return 1; - return 0; - }" - . auto/feature -fi - - -# Linux mallopt(). - -nxt_feature="Linux mallopt()" -nxt_feature_name=NXT_HAVE_MALLOPT -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - mallopt(M_PERTURB, 0x55); - return 0; - }" -. auto/feature diff --git a/auto/mmap b/auto/mmap deleted file mode 100644 index e8ffac78..00000000 --- a/auto/mmap +++ /dev/null @@ -1,87 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# Linux, FreeBSD, Solaris, MacOSX. - -nxt_feature="MAP_ANON" -nxt_feature_name=NXT_HAVE_MAP_ANON -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - if (mmap(NULL, 4096, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0) - == MAP_FAILED) - return 1; - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # Linux, Solaris, HP-UX. - - nxt_feature="MAP_ANONYMOUS" - nxt_feature_name=NXT_HAVE_MAP_ANONYMOUS - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - #include - - int main(void) { - if (mmap(NULL, 4096, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) - == MAP_FAILED) - return 1; - return 0; - }" - . auto/feature -fi - - -# Linux. - -nxt_feature="MAP_POPULATE" -nxt_feature_name=NXT_HAVE_MAP_POPULATE -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - if (mmap(NULL, 4096, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_POPULATE, -1, 0) - == MAP_FAILED) - return 1; - return 0; - }" -. auto/feature - - -# FreeBSD. - -nxt_feature="MAP_PREFAULT_READ" -nxt_feature_name=NXT_HAVE_MAP_PREFAULT_READ -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - if (mmap(NULL, 4096, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_PREFAULT_READ, - -1, 0) - == MAP_FAILED) - return 1; - return 0; - }" -. auto/feature diff --git a/auto/modules/conf b/auto/modules/conf deleted file mode 100644 index ab4ed351..00000000 --- a/auto/modules/conf +++ /dev/null @@ -1,51 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -case "$nxt_module" in - - python) - . auto/modules/python - ;; - - php) - . auto/modules/php - ;; - - go) - . auto/modules/go - ;; - - perl) - . auto/modules/perl - ;; - - ruby) - . auto/modules/ruby - ;; - - nodejs) - . auto/modules/nodejs - ;; - - java) - . auto/modules/java - ;; - - wasm) - . auto/modules/wasm - ;; - - wasm-wasi-component) - . auto/modules/wasm-wasi-component - ;; - - *) - echo - echo $0: error: invalid module \"$nxt_module\". - echo - exit 1 - ;; - -esac diff --git a/auto/modules/go b/auto/modules/go deleted file mode 100644 index 86dfb62d..00000000 --- a/auto/modules/go +++ /dev/null @@ -1,141 +0,0 @@ - -# Copyright (C) Max Romanov -# Copyright (C) NGINX, Inc. - - -shift - -NXT_GO=go - -for nxt_option; do - - case "$nxt_option" in - -*=*) value=`echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) value="" ;; - esac - - case "$nxt_option" in - --go=*) NXT_GO="$value" ;; - --go-path=*) NXT_GO_PATH="$value" ;; - - --help) - cat << END - - --go=NAME set go executable - --go-path=PATH set GOPATH variable to install package - -END - exit 0 - ;; - - *) - echo - echo $0: error: invalid Go option \"$nxt_option\" - echo - exit 1 - ;; - - esac - -done - - -if [ ! -f $NXT_AUTOCONF_DATA ]; then - echo - echo Please run common $0 before configuring module \"$nxt_module\". - echo - exit 1 -fi - -. $NXT_AUTOCONF_DATA - - -$echo "configuring Go package" -$echo "configuring Go package ..." >> $NXT_AUTOCONF_ERR - -$echo -n "checking for Go ..." -$echo "checking for Go ..." >> $NXT_AUTOCONF_ERR - - -if /bin/sh -c "${NXT_GO} version" >> $NXT_AUTOCONF_ERR 2>&1; then - $echo " found" - - NXT_GO_VERSION="`${NXT_GO} version`" - $echo " + ${NXT_GO_VERSION}" - -else - $echo - $echo $0: error: no Go found. - $echo - exit 1; -fi - - -NXT_GO_PATH=${NXT_GO_PATH=`${NXT_GO} env GOPATH`} -NXT_GO_PATH=${NXT_GO_PATH:-${PWD}/${NXT_BUILD_DIR}/${NXT_GO}} - -NXT_GO_PKG=unit.nginx.org/go - -$echo " + Go package path: \"${NXT_GO_PATH}\"" - -if grep ^$NXT_GO: $NXT_MAKEFILE 2>&1 > /dev/null; then - $echo - $echo $0: error: duplicate \"$NXT_GO\" package configured. - $echo - exit 1; -fi - -NXT_GO_LDFLAGS= - -for o in ${CFLAGS} ${NXT_CC_OPT}; do - case "$o" in - -fsanitize* | -L* | -l*) NXT_GO_LDFLAGS="${NXT_GO_LDFLAGS} $o" ;; - esac -done - -cat << END >> $NXT_MAKEFILE - -.PHONY: ${NXT_GO} -.PHONY: ${NXT_GO}-install -.PHONY: ${NXT_GO}-install-src -.PHONY: ${NXT_GO}-uninstall - -GOPATH = $NXT_GO_PATH -GOOS = `${NXT_GO} env GOOS` -GOARCH = `${NXT_GO} env GOARCH` - -NXT_GO_DST = ${NXT_GO_PATH%%:*} - -install: ${NXT_GO}-install - -${NXT_GO}: - -${NXT_GO}-install: ${NXT_GO}-install-src ${NXT_GO}-install-env - cd \$(DESTDIR)\$(NXT_GO_DST)/src/${NXT_GO_PKG} && \ - GOPATH=\$(DESTDIR)\$(GOPATH) ${NXT_GO} build ${NXT_GO_PKG} - -${NXT_GO}-install-src: - install -d \$(DESTDIR)\$(NXT_GO_DST)/src/${NXT_GO_PKG} - install -p -m644 ./go/* \$(DESTDIR)\$(NXT_GO_DST)/src/${NXT_GO_PKG}/ - -${NXT_GO}-install-env: \$(DESTDIR)\$(NXT_GO_DST)/src/${NXT_GO_PKG}/env.go \ - ${NXT_VERSION_H} ${NXT_BUILD_DIR}/lib/${NXT_LIB_UNIT_STATIC} - -\$(DESTDIR)\$(NXT_GO_DST)/src/${NXT_GO_PKG}/env.go: - install -d \$(DESTDIR)\$(NXT_GO_DST)/src/${NXT_GO_PKG} - $echo "package unit" > \$@ - $echo "/*" >> \$@ - $echo "#cgo CFLAGS: ${CFLAGS} ${NXT_CC_OPT}" >> \$@ - $echo "#cgo CPPFLAGS: -I${PWD}/src -I${PWD}/${NXT_BUILD_DIR}/include" >> \$@ - $echo "#cgo LDFLAGS: -L${PWD}/${NXT_BUILD_DIR}/lib ${NXT_GO_LDFLAGS} ${NXT_LD_OPT}" >> \$@ - $echo "*/" >> \$@ - $echo 'import "C"' >> \$@ - - -uninstall: ${NXT_GO}-uninstall - -${NXT_GO}-uninstall: - rm -rf \$(DESTDIR)\$(NXT_GO_DST)/src/${NXT_GO_PKG} - rm -rf \$(DESTDIR)\$(NXT_GO_DST)/pkg/\$(GOOS)_\$(GOARCH)/${NXT_GO_PKG} - -END diff --git a/auto/modules/java b/auto/modules/java deleted file mode 100644 index b5c8d70a..00000000 --- a/auto/modules/java +++ /dev/null @@ -1,641 +0,0 @@ - -# Copyright (C) NGINX, Inc. - - -shift - -NXT_JAVA_HOME=${JAVA_HOME-} -NXT_JAR_REPO=https://repo1.maven.org/maven2/ -NXT_JAR_LOCAL_REPO=$HOME/.m2/repository/ - -for nxt_option; do - - case "$nxt_option" in - -*=*) value=`echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) value="" ;; - esac - - case "$nxt_option" in - - --module=*) NXT_JAVA_MODULE="$value" ;; - --home=*) NXT_JAVA_HOME="$value" ;; - --lib-path=*) NXT_JAVA_LIB_PATH="$value" ;; - --repo=*) NXT_JAR_REPO="$value" ;; - --local-repo=*) NXT_JAR_LOCAL_REPO="$value" ;; - --sha512=*) NXT_SHA512_TOOL="$value" ;; - --jars=*) NXT_JARS="$value" ;; - - --help) - cat << END - - --module=NAME set unit Java module name - --home=DIR set Java home directory - --lib-path=DIRECTORY set directory path to libjvm.so library - --repo=URL set Maven remote repository URL - default: "$NXT_JAR_REPO" - --local-repo=DIR set local repository directory - default: "$NXT_JAR_LOCAL_REPO" - --sha512=SHA512 set command for SHA512 check - --jars=DIR set jars install/search directory - -END - exit 0 - ;; - - *) - echo - echo $0: error: invalid Java option \"$nxt_option\" - echo - exit 1 - ;; - esac - -done - - -if [ ! -f $NXT_AUTOCONF_DATA ]; then - echo - echo Please run common $0 before configuring module \"$nxt_module\". - echo - exit 1 -fi - -. $NXT_AUTOCONF_DATA - - -NXT_JARS=${NXT_JARS=$NXT_MODULESDIR} -NXT_JAVA_MODULE=${NXT_JAVA_MODULE=java} -NXT_JAVA_LIB_PATH=${NXT_JAVA_LIB_PATH=} - -$echo "configuring Java module" -$echo "configuring Java module ..." >> $NXT_AUTOCONF_ERR - -if [ -n "${NXT_JAVA_HOME}" ]; then - $echo "using java.home ${NXT_JAVA_HOME}" - $echo "using java.home ${NXT_JAVA_HOME}" >> $NXT_AUTOCONF_ERR - - if [ ! -d "${NXT_JAVA_HOME}" ]; then - $echo - $echo $0: error: Java home directory not found. - $echo - exit 1 - fi - - NXT_JAVA="${NXT_JAVA_HOME}/bin/java" - -else - $echo -n "checking for java executable ..." - $echo "checking for java executable ..." >> $NXT_AUTOCONF_ERR - - NXT_JAVA=`which java || :` - if [ -z "$NXT_JAVA" -o ! -x "$NXT_JAVA" ]; then - $echo " not found" - $echo - $echo $0: error: java executable not found. - $echo - exit 1 - fi - - $echo " found $NXT_JAVA" - $echo "found $NXT_JAVA" >> $NXT_AUTOCONF_ERR - - "$NXT_JAVA" -version - - $echo -n "checking java.home ..." - $echo "checking java.home ..." >> $NXT_AUTOCONF_ERR - - NXT_JAVA_HOME=`$NXT_JAVA -XshowSettings 2>&1 | grep -F -e java.home | sed -e 's/^.*= //'` - if [ -z "$NXT_JAVA_HOME" ]; then - $echo " not found" - $echo - $echo $0: error: java.home not found. - $echo - exit 1 - fi - - $echo " $NXT_JAVA_HOME" - $echo "got java.home $NXT_JAVA_HOME" >> $NXT_AUTOCONF_ERR - - if [ ! -x "${NXT_JAVA_HOME}/bin/javac" ]; then - NXT_JAVA_HOME_=${NXT_JAVA_HOME%/jre} - if [ -x "${NXT_JAVA_HOME_}/bin/javac" ]; then - $echo "adjust java.home $NXT_JAVA_HOME_" - $echo "adjust java.home $NXT_JAVA_HOME_" >> $NXT_AUTOCONF_ERR - - NXT_JAVA_HOME="$NXT_JAVA_HOME_" - fi - fi -fi - -NXT_JAVAC="${NXT_JAVA_HOME}/bin/javac" - -if [ ! -x "$NXT_JAVAC" ]; then - $echo - $echo $0: error: javac not found. - $echo - exit 1 -fi - -NXT_JAVA_INCLUDE="-I${NXT_JAVA_HOME}/include" - -case "$NXT_SYSTEM" in - Linux) - NXT_JAVA_INCLUDE="${NXT_JAVA_INCLUDE} -I${NXT_JAVA_HOME}/include/linux" - ;; - Darwin) - NXT_JAVA_INCLUDE="${NXT_JAVA_INCLUDE} -I${NXT_JAVA_HOME}/include/darwin" - ;; - FreeBSD) - NXT_JAVA_INCLUDE="${NXT_JAVA_INCLUDE} -I${NXT_JAVA_HOME}/include/freebsd" - ;; -esac - -if [ -z "$NXT_JAVA_LIB_PATH" ]; then - $echo -n "checking library path ..." - $echo "checking library path ..." >> $NXT_AUTOCONF_ERR - - if [ ! -x "$NXT_JAVA" ]; then - $echo " not found" - $echo - $echo $0: error: java executable not found. - $echo - exit 1 - fi - - NXT_JAVA_LIB_PATH=`$NXT_JAVA -XshowSettings 2>&1 | grep -F -e sun.boot.library.path | sed -e 's/^.*= //'` - - if [ -z "$NXT_JAVA_LIB_PATH" ]; then - $echo " not found" - $echo - $echo $0: error: library path not found. - $echo - exit 1 - fi - - $echo " $NXT_JAVA_LIB_PATH" - $echo "got library path $NXT_JAVA_LIB_PATH" >> $NXT_AUTOCONF_ERR -fi - -NXT_JAVA_LIB_SERVER_PATH="${NXT_JAVA_LIB_PATH}/server" - -NXT_JAVA_LDFLAGS="-L${NXT_JAVA_LIB_SERVER_PATH} -Wl,-rpath,${NXT_JAVA_LIB_SERVER_PATH} -ljvm" - - -nxt_found=no - -nxt_feature="JNI" -nxt_feature_name="" -nxt_feature_run=no -nxt_feature_incs="${NXT_JAVA_INCLUDE}" -nxt_feature_libs="${NXT_JAVA_LDFLAGS}" -nxt_feature_test=" - #include - - int main(void) { - JNI_CreateJavaVM(NULL, NULL, NULL); - return 0; - }" - -. auto/feature - - -if [ $nxt_found = no ]; then - $echo - $echo $0: error: no JNI found. - $echo - exit 1; -fi - -NXT_JAVA_VERSION=`$NXT_JAVAC -version 2>&1` -NXT_JAVA_VERSION=${NXT_JAVA_VERSION#javac } -NXT_JAVA_INCLUDE="$NXT_JAVA_INCLUDE -I$NXT_BUILD_DIR/$NXT_JAVA_MODULE -DNXT_JAVA_VERSION=$NXT_JAVA_VERSION" - -if grep ^$NXT_JAVA_MODULE: $NXT_MAKEFILE 2>&1 > /dev/null; then - $echo - $echo $0: error: duplicate \"$NXT_JAVA_MODULE\" module configured. - $echo - exit 1; -fi - -. ./version - -NXT_UNIT_JAR=nginx-unit-jsc-${NXT_JAVA_MODULE}-$NXT_VERSION.jar -NXT_WS_API_JAR=websocket-api-${NXT_JAVA_MODULE}-$NXT_VERSION.jar - -NXT_JAVA_BUILD_CP=$NXT_BUILD_DIR/$NXT_JAVA_MODULE -NXT_JAVA_INSTALL_JARS= -NXT_JAVA_UNINSTALL_JARS= - -NXT_JAVA_JARS=$NXT_BUILD_DIR/$NXT_JAVA_MODULE/nxt_jars.h -mkdir -p $NXT_BUILD_DIR/$NXT_JAVA_MODULE - -cat << END > $NXT_JAVA_JARS -#ifndef _NXT_JAVA_JARS_INCLUDED_ -#define _NXT_JAVA_JARS_INCLUDED_ - -#define NXT_JARS "$NXT_JARS" - -static const char *nxt_java_system_jars[] = { -END - -NXT_TOMCAT_VERSION=9.0.86 - -NXT_JAR_VERSION=$NXT_TOMCAT_VERSION - -NXT_JAR_NAME=tomcat-servlet-api -NXT_JAR_NAMESPACE=org/apache/tomcat/ -. auto/modules/java_get_jar - -NXT_JAR_NAME=tomcat-el-api -. auto/modules/java_get_jar - -NXT_JAR_NAME=tomcat-jsp-api -. auto/modules/java_get_jar - -NXT_JAR_NAME=tomcat-jasper -. auto/modules/java_get_jar - -NXT_JAR_NAME=tomcat-jasper-el -. auto/modules/java_get_jar - -NXT_JAR_NAME=tomcat-juli -. auto/modules/java_get_jar - -NXT_JAR_NAME=tomcat-api -. auto/modules/java_get_jar - -NXT_JAR_NAME=tomcat-util-scan -. auto/modules/java_get_jar - -NXT_JAR_NAME=tomcat-util -. auto/modules/java_get_jar - -NXT_JAR_NAME=ecj -NXT_JAR_VERSION=3.26.0 -NXT_JAR_NAMESPACE=org/eclipse/jdt/ -. auto/modules/java_get_jar - -cat << END >> $NXT_JAVA_JARS - "$NXT_WS_API_JAR", - NULL -}; - -static const char *nxt_java_unit_jars[] = { - "$NXT_UNIT_JAR", -END - -NXT_JAR_VERSION=9.4.54.v20240208 -NXT_JAR_NAMESPACE=org/eclipse/jetty/ - -NXT_JAR_NAME=jetty-util -. auto/modules/java_get_jar - -NXT_JAR_NAME=jetty-server -. auto/modules/java_get_jar - -NXT_JAR_NAME=jetty-http -. auto/modules/java_get_jar - -NXT_JAR_NAME=classgraph -NXT_JAR_VERSION=4.8.165 -NXT_JAR_NAMESPACE=io/github/classgraph/ -. auto/modules/java_get_jar - -cat << END >> $NXT_JAVA_JARS - NULL -}; - -#endif /* _NXT_JAVA_JARS_INCLUDED_ */ -END - -NXT_JAVA_LIBJVM="$NXT_JAVA_LIB_SERVER_PATH/libjvm.so" - -if [ "$NXT_SYSTEM" = "Darwin" ]; then -NXT_JAVA_LIBC_DIR="/usr/lib" -else -NXT_JAVA_LIBC_DIR=`ldd "$NXT_JAVA_LIBJVM" | grep -F libc. | cut -d' ' -f3` -NXT_JAVA_LIBC_DIR=`dirname $NXT_JAVA_LIBC_DIR` -fi - - -NXT_JAVA_MOUNTS_HEADER=nxt_${NXT_JAVA_MODULE}_mounts.h - -cat << END > $NXT_BUILD_DIR/include/$NXT_JAVA_MOUNTS_HEADER -#ifndef _NXT_JAVA_MOUNTS_H_INCLUDED_ -#define _NXT_JAVA_MOUNTS_H_INCLUDED_ - - -static const nxt_fs_mount_t nxt_java_mounts[] = { - {(u_char *) "$NXT_JAVA_LIBC_DIR", (u_char *) "$NXT_JAVA_LIBC_DIR", - NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1}, - {(u_char *) "$NXT_JAVA_HOME", (u_char *) "$NXT_JAVA_HOME", - NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1}, -}; - - -#endif /* _NXT_JAVA_MOUNTS_H_INCLUDED_ */ -END - -$echo " + Java module: ${NXT_JAVA_MODULE}.unit.so" - -. auto/cc/deps - -$echo >> $NXT_MAKEFILE - -NXT_JAVA_MODULE_SRCS=" \ - src/nxt_java.c \ - src/java/nxt_jni.c \ - src/java/nxt_jni_Context.c \ - src/java/nxt_jni_HeaderNamesEnumeration.c \ - src/java/nxt_jni_HeadersEnumeration.c \ - src/java/nxt_jni_InputStream.c \ - src/java/nxt_jni_OutputStream.c \ - src/java/nxt_jni_Request.c \ - src/java/nxt_jni_Response.c \ - src/java/nxt_jni_Thread.c \ - src/java/nxt_jni_URLClassLoader.c \ -" - -# The Java module object files. - -nxt_objs=$NXT_BUILD_DIR/src/nxt_unit.o - -for nxt_src in $NXT_JAVA_MODULE_SRCS; do - - nxt_obj=${nxt_src%.c}-$NXT_JAVA_MODULE.o - nxt_dep=${nxt_src%.c}-$NXT_JAVA_MODULE.dep - nxt_dep_flags=`nxt_gen_dep_flags` - nxt_dep_post=`nxt_gen_dep_post` - nxt_objs="$nxt_objs $NXT_BUILD_DIR/$nxt_obj" - - cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/$nxt_obj: $nxt_src $NXT_VERSION_H - mkdir -p $NXT_BUILD_DIR/src/java - \$(CC) -c \$(CFLAGS) -DNXT_JAVA_MOUNTS_H=\"$NXT_JAVA_MOUNTS_HEADER\" \\ - \$(NXT_INCS) $NXT_JAVA_INCLUDE \\ - $nxt_dep_flags \\ - -o $NXT_BUILD_DIR/$nxt_obj $nxt_src - $nxt_dep_post - --include $NXT_BUILD_DIR/$nxt_dep - -END - -done - -NXT_JAVA_SRCS=" \ - src/java/nginx/unit/Context.java \ - src/java/nginx/unit/DynamicDispatcherRequest.java \ - src/java/nginx/unit/DynamicPathRequest.java \ - src/java/nginx/unit/ForwardRequestWrapper.java \ - src/java/nginx/unit/HeaderNamesEnumeration.java \ - src/java/nginx/unit/HeadersEnumeration.java \ - src/java/nginx/unit/IncludeRequestWrapper.java \ - src/java/nginx/unit/IncludeResponseWrapper.java \ - src/java/nginx/unit/InitParams.java \ - src/java/nginx/unit/InputStream.java \ - src/java/nginx/unit/JspPropertyGroup.java \ - src/java/nginx/unit/OutputStream.java \ - src/java/nginx/unit/Request.java \ - src/java/nginx/unit/RequestAttrProxy.java \ - src/java/nginx/unit/Response.java \ - src/java/nginx/unit/Session.java \ - src/java/nginx/unit/SessionAttrProxy.java \ - src/java/nginx/unit/Taglib.java \ - src/java/nginx/unit/UnitSessionCookieConfig.java \ - src/java/nginx/unit/websocket/AsyncChannelGroupUtil.java \ - src/java/nginx/unit/websocket/AsyncChannelWrapper.java \ - src/java/nginx/unit/websocket/AsyncChannelWrapperNonSecure.java \ - src/java/nginx/unit/websocket/AsyncChannelWrapperSecure.java \ - src/java/nginx/unit/websocket/AuthenticationException.java \ - src/java/nginx/unit/websocket/Authenticator.java \ - src/java/nginx/unit/websocket/AuthenticatorFactory.java \ - src/java/nginx/unit/websocket/BackgroundProcess.java \ - src/java/nginx/unit/websocket/BackgroundProcessManager.java \ - src/java/nginx/unit/websocket/BasicAuthenticator.java \ - src/java/nginx/unit/websocket/Constants.java \ - src/java/nginx/unit/websocket/DecoderEntry.java \ - src/java/nginx/unit/websocket/DigestAuthenticator.java \ - src/java/nginx/unit/websocket/FutureToSendHandler.java \ - src/java/nginx/unit/websocket/MessageHandlerResult.java \ - src/java/nginx/unit/websocket/MessageHandlerResultType.java \ - src/java/nginx/unit/websocket/MessagePart.java \ - src/java/nginx/unit/websocket/PerMessageDeflate.java \ - src/java/nginx/unit/websocket/ReadBufferOverflowException.java \ - src/java/nginx/unit/websocket/Transformation.java \ - src/java/nginx/unit/websocket/TransformationFactory.java \ - src/java/nginx/unit/websocket/TransformationResult.java \ - src/java/nginx/unit/websocket/Util.java \ - src/java/nginx/unit/websocket/WrappedMessageHandler.java \ - src/java/nginx/unit/websocket/WsContainerProvider.java \ - src/java/nginx/unit/websocket/WsExtension.java \ - src/java/nginx/unit/websocket/WsExtensionParameter.java \ - src/java/nginx/unit/websocket/WsFrameBase.java \ - src/java/nginx/unit/websocket/WsFrameClient.java \ - src/java/nginx/unit/websocket/WsHandshakeResponse.java \ - src/java/nginx/unit/websocket/WsIOException.java \ - src/java/nginx/unit/websocket/WsPongMessage.java \ - src/java/nginx/unit/websocket/WsRemoteEndpointAsync.java \ - src/java/nginx/unit/websocket/WsRemoteEndpointBase.java \ - src/java/nginx/unit/websocket/WsRemoteEndpointBasic.java \ - src/java/nginx/unit/websocket/WsRemoteEndpointImplBase.java \ - src/java/nginx/unit/websocket/WsRemoteEndpointImplClient.java \ - src/java/nginx/unit/websocket/WsSession.java \ - src/java/nginx/unit/websocket/WsWebSocketContainer.java \ - src/java/nginx/unit/websocket/pojo/Constants.java \ - src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java \ - src/java/nginx/unit/websocket/pojo/PojoEndpointClient.java \ - src/java/nginx/unit/websocket/pojo/PojoEndpointServer.java \ - src/java/nginx/unit/websocket/pojo/PojoMessageHandlerBase.java \ - src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialBase.java \ - src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialBinary.java \ - src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialText.java \ - src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeBase.java \ - src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeBinary.java \ - src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholePong.java \ - src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeText.java \ - src/java/nginx/unit/websocket/pojo/PojoMethodMapping.java \ - src/java/nginx/unit/websocket/pojo/PojoPathParam.java \ - src/java/nginx/unit/websocket/pojo/package-info.java \ - src/java/nginx/unit/websocket/server/Constants.java \ - src/java/nginx/unit/websocket/server/DefaultServerEndpointConfigurator.java \ - src/java/nginx/unit/websocket/server/UpgradeUtil.java \ - src/java/nginx/unit/websocket/server/UriTemplate.java \ - src/java/nginx/unit/websocket/server/WsContextListener.java \ - src/java/nginx/unit/websocket/server/WsFilter.java \ - src/java/nginx/unit/websocket/server/WsHandshakeRequest.java \ - src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java \ - src/java/nginx/unit/websocket/server/WsMappingResult.java \ - src/java/nginx/unit/websocket/server/WsPerSessionServerEndpointConfig.java \ - src/java/nginx/unit/websocket/server/WsRemoteEndpointImplServer.java \ - src/java/nginx/unit/websocket/server/WsSci.java \ - src/java/nginx/unit/websocket/server/WsServerContainer.java \ - src/java/nginx/unit/websocket/server/WsSessionListener.java \ - src/java/nginx/unit/websocket/server/WsWriteTimeout.java \ - src/java/nginx/unit/websocket/server/package-info.java \ -" - -NXT_JAVA_WS_API_SRCS=" \ - src/java/javax/websocket/ClientEndpoint.java \ - src/java/javax/websocket/ClientEndpointConfig.java \ - src/java/javax/websocket/CloseReason.java \ - src/java/javax/websocket/ContainerProvider.java \ - src/java/javax/websocket/DecodeException.java \ - src/java/javax/websocket/Decoder.java \ - src/java/javax/websocket/DefaultClientEndpointConfig.java \ - src/java/javax/websocket/DeploymentException.java \ - src/java/javax/websocket/EncodeException.java \ - src/java/javax/websocket/Encoder.java \ - src/java/javax/websocket/Endpoint.java \ - src/java/javax/websocket/EndpointConfig.java \ - src/java/javax/websocket/Extension.java \ - src/java/javax/websocket/HandshakeResponse.java \ - src/java/javax/websocket/MessageHandler.java \ - src/java/javax/websocket/OnClose.java \ - src/java/javax/websocket/OnError.java \ - src/java/javax/websocket/OnMessage.java \ - src/java/javax/websocket/OnOpen.java \ - src/java/javax/websocket/PongMessage.java \ - src/java/javax/websocket/RemoteEndpoint.java \ - src/java/javax/websocket/SendHandler.java \ - src/java/javax/websocket/SendResult.java \ - src/java/javax/websocket/Session.java \ - src/java/javax/websocket/SessionException.java \ - src/java/javax/websocket/WebSocketContainer.java \ - src/java/javax/websocket/server/DefaultServerEndpointConfig.java \ - src/java/javax/websocket/server/HandshakeRequest.java \ - src/java/javax/websocket/server/PathParam.java \ - src/java/javax/websocket/server/ServerApplicationConfig.java \ - src/java/javax/websocket/server/ServerContainer.java \ - src/java/javax/websocket/server/ServerEndpoint.java \ - src/java/javax/websocket/server/ServerEndpointConfig.java \ -" - -cat << END >> $NXT_MAKEFILE - -.PHONY: ${NXT_JAVA_MODULE} -.PHONY: ${NXT_JAVA_MODULE}-install -.PHONY: ${NXT_JAVA_MODULE}-uninstall - -all: ${NXT_JAVA_MODULE} - -${NXT_JAVA_MODULE}: $NXT_BUILD_DIR/lib/unit/modules/${NXT_JAVA_MODULE}.unit.so \ - $NXT_BUILD_DIR/$NXT_UNIT_JAR \ - $NXT_BUILD_DIR/$NXT_WS_API_JAR - -$NXT_BUILD_DIR/lib/unit/modules/${NXT_JAVA_MODULE}.unit.so: $nxt_objs - \$(NXT_MODULE_LINK) -o \$@ $nxt_objs $NXT_JAVA_LDFLAGS $NXT_LD_OPT - - -install: ${NXT_JAVA_MODULE}-install - -${NXT_JAVA_MODULE}-install: \\ - $NXT_BUILD_DIR/lib/unit/modules/${NXT_JAVA_MODULE}.unit.so \\ - $NXT_BUILD_DIR/$NXT_UNIT_JAR \\ - $NXT_BUILD_DIR/$NXT_WS_API_JAR \\ - java-shared-install - install -d \$(DESTDIR)$NXT_MODULESDIR - install -p $NXT_BUILD_DIR/lib/unit/modules/${NXT_JAVA_MODULE}.unit.so \\ - \$(DESTDIR)$NXT_MODULESDIR/ - install -d \$(DESTDIR)$NXT_JARS - install -p -m 0644 $NXT_BUILD_DIR/$NXT_UNIT_JAR \$(DESTDIR)$NXT_JARS/ - install -p -m 0644 $NXT_BUILD_DIR/$NXT_WS_API_JAR \$(DESTDIR)$NXT_JARS/ - - -uninstall: ${NXT_JAVA_MODULE}-uninstall - -${NXT_JAVA_MODULE}-uninstall: java-shared-uninstall - rm -f \$(DESTDIR)$NXT_MODULESDIR/${NXT_JAVA_MODULE}.unit.so - @rmdir -p \$(DESTDIR)$NXT_MODULESDIR 2>/dev/null || true - rm -f \$(DESTDIR)$NXT_JARS/$NXT_UNIT_JAR - rm -f \$(DESTDIR)$NXT_JARS/$NXT_WS_API_JAR - @rmdir -p \$(DESTDIR)$NXT_JARS 2>/dev/null || true - -END - -if ! grep ^$NXT_BUILD_DIR/$NXT_UNIT_JAR: $NXT_MAKEFILE 2>&1 > /dev/null; then - - cat << END >> $NXT_MAKEFILE - -NXT_JAVA_SRCS = $NXT_JAVA_SRCS - -$NXT_BUILD_DIR/$NXT_JAVA_MODULE/.nginx.unit.classes: \$(NXT_JAVA_SRCS) \\ - $NXT_BUILD_DIR/$NXT_WS_API_JAR - rm -rf $NXT_BUILD_DIR/$NXT_JAVA_MODULE/nginx/unit - $NXT_JAVAC -d $NXT_BUILD_DIR/$NXT_JAVA_MODULE \\ - -cp $NXT_JAVA_BUILD_CP:$NXT_BUILD_DIR/$NXT_WS_API_JAR \\ - \$(NXT_JAVA_SRCS) - touch \$@ - -$NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF/LICENSE: LICENSE - mkdir -p $NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF - cp -p LICENSE \$@ - -$NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF/NOTICE: NOTICE - mkdir -p $NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF - cp -p NOTICE \$@ - -$NXT_BUILD_DIR/$NXT_UNIT_JAR: \\ - $NXT_BUILD_DIR/$NXT_JAVA_MODULE/.nginx.unit.classes \\ - $NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF/LICENSE \\ - $NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF/NOTICE - $NXT_JAVA_HOME/bin/jar c -C $NXT_BUILD_DIR/$NXT_JAVA_MODULE META-INF \\ - -C $NXT_BUILD_DIR/$NXT_JAVA_MODULE nginx/unit > \$@ - -NXT_JAVA_WS_API_SRCS = $NXT_JAVA_WS_API_SRCS - -$NXT_BUILD_DIR/$NXT_JAVA_MODULE/.javax.websocket.classes: \$(NXT_JAVA_WS_API_SRCS) - rm -rf $NXT_BUILD_DIR/$NXT_JAVA_MODULE/javax/websocket - $NXT_JAVAC -d $NXT_BUILD_DIR/$NXT_JAVA_MODULE -cp $NXT_JAVA_BUILD_CP \\ - \$(NXT_JAVA_WS_API_SRCS) - touch \$@ - -$NXT_BUILD_DIR/$NXT_WS_API_JAR: \\ - $NXT_BUILD_DIR/$NXT_JAVA_MODULE/.javax.websocket.classes \\ - $NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF/LICENSE \\ - $NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF/NOTICE - $NXT_JAVA_HOME/bin/jar c -C $NXT_BUILD_DIR/$NXT_JAVA_MODULE META-INF \\ - -C $NXT_BUILD_DIR/$NXT_JAVA_MODULE javax/websocket > \$@ - -END - -NXT_PROPS="\ - nginx/unit/websocket/LocalStrings.properties \ - nginx/unit/websocket/pojo/LocalStrings.properties \ - nginx/unit/websocket/server/LocalStrings.properties \ -" - -for nxt_prop in $NXT_PROPS ; do - - cat << END >> $NXT_MAKEFILE -$NXT_BUILD_DIR/$NXT_JAVA_MODULE/$nxt_prop: src/java/$nxt_prop \\ - $NXT_BUILD_DIR/$NXT_JAVA_MODULE/.nginx.unit.classes - cp src/java/$nxt_prop \$@ - -$NXT_BUILD_DIR/$NXT_UNIT_JAR: $NXT_BUILD_DIR/$NXT_JAVA_MODULE/$nxt_prop - -END - -done - -fi - -if ! grep ^java-shared-install: $NXT_MAKEFILE 2>&1 > /dev/null; then - - cat << END >> $NXT_MAKEFILE - -.PHONY: java-shared-install -.PHONY: java-shared-uninstall - -java-shared-install: $NXT_JAVA_INSTALL_JARS - install -d \$(DESTDIR)$NXT_JARS - install -p -m 0644 $NXT_JAVA_INSTALL_JARS \$(DESTDIR)$NXT_JARS/ - -java-shared-uninstall: - rm -f $NXT_JAVA_UNINSTALL_JARS - @rmdir -p \$(DESTDIR)$NXT_JARS 2>/dev/null || true - -END - -fi diff --git a/auto/modules/java_chk_sha512 b/auto/modules/java_chk_sha512 deleted file mode 100644 index 10891cee..00000000 --- a/auto/modules/java_chk_sha512 +++ /dev/null @@ -1,49 +0,0 @@ - -# Copyright (C) NGINX, Inc. - -# NXT_JAR_FILE= -# NXT_JAR_CHK_FILE= - -NXT_SHA512_TOOL=${NXT_SHA512_TOOL=} - -if [ -z "$NXT_SHA512_TOOL" ]; then - $echo -n "looking for sha512 check tool ..." - $echo "looking for sha512 check tool ..." >> $NXT_AUTOCONF_ERR - - if sha512sum --version >/dev/null 2>&1; then - NXT_SHA512_TOOL="sha512sum --check" - else - if shasum --version >/dev/null 2>&1; then - NXT_SHA512_TOOL="shasum -a 512 --check" - else - if openssl version >/dev/null 2>&1; then - NXT_SHA512_TOOL="openssl dgst -sha512" - fi - fi - fi - - if [ -z "$NXT_SHA512_TOOL" ]; then - $echo " not found" - $echo - $echo $0: error: no sha512 tool found. - $echo - $echo "error: no sha512 tool found" >> $NXT_AUTOCONF_ERR - exit 1 - fi - - $echo " $NXT_SHA512_TOOL" - $echo "found $NXT_SHA512_TOOL" >> $NXT_AUTOCONF_ERR -fi - -if [ -f "$NXT_JAR_CHK_FILE" ]; then - NXT_JAR_SHA512=`grep -F $NXT_JAR_FILE auto/modules/java_jar.sha512 | head -c 128` - NXT_JAR_CHK=${NXT_JAR_CHK_FILE}.sha512.$$ - $echo "$NXT_JAR_SHA512 $NXT_JAR_CHK_FILE" > $NXT_JAR_CHK - - if ! $NXT_SHA512_TOOL $NXT_JAR_CHK >/dev/null 2>&1; then - $echo "SHA512 not matched for $NXT_JAR_FILE, removing $NXT_JAR_CHK_FILE" - rm -f $NXT_JAR_CHK_FILE - fi - - rm -f $NXT_JAR_CHK -fi diff --git a/auto/modules/java_get_jar b/auto/modules/java_get_jar deleted file mode 100644 index 81b300f9..00000000 --- a/auto/modules/java_get_jar +++ /dev/null @@ -1,46 +0,0 @@ - -# Copyright (C) NGINX, Inc. - -# NXT_JAR_NAME= -# NXT_JAR_VERSION= -# NXT_JAR_NAMESPACE= -# NXT_JAR_REPO=http://central.maven.org/maven2/ -# NXT_JAR_LOCAL_REPO=$HOME/.m2/repository/ - -NXT_JAR_FILE=${NXT_JAR_NAME}-${NXT_JAR_VERSION}.jar -NXT_JAR_LOCAL_DIR="${NXT_JAR_LOCAL_REPO}${NXT_JAR_NAMESPACE}${NXT_JAR_NAME}/${NXT_JAR_VERSION}" -NXT_JAR_LOCAL="${NXT_JAR_LOCAL_DIR}/${NXT_JAR_FILE}" -NXT_JAR_LOCAL_TMP="${NXT_JAR_LOCAL_DIR}/.${NXT_JAR_FILE}.$$" -NXT_JAR_URL=${NXT_JAR_REPO}${NXT_JAR_NAMESPACE}${NXT_JAR_NAME}/${NXT_JAR_VERSION}/${NXT_JAR_FILE} - -NXT_JAR_CHK_FILE="$NXT_BUILD_DIR/$NXT_JAR_FILE" -. auto/modules/java_chk_sha512 - -if [ ! -f "$NXT_BUILD_DIR/$NXT_JAR_FILE" ]; then - NXT_JAR_CHK_FILE=$NXT_JAR_LOCAL - . auto/modules/java_chk_sha512 - - if [ ! -f "${NXT_JAR_LOCAL}" ]; then - $echo "getting remote $NXT_JAR_FILE ... " - $echo "getting remote $NXT_JAR_FILE ..." >> $NXT_AUTOCONF_ERR - - mkdir -p "${NXT_JAR_LOCAL_DIR}" - curl --progress-bar "$NXT_JAR_URL" -o "$NXT_JAR_LOCAL_TMP" - - NXT_JAR_CHK_FILE=$NXT_JAR_LOCAL_TMP - . auto/modules/java_chk_sha512 - - mv "$NXT_JAR_LOCAL_TMP" "$NXT_JAR_LOCAL" - else - $echo "getting local $NXT_JAR_FILE" - $echo "getting local $NXT_JAR_FILE ..." >> $NXT_AUTOCONF_ERR - fi - - cp "$NXT_JAR_LOCAL" "$NXT_BUILD_DIR/$NXT_JAR_FILE" -fi - -NXT_JAVA_BUILD_CP="${NXT_JAVA_BUILD_CP}:$NXT_BUILD_DIR/$NXT_JAR_FILE" -NXT_JAVA_INSTALL_JARS="$NXT_JAVA_INSTALL_JARS $NXT_BUILD_DIR/$NXT_JAR_FILE" -NXT_JAVA_UNINSTALL_JARS="$NXT_JAVA_UNINSTALL_JARS \$(DESTDIR)$NXT_JARS/$NXT_JAR_FILE" - -$echo " \"$NXT_JAR_FILE\"," >> $NXT_JAVA_JARS diff --git a/auto/modules/java_jar.sha512 b/auto/modules/java_jar.sha512 deleted file mode 100644 index a689b901..00000000 --- a/auto/modules/java_jar.sha512 +++ /dev/null @@ -1,14 +0,0 @@ -d0c17607eee55e181baa03f1abb2cf77f50e5114c471c2031607206768d8549c74ebb0a276d87dd3f8ea44db5e54e56087311c229ba18ad6013c388fc861beed classgraph-4.8.165.jar -ab441acf5551a7dc81c353eaccb3b3df9e89a48987294d19e39acdb83a5b640fcdff7414cee29f5b96eaa8826647f1d5323e185018fe33a64c402d69c73c9158 ecj-3.26.0.jar -6e1d6fdffcb2acf8daa9ce5b3ad973526a30b3556dc8e950254c68c64cd70e101b28a8acac41b3bd74de6b9c8eac10676afdc3c58ccb1f61a74323721592e0b5 jetty-http-9.4.54.v20240208.jar -780ee47a8722bdfb4b159f440acbfb69afdb73cc329906392b10eba8d30c564aa6377fab129e61b85a56945f01c4403913c80b6ce3158d108d88a3ad64527f06 jetty-server-9.4.54.v20240208.jar -fbe9cf7efeba9f29297f75de3f1c2d98f0e02816a1dc9e6eaddcabb84c3a699a9332218c532017a3707ec57f4f99066bc671708bde4ec84dd873b8403422d7e9 jetty-util-9.4.54.v20240208.jar -1aa9024f49f74b44252f7c90d00bbfdd6aae4e96866708a0c2325def0314c8b7e5ad2fd17bb6b4b135eb2c513fe74b5b591d4b0fe3d1921192cfecadf140b7fa tomcat-api-9.0.86.jar -60a9991ff7b95ef4edfac57cd7c18b6c5177d9aee4f775b5794b5833246b928e1a685b80785babd2f450e3cd18383c58b843b0b5e742252a37044494bc90d608 tomcat-el-api-9.0.86.jar -b09cbfb834564cc7025ffad7bf069569989d3efa3bd176696045aea08bfb53622aa1aece5c84ea4371f0193d4fd477b9179999399e75d04205b219a3ab19bb66 tomcat-jasper-9.0.86.jar -1431469e91debc0ffcf820df2973782221be955dac0739a77d9030ac619cde96320970cb27eb2ff9de1e6bde3227a70b1645d1934da8e10fe2b32c069d33afec tomcat-jasper-el-9.0.86.jar -1ad9ebc1c49beb243c18ab2c459dbd54cab9514223c44b5c7e05d53d290c64c49990fc0fe276c66b1f6f6625acca651fdcb4b7df9e23fb0cc43bc05ad3900798 tomcat-jsp-api-9.0.86.jar -d30055aabf5d45ad350e01702ed0ff4bfbcdd14bee40e1e8a9a7690719816aff019ca961b7970234eaba673c3c13f5cea5dbf1bc0612ce4e8f7de795af2f170d tomcat-juli-9.0.86.jar -d7fa7d7bf35b35b7bb925cce6284e2f750e8e94ee54057daff4e369a32b361e6044e9011048a9dff54b12371ee785d34e82306b60ffae8add76602071e5fc9c5 tomcat-servlet-api-9.0.86.jar -b4a268b79fbfcd610ea5d14446ef71ad5f2ad3da247ae148669e3082ff5fd7f7256a2ecdf2529e4280ed393f53c3a7f6d09a5c38d5653b30b25ab3c4b74ed732 tomcat-util-9.0.86.jar -f2086356c8eca5cfe890232056ce30378422d3994c499845f52ec8641453af02041ae31ffdcb567bb998f0f24465d1ab65456b23e8f781058efdc01658c7252d tomcat-util-scan-9.0.86.jar diff --git a/auto/modules/nodejs b/auto/modules/nodejs deleted file mode 100644 index 472fb3be..00000000 --- a/auto/modules/nodejs +++ /dev/null @@ -1,216 +0,0 @@ - -# Copyright (C) NGINX, Inc. - - -shift - -for nxt_option; do - - case "$nxt_option" in - -*=*) value=`echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) value="" ;; - esac - - case "$nxt_option" in - --node=*) NXT_NODE="$value" ;; - --npm=*) NXT_NPM="$value" ;; - --node-gyp=*) NXT_NODE_GYP="$value" ;; - --local=*) NXT_NODE_LOCAL="$value" ;; - - --help) - cat << END - - --node=FILE set node executable - --npm=FILE set npm executable - --node-gyp=FILE set node-gyp executable - --local=DIRECTORY set directory path for local installation - -END - exit 0 - ;; - - *) - echo - echo $0: error: invalid Node option \"$nxt_option\" - echo - exit 1 - ;; - - esac - -done - - -if [ ! -f $NXT_AUTOCONF_DATA ]; then - echo - echo Please run common $0 before configuring module \"$nxt_module\". - echo - exit 1 -fi - -. $NXT_AUTOCONF_DATA - - -NXT_NODE=${NXT_NODE=node} -NXT_NPM=${NXT_NPM=npm} -NXT_NODE_GYP=${NXT_NODE_GYP=node-gyp} -NXT_NODE_LOCAL=${NXT_NODE_LOCAL=} - - -$echo "configuring nodejs module" -$echo "configuring nodejs module..." >> $NXT_AUTOCONF_ERR - -$echo -n "checking for node ..." -$echo "checking for node ..." >> $NXT_AUTOCONF_ERR - -if /bin/sh -c "${NXT_NODE} -v" >> $NXT_AUTOCONF_ERR 2>&1; then - $echo " found" - - NXT_NODE_VERSION="`${NXT_NODE} -v`" - $echo " + node version ${NXT_NODE_VERSION}" - -else - $echo " not found" - $echo - $echo $0: error: no Node found. - $echo - exit 1; -fi - - -$echo -n "checking for npm ..." -$echo "checking for npm ..." >> $NXT_AUTOCONF_ERR - -if /bin/sh -c "${NXT_NPM} -v" >> $NXT_AUTOCONF_ERR 2>&1; then - $echo " found" - - NXT_NPM_VERSION="`${NXT_NPM} -v`" - $echo " + npm version ${NXT_NPM_VERSION}" - -else - $echo " not found" - $echo - $echo $0: error: no npm found. - $echo - exit 1; -fi - - -$echo -n "checking for node-gyp ..." -$echo "checking for node-gyp ..." >> $NXT_AUTOCONF_ERR - -if /bin/sh -c "${NXT_NODE_GYP} -v" >> $NXT_AUTOCONF_ERR 2>&1; then - $echo " found" - - NXT_NODE_GYP_VERSION="`${NXT_NODE_GYP} -v`" - $echo " + node-gyp version ${NXT_NODE_GYP_VERSION}" - -else - $echo " not found" - $echo - $echo $0: error: no node-gyp found. - $echo - exit 1; -fi - -if grep ^$NXT_NODE: $NXT_MAKEFILE 2>&1 > /dev/null; then - $echo - $echo $0: error: duplicate \"$NXT_NODE\" package configured. - $echo - exit 1; -fi - - -NXT_NODE_TMP=${NXT_BUILD_DIR}/src/${NXT_NODE}/unit-http -NXT_NODE_TMP_G=${NXT_BUILD_DIR}/src/${NXT_NODE}/unit-http-g -NXT_NODE_TARBALL=${NXT_BUILD_DIR}/src/${NXT_NODE}-unit-http.tar.gz -NXT_NODE_TARBALL_G=${NXT_BUILD_DIR}/src/${NXT_NODE}-unit-http-g.tar.gz -NXT_NODE_VERSION_FILE=${NXT_BUILD_DIR}/src/${NXT_NODE}/version.h -NXT_NODE_PACKAGE_FILE=${NXT_BUILD_DIR}/src/${NXT_NODE}/package.json -NXT_NODE_EXPORTS="export UNIT_SRC_PATH=${PWD}/src \ - && export UNIT_BUILD_PATH=${PWD}/${NXT_BUILD_DIR} \ - && export UNIT_LIB_STATIC_PATH=${PWD}/${NXT_BUILD_DIR}/lib/libunit.a" - -if [ -n "$NXT_NODE_LOCAL" ]; then - NXT_NODE_INSTALL=local-install -else - NXT_NODE_INSTALL=install -fi - -cat << END >> $NXT_MAKEFILE - -.PHONY: ${NXT_NODE} -.PHONY: ${NXT_NODE}-copy -.PHONY: ${NXT_NODE}-copy-g -.PHONY: ${NXT_NODE}-install -.PHONY: ${NXT_NODE}-uninstall -.PHONY: ${NXT_NODE}-local-check -.PHONY: ${NXT_NODE}-local-install -.PHONY: ${NXT_NODE}-build -.PHONY: ${NXT_NODE}-publish - -${NXT_NODE}: ${NXT_NODE}-copy $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC - ${NXT_NODE_EXPORTS} && \\ - cd ${NXT_NODE_TMP} && ${NXT_NODE_GYP} configure build clean - -${NXT_NODE}-copy: ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE} - mkdir -p ${NXT_NODE_TMP} - cp -rp src/nodejs/unit-http/* ${NXT_NODE_TMP}/ - cp -p ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE} ${NXT_NODE_TMP}/ - rm -f ${NXT_NODE_TMP}/binding_pub.gyp - -${NXT_NODE}-copy-g: ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE} - mkdir -p ${NXT_NODE_TMP_G} - cp -rp src/nodejs/unit-http/* ${NXT_NODE_TMP_G}/ - cp -p ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE} ${NXT_NODE_TMP_G}/ - mv ${NXT_NODE_TMP_G}/binding_pub.gyp ${NXT_NODE_TMP_G}/binding.gyp - -${NXT_NODE_VERSION_FILE}: ${NXT_VERSION_H} - mkdir -p ${NXT_BUILD_DIR}/src/${NXT_NODE} - $echo '#define NXT_NODE_VERNUM \$(NXT_VERNUM)' > $NXT_NODE_VERSION_FILE - -${NXT_NODE_PACKAGE_FILE}: ${NXT_VERSION_H} src/nodejs/unit-http/package.json - mkdir -p ${NXT_BUILD_DIR}/src/${NXT_NODE} - sed -e "s|%%VERSION%%|\$(NXT_VERSION)|" \ - src/nodejs/unit-http/package.json > ${NXT_NODE_PACKAGE_FILE} - -${NXT_NODE_TARBALL}: ${NXT_NODE}-copy - cd ${NXT_NODE_TMP} && npm pack - mv ${NXT_NODE_TMP}/unit-http-\$(NXT_VERSION).tgz ${NXT_NODE_TARBALL} - -${NXT_NODE_TARBALL_G}: ${NXT_NODE}-copy-g - cd ${NXT_NODE_TMP_G} && npm pack - mv ${NXT_NODE_TMP_G}/unit-http-\$(NXT_VERSION).tgz ${NXT_NODE_TARBALL_G} - - -install: ${NXT_NODE}-$NXT_NODE_INSTALL - -${NXT_NODE}-install: ${NXT_NODE_TARBALL_G} libunit-install - ${NXT_NPM} install -g --unsafe-perm ${PWD}/${NXT_NODE_TARBALL_G} - -${NXT_NODE}-uninstall: - ${NXT_NPM} uninstall -g unit-http - -${NXT_NODE}-local-check: - @test -n "\$(DESTDIR)$NXT_NODE_LOCAL" \\ - || (echo; \\ - echo "error: to make ${NXT_NODE}-local-install you need either"; \\ - echo " to configure --local option"; \\ - echo " or to set DESTDIR environment variable."; \\ - echo; \\ - exit 1) - -${NXT_NODE}-local-install: ${NXT_NODE_TARBALL} ${NXT_NODE}-local-check \ - $NXT_BUILD_DIR/lib/$NXT_LIB_UNIT_STATIC - ${NXT_NODE_EXPORTS} && \\ - mkdir -p \$(DESTDIR)${NXT_NODE_LOCAL} && \\ - cd \$(DESTDIR)${NXT_NODE_LOCAL} && \\ - ${NXT_NPM} install ${PWD}/${NXT_NODE_TARBALL} - - -${NXT_NODE}-build: ${NXT_NODE} - -${NXT_NODE}-publish: ${NXT_NODE} - cd ${NXT_NODE_TMP} && ${NXT_NPM} publish - -END diff --git a/auto/modules/perl b/auto/modules/perl deleted file mode 100644 index 3c88ef0e..00000000 --- a/auto/modules/perl +++ /dev/null @@ -1,208 +0,0 @@ - -# Copyright (C) Alexander Borisov -# Copyright (C) NGINX, Inc. - - -shift - -for nxt_option; do - - case "$nxt_option" in - -*=*) value=`echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) value="" ;; - esac - - case "$nxt_option" in - --perl=*) NXT_PERL="$value" ;; - --module=*) NXT_PERL_MODULE="$value" ;; - - --help) - cat << END - - --perl=FILE set perl executable, default: perl - --module=NAME set unit perl module name - -END - exit 0 - ;; - - *) - echo - echo $0: error: invalid Perl option \"$nxt_option\" - echo - exit 1 - ;; - esac - -done - - -if [ ! -f $NXT_AUTOCONF_DATA ]; then - echo - echo Please run common $0 before configuring module \"$nxt_module\". - echo - exit 1 -fi - -. $NXT_AUTOCONF_DATA - -$echo "configuring Perl module" -$echo "configuring Perl module ..." >> $NXT_AUTOCONF_ERR - -NXT_PERL=${NXT_PERL=perl} -NXT_PERL_MODULE=${NXT_PERL_MODULE=${NXT_PERL##*/}} - -nxt_found=no - -if /bin/sh -c "$NXT_PERL -MConfig -e 'print \"Perl version: \", - \$Config{version}, \"\\n\"'" >> $NXT_AUTOCONF_ERR 2>&1; then - - NXT_PERL_CFLAGS=`$NXT_PERL -MExtUtils::Embed -e ccflags | sed -e 's/^ //;s/ $//'` - NXT_PERL_INCLUDE=`$NXT_PERL -MExtUtils::Embed -e perl_inc | sed -e 's/^ //;s/ $//'` - NXT_PERL_LDOPTS=`$NXT_PERL -MExtUtils::Embed -e ldopts | sed -e 's/^ //;s/ $//'` - - if [ "$NXT_SYSTEM" = "Darwin" ]; then - # OS X system perl wants to link universal binaries - NXT_PERL_LDOPTS=`echo $NXT_PERL_LDOPTS \ - | sed -e 's/-arch i386//' -e 's/-arch x86_64//'` - fi - - nxt_feature="Perl" - nxt_feature_name="" - nxt_feature_run=no - nxt_feature_incs="${NXT_PERL_INCLUDE}" - nxt_feature_libs="${NXT_PERL_LDOPTS}" - nxt_feature_test=" - #define _GNU_SOURCE - #include - #include - - static PerlInterpreter *my_perl; - - int main(void) { - char argv[] = \"\\0-e\\00\"; - char *embedding[] = { &argv[0], &argv[1], &argv[4] }; - - int pargc = 0; - char **pargv = NULL, **penv = NULL; - PERL_SYS_INIT3(&pargc, &pargv, &penv); - - my_perl = perl_alloc(); - perl_construct(my_perl); - perl_parse(my_perl, NULL, 3, embedding, NULL); - PL_exit_flags |= PERL_EXIT_DESTRUCT_END; - perl_run(my_perl); - - perl_destruct(my_perl); - perl_free(my_perl); - PERL_SYS_TERM(); - - return 0; - }" - - . auto/feature - -else - $echo "checking for Perl ... not found" -fi - -if [ $nxt_found = no ]; then - $echo - $echo $0: error: no Perl found. - $echo - exit 1; -fi - - -nxt_feature="Perl version" -nxt_feature_name="" -nxt_feature_run=value -nxt_feature_incs="${NXT_PERL_INCLUDE}" -nxt_feature_libs="${NXT_PERL_LDOPTS}" -nxt_feature_test=" - #define _GNU_SOURCE - #include - #include - - int main(void) { - printf(\"%s\", PERL_VERSION_STRING); - return 0; - }" - -. auto/feature - - -if grep ^$NXT_PERL_MODULE: $NXT_MAKEFILE 2>&1 > /dev/null; then - $echo - $echo $0: error: duplicate \"$NXT_PERL_MODULE\" module configured. - $echo - exit 1; -fi - -$echo " + Perl module: ${NXT_PERL_MODULE}.unit.so" - -. auto/cc/deps - -$echo >> $NXT_MAKEFILE - -NXT_PERL_MODULE_SRCS=" \ - src/perl/nxt_perl_psgi.c \ - src/perl/nxt_perl_psgi_layer.c -" - -# The Perl module object files. - -nxt_objs=$NXT_BUILD_DIR/src/nxt_unit.o - -for nxt_src in $NXT_PERL_MODULE_SRCS; do - - nxt_obj=${nxt_src%.c}-$NXT_PERL_MODULE.o - nxt_dep=${nxt_src%.c}-$NXT_PERL_MODULE.dep - nxt_dep_flags=`nxt_gen_dep_flags` - nxt_dep_post=`nxt_gen_dep_post` - nxt_objs="$nxt_objs $NXT_BUILD_DIR/$nxt_obj" - - cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/$nxt_obj: $nxt_src $NXT_VERSION_H - mkdir -p $NXT_BUILD_DIR/src/perl - \$(CC) -c \$(CFLAGS) $NXT_PERL_CFLAGS \$(NXT_INCS) $NXT_PERL_INCLUDE \\ - $nxt_dep_flags \\ - -o $NXT_BUILD_DIR/$nxt_obj $nxt_src - $nxt_dep_post - --include $NXT_BUILD_DIR/$nxt_dep - -END - -done - -cat << END >> $NXT_MAKEFILE - -.PHONY: ${NXT_PERL_MODULE} -.PHONY: ${NXT_PERL_MODULE}-install -.PHONY: ${NXT_PERL_MODULE}-uninstall - -all: ${NXT_PERL_MODULE} - -${NXT_PERL_MODULE}: $NXT_BUILD_DIR/lib/unit/modules/${NXT_PERL_MODULE}.unit.so - -$NXT_BUILD_DIR/lib/unit/modules/${NXT_PERL_MODULE}.unit.so: $nxt_objs - \$(NXT_MODULE_LINK) -o \$@ $nxt_objs $NXT_PERL_LDOPTS $NXT_LD_OPT - - -install: ${NXT_PERL_MODULE}-install - -${NXT_PERL_MODULE}-install: ${NXT_PERL_MODULE} install-check - install -d \$(DESTDIR)$NXT_MODULESDIR - install -p $NXT_BUILD_DIR/lib/unit/modules/${NXT_PERL_MODULE}.unit.so \\ - \$(DESTDIR)$NXT_MODULESDIR/ - - -uninstall: ${NXT_PERL_MODULE}-uninstall - -${NXT_PERL_MODULE}-uninstall: - rm -f \$(DESTDIR)$NXT_MODULESDIR/${NXT_PERL_MODULE}.unit.so - @rmdir -p \$(DESTDIR)$NXT_MODULESDIR 2>/dev/null || true - -END diff --git a/auto/modules/php b/auto/modules/php deleted file mode 100644 index a0f5379c..00000000 --- a/auto/modules/php +++ /dev/null @@ -1,289 +0,0 @@ - -# Copyright (C) Max Romanov -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -shift - -for nxt_option; do - - case "$nxt_option" in - -*=*) value=`echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) value="" ;; - esac - - case "$nxt_option" in - --config=*) NXT_PHP_CONFIG="$value" ;; - --module=*) NXT_PHP_MODULE="$value" ;; - --lib-path=*) NXT_PHP_LIB_PATH="$value" ;; - --lib-static) NXT_PHP_LIB_STATIC=yes ;; - - --help) - cat << END - - --config=FILE set php-config filename - --module=NAME set unit php module name - --lib-path=DIRECTORY set directory path to libphp.so library - --lib-static enable linking with static libphp.a library - -END - exit 0 - ;; - - *) - echo - echo $0: error: invalid PHP option \"$nxt_option\" - echo - exit 1 - ;; - - esac - -done - - -if [ ! -f $NXT_AUTOCONF_DATA ]; then - echo - echo Please run common $0 before configuring module \"$nxt_module\". - echo - exit 1 -fi - -. $NXT_AUTOCONF_DATA - - -NXT_PHP_CONFIG=${NXT_PHP_CONFIG=php-config} -NXT_PHP=${NXT_PHP_CONFIG%-config*} -NXT_PHP_MODULE=${NXT_PHP_MODULE=${NXT_PHP##*/}} -NXT_PHP_LIB_PATH=${NXT_PHP_LIB_PATH=} -NXT_PHP_LIB_STATIC=${NXT_PHP_LIB_STATIC=no} -NXT_PHP_ADDITIONAL_FLAGS= - - -$echo "configuring PHP module" -$echo "configuring PHP module ..." >> $NXT_AUTOCONF_ERR - -$echo -n "checking for PHP ..." -$echo "checking for PHP ..." >> $NXT_AUTOCONF_ERR - -NXT_PHP_LDFLAGS= - -if /bin/sh -c "${NXT_PHP_CONFIG} --version" >> $NXT_AUTOCONF_ERR 2>&1; then - - $echo " found" - - NXT_PHP_VERSION="`${NXT_PHP_CONFIG} --version`" - NXT_PHP_EXT_DIR="`${NXT_PHP_CONFIG} --extension-dir`" - - $echo " + PHP SAPI: [`${NXT_PHP_CONFIG} --php-sapis`]" - - NXT_PHP_MAJOR_VERSION=${NXT_PHP_VERSION%%.*} - NXT_PHP_MINOR_VERSION=${NXT_PHP_VERSION#*.} - NXT_PHP_MINOR_VERSION=${NXT_PHP_MINOR_VERSION%%.*} - - if [ $NXT_PHP_MAJOR_VERSION = 5 -a $NXT_PHP_MINOR_VERSION -lt 4 ]; then - NXT_PHP_ADDITIONAL_FLAGS=-Wno-write-strings - fi - - NXT_PHP_INCLUDE="`${NXT_PHP_CONFIG} --includes`" - - if [ $NXT_PHP_LIB_STATIC = yes ]; then - - if [ "$NXT_PHP_LIB_PATH" = "" ]; then - $echo - $echo $0: error: --lib-static option requires --lib-path option. - $echo - exit 1; - fi - - NXT_PHP_LIB="$NXT_PHP_LIB_PATH/libphp${NXT_PHP_VERSION%%.*}.a" - NXT_PHP_LDFLAGS="`${NXT_PHP_CONFIG} --ldflags` \ - `${NXT_PHP_CONFIG} --libs`" - - else - if [ $NXT_PHP_MAJOR_VERSION -ge 8 ]; then - NXT_PHP_LIB="-lphp" - else - NXT_PHP_LIB="-lphp${NXT_PHP_VERSION%%.*}" - fi - - if [ "$NXT_PHP_LIB_PATH" != "" ]; then - # "php-config --ldflags" does not contain path to libphp, but - # contains usually path to libraries required by extensions. - NXT_PHP_LDFLAGS="-L${NXT_PHP_LIB_PATH} -Wl,-rpath,${NXT_PHP_LIB_PATH}" - fi - fi - -else - $echo - $echo $0: error: no PHP found. - $echo - exit 1; -fi - - -nxt_feature="PHP version" -nxt_feature_name="" -nxt_feature_run=value -nxt_feature_incs="${NXT_PHP_INCLUDE}" -nxt_feature_libs="${NXT_PHP_LIB} ${NXT_PHP_LDFLAGS}" -nxt_feature_test=" - #include - - int main(void) { - printf(\"%s\", PHP_VERSION); - return 0; - }" - -. auto/feature - - -nxt_feature="PHP embed SAPI" -nxt_feature_name="" -nxt_feature_run=no -nxt_feature_incs="${NXT_PHP_INCLUDE}" -nxt_feature_libs="${NXT_PHP_LIB} ${NXT_PHP_LDFLAGS}" -nxt_feature_test=" - #include - #include - - int main(void) { - #if (PHP_VERSION_ID < 80200) - php_module_startup(NULL, NULL, 0); - #else - php_module_startup(NULL, NULL); - #endif - return 0; - }" - -. auto/feature - -if [ $nxt_found = no ]; then - $echo - $echo $0: error: no PHP embed SAPI found. - $echo - exit 1; -fi - - -nxt_feature="PHP Zend Thread Safety" -nxt_feature_name="" -nxt_feature_run=no -nxt_feature_incs="${NXT_PHP_INCLUDE}" -nxt_feature_libs="${NXT_PHP_LIB} ${NXT_PHP_LDFLAGS}" -nxt_feature_test=" - #include - #include - - int main(void) { - #ifndef ZTS - #error ZTS is not defined. - #endif - return 0; - }" - -. auto/feature - - -# Bug #71041 (https://bugs.php.net/bug.php?id=71041). - -nxt_feature="PHP zend_signal_startup()" -nxt_feature_name="" -nxt_feature_run=no -nxt_feature_incs="${NXT_PHP_INCLUDE}" -nxt_feature_libs="${NXT_PHP_LIB} ${NXT_PHP_LDFLAGS}" -nxt_feature_test=" - #include - #include - - int main(void) { - zend_signal_startup(); - return 0; - }" - -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_ZEND_SIGNAL_STARTUP=1 -else - NXT_ZEND_SIGNAL_STARTUP=0 -fi - - -if grep ^$NXT_PHP_MODULE: $NXT_MAKEFILE 2>&1 > /dev/null; then - $echo - $echo $0: error: duplicate \"$NXT_PHP_MODULE\" module configured. - $echo - exit 1; -fi - - -$echo " + PHP module: ${NXT_PHP_MODULE}.unit.so" - -. auto/cc/deps - -$echo >> $NXT_MAKEFILE - -NXT_PHP_MODULE_SRCS=" \ - src/nxt_php_sapi.c \ -" - -# The php module object files. - -nxt_objs=$NXT_BUILD_DIR/src/nxt_unit.o - -for nxt_src in $NXT_PHP_MODULE_SRCS; do - - nxt_obj=${nxt_src%.c}-$NXT_PHP_MODULE.o - nxt_dep=${nxt_src%.c}-$NXT_PHP_MODULE.dep - nxt_dep_flags=`nxt_gen_dep_flags` - nxt_dep_post=`nxt_gen_dep_post` - nxt_objs="$nxt_objs $NXT_BUILD_DIR/$nxt_obj" - - cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/$nxt_obj: $nxt_src $NXT_VERSION_H - \$(CC) -c \$(CFLAGS) $NXT_PHP_ADDITIONAL_FLAGS \$(NXT_INCS) \\ - $NXT_PHP_INCLUDE -DNXT_ZEND_SIGNAL_STARTUP=$NXT_ZEND_SIGNAL_STARTUP \\ - $nxt_dep_flags \\ - -o $NXT_BUILD_DIR/$nxt_obj $nxt_src - $nxt_dep_post - --include $NXT_BUILD_DIR/$nxt_dep - -END - -done - - -cat << END >> $NXT_MAKEFILE - -.PHONY: ${NXT_PHP_MODULE} -.PHONY: ${NXT_PHP_MODULE}-install -.PHONY: ${NXT_PHP_MODULE}-uninstall - -all: ${NXT_PHP_MODULE} - -${NXT_PHP_MODULE}: $NXT_BUILD_DIR/lib/unit/modules/${NXT_PHP_MODULE}.unit.so - -$NXT_BUILD_DIR/lib/unit/modules/${NXT_PHP_MODULE}.unit.so: $nxt_objs - \$(NXT_MODULE_LINK) -o \$@ \\ - $nxt_objs ${NXT_PHP_LIB} ${NXT_PHP_LDFLAGS} $NXT_LD_OPT - - -install: ${NXT_PHP_MODULE}-install - -${NXT_PHP_MODULE}-install: ${NXT_PHP_MODULE} install-check - install -d \$(DESTDIR)$NXT_MODULESDIR - install -p $NXT_BUILD_DIR/lib/unit/modules/${NXT_PHP_MODULE}.unit.so \\ - \$(DESTDIR)$NXT_MODULESDIR/ - - -uninstall: ${NXT_PHP_MODULE}-uninstall - -${NXT_PHP_MODULE}-uninstall: - rm -f \$(DESTDIR)$NXT_MODULESDIR/${NXT_PHP_MODULE}.unit.so - @rmdir -p \$(DESTDIR)$NXT_MODULESDIR 2>/dev/null || true - -END diff --git a/auto/modules/python b/auto/modules/python deleted file mode 100644 index dfd632a1..00000000 --- a/auto/modules/python +++ /dev/null @@ -1,237 +0,0 @@ - -# Copyright (C) Valentin V. Bartenev -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -shift - -for nxt_option; do - - case "$nxt_option" in - -*=*) value=`echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) value="" ;; - esac - - case "$nxt_option" in - - --config=*) NXT_PYTHON_CONFIG="$value" ;; - --module=*) NXT_PYTHON_MODULE="$value" ;; - --lib-path=*) NXT_PYTHON_LIB_PATH="$value" ;; - - --help) - cat << END - - --config=FILE set python-config filename - --module=NAME set unit python module name - --lib-path=DIRECTORY set directory path to libpython.so library - -END - exit 0 - ;; - - *) - echo - echo $0: error: invalid Python option \"$nxt_option\" - echo - exit 1 - ;; - esac - -done - - -if [ ! -f $NXT_AUTOCONF_DATA ]; then - echo - echo Please run common $0 before configuring module \"$nxt_module\". - echo - exit 1 -fi - -. $NXT_AUTOCONF_DATA - - -NXT_PYTHON_CONFIG=${NXT_PYTHON_CONFIG=python-config} -NXT_PYTHON=${NXT_PYTHON_CONFIG%-config*} -NXT_PYTHON_MODULE=${NXT_PYTHON_MODULE=${NXT_PYTHON##*/}} -NXT_PYTHON_LIB_PATH=${NXT_PYTHON_LIB_PATH=} - - -$echo "configuring Python module" -$echo "configuring Python module ..." >> $NXT_AUTOCONF_ERR - -nxt_found=no - -if /bin/sh -c "$NXT_PYTHON_CONFIG --prefix" >> $NXT_AUTOCONF_ERR 2>&1; then - - if ${NXT_PYTHON_CONFIG} --embed >/dev/null 2>&1; then - NXT_PYTHON_CONFIG="${NXT_PYTHON_CONFIG} --embed" - fi - - NXT_PYTHON_INCLUDE=`${NXT_PYTHON_CONFIG} --includes` - NXT_PYTHON_LIBS=`${NXT_PYTHON_CONFIG} --ldflags` - - if [ "$NXT_PYTHON_LIB_PATH" != "" ]; then - # "python-config --ldflags" may not contain path to libpython. - NXT_PYTHON_LDFLAGS="-L$NXT_PYTHON_LIB_PATH -Wl,-rpath,$NXT_PYTHON_LIB_PATH" - else - NXT_PYTHON_LDFLAGS="" - fi - - nxt_feature="Python" - nxt_feature_name="" - nxt_feature_run=no - nxt_feature_incs="${NXT_PYTHON_INCLUDE}" - nxt_feature_libs="${NXT_PYTHON_LIBS} $NXT_PYTHON_LDFLAGS" - nxt_feature_test=" - #include - - int main(void) { - Py_Initialize(); - return 0; - }" - - . auto/feature - -else - $echo "checking for Python ... not found" -fi - -if [ $nxt_found = no ]; then - $echo - $echo $0: error: no Python found. - $echo - exit 1; -fi - - -nxt_feature="Python version" -nxt_feature_name="" -nxt_feature_run=value -nxt_feature_incs="${NXT_PYTHON_INCLUDE}" -nxt_feature_libs="${NXT_PYTHON_LIBS} $NXT_PYTHON_LDFLAGS" -nxt_feature_test=" - #include - #include - - int main(void) { - printf(\"%s\", PY_VERSION); - return 0; - }" - -. auto/feature - - -if grep ^$NXT_PYTHON_MODULE: $NXT_MAKEFILE 2>&1 > /dev/null; then - $echo - $echo $0: error: duplicate \"$NXT_PYTHON_MODULE\" module configured. - $echo - exit 1; -fi - - -NXT_PYTHON_MOUNTS_HEADER=nxt_${NXT_PYTHON_MODULE}_mounts.h - -$NXT_PYTHON -c 'import os.path -import sys -pyver = "python" + str(sys.version_info[0]) + "." + str(sys.version_info[1]) - -print("static const nxt_fs_mount_t nxt_python_mounts[] = {") - -pattern = "{(u_char *) \"%s\", (u_char *) \"%s\", NXT_FS_BIND, (u_char *) \"bind\", 0, NULL, 1, 1}," -base = None -for p in sys.path: - if len(p) > 0: - if os.path.basename(p) == pyver: - base = p - -if base is None: - raise Exception("failed to compute sys.path mount points") - -print(pattern % (base, base)) - -for p in sys.path: - if len(p) > 0: - if not p.startswith(base): - print(pattern % (p, p)) - -print("};\n\n") - -' > $NXT_BUILD_DIR/include/$NXT_PYTHON_MOUNTS_HEADER - - -$echo " + Python module: ${NXT_PYTHON_MODULE}.unit.so" - -. auto/cc/deps - -$echo >> $NXT_MAKEFILE - -NXT_PYTHON_MODULE_SRCS=" \ - src/python/nxt_python.c \ - src/python/nxt_python_asgi.c \ - src/python/nxt_python_asgi_http.c \ - src/python/nxt_python_asgi_lifespan.c \ - src/python/nxt_python_asgi_str.c \ - src/python/nxt_python_asgi_websocket.c \ - src/python/nxt_python_wsgi.c \ -" - -# The python module object files. - -nxt_objs=$NXT_BUILD_DIR/src/nxt_unit.o - -for nxt_src in $NXT_PYTHON_MODULE_SRCS; do - - nxt_obj=${nxt_src%.c}-$NXT_PYTHON_MODULE.o - nxt_dep=${nxt_src%.c}-$NXT_PYTHON_MODULE.dep - nxt_dep_flags=`nxt_gen_dep_flags` - nxt_dep_post=`nxt_gen_dep_post` - nxt_objs="$nxt_objs $NXT_BUILD_DIR/$nxt_obj" - - cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/$nxt_obj: $nxt_src $NXT_VERSION_H - mkdir -p $NXT_BUILD_DIR/src/python - \$(CC) -c \$(CFLAGS) -DNXT_PYTHON_MOUNTS_H=\"$NXT_PYTHON_MOUNTS_HEADER\" \\ - \$(NXT_INCS) $NXT_PYTHON_INCLUDE \\ - $nxt_dep_flags \\ - -o $NXT_BUILD_DIR/$nxt_obj $nxt_src - $nxt_dep_post - --include $NXT_BUILD_DIR/$nxt_dep - -END - -done - - -cat << END >> $NXT_MAKEFILE - -.PHONY: ${NXT_PYTHON_MODULE} -.PHONY: ${NXT_PYTHON_MODULE}-install -.PHONY: ${NXT_PYTHON_MODULE}-uninstall - -all: ${NXT_PYTHON_MODULE} - -${NXT_PYTHON_MODULE}: $NXT_BUILD_DIR/lib/unit/modules/${NXT_PYTHON_MODULE}.unit.so - -$NXT_BUILD_DIR/lib/unit/modules/${NXT_PYTHON_MODULE}.unit.so: $nxt_objs - \$(NXT_MODULE_LINK) -o \$@ \\ - $nxt_objs $NXT_PYTHON_LIBS $NXT_PYTHON_LDFLAGS $NXT_LD_OPT - - -install: ${NXT_PYTHON_MODULE}-install - -${NXT_PYTHON_MODULE}-install: ${NXT_PYTHON_MODULE} install-check - install -d \$(DESTDIR)$NXT_MODULESDIR - install -p $NXT_BUILD_DIR/lib/unit/modules/${NXT_PYTHON_MODULE}.unit.so \\ - \$(DESTDIR)$NXT_MODULESDIR/ - - -uninstall: ${NXT_PYTHON_MODULE}-uninstall - -${NXT_PYTHON_MODULE}-uninstall: - rm -f \$(DESTDIR)$NXT_MODULESDIR/${NXT_PYTHON_MODULE}.unit.so - @rmdir -p \$(DESTDIR)$NXT_MODULESDIR 2>/dev/null || true - -END diff --git a/auto/modules/ruby b/auto/modules/ruby deleted file mode 100644 index 7a7c9bd3..00000000 --- a/auto/modules/ruby +++ /dev/null @@ -1,274 +0,0 @@ - -# Copyright (C) Alexander Borisov -# Copyright (C) NGINX, Inc. - - -shift - -for nxt_option; do - - case "$nxt_option" in - -*=*) value=`echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) value="" ;; - esac - - case "$nxt_option" in - --ruby=*) NXT_RUBY="$value" ;; - --module=*) NXT_RUBY_MODULE="$value" ;; - - --help) - cat << END - - --ruby=FILE set ruby executable, default: ruby - --module=NAME set unit ruby module name - -END - exit 0 - ;; - - *) - echo - echo $0: error: invalid Ruby option \"$nxt_option\" - echo - exit 1 - ;; - esac - -done - - -if [ ! -f $NXT_AUTOCONF_DATA ]; then - echo - echo Please run common $0 before configuring module \"$nxt_module\". - echo - exit 1 -fi - -. $NXT_AUTOCONF_DATA - -$echo "configuring Ruby module" -$echo "configuring Ruby module ..." >> $NXT_AUTOCONF_ERR - -NXT_RUBY=${NXT_RUBY=ruby} -NXT_RUBY_MODULE=${NXT_RUBY_MODULE=${NXT_RUBY}} - -nxt_found=no - -if /bin/sh -c "$NXT_RUBY -v" >> $NXT_AUTOCONF_ERR 2>&1; then - - NXT_RUBY_CFLAGS= - NXT_RUBY_RUBYHDRDIR=`$NXT_RUBY -rrbconfig -e 'print RbConfig::CONFIG["rubyhdrdir"]'` - NXT_RUBY_ARCHHDRDIR=`$NXT_RUBY -rrbconfig -e 'print RbConfig::CONFIG["rubyarchhdrdir"]'` - NXT_RUBY_SITEDIR=`$NXT_RUBY -rrbconfig -e 'print RbConfig::CONFIG["sitedir"]'` - NXT_RUBY_LIBDIR=`$NXT_RUBY -rrbconfig -e 'print RbConfig::CONFIG["rubylibdir"]'` - NXT_RUBY_TOPDIR=`$NXT_RUBY -rrbconfig -e 'print RbConfig::CONFIG["topdir"]'` - NXT_RUBY_PREFIXDIR=`$NXT_RUBY -rrbconfig -e 'print RbConfig::CONFIG["rubylibprefix"]'` - - NXT_RUBY_GEMPATH=`$NXT_RUBY -rrubygems -e 'print Gem.default_path().join(":")'` - - NXT_RUBY_INCPATH="-I$NXT_RUBY_ARCHHDRDIR -I$NXT_RUBY_RUBYHDRDIR" - - NXT_RUBY_LIBNAME=`$NXT_RUBY -rrbconfig -e 'print RbConfig::CONFIG["RUBY_SO_NAME"]'` - NXT_RUBY_LIBSCONF=`$NXT_RUBY -rrbconfig -e 'print RbConfig::CONFIG["LIBS"]'` - NXT_RUBY_LIBPATH=`$NXT_RUBY -rrbconfig -e 'print RbConfig::CONFIG["libdir"]'` - NXT_RUBY_LIBS="-l$NXT_RUBY_LIBNAME $NXT_RUBY_LIBSCONF" - - if [ $NXT_CC_NAME = clang ]; then - # Workaround Clang bug - nxt_feature="-fdeclspec" - nxt_feature_name= - nxt_feature_run= - nxt_feature_incs="-fdeclspec" - nxt_feature_libs= - nxt_feature_test="#include - - __declspec(noreturn) static void f(void); - - static void f(void) { - exit(0); - } - - int main(void) { - f(); - }" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_RUBY_CFLAGS="$NXT_RUBY_CFLAGS -fdeclspec" - fi - fi - - nxt_feature="Ruby library" - nxt_feature_name="" - nxt_feature_run=value - nxt_feature_incs="${NXT_RUBY_INCPATH} ${NXT_RUBY_CFLAGS}" - nxt_feature_libs="${NXT_RUBY_LIBS}" - nxt_feature_test=" - #include - - int main(void) { - static const char *argv[3] = { - \"NGINX_Unit\", \"-rrbconfig\", - \"-eprint RbConfig::CONFIG['libdir']\" - }; - - RUBY_INIT_STACK; - ruby_init(); - return ruby_run_node(ruby_options(3, (char **) argv)); - }" - - . auto/feature - - if [ "$nxt_feature_value" != "$NXT_RUBY_LIBPATH" ]; then - NXT_RUBY_LIBS="-L$NXT_RUBY_LIBPATH -Wl,-rpath,${NXT_RUBY_LIBPATH} $NXT_RUBY_LIBS" - - nxt_feature="Ruby library in $NXT_RUBY_LIBPATH" - nxt_feature_name="" - nxt_feature_run=no - nxt_feature_incs="${NXT_RUBY_INCPATH} ${NXT_RUBY_CFLAGS}" - nxt_feature_libs="${NXT_RUBY_LIBS}" - nxt_feature_test=" - #include - - int main(void) { - ruby_init(); - return ruby_cleanup(0); - }" - - . auto/feature - fi - -else - $echo "checking for Ruby ... not found" -fi - -if [ $nxt_found = no ]; then - $echo - $echo $0: error: no Ruby found. - $echo - exit 1; -fi - - -nxt_feature="Ruby version" -nxt_feature_name="" -nxt_feature_run=value -nxt_feature_incs="${NXT_RUBY_INCPATH} ${NXT_RUBY_CFLAGS}" -nxt_feature_libs="${NXT_RUBY_LIBS}" -nxt_feature_test=" - #include - #include - - int main(void) { - printf(\"%s\", ruby_version); - return 0; - }" - -. auto/feature - - -if grep ^$NXT_RUBY_MODULE: $NXT_MAKEFILE 2>&1 > /dev/null; then - $echo - $echo $0: error: duplicate \"$NXT_RUBY_MODULE\" module configured. - $echo - exit 1; -fi - - -NXT_RUBY_MOUNTS_HEADER=nxt_${NXT_RUBY_MODULE}_mounts.h -NXT_RUBY_MOUNTS_PATH=$NXT_BUILD_DIR/include/$NXT_RUBY_MOUNTS_HEADER - -cat << END > $NXT_RUBY_MOUNTS_PATH - -static const nxt_fs_mount_t nxt_ruby_mounts[] = { - {(u_char *) "$NXT_RUBY_RUBYHDRDIR", (u_char *) "$NXT_RUBY_RUBYHDRDIR", - NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1}, - {(u_char *) "$NXT_RUBY_ARCHHDRDIR", (u_char *) "$NXT_RUBY_ARCHHDRDIR", - NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1}, - {(u_char *) "$NXT_RUBY_SITEDIR", (u_char *) "$NXT_RUBY_SITEDIR", - NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1}, - {(u_char *) "$NXT_RUBY_LIBDIR", (u_char *) "$NXT_RUBY_LIBDIR", - NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1}, - {(u_char *) "$NXT_RUBY_TOPDIR", (u_char *) "$NXT_RUBY_TOPDIR", - NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1}, - {(u_char *) "$NXT_RUBY_PREFIXDIR", (u_char *) "$NXT_RUBY_PREFIXDIR", - NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1}, - -END - -for path in `echo $NXT_RUBY_GEMPATH | tr ':' '\n'`; do - $echo "{(u_char *) \"$path\", (u_char *) \"$path\"," >> $NXT_RUBY_MOUNTS_PATH - $echo "NXT_FS_BIND, (u_char *) \"bind\", 0, NULL, 1, 1}," >> $NXT_RUBY_MOUNTS_PATH -done - -$echo "};" >> $NXT_RUBY_MOUNTS_PATH - - -$echo " + Ruby module: ${NXT_RUBY_MODULE}.unit.so" - -. auto/cc/deps - -$echo >> $NXT_MAKEFILE - -NXT_RUBY_MODULE_SRCS=" \ - src/ruby/nxt_ruby.c \ - src/ruby/nxt_ruby_stream_io.c -" - -# The Ruby module object files. - -nxt_objs=$NXT_BUILD_DIR/src/nxt_unit.o - -for nxt_src in $NXT_RUBY_MODULE_SRCS; do - - nxt_obj=${nxt_src%.c}-$NXT_RUBY_MODULE.o - nxt_dep=${nxt_src%.c}-$NXT_RUBY_MODULE.dep - nxt_dep_flags=`nxt_gen_dep_flags` - nxt_dep_post=`nxt_gen_dep_post` - nxt_objs="$nxt_objs $NXT_BUILD_DIR/$nxt_obj" - - cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/$nxt_obj: $nxt_src $NXT_VERSION_H - mkdir -p $NXT_BUILD_DIR/src/ruby - \$(CC) -c \$(CFLAGS) $NXT_RUBY_CFLAGS -DNXT_RUBY_MOUNTS_H=\"$NXT_RUBY_MOUNTS_HEADER\" \\ - \$(NXT_INCS) $NXT_RUBY_INCPATH \\ - $nxt_dep_flags \\ - -o \$@ $nxt_src - $nxt_dep_post - --include $NXT_BUILD_DIR/$nxt_dep - -END - -done - -cat << END >> $NXT_MAKEFILE - -.PHONY: ${NXT_RUBY_MODULE} -.PHONY: ${NXT_RUBY_MODULE}-install -.PHONY: ${NXT_RUBY_MODULE}-uninstall - -all: ${NXT_RUBY_MODULE} - -${NXT_RUBY_MODULE}: $NXT_BUILD_DIR/lib/unit/modules/${NXT_RUBY_MODULE}.unit.so - -$NXT_BUILD_DIR/lib/unit/modules/${NXT_RUBY_MODULE}.unit.so: $nxt_objs - \$(NXT_MODULE_LINK) -o \$@ $nxt_objs $NXT_RUBY_LIBS $NXT_LD_OPT - - -install: ${NXT_RUBY_MODULE}-install - -${NXT_RUBY_MODULE}-install: ${NXT_RUBY_MODULE} install-check - install -d \$(DESTDIR)$NXT_MODULESDIR - install -p $NXT_BUILD_DIR/lib/unit/modules/${NXT_RUBY_MODULE}.unit.so \\ - \$(DESTDIR)$NXT_MODULESDIR/ - - -uninstall: ${NXT_RUBY_MODULE}-uninstall - -${NXT_RUBY_MODULE}-uninstall: - rm -f \$(DESTDIR)$NXT_MODULESDIR/${NXT_RUBY_MODULE}.unit.so - @rmdir -p \$(DESTDIR)$NXT_MODULESDIR 2>/dev/null || true - -END diff --git a/auto/modules/wasm b/auto/modules/wasm deleted file mode 100644 index 1f388de6..00000000 --- a/auto/modules/wasm +++ /dev/null @@ -1,207 +0,0 @@ -# Copyright (C) Andrew Clayton -# Copyright (C) F5, Inc. - - -NXT_WASM_RUNTIME=wasmtime - -shift - -for nxt_option; do - - case "$nxt_option" in - -*=*) value=`echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) value="" ;; - esac - - case "$nxt_option" in - - --runtime=*) NXT_WASM_RUNTIME="$value" ;; - --module=*) NXT_WASM_MODULE="$value" ;; - --include-path=*) NXT_WASM_INCLUDE_PATH="$value" ;; - --lib-path=*) NXT_WASM_LIB_PATH="$value" ;; - --rpath*) NXT_WASM_RPATH="$value" ;; - - --help) - cat << END - - --runtime=RUNTIME set the WASM runtime to use (default: wasmtime) - --module=NAME set Unit WASM module name (default: wasm) - --include-path=DIRECTORY set directory path to wasmtime includes - --lib-path=DIRECTORY set directory path to libwasmtime.so library - --rpath[=DIRECTORY] set the rpath (default: --lib-path) - -END - exit 0 - ;; - - *) - echo - echo $0: error: invalid wasm option \"$nxt_option\" - echo - exit 1 - ;; - esac - -done - - -if [ ! -f $NXT_AUTOCONF_DATA ]; then - echo - echo Please run common $0 before configuring module \"$nxt_module\". - echo - exit 1 -fi - -. $NXT_AUTOCONF_DATA - -NXT_WASM=wasm -NXT_WASM_MODULE=${NXT_WASM_MODULE=${NXT_WASM##*/}} - -NXT_WASM_INCLUDE_PATH=${NXT_WASM_INCLUDE_PATH=} -NXT_WASM_LIB_PATH=${NXT_WASM_LIB_PATH=} -NXT_WASM_LDFLAGS= -if [ "$NXT_WASM_RUNTIME" = "wasmtime" ]; then - NXT_WASM_LDFLAGS=-lwasmtime -fi -NXT_WASM_ADDITIONAL_FLAGS="-fno-strict-aliasing \ - -Wno-missing-field-initializers \ - -DNXT_HAVE_WASM_$(echo ${NXT_WASM_RUNTIME} | tr 'a-z' 'A-Z') \ -" - -# Set the RPATH/RUNPATH. -# -# We temporarily disable warning on unbound variables here as -# NXT_WASM_RPATH may be legitimately unset, in which case we -# don't set a RPATH. -# -# If NXT_WASM_RPATH is set but null then we set a RPATH of the -# value of $NXT_WASM_LIB (--lib-path) otherwise use the value -# provided. -set +u -if [ "${NXT_WASM_RPATH+set}" = set ]; then - if [ "$NXT_WASM_RPATH" = "" ]; then - NXT_WASM_RPATH=$NXT_WASM_LIB_PATH - fi - - NXT_WASM_LDFLAGS="-Wl,-rpath,$NXT_WASM_RPATH $NXT_WASM_LDFLAGS" -fi -set -u - -$echo "configuring WASM module" -$echo "configuring WASM module ..." >> $NXT_AUTOCONF_ERR - -nxt_found=no - -if [ "$NXT_WASM_RUNTIME" = "wasmtime" ]; then - nxt_feature="wasmtime" - nxt_feature_name="" - nxt_feature_run=no - nxt_feature_incs="-I${NXT_WASM_INCLUDE_PATH}" - nxt_feature_libs="-L${NXT_WASM_LIB_PATH} $NXT_WASM_LDFLAGS" - nxt_feature_test=" - #include - #include - #include - - int main(void) { - wasm_config_t *c; - - c = wasm_config_new(); - wasm_config_delete(c); - - return 0; - }" - - . auto/feature -fi - -if [ $nxt_found = no ]; then - $echo - $echo $0: error: no $NXT_WASM_RUNTIME found. - $echo - exit 1; -fi - - -if grep ^$NXT_WASM_MODULE: $NXT_MAKEFILE 2>&1 > /dev/null; then - $echo - $echo $0: error: duplicate \"$NXT_WASM_MODULE\" module configured. - $echo - exit 1; -fi - - -$echo " + WASM module: ${NXT_WASM_MODULE}.unit.so" - -. auto/cc/deps - -$echo >> $NXT_MAKEFILE - -NXT_WASM_MODULE_SRCS=" \ - src/wasm/nxt_wasm.c \ -" - -if [ "$NXT_WASM_RUNTIME" = "wasmtime" ]; then - NXT_WASM_MODULE_SRCS="$NXT_WASM_MODULE_SRCS src/wasm/nxt_rt_wasmtime.c" -fi - - -# The wasm module object files. - -nxt_objs=$NXT_BUILD_DIR/src/nxt_unit.o - -for nxt_src in $NXT_WASM_MODULE_SRCS; do - - nxt_obj=${nxt_src%.c}-$NXT_WASM_MODULE.o - nxt_dep=${nxt_src%.c}-$NXT_WASM_MODULE.dep - nxt_dep_flags=`nxt_gen_dep_flags` - nxt_dep_post=`nxt_gen_dep_post` - nxt_objs="$nxt_objs $NXT_BUILD_DIR/$nxt_obj" - - cat << END >> $NXT_MAKEFILE - -$NXT_BUILD_DIR/$nxt_obj: $nxt_src $NXT_VERSION_H - mkdir -p $NXT_BUILD_DIR/src/wasm - \$(CC) -c \$(CFLAGS) $NXT_WASM_ADDITIONAL_FLAGS \$(NXT_INCS) \\ - -I$NXT_WASM_INCLUDE_PATH \\ - $nxt_dep_flags \\ - -o $NXT_BUILD_DIR/$nxt_obj $nxt_src - $nxt_dep_post - --include $NXT_BUILD_DIR/$nxt_dep - -END - -done - - -cat << END >> $NXT_MAKEFILE - -.PHONY: ${NXT_WASM_MODULE} -.PHONY: ${NXT_WASM_MODULE}-install -.PHONY: ${NXT_WASM_MODULE}-uninstall - -all: ${NXT_WASM_MODULE} - -${NXT_WASM_MODULE}: $NXT_BUILD_DIR/lib/unit/modules/${NXT_WASM_MODULE}.unit.so - -$NXT_BUILD_DIR/lib/unit/modules/${NXT_WASM_MODULE}.unit.so: $nxt_objs - \$(NXT_MODULE_LINK) -o \$@ \\ - $nxt_objs -L${NXT_WASM_LIB_PATH} ${NXT_WASM_LDFLAGS} $NXT_LD_OPT - - -install: ${NXT_WASM_MODULE}-install - -${NXT_WASM_MODULE}-install: ${NXT_WASM_MODULE} install-check - install -d \$(DESTDIR)$NXT_MODULESDIR - install -p $NXT_BUILD_DIR/lib/unit/modules/${NXT_WASM_MODULE}.unit.so \\ - \$(DESTDIR)$NXT_MODULESDIR/ - - -uninstall: ${NXT_WASM_MODULE}-uninstall - -${NXT_WASM_MODULE}-uninstall: - rm -f \$(DESTDIR)$NXT_MODULESDIR/${NXT_WASM_MODULE}.unit.so - @rmdir -p \$(DESTDIR)$NXT_MODULESDIR 2>/dev/null || true - -END diff --git a/auto/modules/wasm-wasi-component b/auto/modules/wasm-wasi-component deleted file mode 100644 index bfb6ffcb..00000000 --- a/auto/modules/wasm-wasi-component +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright (C) Andrew Clayton -# Copyright (C) F5, Inc. - - -NXT_WCM_MODULE=wasm-wasi-component -NXT_WCM_MOD_NAME=`echo $NXT_WCM_MODULE | tr '-' '_'`.unit.so - -NXT_WCM_MOD_CARGO="src/wasm-wasi-component/target/release/libwasm_wasi_component.so" - - -shift - -for nxt_option; do - - case "$nxt_option" in - -*=*) value=`echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) value="" ;; - esac - - case "$nxt_option" in - - --help) - cat << END - -END - exit 0 - ;; - - *) - echo - echo $0: error: invalid $NXT_WCM_MODULE option \"$nxt_option\" - echo - exit 1 - ;; - esac - -done - - -if [ ! -f $NXT_AUTOCONF_DATA ]; then - echo - echo Please run common $0 before configuring module \"$nxt_module\". - echo - exit 1 -fi - -. $NXT_AUTOCONF_DATA - -NXT_WCM_WASM_TOOLS_BIN=${NXT_WCM_WASM_TOOLS_BIN=} - - -$echo "configuring $NXT_WCM_MODULE module" -$echo "configuring $NXT_WCM_MODULE module ..." >> $NXT_AUTOCONF_ERR - -$echo -n "looking for rust compiler ... " - -if [ -z `which rustc 2>/dev/null` ]; then - $echo "not found." - exit 1; -fi - -$echo "found." - -$echo -n "looking for cargo ... " - -if [ -z `which cargo 2>/dev/null` ]; then - $echo "not found." - exit 1; -fi - -$echo "found." - - -if grep ^$NXT_WCM_MODULE: $NXT_MAKEFILE 2>&1 > /dev/null; then - $echo - $echo $0: error: duplicate \"$NXT_WCM_MODULE\" module configured. - $echo - exit 1; -fi - - -$echo " + $NXT_WCM_MODULE module: $NXT_WCM_MOD_NAME" - - -NXT_OS=$(uname -o) - -if [ $NXT_OS = "Darwin" ]; then - NXT_CARGO_CMD="cargo rustc --release --manifest-path src/wasm-wasi-component/Cargo.toml -- --emit link=target/release/libwasm_wasi_component.so -C link-args='-undefined dynamic_lookup'" -else - NXT_CARGO_CMD="cargo build --release --manifest-path src/wasm-wasi-component/Cargo.toml" -fi - - -cat << END >> $NXT_MAKEFILE - -.PHONY: ${NXT_WCM_MODULE} -.PHONY: ${NXT_WCM_MODULE}-install -.PHONY: ${NXT_WCM_MODULE}-uninstall - -all: ${NXT_WCM_MODULE} - -${NXT_WCM_MODULE}: ${NXT_WCM_MOD_CARGO} - -${NXT_WCM_MOD_CARGO}: build/src/nxt_unit.o - $NXT_CARGO_CMD - -install: ${NXT_WCM_MODULE}-install - -${NXT_WCM_MODULE}-install: ${NXT_WCM_MODULE} install-check - install -d \$(DESTDIR)$NXT_MODULESDIR - install -p ${NXT_WCM_MOD_CARGO} \\ - \$(DESTDIR)$NXT_MODULESDIR/$NXT_WCM_MOD_NAME - -uninstall: ${NXT_WCM_MODULE}-uninstall - -${NXT_WCM_MODULE}-uninstall: - rm -f \$(DESTDIR)$NXT_MODULESDIR/$NXT_WCM_MOD_NAME - @rmdir -p \$(DESTDIR)$NXT_MODULESDIR 2>/dev/null || true - -END diff --git a/auto/njs b/auto/njs deleted file mode 100644 index c54a27c7..00000000 --- a/auto/njs +++ /dev/null @@ -1,53 +0,0 @@ - -# Copyright (C) NGINX, Inc. - - -nxt_found=no -NXT_HAVE_NJS=NO - -if /bin/sh -c "(pkg-config njs --exists)" >> $NXT_AUTOCONF_ERR 2>&1; -then - NXT_NJS_AUX_CFLAGS= - NXT_NJS_AUX_LIBS= - NXT_NJS_CFLAGS=`pkg-config njs --cflags` - NXT_NJS_LIBS=`pkg-config njs --libs` -else - NXT_NJS_AUX_CFLAGS= - NXT_NJS_AUX_LIBS="$NXT_LIBM $NXT_LIB_AUX_LIBS" - NXT_NJS_CFLAGS= - NXT_NJS_LIBS="-lnjs" -fi - -nxt_feature="NJS" -nxt_feature_name=NXT_HAVE_NJS -nxt_feature_run=no -nxt_feature_incs="$NXT_NJS_CFLAGS $NXT_NJS_AUX_CFLAGS" -nxt_feature_libs="$NXT_NJS_LIBS $NXT_NJS_AUX_LIBS" -nxt_feature_test="#include - - #if NJS_VERSION_NUMBER < 0x000800 - # error NJS < 0.8.0 is not supported. - #endif - - int main(void) { - njs_vm_t *vm; - njs_vm_opt_t opts; - - njs_vm_opt_init(&opts); - - vm = njs_vm_create(&opts); - if (vm == NULL) - return 1; - return 0; - }" -. auto/feature - -if [ $nxt_found = no ]; then - $echo - $echo $0: error: no NJS library \>= 0.8.0 found. - $echo - exit 1; -fi - -NXT_LIB_AUX_CFLAGS="$NXT_LIB_AUX_CFLAGS $NXT_NJS_CFLAGS" -NXT_LIB_AUX_LIBS="$NXT_NJS_LIBS $NXT_LIB_AUX_LIBS" diff --git a/auto/options b/auto/options deleted file mode 100644 index 0550c699..00000000 --- a/auto/options +++ /dev/null @@ -1,172 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Valentin V. Bartenev -# Copyright (C) NGINX, Inc. - - -NXT_CONFIGURE_OPTIONS= -NXT_CFLAGS= -NXT_CC_OPT= -NXT_LD_OPT= - -NXT_DEBUG=NO - -NXT_INET6=YES -NXT_UNIX_DOMAIN=YES - -NXT_PCRE_CFLAGS= -NXT_PCRE_LIB= - -NXT_REGEX=YES -NXT_TRY_PCRE2=YES - -NXT_TLS=NO -NXT_OPENSSL=NO -NXT_GNUTLS=NO -NXT_CYASSL=NO -NXT_POLARSSL=NO - -NXT_NJS=NO - -NXT_TEST_BUILD_EPOLL=NO -NXT_TEST_BUILD_EVENTPORT=NO -NXT_TEST_BUILD_DEVPOLL=NO -NXT_TEST_BUILD_POLLSET=NO - -NXT_TEST_BUILD_FREEBSD_SENDFILE=NO -NXT_TEST_BUILD_LINUX_SENDFILE=NO -NXT_TEST_BUILD_MACOSX_SENDFILE=NO -NXT_TEST_BUILD_SOLARIS_SENDFILEV=NO -NXT_TEST_BUILD_AIX_SEND_FILE=NO -NXT_TEST_BUILD_HPUX_SENDFILE=NO - -NXT_TESTS=NO - -NXT_HELP=NO - -for nxt_option -do - case "$nxt_option" in - -*=*) value=`$echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) value="" ;; - esac - - case "$nxt_option" in - --cc=*) CC="$value" ;; - --cc-opt=*) NXT_CC_OPT="$value" ;; - --ld-opt=*) NXT_LD_OPT="$value" ;; - - --prefix=*) NXT_PREFIX="$value" ;; - --exec-prefix=*) NXT_EXEC_PREFIX="$value" ;; - --bindir=*) NXT_BINDIR="$value" ;; - --sbindir=*) NXT_SBINDIR="$value" ;; - --includedir=*) NXT_INCLUDEDIR="$value" ;; - --incdir=*) - >&2 echo "[warn] option --incdir is deprecated; use --includedir" - NXT_INCLUDEDIR="$value" - ;; - --libdir=*) NXT_LIBDIR="$value" ;; - --modulesdir=*) NXT_MODULESDIR="$value" ;; - --modules=*) - >&2 echo "[warn] option --modules is deprecated; use --modulesdir" - NXT_MODULESDIR="$value" - ;; - --datarootdir=*) NXT_DATAROOTDIR="$value" ;; - --mandir=*) NXT_MANDIR="$value" ;; - --pkgconfigdir=*) NXT_PKGCONFIGDIR="$value" ;; - --localstatedir=*) NXT_LOCALSTATEDIR="$value" ;; - --statedir=*) NXT_STATEDIR="$value" ;; - --state=*) - >&2 echo "[warn] option --state is deprecated; use --statedir" - NXT_STATEDIR="$value" - ;; - --logdir=*) NXT_LOGDIR="$value" ;; - --runstatedir=*) NXT_RUNSTATEDIR="$value" ;; - --tmpdir=*) NXT_TMPDIR="$value" ;; - --tmp=*) - >&2 echo "[warn] option --tmp is deprecated; use --tmpdir" - NXT_TMPDIR="$value" - ;; - - --pid=*) NXT_PID="$value" ;; - --log=*) NXT_LOG="$value" ;; - - --control=*) NXT_CONTROL="$value" ;; - - --user=*) NXT_USER="$value" ;; - --group=*) NXT_GROUP="$value" ;; - - --debug) NXT_DEBUG=YES ;; - - --no-ipv6) NXT_INET6=NO ;; - --no-unix-sockets) NXT_UNIX_DOMAIN=NO ;; - - --no-regex) NXT_REGEX=NO ;; - --no-pcre2) NXT_TRY_PCRE2=NO ;; - - --openssl) NXT_OPENSSL=YES ;; - --gnutls) NXT_GNUTLS=YES ;; - --cyassl) NXT_CYASSL=YES ;; - --polarssl) NXT_POLARSSL=YES ;; - - --njs) NXT_NJS=YES ;; - - --test-build-epoll) NXT_TEST_BUILD_EPOLL=YES ;; - --test-build-eventport) NXT_TEST_BUILD_EVENTPORT=YES ;; - --test-build-devpoll) NXT_TEST_BUILD_DEVPOLL=YES ;; - --test-build-pollset) NXT_TEST_BUILD_POLLSET=YES ;; - - --test-build-freebsd-sendfile) NXT_TEST_BUILD_FREEBSD_SENDFILE=YES ;; - --test-build-linux-sendfile) NXT_TEST_BUILD_LINUX_SENDFILE=YES ;; - --test-build-solaris-sendfilev) NXT_TEST_BUILD_SOLARIS_SENDFILEV=YES ;; - --test-build-macosx-sendfile) NXT_TEST_BUILD_MACOSX_SENDFILE=YES ;; - --test-build-aix-send_file) NXT_TEST_BUILD_AIX_SEND_FILE=YES ;; - --test-build-hpux-sendfile) NXT_TEST_BUILD_HPUX_SENDFILE=YES ;; - - --tests) NXT_TESTS=YES ;; - - --help) - . auto/help - exit 0 - ;; - - *) - $echo - $echo $0: error: invalid option \"$nxt_option\". - $echo Run \"$0 --help\" to see available options. - $echo - exit 1 - ;; - esac - - nxt_opt=`$echo $nxt_option | sed -e "s/\(--[^=]*=\)\(.* .*\)/\1'\2'/"` - - NXT_CONFIGURE_OPTIONS="$NXT_CONFIGURE_OPTIONS $nxt_opt" - -done - - -NXT_PREFIX="${NXT_PREFIX-"/usr/local"}" - -NXT_EXEC_PREFIX="${NXT_EXEC_PREFIX-"$NXT_PREFIX"}" -NXT_BINDIR="${NXT_BINDIR-"$NXT_EXEC_PREFIX/bin"}" -NXT_SBINDIR="${NXT_SBINDIR-"$NXT_EXEC_PREFIX/sbin"}" - -NXT_INCLUDEDIR="${NXT_INCLUDEDIR-"$NXT_PREFIX/include"}" - -NXT_LIBDIR="${NXT_LIBDIR-"$NXT_PREFIX/lib"}" -NXT_MODULESDIR="${NXT_MODULESDIR-"$NXT_LIBDIR/unit/modules"}" - -NXT_DATAROOTDIR="${NXT_DATAROOTDIR-"$NXT_PREFIX/share"}" -NXT_MANDIR="${NXT_MANDIR-"$NXT_DATAROOTDIR/man"}" -NXT_PKGCONFIGDIR="${NXT_PKGCONFIGDIR-"$NXT_DATAROOTDIR/pkgconfig"}" - -NXT_LOCALSTATEDIR="${NXT_LOCALSTATEDIR-"$NXT_PREFIX/var"}" -NXT_STATEDIR="${NXT_STATEDIR-"$NXT_LOCALSTATEDIR/lib/unit"}" -NXT_LOGDIR="${NXT_LOGDIR-"$NXT_LOCALSTATEDIR/log/unit"}" -NXT_LOG="${NXT_LOG-"$NXT_LOGDIR/unit.log"}" -NXT_RUNSTATEDIR="${NXT_RUNSTATEDIR-"$NXT_LOCALSTATEDIR/run/unit"}" -NXT_CONTROL="${NXT_CONTROL-"unix:$NXT_RUNSTATEDIR/control.unit.sock"}" -NXT_PID="${NXT_PID-"$NXT_RUNSTATEDIR/unit.pid"}" - -NXT_TMPDIR="${NXT_TMPDIR-"/tmp"}" diff --git a/auto/os/conf b/auto/os/conf deleted file mode 100644 index bc1f5ef7..00000000 --- a/auto/os/conf +++ /dev/null @@ -1,278 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# To support dynamically loaded modules libnxt library must be a shared -# object itself because an application linked with static libnxt library -# may lack code required by the modules. Dynamic linkers allow to specify -# relative path in SONAME library entry or in RPATH executable entry. -# -# Solaris 7, Linux 2.2, and FreeBSD 7.3 support $ORIGIN variable. -# MacOSX supports @executable_path variable. -# NetBSD does not support $ORIGIN variable. -# -# "ar -r" is enough to create a static library, ranlib is surplus. -# "ar -c" disables the "creating archive" warning. - - -case "$NXT_SYSTEM" in - - Linux) - nxt_have=NXT_LINUX . auto/have - - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -shared -Wl,-soname,libnxt.so" - NXT_SHARED_LOCAL_LINK="\$(CC) -shared \ - -Wl,-soname,\\\$\$ORIGIN/libnxt.so" - NXT_MODULE_LINK="\$(CC) -shared" - - # "-Wl,-E" exports symbols of executable file. - NXT_EXEC_LINK="\$(CC) -Wl,-E" - NXT_SHARED_LOCAL_EXEC_LINK= - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.so" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.so" - - NXT_LIB_UNIT_STATIC="libunit.a" - - NXT_LIBM="-lm" - NXT_LIBS="$NXT_LIBRT $NXT_LIBDL $NXT_PTHREAD" - ;; - - FreeBSD) - nxt_have=NXT_FREEBSD . auto/have - - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -shared -Wl,-soname,libnxt.so" - NXT_SHARED_LOCAL_LINK="\$(CC) -shared \ - -Wl,-soname,\\\$\$ORIGIN/libnxt.so" - NXT_MODULE_LINK="\$(CC) -shared" - - # "-Wl,-E" exports symbols of executable file. - NXT_EXEC_LINK="\$(CC) -Wl,-E" - # "-Wl,-z,origin" enables $ORIGIN processing. - NXT_SHARED_LOCAL_EXEC_LINK="-Wl,-z,origin" - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.so" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.so" - - NXT_LIB_UNIT_STATIC="libunit.a" - - NXT_LIBM="-lm" - NXT_LIBS="$NXT_LIBRT $NXT_PTHREAD" - ;; - - SunOS) - nxt_have=NXT_SOLARIS . auto/have - - case "$NXT_CC_NAME" in - - SunC): - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -G -h libnxt.so" - NXT_SHARED_LOCAL_LINK="\$(CC) -G -h \\\$\$ORIGIN/libnxt.so" - NXT_MODULE_LINK="\$(CC) -G" - ;; - - *) - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -shared -Wl,-soname,libnxt.so" - NXT_SHARED_LOCAL_LINK="\$(CC) -shared \ - -Wl,-soname,\\\$\$ORIGIN/libnxt.so" - NXT_MODULE_LINK="\$(CC) -shared" - ;; - esac - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.so" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.so" - - NXT_LIB_UNIT_STATIC="libunit.a" - - NXT_EXEC_LINK="\$(CC)" - NXT_SHARED_LOCAL_EXEC_LINK= - - NXT_LIBM="-lm" - NXT_LIBS="-lsocket $NXT_LIBSENDFILE" - NXT_LIBS="$NXT_LIBS $NXT_LIBRT $NXT_LIBDL $NXT_PTHREAD" - ;; - - Darwin) - nxt_have=NXT_MACOSX . auto/have - - # HFS+ volumes are caseless by default. - nxt_have=NXT_HAVE_CASELESS_FILESYSTEM . auto/have - - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -dynamiclib" - NXT_SHARED_LOCAL_LINK="\$(CC) -dynamiclib \ - -install_name @executable_path/libnxt.dylib" - NXT_MODULE_LINK="\$(CC) -dynamiclib -undefined dynamic_lookup" - - NXT_EXEC_LINK="\$(CC)" - NXT_SHARED_LOCAL_EXEC_LINK= - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.dylib" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.dylib" - - NXT_LIB_UNIT_STATIC="libunit.a" - - # MacOSX libm.dylib is a symlink to libSystem.dylib. - NXT_LIBM= - NXT_LIBS= - - ;; - - NetBSD) - nxt_have=NXT_NETBSD . auto/have - - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -shared" - NXT_SHARED_LOCAL_LINK="\$(CC) -shared" - NXT_MODULE_LINK="\$(CC) -shared" - - # "-Wl,-E" exports symbols of executable file. - NXT_EXEC_LINK="\$(CC) -Wl,-E" - NXT_SHARED_LOCAL_EXEC_LINK= - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.so" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.so" - - NXT_LIB_UNIT_STATIC="libunit.a" - - NXT_LIBM="-lm" - NXT_LIBS="$NXT_LIBRT $NXT_PTHREAD" - ;; - - OpenBSD) - nxt_have=NXT_OPENBSD . auto/have - - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -shared" - NXT_SHARED_LOCAL_LINK="\$(CC) -shared" - NXT_MODULE_LINK="\$(CC) -shared" - - # "-Wl,-E" exports symbols of executable file. - NXT_EXEC_LINK="\$(CC) -Wl,-E" - NXT_SHARED_LOCAL_EXEC_LINK= - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.so" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.so" - - NXT_LIB_UNIT_STATIC="libunit.a" - - NXT_LIBM="-lm" - NXT_LIBS="$NXT_PTHREAD" - ;; - - DragonFly) - nxt_have=NXT_DRAGONFLY . auto/have - - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -shared" - NXT_SHARED_LOCAL_LINK="\$(CC) -shared" - NXT_MODULE_LINK="\$(CC) -shared" - - # "-Wl,-E" exports symbols of executable file. - NXT_EXEC_LINK="\$(CC) -Wl,-E" - NXT_SHARED_LOCAL_EXEC_LINK= - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.so" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.so" - - NXT_LIB_UNIT_STATIC="libunit.a" - - NXT_LIBM="-lm" - NXT_LIBS="$NXT_LIBRT $NXT_PTHREAD" - ;; - - AIX) - nxt_have=NXT_AIX . auto/have - - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -G" - NXT_SHARED_LOCAL_LINK="\$(CC) -G" - NXT_MODULE_LINK="\$(CC) -G" - - NXT_EXEC_LINK="\$(CC)" - NXT_SHARED_LOCAL_EXEC_LINK= - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.so" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.so" - - NXT_LIB_UNIT_STATIC="libunit.a" - - NXT_LIBM="-lm" - NXT_LIBS="$NXT_PTHREAD" - ;; - - HP-UX) - nxt_have=NXT_HPUX . auto/have - - NXT_EXEC_LINK="\$(CC)" - NXT_SHARED_LOCAL_EXEC_LINK= - - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -shared" - NXT_SHARED_LOCAL_LINK="\$(CC) -shared" - NXT_MODULE_LINK="\$(CC) -shared" - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.so" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.so" - - NXT_LIB_UNIT_STATIC="libunit.a" - - NXT_LIBM="-lm" - NXT_LIBS="$NXT_PTHREAD $NXT_LIBHG" - ;; - - QNX) - nxt_have=NXT_QNX . auto/have - - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -shared" - NXT_SHARED_LOCAL_LINK="\$(CC) -shared" - NXT_MODULE_LINK="\$(CC) -shared" - - NXT_EXEC_LINK="\$(CC)" - NXT_SHARED_LOCAL_EXEC_LINK= - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.so" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.so" - - NXT_LIB_UNIT_STATIC="libunit.a" - - NXT_LIBM="-lm" - NXT_LIBS="$NXT_PTHREAD" - ;; - - *) - NXT_STATIC_LINK="\$(AR) -r -c" - NXT_SHARED_LINK="\$(CC) -shared" - NXT_SHARED_LOCAL_LINK="\$(CC) -shared" - NXT_MODULE_LINK="\$(CC) -shared" - - # "-Wl,-E" exports symbols of executable file. - NXT_EXEC_LINK="\$(CC) -Wl,-E" - NXT_SHARED_LOCAL_EXEC_LINK= - - NXT_LIB_STATIC="libnxt.a" - NXT_LIB_SHARED="libnxt.so" - NXT_LIB_SHARED_LOCAL="$NXT_BUILD_DIR/lib/libnxt.so" - - NXT_LIB_UNIT_STATIC="libunit.a" - - NXT_LIBM="-lm" - NXT_LIBS="$NXT_LIBRT $NXT_LIBDL $NXT_PTHREAD" - ;; -esac diff --git a/auto/os/test b/auto/os/test deleted file mode 100644 index b7e73299..00000000 --- a/auto/os/test +++ /dev/null @@ -1,101 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -NXT_SYSTEM=`uname -s 2>/dev/null` - - -case "$NXT_SYSTEM" in - - Linux) - NXT_SYSTEM_VERSION=`uname -r 2>/dev/null` - # Linux uname -p can return "unknown". - NXT_SYSTEM_PLATFORM=`uname -m 2>/dev/null` - echo=echo - CC=${CC:-cc} - AR=${AR:-ar} - ;; - - FreeBSD | NetBSD | OpenBSD | DragonFly) - NXT_SYSTEM_VERSION=`uname -r 2>/dev/null` - NXT_SYSTEM_PLATFORM=`uname -m 2>/dev/null` - echo=echo - CC=${CC:-cc} - AR=${AR:-ar} - ;; - - SunOS) - NXT_SYSTEM_VERSION=`uname -r 2>/dev/null` - NXT_SYSTEM_PLATFORM=`uname -p 2>/dev/null` - echo=echo - CC=${CC:-gcc} - AR=${AR:-ar} - - NXT_TEST_CFLAGS="$NXT_TEST_CFLAGS -D_XOPEN_SOURCE" - NXT_TEST_CFLAGS="$NXT_TEST_CFLAGS -D_XOPEN_SOURCE_EXTENDED=1" - NXT_TEST_CFLAGS="$NXT_TEST_CFLAGS -D__EXTENSIONS__" - NXT_TEST_LIBS="-lsocket" - ;; - - Darwin) - NXT_SYSTEM_VERSION=`uname -r 2>/dev/null` - NXT_SYSTEM_PLATFORM=`uname -m 2>/dev/null` - echo=echo - CC=${CC:-cc} - AR=${AR:-ar} - ;; - - AIX) - NXT_SYSTEM_VERSION="`uname -v 2>/dev/null`.`uname -r 2>/dev/null`" - NXT_SYSTEM_PLATFORM=`uname -p 2>/dev/null` - echo=echo - CC=${CC:-gcc} - AR=${AR:-ar} - ;; - - HP-UX) - NXT_SYSTEM_VERSION=`uname -r 2>/dev/null` - NXT_SYSTEM_PLATFORM=`uname -m 2>/dev/null` - echo=echo - CC=${CC:-gcc} - AR=${AR:-ar} - - NXT_TEST_CFLAGS="$NXT_TEST_CFLAGS -D_XOPEN_SOURCE" - NXT_TEST_CFLAGS="$NXT_TEST_CFLAGS -D_XOPEN_SOURCE_EXTENDED" - NXT_TEST_CFLAGS="$NXT_TEST_CFLAGS -D_HPUX_ALT_XOPEN_SOCKET_API" - ;; - - QNX) - NXT_SYSTEM_VERSION=`uname -r 2>/dev/null` - NXT_SYSTEM_PLATFORM=`uname -p 2>/dev/null` - echo=echo - CC=${CC:-gcc} - AR=${AR:-ar} - ;; - - MINGW*) - # MinGW /bin/sh builtin "echo" omits newline under Wine - # for some reason, so use a portable echo.c program built - # using MinGW GCC with only msvcrt.dll dependence. - - NXT_SYSTEM_VERSION=`uname -r 2>/dev/null` - NXT_SYSTEM_PLATFORM=`uname -m 2>/dev/null` - echo=auto/echo/echo.exe - CC=${CC:-cl} - AR=${AR:-ar} - NXT_WINDOWS=YES - ;; - - *) - NXT_SYSTEM_VERSION=`uname -r 2>/dev/null` - NXT_SYSTEM_PLATFORM=`uname -p 2>/dev/null` - echo=echo - CC=${CC:-gcc} - AR=${AR:-ar} - ;; - -esac - -$echo "configuring Unit $NXT_VERSION" \ - "for $NXT_SYSTEM $NXT_SYSTEM_VERSION $NXT_SYSTEM_PLATFORM" diff --git a/auto/pcre b/auto/pcre deleted file mode 100644 index 27205118..00000000 --- a/auto/pcre +++ /dev/null @@ -1,77 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -nxt_found=no -NXT_HAVE_PCRE2=NO - -if [ $NXT_TRY_PCRE2 = YES ]; then - if /bin/sh -c "(pcre2-config --version)" >> $NXT_AUTOCONF_ERR 2>&1; then - - NXT_PCRE_CFLAGS=`pcre2-config --cflags` - NXT_PCRE_LIB=`pcre2-config --libs8` - - nxt_feature="PCRE2 library" - nxt_feature_name=NXT_HAVE_PCRE2 - nxt_feature_run=no - nxt_feature_incs="-DPCRE2_CODE_UNIT_WIDTH=8 $NXT_PCRE_CFLAGS" - nxt_feature_libs=$NXT_PCRE_LIB - nxt_feature_test="#include - - int main(void) { - pcre2_code *re; - - re = pcre2_compile((PCRE2_SPTR)\"\", - PCRE2_ZERO_TERMINATED, 0, - NULL, NULL, NULL); - return (re == NULL); - }" - - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_HAVE_PCRE2=YES - $echo " + PCRE2 version: `pcre2-config --version`" - fi - fi -fi - -if [ $nxt_found = no ]; then - if /bin/sh -c "(pcre-config --version)" >> $NXT_AUTOCONF_ERR 2>&1; then - - NXT_PCRE_CFLAGS=`pcre-config --cflags` - NXT_PCRE_LIB=`pcre-config --libs` - - nxt_feature="PCRE library" - nxt_feature_name=NXT_HAVE_PCRE - nxt_feature_run=no - nxt_feature_incs=$NXT_PCRE_CFLAGS - nxt_feature_libs=$NXT_PCRE_LIB - nxt_feature_test="#include - - int main(void) { - pcre *re; - - re = pcre_compile(NULL, 0, NULL, 0, NULL); - if (re == NULL) - return 1; - return 0; - }" - . auto/feature - - if [ $nxt_found = yes ]; then - $echo " + PCRE version: `pcre-config --version`" - fi - fi -fi - -if [ $nxt_found = yes ]; then - nxt_have=NXT_HAVE_REGEX . auto/have - -else - $echo - $echo $0: error: no PCRE library found. - $echo - exit 1; -fi diff --git a/auto/save b/auto/save deleted file mode 100644 index 9fb0ca12..00000000 --- a/auto/save +++ /dev/null @@ -1,34 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -cat << END > $NXT_AUTOCONF_DATA - -NXT_SYSTEM='$NXT_SYSTEM' - -CC='$CC' -CFLAGS='$CFLAGS' - -NXT_CC_NAME='$NXT_CC_NAME' -NXT_CFLAGS='$NXT_CFLAGS' -NXT_CC_OPT='$NXT_CC_OPT' -NXT_LD_OPT='$NXT_LD_OPT' -NXT_MODULE_LINK='$NXT_MODULE_LINK' - -NXT_TEST_CFLAGS='$NXT_TEST_CFLAGS' -NXT_TEST_LIBS='$NXT_TEST_LIBS' - -NXT_LIBRT='$NXT_LIBRT' - -echo=$NXT_BUILD_DIR/bin/echo - -NXT_LIB_AUX_CFLAGS= -NXT_LIB_AUX_LIBS= - -NXT_LIB_UNIT_STATIC='$NXT_LIB_UNIT_STATIC' - -NXT_MODULESDIR='$NXT_MODULESDIR' -NXT_TMPDIR='$NXT_TMPDIR' - -END diff --git a/auto/sendfile b/auto/sendfile deleted file mode 100644 index abbda6c7..00000000 --- a/auto/sendfile +++ /dev/null @@ -1,164 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -NXT_HAVE_LINUX_SENDFILE=NO -NXT_HAVE_FREEBSD_SENDFILE=NO -NXT_HAVE_MACOSX_SENDFILE=NO -NXT_HAVE_SOLARIS_SENDFILEV=NO -NXT_HAVE_AIX_SEND_FILE=NO -NXT_HAVE_HPUX_SENDFILE=NO - - -# Linux sendfile(). - -nxt_feature="Linux sendfile()" -nxt_feature_name=NXT_HAVE_LINUX_SENDFILE -nxt_feature_test="#include - - int main(void) { - off_t offset; - - sendfile(-1, -1, &offset, 0); - return 0; - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_HAVE_LINUX_SENDFILE=YES -fi - - -if [ $nxt_found = no ]; then - # FreeBSD sendfile(). - - nxt_feature="FreeBSD sendfile()" - nxt_feature_name=NXT_HAVE_FREEBSD_SENDFILE - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - #include - #include - #include - - int main(void) { - off_t sent; - - sendfile(-1, -1, 0, 0, NULL, &sent, 0); - return 0; - }" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_HAVE_FREEBSD_SENDFILE=YES - fi -fi - - -if [ $nxt_found = no ]; then - - # MacOSX sendfile(). - - nxt_feature="MacOSX sendfile()" - nxt_feature_name=NXT_HAVE_MACOSX_SENDFILE - nxt_feature_libs= - nxt_feature_test="#include - #include - #include - #include - - int main(void) { - off_t sent; - - sendfile(-1, -1, 0, &sent, NULL, 0); - return 0; - }" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_HAVE_MACOSX_SENDFILE=YES - fi -fi - - -if [ $nxt_found = no ]; then - # No supported sendfile() found. Using our replacement. - nxt_found=yes -fi - - -NXT_LIBSENDFILE= - -if [ $nxt_found = no ]; then - - # Solaris 8 sendfilev(). - - nxt_feature="Solaris sendfilev()" - nxt_feature_name=NXT_HAVE_SOLARIS_SENDFILEV - nxt_feature_libs="-lsendfile" - nxt_feature_test="#include - - int main(void) { - size_t sent; - struct sendfilevec vec; - - sendfilev(-1, &vec, 0, &sent); - return 0; - }" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_HAVE_SOLARIS_SENDFILEV=YES - NXT_LIBSENDFILE=$nxt_feature_libs - fi -fi - - -if [ $nxt_found = no ]; then - - # AIX send_file(). - - nxt_feature="AIX send_file()" - nxt_feature_name=NXT_HAVE_AIX_SEND_FILE - nxt_feature_test="#include - - int main(void) { - int s; - struct sf_parms sf_iobuf; - - send_file(&s, &sf_iobuf, 0); - return 0; - }" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_HAVE_AIX_SEND_FILE=YES - fi -fi - - -if [ $nxt_found = no ]; then - - # HP-UX sendfile(). - - nxt_feature="HP-UX sendfile()" - nxt_feature_name=NXT_HAVE_HPUX_SENDFILE - nxt_feature_libs= - nxt_feature_test="#include - #include - - sbsize_t sendfile(int s, int fd, off_t offset, - bsize_t nbytes, const struct iovec *hdtrl, int flags); - - int main(void) { - sendfile(-1, -1, 0, 0, NULL, 0); - return 0; - }" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_HAVE_HPUX_SENDFILE=YES - fi -fi diff --git a/auto/shmem b/auto/shmem deleted file mode 100644 index c434a58f..00000000 --- a/auto/shmem +++ /dev/null @@ -1,139 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -NXT_SHM_PREFIX="/" - -# FreeBSD, Solaris, MacOSX - -nxt_feature="shm_open()" -nxt_feature_name=NXT_HAVE_SHM_OPEN -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - #include - #include - - int main(void) { - int ret; - static char name[] = \"/unit.configure\"; - - shm_unlink(name); - - int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, - S_IRUSR | S_IWUSR); - if (fd == -1) - return 1; - - ret = (access(name, F_OK) == 0); - shm_unlink(name); - - return ret; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # Linux and NetBSD 7.0 shm_open() are in librt. - - nxt_feature="shm_open() in librt" - nxt_feature_libs="-lrt" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_LIBRT=$nxt_feature_libs - fi -fi - - -if [ $nxt_found = no ]; then - - # DragonFly has no separate namespace for shm_open(). - - nxt_feature="shm_open() in /tmp directory" - nxt_feature_libs= - nxt_feature_test="#include - #include - #include - #include - - int main(void) { - static char name[] = \"/tmp/unit.configure\"; - - shm_unlink(name); - - int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, - S_IRUSR | S_IWUSR); - if (fd == -1) - return 1; - - shm_unlink(name); - return 0; - }" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_SHM_PREFIX="/tmp/" - fi -fi - -nxt_shm_open_found=$nxt_found - - -# FreeBSD 8.0 - -nxt_feature="shm_open(SHM_ANON)" -nxt_feature_name=NXT_HAVE_SHM_OPEN_ANON -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - - int main(void) { - int fd = shm_open(SHM_ANON, O_RDWR, S_IRUSR | S_IWUSR); - if (fd == -1) - return 1; - - return 0; - }" -. auto/feature - -if [ "$nxt_shm_open_found" = no ]; then - nxt_shm_open_found=$nxt_found -fi - - -# Linux - -nxt_feature="memfd_create()" -nxt_feature_name=NXT_HAVE_MEMFD_CREATE -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - - int main(void) { - static char name[] = \"/unit.configure\"; - - int fd = syscall(SYS_memfd_create, name, MFD_CLOEXEC); - if (fd == -1) - return 1; - - return 0; - }" -. auto/feature - - -if [ "$nxt_shm_open_found$nxt_found" = nono ]; then - $echo - $echo $0: error: no shared memory implementation found. - $echo - exit 1; -fi diff --git a/auto/sockets b/auto/sockets deleted file mode 100644 index 241b88eb..00000000 --- a/auto/sockets +++ /dev/null @@ -1,280 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -if [ $NXT_INET6 = YES ]; then - - nxt_feature="AF_INET6" - nxt_feature_name=NXT_INET6 - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - #include - #include - #include - - int main(void) { - struct sockaddr_in6 sin6; - - sin6.sin6_family = AF_INET6; - printf(\"%d\", sin6.sin6_family); - return 0; - }" - . auto/feature -fi - - -# FreeBSD, MacOSX, NetBSD, OpenBSD. - -nxt_feature="sockaddr.sa_len" -nxt_feature_name=NXT_SOCKADDR_SA_LEN -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - struct sockaddr sa; - - sa.sa_len = 0; - printf(\"%d\", sa.sa_len); - return 0; - }" -. auto/feature - - -nxt_feature="struct sockaddr size" -nxt_feature_name=NXT_HAVE_SOCKADDR -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - printf(\"%d\", (int) sizeof(struct sockaddr)); - return 0; - }" -. auto/feature - - -nxt_feature="struct sockaddr_in size" -nxt_feature_name=NXT_HAVE_SOCKADDR_IN -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - - int main(void) { - printf(\"%d\", (int) sizeof(struct sockaddr_in)); - return 0; - }" -. auto/feature - - -nxt_feature="struct sockaddr_in6 size" -nxt_feature_name=NXT_HAVE_SOCKADDR_IN6 -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - - int main(void) { - printf(\"%d\", (int) sizeof(struct sockaddr_in6)); - return 0; - }" -. auto/feature - - -nxt_feature="struct sockaddr_un size" -nxt_feature_name=NXT_HAVE_SOCKADDR_UN -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - - int main(void) { - printf(\"%d\", (int) sizeof(struct sockaddr_un)); - return 0; - }" -. auto/feature - - -nxt_feature="struct sockaddr_storage size" -nxt_feature_name=NXT_HAVE_SOCKADDR_STORAGE -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - printf(\"%d\", (int) sizeof(struct sockaddr_storage)); - return 0; - }" -. auto/feature - - -nxt_feature="socketpair(AF_UNIX, SOCK_SEQPACKET)" -nxt_feature_name=NXT_HAVE_AF_UNIX_SOCK_SEQPACKET -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - int pair[2]; - - if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) != 0) - return 1; - return 0; - }" -. auto/feature - - -nxt_feature="struct msghdr.msg_control" -nxt_feature_name=NXT_HAVE_MSGHDR_MSG_CONTROL -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - struct msghdr msg; - - printf(\"%d\", (int) sizeof(msg.msg_control)); - return 0; - }" -. auto/feature - -if [ $nxt_found = no ]; then - $echo - $echo $0: error: no msghdr.msg_control struct member. - $echo - exit 1; -fi - - -if [ $NXT_SYSTEM != DragonFly ]; then - nxt_feature="sockopt SO_PASSCRED" - nxt_feature_name=NXT_HAVE_SOCKOPT_SO_PASSCRED - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#define _GNU_SOURCE - #include - - int main(void) { - return SO_PASSCRED == 0; - }" - . auto/feature - - - if [ $nxt_found = yes ]; then - nxt_feature="struct ucred" - nxt_feature_name=NXT_HAVE_UCRED - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#define _GNU_SOURCE - #include - #include - - int main(void) { - return sizeof(struct ucred); - }" - . auto/feature - fi - - - nxt_feature="struct cmsgcred" - nxt_feature_name=NXT_HAVE_MSGHDR_CMSGCRED - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#define _GNU_SOURCE - #include - - int main(void) { - return sizeof(struct cmsgcred); - }" - . auto/feature -fi - - -nxt_feature="sys/filio.h" -nxt_feature_name=NXT_HAVE_SYS_FILIO_H -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - return 0; - }" -. auto/feature - - -nxt_feature="ioctl(FIONBIO)" -nxt_feature_name=NXT_HAVE_FIONBIO -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - #include - - int main(void) { - int nb; - - nb = 0; - ioctl(-1, FIONBIO, &nb); - return 0; - }" -. auto/feature - - -# socket(SOCK_NONBLOCK), Linux 2.6.27/glibc 2.10, NetBSD 6.0, FreeBSD 9.2. - -nxt_feature="socket(SOCK_NONBLOCK)" -nxt_feature_name=NXT_HAVE_SOCK_NONBLOCK -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#define _GNU_SOURCE - #include - - int main(void) { - socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - return 0; - }" -. auto/feature - - -# accept4(), Linux 2.6.28/glibc 2.10, NetBSD 6.0, FreeBSD 9.2. - -nxt_feature="accept4()" -nxt_feature_name=NXT_HAVE_ACCEPT4 -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#define _GNU_SOURCE - #include - #include - - int main(void) { - accept4(0, NULL, NULL, SOCK_NONBLOCK); - return 0; - }" -. auto/feature diff --git a/auto/sources b/auto/sources deleted file mode 100644 index 6ee4d87b..00000000 --- a/auto/sources +++ /dev/null @@ -1,313 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -NXT_LIB_SRCS=" \ - src/nxt_lib.c \ - src/nxt_gmtime.c \ - src/nxt_errno.c \ - src/nxt_time.c \ - src/nxt_malloc.c \ - src/nxt_file.c \ - src/nxt_mem_map.c \ - src/nxt_socket.c \ - src/nxt_socketpair.c \ - src/nxt_socket_msg.c \ - src/nxt_credential.c \ - src/nxt_isolation.c \ - src/nxt_process.c \ - src/nxt_process_title.c \ - src/nxt_signal.c \ - src/nxt_port_socket.c \ - src/nxt_port_memory.c \ - src/nxt_port_rpc.c \ - src/nxt_port.c \ - src/nxt_dyld.c \ - src/nxt_random.c \ - src/nxt_queue.c \ - src/nxt_rbtree.c \ - src/nxt_mp.c \ - src/nxt_mem_zone.c \ - src/nxt_string.c \ - src/nxt_utf8.c \ - src/nxt_parse.c \ - src/nxt_sprintf.c \ - src/nxt_var.c \ - src/nxt_tstr.c \ - src/nxt_file_name.c \ - src/nxt_log.c \ - src/nxt_djb_hash.c \ - src/nxt_murmur_hash.c \ - src/nxt_lvlhsh.c \ - src/nxt_array.c \ - src/nxt_vector.c \ - src/nxt_list.c \ - src/nxt_buf.c \ - src/nxt_buf_pool.c \ - src/nxt_recvbuf.c \ - src/nxt_sendbuf.c \ - src/nxt_thread.c \ - src/nxt_thread_mutex.c \ - src/nxt_thread_cond.c \ - src/nxt_spinlock.c \ - src/nxt_semaphore.c \ - src/nxt_thread_pool.c \ - src/nxt_thread_time.c \ - src/nxt_time_parse.c \ - src/nxt_work_queue.c \ - src/nxt_service.c \ - src/nxt_log_moderation.c \ - src/nxt_event_engine.c \ - src/nxt_timer.c \ - src/nxt_fd_event.c \ - src/nxt_conn.c \ - src/nxt_conn_connect.c \ - src/nxt_conn_accept.c \ - src/nxt_conn_read.c \ - src/nxt_conn_write.c \ - src/nxt_conn_close.c \ - src/nxt_event_conn_job_sendfile.c \ - src/nxt_conn_proxy.c \ - src/nxt_job.c \ - src/nxt_sockaddr.c \ - src/nxt_listen_socket.c \ - src/nxt_upstream.c \ - src/nxt_upstream_round_robin.c \ - src/nxt_http_parse.c \ - src/nxt_app_log.c \ - src/nxt_capability.c \ - src/nxt_runtime.c \ - src/nxt_conf.c \ - src/nxt_conf_validation.c \ - src/nxt_main_process.c \ - src/nxt_signal_handlers.c \ - src/nxt_controller.c \ - src/nxt_router.c \ - src/nxt_router_access_log.c \ - src/nxt_h1proto.c \ - src/nxt_status.c \ - src/nxt_http_request.c \ - src/nxt_http_response.c \ - src/nxt_http_error.c \ - src/nxt_http_route.c \ - src/nxt_http_route_addr.c \ - src/nxt_http_rewrite.c \ - src/nxt_http_set_headers.c \ - src/nxt_http_return.c \ - src/nxt_http_static.c \ - src/nxt_http_proxy.c \ - src/nxt_http_chunk_parse.c \ - src/nxt_http_variables.c \ - src/nxt_application.c \ - src/nxt_external.c \ - src/nxt_port_hash.c \ - src/nxt_sha1.c \ - src/nxt_websocket.c \ - src/nxt_websocket_accept.c \ - src/nxt_http_websocket.c \ - src/nxt_h1proto_websocket.c \ - src/nxt_fs.c \ -" - - -NXT_LIB_UNIT_SRCS="src/nxt_unit.c" - - -NXT_LIB_TLS_DEPS="src/nxt_tls.h" -NXT_LIB_TLS_SRCS="src/nxt_cert.c" -NXT_LIB_OPENSSL_SRCS="src/nxt_openssl.c" -NXT_LIB_GNUTLS_SRCS="src/nxt_gnutls.c" -NXT_LIB_CYASSL_SRCS="src/nxt_cyassl.c" -NXT_LIB_POLARSSL_SRCS="src/nxt_polarssl.c" - -NXT_LIB_PCRE_SRCS="src/nxt_pcre.c" -NXT_LIB_PCRE2_SRCS="src/nxt_pcre2.c" - -if [ "$NXT_NJS" != "NO" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS src/nxt_js.c src/nxt_http_js.c src/nxt_script.c" -fi - -NXT_LIB_EPOLL_SRCS="src/nxt_epoll_engine.c" -NXT_LIB_KQUEUE_SRCS="src/nxt_kqueue_engine.c" -NXT_LIB_EVENTPORT_SRCS="src/nxt_eventport_engine.c" -NXT_LIB_DEVPOLL_SRCS="src/nxt_devpoll_engine.c" -NXT_LIB_POLLSET_SRCS="src/nxt_pollset_engine.c" -NXT_LIB_POLL_SRCS="src/nxt_poll_engine.c" -NXT_LIB_SELECT_SRCS="src/nxt_select_engine.c" - -NXT_LIB_LINUX_SENDFILE_SRCS="src/nxt_linux_sendfile.c" -NXT_LIB_FREEBSD_SENDFILE_SRCS="src/nxt_freebsd_sendfile.c" -NXT_LIB_SOLARIS_SENDFILEV_SRCS="src/nxt_solaris_sendfilev.c" -NXT_LIB_MACOSX_SENDFILE_SRCS="src/nxt_macosx_sendfile.c" -NXT_LIB_AIX_SEND_FILE_SRCS="src/nxt_aix_send_file.c" -NXT_LIB_HPUX_SENDFILE_SRCS="src/nxt_hpux_sendfile.c" -NXT_LIB_CLONE_SRCS="src/nxt_clone.c" - -NXT_TEST_BUILD_DEPS="src/nxt_test_build.h" -NXT_TEST_BUILD_SRCS="src/nxt_test_build.c" - -NXT_TEST_DEPS="src/test/nxt_tests.h \ - src/test/nxt_rbtree1.h \ -" - -NXT_TEST_SRCS=" \ - src/test/nxt_tests.c \ - src/test/nxt_rbtree1.c \ - src/test/nxt_rbtree_test.c \ - src/test/nxt_term_parse_test.c \ - src/test/nxt_msec_diff_test.c \ - src/test/nxt_mp_test.c \ - src/test/nxt_mem_zone_test.c \ - src/test/nxt_lvlhsh_test.c \ - src/test/nxt_gmtime_test.c \ - src/test/nxt_sprintf_test.c \ - src/test/nxt_malloc_test.c \ - src/test/nxt_utf8_test.c \ - src/test/nxt_rbtree1_test.c \ - src/test/nxt_http_parse_test.c \ - src/test/nxt_strverscmp_test.c \ - src/test/nxt_base64_test.c \ -" - - -if [ $NXT_HAVE_CLONE_NEWUSER = YES ]; then - NXT_TEST_SRCS="$NXT_TEST_SRCS src/test/nxt_clone_test.c" -fi - - -NXT_LIB_UTF8_FILE_NAME_TEST_SRCS=" \ - src/test/nxt_utf8_file_name_test.c \ -" - - -if [ $NXT_HAVE_ROOTFS = YES ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS src/nxt_fs_mount.c" -fi - - -if [ $NXT_TLS = YES ]; then - nxt_have=NXT_TLS . auto/have - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_TLS_SRCS" -fi - - -if [ $NXT_OPENSSL = YES ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_OPENSSL_SRCS" -fi - - -if [ $NXT_GNUTLS = YES ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_GNUTLS_SRCS" -fi - - -if [ $NXT_CYASSL = YES ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_CYASSL_SRCS" -fi - - -if [ $NXT_POLARSSL = YES ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_POLARSSL_SRCS" -fi - - -if [ "$NXT_REGEX" = "YES" ]; then - if [ "$NXT_HAVE_PCRE2" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_PCRE2_SRCS" - else - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_PCRE_SRCS" - fi -fi - -if [ "$NXT_HAVE_EPOLL" = "YES" -o "$NXT_TEST_BUILD_EPOLL" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_EPOLL_SRCS" -fi - - -if [ "$NXT_HAVE_KQUEUE" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_KQUEUE_SRCS" -fi - - -if [ "$NXT_HAVE_EVENTPORT" = "YES" -o "$NXT_TEST_BUILD_EVENTPORT" = "YES" ]; -then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_EVENTPORT_SRCS" -fi - - -if [ "$NXT_HAVE_DEVPOLL" = "YES" -o "$NXT_TEST_BUILD_DEVPOLL" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_DEVPOLL_SRCS" -fi - - -if [ "$NXT_HAVE_POLLSET" = "YES" -o "$NXT_TEST_BUILD_POLLSET" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_POLLSET_SRCS" -fi - - -NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_POLL_SRCS" -NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_SELECT_SRCS" - - -if [ "$NXT_HAVE_LINUX_SENDFILE" = "YES" \ - -o "$NXT_TEST_BUILD_LINUX_SENDFILE" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_LINUX_SENDFILE_SRCS" -fi - - -if [ "$NXT_HAVE_FREEBSD_SENDFILE" = "YES" \ - -o "$NXT_TEST_BUILD_FREEBSD_SENDFILE" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_FREEBSD_SENDFILE_SRCS" -fi - - -if [ "$NXT_HAVE_SOLARIS_SENDFILEV" = "YES" \ - -o "$NXT_TEST_BUILD_SOLARIS_SENDFILEV" = "YES" ]; -then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_SOLARIS_SENDFILEV_SRCS" -fi - - -if [ "$NXT_HAVE_MACOSX_SENDFILE" = "YES" \ - -o "$NXT_TEST_BUILD_MACOSX_SENDFILE" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_MACOSX_SENDFILE_SRCS" -fi - - -if [ "$NXT_HAVE_AIX_SEND_FILE" = "YES" \ - -o "$NXT_TEST_BUILD_AIX_SEND_FILE" = "YES" ]; -then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_AIX_SEND_FILE_SRCS" -fi - - -if [ "$NXT_HAVE_HPUX_SENDFILE" = "YES" \ - -o "$NXT_TEST_BUILD_HPUX_SENDFILE" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_HPUX_SENDFILE_SRCS" -fi - - -if [ "$NXT_HAVE_LINUX_NS" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_CLONE_SRCS" -fi - - -if [ "$NXT_HAVE_CGROUP" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS src/nxt_cgroup.c" -fi - - -if [ "$NXT_TEST_BUILD" = "YES" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_TEST_BUILD_SRCS" -fi - - -if [ $NXT_TESTS = YES ]; then - nxt_have=NXT_TESTS . auto/have -fi - - -NXT_SRCS=" \ - src/nxt_main.c \ -" diff --git a/auto/ssltls b/auto/ssltls deleted file mode 100644 index 6512d330..00000000 --- a/auto/ssltls +++ /dev/null @@ -1,215 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -NXT_OPENSSL_CFLAGS= -NXT_OPENSSL_LIBS= -NXT_GNUTLS_CFLAGS= -NXT_GNUTLS_LIBS= -NXT_OPENSSL_LIBS= -NXT_CYASSL_CFLAGS= -NXT_CYASSL_LIBS= -NXT_POLARSSL_CFLAGS= -NXT_POLARSSL_LIBS= - - -if [ $NXT_OPENSSL = YES ]; then - - nxt_feature="OpenSSL library" - nxt_feature_name=NXT_HAVE_OPENSSL - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs="-lssl -lcrypto" - nxt_feature_test="#include - - int main(void) { - SSL_library_init(); - return 0; - }" - . auto/feature - - - if [ $nxt_found = yes ]; then - NXT_TLS=YES - NXT_OPENSSL_LIBS="$nxt_feature_libs" - - nxt_feature="OpenSSL version" - nxt_feature_name=NXT_HAVE_OPENSSL_VERSION - nxt_feature_run=value - nxt_feature_test="#include - - int main(void) { - printf(\"\\\"%s\\\"\", - SSLeay_version(SSLEAY_VERSION)); - return 0; - }" - . auto/feature - - else - $echo - $echo $0: error: no OpenSSL library found. - $echo - exit 1; - fi - - - nxt_feature="OpenSSL SSL_CONF_cmd()" - nxt_feature_name=NXT_HAVE_OPENSSL_CONF_CMD - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs="$NXT_OPENSSL_LIBS" - nxt_feature_test="#include - - int main(void) { - SSL_CONF_cmd(NULL, NULL, NULL); - return 0; - }" - . auto/feature - - - nxt_feature="OpenSSL tlsext support" - nxt_feature_name=NXT_HAVE_OPENSSL_TLSEXT - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs="$NXT_OPENSSL_LIBS" - nxt_feature_test="#include - - int main(void) { - #if (OPENSSL_NO_TLSEXT) - #error OpenSSL: no tlsext support. - #else - return 0; - #endif - }" - . auto/feature -fi - - -if [ $NXT_GNUTLS = YES ]; then - - if /bin/sh -c "(pkg-config gnutls --exists)" >> $NXT_AUTOCONF_ERR 2>&1; - then - NXT_GNUTLS_CFLAGS=`pkg-config gnutls --cflags` - NXT_GNUTLS_LIBS=`pkg-config gnutls --libs` - - nxt_feature="GnuTLS library" - nxt_feature_name=NXT_HAVE_GNUTLS - nxt_feature_run=yes - nxt_feature_incs=$NXT_GNUTLS_CFLAGS - nxt_feature_libs=$NXT_GNUTLS_LIBS - nxt_feature_test="#include - - int main(void) { - gnutls_global_init(); - gnutls_global_deinit(); - return 0; - }" - . auto/feature - - - if [ $nxt_found = yes ]; then - NXT_TLS=YES - - $echo " + GnuTLS version: `pkg-config gnutls --modversion`" - - - nxt_feature="gnutls_transport_set_vec_push_function" - nxt_feature_name=NXT_HAVE_GNUTLS_VEC_PUSH - nxt_feature_run=no - nxt_feature_incs=$NXT_GNUTLS_CFLAGS - nxt_feature_libs=$NXT_GNUTLS_LIBS - nxt_feature_test="#include - - int main(void) { - gnutls_transport_set_vec_push_function(NULL, NULL); - return 0; - }" - . auto/feature - - - nxt_feature="gnutls_global_set_time_function" - nxt_feature_name=NXT_HAVE_GNUTLS_SET_TIME - nxt_feature_run=no - nxt_feature_incs=$NXT_GNUTLS_CFLAGS - nxt_feature_libs=$NXT_GNUTLS_LIBS - nxt_feature_test="#include - - int main(void) { - gnutls_global_set_time_function(NULL); - return 0; - }" - . auto/feature - - else - $echo - $echo $0: error: no GnuTLS library found. - $echo - exit 1; - fi - fi -fi - - -if [ $NXT_CYASSL = YES ]; then - - nxt_feature="CyaSSL library" - nxt_feature_name=NXT_HAVE_CYASSL - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs="-lcyassl" - nxt_feature_test="#include - - int main(void) { - CyaSSL_Init(); - CyaSSL_Cleanup(); - return 0; - }" - . auto/feature - - - if [ $nxt_found = yes ]; then - NXT_TLS=YES - NXT_CYASSL_CFLAGS="$nxt_feature_incs" - NXT_CYASSL_LIBS="$nxt_feature_libs" - - else - $echo - $echo $0: error: no CyaSSL library found. - $echo - exit 1; - fi -fi - - -if [ $NXT_POLARSSL = YES ]; then - - nxt_feature="PolarSSL library" - nxt_feature_name=NXT_HAVE_POLARSSL - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs="-lpolarssl" - nxt_feature_test="#include - - int main(void) { - ssl_context ssl; - memset(&ssl, '\0', sizeof(ssl)); - ssl_init(&ssl); - ssl_free(&ssl); - return 0; - }" - . auto/feature - - - if [ $nxt_found = yes ]; then - NXT_TLS=YES - NXT_POLARSSL_CFLAGS="$nxt_feature_incs" - NXT_POLARSSL_LIBS="$nxt_feature_libs" - - else - $echo - $echo $0: error: no PolarSSL library found. - $echo - exit 1; - fi -fi diff --git a/auto/summary b/auto/summary deleted file mode 100644 index 3aa41669..00000000 --- a/auto/summary +++ /dev/null @@ -1,39 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -cat << END - -Unit configuration summary: - - bin directory: ............. "$NXT_BINDIR" - sbin directory: ............ "$NXT_SBINDIR" - lib directory: ............. "$NXT_LIBDIR" - include directory: ......... "$NXT_INCLUDEDIR" - pkgconfig directory: ....... "$NXT_PKGCONFIGDIR" - man pages directory: ....... "$NXT_MANDIR" - modules directory: ......... "$NXT_MODULESDIR" - state directory: ........... "$NXT_STATEDIR" - tmp directory: ............. "$NXT_TMPDIR" - - pid file: .................. "$NXT_PID" - log file: .................. "$NXT_LOG" - - control API socket: ........ "$NXT_CONTROL" - - non-privileged user: ....... "$NXT_USER" - non-privileged group: ...... "$NXT_GROUP" - - IPv6 support: .............. $NXT_INET6 - Unix domain sockets support: $NXT_UNIX_DOMAIN - TLS support: ............... $NXT_OPENSSL - Regex support: ............. $NXT_REGEX - NJS support: ............... $NXT_NJS - - process isolation: ......... $NXT_ISOLATION - cgroupv2: .................. $NXT_HAVE_CGROUP - - debug logging: ............. $NXT_DEBUG - -END diff --git a/auto/test_build b/auto/test_build deleted file mode 100644 index 6889048e..00000000 --- a/auto/test_build +++ /dev/null @@ -1,76 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -NXT_TEST_BUILD=NO - - -if [ $NXT_TEST_BUILD_EPOLL = YES ]; then - nxt_have=NXT_TEST_BUILD_EPOLL . auto/have - nxt_have=NXT_TEST_BUILD . auto/have - NXT_TEST_BUILD=YES -fi - - -if [ $NXT_TEST_BUILD_EVENTPORT = YES ]; then - nxt_have=NXT_TEST_BUILD_EVENTPORT . auto/have - nxt_have=NXT_TEST_BUILD . auto/have - NXT_TEST_BUILD=YES -fi - - -if [ $NXT_TEST_BUILD_DEVPOLL = YES ]; then - nxt_have=NXT_TEST_BUILD_DEVPOLL . auto/have - nxt_have=NXT_TEST_BUILD . auto/have - NXT_TEST_BUILD=YES -fi - - -if [ $NXT_TEST_BUILD_POLLSET = YES ]; then - nxt_have=NXT_TEST_BUILD_POLLSET . auto/have - nxt_have=NXT_TEST_BUILD . auto/have - NXT_TEST_BUILD=YES -fi - - -if [ $NXT_TEST_BUILD_LINUX_SENDFILE = YES ]; then - nxt_have=NXT_TEST_BUILD_LINUX_SENDFILE . auto/have - nxt_have=NXT_TEST_BUILD . auto/have - NXT_TEST_BUILD=YES -fi - - -if [ $NXT_TEST_BUILD_FREEBSD_SENDFILE = YES ]; then - nxt_have=NXT_TEST_BUILD_FREEBSD_SENDFILE . auto/have - nxt_have=NXT_TEST_BUILD . auto/have - NXT_TEST_BUILD=YES -fi - - -if [ $NXT_TEST_BUILD_SOLARIS_SENDFILEV = YES ]; then - nxt_have=NXT_TEST_BUILD_SOLARIS_SENDFILEV . auto/have - nxt_have=NXT_TEST_BUILD . auto/have - NXT_TEST_BUILD=YES -fi - - -if [ $NXT_TEST_BUILD_MACOSX_SENDFILE = YES ]; then - nxt_have=NXT_TEST_BUILD_MACOSX_SENDFILE . auto/have - nxt_have=NXT_TEST_BUILD . auto/have - NXT_TEST_BUILD=YES -fi - - -if [ $NXT_TEST_BUILD_AIX_SEND_FILE = YES ]; then - nxt_have=NXT_TEST_BUILD_AIX_SEND_FILE . auto/have - nxt_have=NXT_TEST_BUILD . auto/have - NXT_TEST_BUILD=YES -fi - - -if [ $NXT_TEST_BUILD_HPUX_SENDFILE = YES ]; then - nxt_have=NXT_TEST_BUILD_HPUX_SENDFILE . auto/have - nxt_have=NXT_TEST_BUILD . auto/have - NXT_TEST_BUILD=YES -fi diff --git a/auto/threads b/auto/threads deleted file mode 100644 index 67b46690..00000000 --- a/auto/threads +++ /dev/null @@ -1,258 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -case "$NXT_SYSTEM" in - - Linux) - NXT_PTHREAD="-lpthread" - ;; - - FreeBSD) - # FreeBSD libc supports only pthread stubs. - NXT_PTHREAD="-lpthread" - ;; - - SunOS) - case "$NXT_SYSTEM_VERSION" in - 5.8 | 5.9) - NXT_PTHREAD="-lpthread" - ;; - *) - # Solaris 10 libpthread.so.1 is a filter to libc.so.1. - NXT_PTHREAD= - ;; - esac - ;; - - Darwin) - # MacOSX libpthread.dylib is a symlink to libSystem.dylib. - NXT_PTHREAD= - ;; - - *) - NXT_PTHREAD="-lpthread" - ;; -esac - - -# Linux, FreeBSD. - -nxt_feature="pthread_yield()" -nxt_feature_name=NXT_HAVE_PTHREAD_YIELD -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs=$NXT_PTHREAD -nxt_feature_test="#define _GNU_SOURCE - #include - - int main(void) { - pthread_yield(); - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # MacOSX. - - nxt_feature="pthread_yield_np()" - nxt_feature_name=NXT_HAVE_PTHREAD_YIELD_NP - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs=$NXT_PTHREAD - nxt_feature_test="#include - - int main(void) { - pthread_yield_np(); - return 0; - }" - . auto/feature -fi - - -# FreeBSD, Solaris, AIX. - -nxt_feature="pthread spinlock" -nxt_feature_name=NXT_HAVE_PTHREAD_SPINLOCK -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs=$NXT_PTHREAD -nxt_feature_test="#include - - int main(void) { - pthread_spinlock_t lock; - - if (pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE) != 0) - return 1; - if (pthread_spin_lock(&lock) != 0) - return 1; - if (pthread_spin_unlock(&lock) != 0) - return 1; - if (pthread_spin_destroy(&lock) != 0) - return 1; - return 0; - }" -. auto/feature - - -if [ $nxt_found = yes ]; then - - # Linux glibc uses 0 as pthread_spinlock_t initial value on the most - # platforms. However, on i386 and x86_64 the initial value is 1. - - nxt_feature="pthread spinlock zero initial value" - nxt_feature_name=NXT_HAVE_PTHREAD_SPINLOCK_ZERO - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs=$NXT_PTHREAD - nxt_feature_test="#include - - pthread_spinlock_t lock = 0; - - int main(void) { - if (pthread_spin_trylock(&lock) != 0) - return 1; - if (pthread_spin_unlock(&lock) != 0) - return 1; - return 0; - }" - . auto/feature -fi - - -nxt_feature="sem_timedwait()" -nxt_feature_name=NXT_HAVE_SEM_TIMEDWAIT -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - sem_t sem; - struct timespec ts; - - if (sem_init(&sem, 0, 0) != 0) - return 1; - if (sem_post(&sem) != 0) - return 1; - - ts.tv_sec = 0; - ts.tv_nsec = 0; - if (sem_timedwait(&sem, &ts) != 0) - return 1; - - if (sem_destroy(&sem) != 0) - return 1; - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - if [ -n "$NXT_PTHREAD" ]; then - - # Linux requires libpthread. - - nxt_feature="sem_timedwait() in libpthread" - nxt_feature_libs=$NXT_PTHREAD - . auto/feature - fi - - if [ $nxt_found = no ]; then - - # Solaris 10 requires librt. - - nxt_feature="sem_timedwait() in librt" - nxt_feature_libs="-lrt" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_LIBRT="-lrt" - fi - fi -fi - - -# Thread Local Storage / Thread Specific Data. -# -# Linux, FreeBSD 5.3, Solaris. -# MacOSX 10.7 (Lion) Clang. - -nxt_feature="__thread" -nxt_feature_name=NXT_HAVE_THREAD_STORAGE_CLASS -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs=$NXT_PTHREAD -nxt_feature_test="#include - #include - - __thread int key; - - void *func(void *p); - - void *func(void *p) { - key = 0x9abcdef0; - return NULL; - } - - int main(void) { - void *n; - pthread_t pt; - - key = 0x12345678; - if (pthread_create(&pt, NULL, func, NULL)) - return 1; - if (pthread_join(pt, &n)) - return 1; - if (key != 0x12345678) - return 1; - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # MacOSX GCC lacks __thread support. - # On NetBSD __thread causes segmentation fault. - - nxt_feature="phtread_key_t" - nxt_feature_name=NXT_HAVE_PTHREAD_SPECIFIC_DATA - nxt_feature_run=yes - nxt_feature_incs= - nxt_feature_libs=$NXT_PTHREAD - nxt_feature_test="#include - - int main(void) { - pthread_key_t key = -1; - - if (pthread_key_create(&key, NULL)) - return 1; - if (pthread_setspecific(key, (void *) 0x12345678)) - return 1; - if (pthread_getspecific(key) != (void *) 0x12345678) - return 1; - return 0; - }" - . auto/feature - - - nxt_feature="PTHREAD_KEYS_MAX" - nxt_feature_name= - nxt_feature_run=value - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#include - #include - #include - - int main(void) { - printf(\"%d\", PTHREAD_KEYS_MAX); - return 0; - }" - . auto/feature -fi diff --git a/auto/time b/auto/time deleted file mode 100644 index 402a219c..00000000 --- a/auto/time +++ /dev/null @@ -1,224 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# Linux 2.6.32 CLOCK_REALTIME_COARSE. -# Linux clock_gettime() is in librt. - -nxt_feature="Linux clock_gettime(CLOCK_REALTIME_COARSE)" -nxt_feature_name=NXT_HAVE_CLOCK_REALTIME_COARSE -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs="-lrt" -nxt_feature_test="#include - - int main(void) { - struct timespec ts; - - if (clock_gettime(CLOCK_REALTIME_COARSE, &ts) == -1) - return 1; - return 0; - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_LIBRT=$nxt_feature_libs -fi - - -# FreeBSD 7.0 CLOCK_REALTIME_FAST - -nxt_feature="FreeBSD clock_gettime(CLOCK_REALTIME_FAST)" -nxt_feature_name=NXT_HAVE_CLOCK_REALTIME_FAST -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - struct timespec ts; - - if (clock_gettime(CLOCK_REALTIME_FAST, &ts) == -1) - return 1; - return 0; - }" -. auto/feature - - -nxt_feature="clock_gettime(CLOCK_REALTIME)" -nxt_feature_name=NXT_HAVE_CLOCK_REALTIME -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - struct timespec ts; - - if (clock_gettime(CLOCK_REALTIME, &ts) == -1) - return 1; - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # Linux and Solaris 10 clock_gettime() are in librt. - - nxt_feature="clock_gettime(CLOCK_REALTIME) in librt" - nxt_feature_libs="-lrt" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_LIBRT=$nxt_feature_libs - fi -fi - - -# Linux 2.6.32 CLOCK_MONOTONIC_COARSE. -# Linux clock_gettime() is in librt. - -nxt_feature="Linux clock_gettime(CLOCK_MONOTONIC_COARSE)" -nxt_feature_name=NXT_HAVE_CLOCK_MONOTONIC_COARSE -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs="-lrt" -nxt_feature_test="#include - - int main(void) { - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == -1) - return 1; - return 0; - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_LIBRT=$nxt_feature_libs -fi - - -# FreeBSD 7.0 CLOCK_MONOTONIC_FAST - -nxt_feature="FreeBSD clock_gettime(CLOCK_MONOTONIC_FAST)" -nxt_feature_name=NXT_HAVE_CLOCK_MONOTONIC_FAST -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC_FAST, &ts) == -1) - return 1; - return 0; - }" -. auto/feature - - -nxt_feature="clock_gettime(CLOCK_MONOTONIC)" -nxt_feature_name=NXT_HAVE_CLOCK_MONOTONIC -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) - return 1; - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # Linux and Solaris 10 clock_gettime() are in librt. - - nxt_feature="clock_gettime(CLOCK_MONOTONIC) in librt" - nxt_feature_libs="-lrt" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_LIBRT=$nxt_feature_libs - fi -fi - - -# HP-UX Mercury Library hg_gethrtime(). - -NXT_LIBHG= - -nxt_feature="HP-UX hg_gethrtime()" -nxt_feature_name=NXT_HAVE_HG_GETHRTIME -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs="-lhg" -nxt_feature_test="#include - #include - - int main(void) { - hg_gethrtime(); - return 0; - }" -. auto/feature - -if [ $nxt_found = yes ]; then - NXT_LIBHG=$nxt_feature_libs -fi - - -nxt_feature="struct tm.tm_gmtoff" -nxt_feature_name=NXT_HAVE_TM_GMTOFF -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - time_t t; - struct tm tm; - - t = 0; - localtime_r(&t, &tm); - return tm.tm_gmtoff; - }" -. auto/feature - - -nxt_feature="altzone" -nxt_feature_name=NXT_HAVE_ALTZONE -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - altzone = 0; - return 0; - }" -. auto/feature - - -nxt_feature="localtime_r()" -nxt_feature_name=NXT_HAVE_LOCALTIME_R -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - time_t t; - struct tm tm; - - t = 0; - localtime_r(&t, &tm); - return 0; - }" -. auto/feature diff --git a/auto/types b/auto/types deleted file mode 100644 index c0a871dd..00000000 --- a/auto/types +++ /dev/null @@ -1,118 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# Sizes of C types. - -# "-Wall -Werror" or similar constraints in default CFLAGS may require -# to use "%zu" format to printf() result of sizeof(). But "%zu" may -# be unavailable, so the "(int)" cast is a simple and portable solution: -# printf("%d", (int) sizeof(TYPE)); - - -nxt_feature="int size" -nxt_feature_name=NXT_INT_SIZE -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - printf(\"%d\", (int) sizeof(int)); - return 0; - }" -. auto/feature - - -nxt_feature="long size" -nxt_feature_name=NXT_LONG_SIZE -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - printf(\"%d\", (int) sizeof(long)); - return 0; - }" -. auto/feature - - -nxt_feature="long long size" -nxt_feature_name=NXT_LONG_LONG_SIZE -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - printf(\"%d\", (int) sizeof(long long)); - return 0; - }" -. auto/feature - - -nxt_feature="void * size" -nxt_feature_name=NXT_PTR_SIZE -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - printf(\"%d\", (int) sizeof(void *)); - return 0; - }" -. auto/feature - - -case "$nxt_feature_value" in - 8) NXT_64BIT=1 ;; - *) NXT_64BIT=0 ;; -esac - - -nxt_feature="size_t size" -nxt_feature_name=NXT_SIZE_T_SIZE -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - - int main(void) { - printf(\"%d\", (int) sizeof(size_t)); - return 0; - }" -. auto/feature - - -nxt_feature="off_t size" -nxt_feature_name=NXT_OFF_T_SIZE -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#define _FILE_OFFSET_BITS 64 - #include - #include - - int main(void) { - printf(\"%d\", (int) sizeof(off_t)); - return 0; - }" -. auto/feature - - -nxt_feature="time_t size" -nxt_feature_name=NXT_TIME_T_SIZE -nxt_feature_run=value -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - printf(\"%d\", (int) sizeof(time_t)); - return 0; - }" -. auto/feature diff --git a/auto/unix b/auto/unix deleted file mode 100644 index 1307bdbd..00000000 --- a/auto/unix +++ /dev/null @@ -1,211 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# Linux 3.17 with glibc 2.25, FreeBSD 12, Solaris 11.3. - -nxt_feature="getrandom()" -nxt_feature_name=NXT_HAVE_GETRANDOM -nxt_feature_run=yes -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - char buf[4]; - - if (getrandom(buf, 4, 0) < 0) { - return 1; - } - - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # Linux 3.17 SYS_getrandom. - - nxt_feature="SYS_getrandom in Linux" - nxt_feature_name=NXT_HAVE_LINUX_SYS_GETRANDOM - nxt_feature_test="#include - #include - #include - - int main(void) { - char buf[4]; - - if (syscall(SYS_getrandom, buf, 4, 0) < 0) { - return 1; - } - - return 0; - }" - . auto/feature -fi - - -if [ $nxt_found = no ]; then - - # OpenBSD 5.6 lacks . - - nxt_feature="getentropy()" - nxt_feature_name=NXT_HAVE_GETENTROPY - nxt_feature_test="#include - - int main(void) { - char buf[4]; - - if (getentropy(buf, 4) == -1) { - return 1; - } - - return 0; - }" - . auto/feature -fi - - -if [ $nxt_found = no ]; then - - # macOS 10.12. - - nxt_feature="getentropy() in sys/random.h" - nxt_feature_name=NXT_HAVE_GETENTROPY_SYS_RANDOM - nxt_feature_test="#include - #include - - int main(void) { - char buf[4]; - - if (getentropy(buf, 4) == -1) { - return 1; - } - - return 0; - }" - . auto/feature -fi - - -nxt_feature="ucontext" -nxt_feature_name=NXT_HAVE_UCONTEXT -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - ucontext_t uc; - - if (getcontext(&uc) == 0) { - makecontext(&uc, NULL, 0); - setcontext(&uc); - } - - return 0; - }" -. auto/feature - - -if [ $nxt_found = no ]; then - - # MacOSX 10.6 (Snow Leopard) has deprecated ucontext - # and requires _XOPEN_SOURCE to be defined. - - nxt_feature="_XOPEN_SOURCE ucontext" - nxt_feature_name=NXT_HAVE_UCONTEXT - nxt_feature_run= - nxt_feature_incs= - nxt_feature_libs= - nxt_feature_test="#define _XOPEN_SOURCE - #include - #include - - int main(void) { - ucontext_t uc; - - if (getcontext(&uc) == 0) { - makecontext(&uc, NULL, 0); - setcontext(&uc); - } - - return 0; - }" - . auto/feature -fi - - -# FreeBSD dlopen() is in libc. -# MacOSX libdl.dylib is a symlink to libSystem.dylib. -# GCC5 AddressSanitizer intercepts dlopen() and dlclose() but not dlsym() -# so all dynamic linker functions should be tested. - -NXT_LIBDL= - -nxt_feature="dlopen()" -nxt_feature_name=NXT_HAVE_DLOPEN -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - void *h = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); - dlsym(h, \"\"); - dlclose(h); - return 0; - }" -. auto/feature - -if [ $nxt_found = no ]; then - - # Linux and Solaris prior to 10 require libdl. - # Solaris 10 libdl.so.1 is a filter to /usr/lib/ld.so.1. - - nxt_feature="dlopen() in libdl" - nxt_feature_libs="-ldl" - . auto/feature - - if [ $nxt_found = yes ]; then - NXT_LIBDL="-ldl" - fi -fi - - -# NetBSD 1.0, OpenBSD 1.0, FreeBSD 2.2 setproctitle(). - -nxt_feature="setproctitle()" -nxt_feature_name=NXT_HAVE_SETPROCTITLE -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - setproctitle(\"%s\", \"title\"); - return 0; - }" -. auto/feature - - -# Linux, FreeBSD, Solaris getgrouplist() -nxt_feature="getgrouplist()" -nxt_feature_name=NXT_HAVE_GETGROUPLIST -nxt_feature_run= -nxt_feature_incs= -nxt_feature_libs= -nxt_feature_test="#include - #include - - int main(void) { - getgrouplist(\"root\", 0, NULL, NULL); - return 0; - }" -. auto/feature diff --git a/configure b/configure deleted file mode 100755 index 2cb4d457..00000000 --- a/configure +++ /dev/null @@ -1,182 +0,0 @@ -#!/bin/sh - -# Copyright (C) Igor Sysoev -# Copyright (C) NGINX, Inc. - - -# Disable localized program messages. -LC_ALL=C -export LC_ALL - -# Stop on error exit status. -set -e - -# Stop on uninitialized variable. -set -u - -# Initialize variables with null values if they are not defined. -CFLAGS=${CFLAGS=} -NXT_TEST_CFLAGS=${NXT_TEST_CFLAGS=} -NXT_TEST_LIBS=${NXT_TEST_LIBS=} - -NXT_BUILD_DIR=${NXT_BUILD_DIR:-build} - -NXT_AUTOTEST=$NXT_BUILD_DIR/autotest -NXT_AUTOCONF_ERR=$NXT_BUILD_DIR/autoconf.err -NXT_AUTOCONF_DATA=$NXT_BUILD_DIR/autoconf.data -NXT_AUTO_CONFIG_H=$NXT_BUILD_DIR/include/nxt_auto_config.h -NXT_VERSION_H=$NXT_BUILD_DIR/include/nxt_version.h -NXT_MAKEFILE=$NXT_BUILD_DIR/Makefile - -CC=${CC:-cc} - -NXT_DAEMON=unitd -NXT_USER="nobody" -NXT_GROUP= - -nxt_module=${1:-""} - -case $nxt_module in - ""|--*) - ;; - - unit) - shift - ;; - - *) - . auto/modules/conf - exit 0 - ;; -esac - - -. ./version -. auto/os/test -. auto/options - -mkdir -p $NXT_BUILD_DIR -mkdir -p $NXT_BUILD_DIR/bin -mkdir -p $NXT_BUILD_DIR/include -mkdir -p $NXT_BUILD_DIR/lib -mkdir -p $NXT_BUILD_DIR/lib/unit/modules -mkdir -p $NXT_BUILD_DIR/sbin -mkdir -p $NXT_BUILD_DIR/share/man/man8 -mkdir -p $NXT_BUILD_DIR/share/pkgconfig -mkdir -p $NXT_BUILD_DIR/src -mkdir -p $NXT_BUILD_DIR/src/test -mkdir -p $NXT_BUILD_DIR/var/lib/unit -mkdir -p $NXT_BUILD_DIR/var/log/unit -mkdir -p $NXT_BUILD_DIR/var/run/unit - - -> $NXT_AUTOCONF_ERR -> $NXT_AUTO_CONFIG_H - -. auto/cc/test - - -cat << END >> $NXT_AUTO_CONFIG_H - -#define NXT_CONFIGURE_OPTIONS "$NXT_CONFIGURE_OPTIONS" -#define NXT_SYSTEM_VERSION "$NXT_SYSTEM $NXT_SYSTEM_VERSION $NXT_SYSTEM_PLATFORM" -#define NXT_COMPILER_VERSION "$NXT_CC_VERSION" - -#define NXT_PID "$NXT_PID" -#define NXT_LOG "$NXT_LOG" -#define NXT_MODULESDIR "$NXT_MODULESDIR" -#define NXT_STATEDIR "$NXT_STATEDIR" -#define NXT_TMPDIR "$NXT_TMPDIR" - -#define NXT_CONTROL_SOCK "$NXT_CONTROL" - -#define NXT_USER "$NXT_USER" -#define NXT_GROUP "$NXT_GROUP" - -END - - -if [ $echo = echo ]; then - # Build a portable "echo" program that supports only "-n" option. - # This also tests C compiler ability to create executables. - . auto/echo/build -fi - - -nxt_have=NXT_UNIX . auto/have - -if [ $NXT_UNIX_DOMAIN = YES ]; then - nxt_have=NXT_HAVE_UNIX_DOMAIN . auto/have -fi - -NXT_LIBRT= - -. auto/endian -. auto/types -. auto/clang -. auto/atomic -. auto/malloc -. auto/mmap -. auto/shmem -. auto/time -. auto/threads -. auto/events -. auto/sockets -. auto/sendfile -. auto/files -. auto/unix -. auto/os/conf -. auto/ssltls - -if [ $NXT_REGEX = YES ]; then - . auto/pcre -fi - -. auto/cgroup -. auto/isolation -. auto/capability - - -case "$NXT_SYSTEM_PLATFORM" in - i386 | amd64 | x86_64) - nxt_have=NXT_HAVE_NONALIGNED . auto/have - ;; -esac - - -if [ $NXT_DEBUG = YES ]; then - nxt_debug=1 -else - nxt_debug=0 -fi - -cat << END >> $NXT_AUTO_CONFIG_H - -#ifndef NXT_DEBUG -#define NXT_DEBUG $nxt_debug -#endif - -#define NXT_SHM_PREFIX "$NXT_SHM_PREFIX" - -END - -. auto/test_build -. auto/sources -. auto/save - -# LOOK - -NXT_LIB_AUX_CFLAGS="$NXT_OPENSSL_CFLAGS $NXT_GNUTLS_CFLAGS \\ - $NXT_CYASSL_CFLAGS $NXT_POLARSSL_CFLAGS \\ - $NXT_PCRE_CFLAGS" - -NXT_LIB_AUX_LIBS="$NXT_OPENSSL_LIBS $NXT_GNUTLS_LIBS \\ - $NXT_CYASSL_LIBS $NXT_POLARSSL_LIBS \\ - $NXT_PCRE_LIB" - -if [ $NXT_NJS != NO ]; then - . auto/njs -fi - -. auto/make -. auto/summary diff --git a/pkg/docker/docker-entrypoint.sh b/docker-entrypoint.sh similarity index 100% rename from pkg/docker/docker-entrypoint.sh rename to docker-entrypoint.sh diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 5192b690..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/make - -DEST= ../build -XSLS?= xslscript.pl - -PACKAGES= unit \ - unit-php \ - unit-python unit-python2.7 unit-python3.4 \ - unit-python3.5 unit-python3.6 unit-python3.7 \ - unit-python3.8 unit-python3.9 unit-python3.10 \ - unit-python3.11 \ - unit-go unit-go1.7 unit-go1.8 unit-go1.9 unit-go1.10 \ - unit-go1.12 unit-go1.13 \ - unit-perl \ - unit-ruby \ - unit-jsc-common unit-jsc8 unit-jsc10 unit-jsc11 \ - unit-jsc13 unit-jsc14 unit-jsc15 unit-jsc16 unit-jsc17 - -CURDATE:=$(shell date +"%Y-%m-%d") -CURTIME:=$(shell date +"%H:%M:%S %z") - - -all: changes changelogs - -changes: $(DEST)/CHANGES - -changelogs: $(addsuffix .rpm-changelog, $(addprefix $(DEST)/, $(PACKAGES))) \ - $(addsuffix .deb-changelog, $(addprefix $(DEST)/, $(PACKAGES))) - -$(DEST)/CHANGES: changes.dtd \ - changes.xml \ - change_log_conf.xml \ - changes.xslt - - mkdir -p $(DEST) - - xmllint --noout --valid changes.xml - xsltproc --stringparam format generic \ - --stringparam curdate '$(CURDATE)' \ - --stringparam curtime '$(CURTIME)' \ - -o $@ changes.xslt changes.xml - -$(DEST)/%.rpm-changelog: changes.dtd \ - changes.xml \ - change_log_conf.xml \ - changes.xslt - mkdir -p $(DEST) - xmllint --noout --valid changes.xml - xsltproc --stringparam pkgname $* --stringparam format rpm \ - --stringparam curdate '$(CURDATE)' \ - --stringparam curtime '$(CURTIME)' \ - -o $@ changes.xslt changes.xml - -$(DEST)/%.deb-changelog: changes.dtd \ - changes.xml \ - change_log_conf.xml \ - changes.xslt - mkdir -p $(DEST) - xmllint --noout --valid changes.xml - xsltproc --stringparam pkgname $* --stringparam format deb \ - --stringparam curdate '$(CURDATE)' \ - --stringparam curtime '$(CURTIME)' \ - -o $@ changes.xslt changes.xml - -changes.xslt: changes.xsls - $(XSLS) -o $@ $< - -clean: - rm -rf $(DEST) diff --git a/docs/change_log_conf.dtd b/docs/change_log_conf.dtd deleted file mode 100644 index d8e90e35..00000000 --- a/docs/change_log_conf.dtd +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/change_log_conf.xml b/docs/change_log_conf.xml deleted file mode 100644 index 1b99da95..00000000 --- a/docs/change_log_conf.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - -76 - *) - - - - -76 -- - - - - -76 - * - - - - - Changes with - 65 - - Bugfix - Feature - Change - Security - Workaround - - Jan - Feb - Mar - Apr - May - Jun - Jul - Aug - Sep - Oct - Nov - Dec - - Sun - Mon - Tue - Wed - Thu - Fri - Sat - - - diff --git a/docs/changes.dtd b/docs/changes.dtd deleted file mode 100644 index 9a15ed1e..00000000 --- a/docs/changes.dtd +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/docs/changes.xml b/docs/changes.xml deleted file mode 100644 index 6bda704b..00000000 --- a/docs/changes.xml +++ /dev/null @@ -1,4138 +0,0 @@ - - - - - - - - - - - -NGINX Unit updated to 1.32.1. - - - - - - - - - - - -NJS variables in templates may have incorrect values due to improper caching. - - - - - -Wasm application process hangs after receiving restart signal from the control. - - - - - - - - - - -Initial release of Java 21 module for NGINX Unit. - - - - - - - - - - -Initial release of Python 3.12 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.32.0. - - - - - - - - - - - -WebAssembly Components using WASI interfaces defined in wasi:http/proxy@0.2.0. - - - - - -conditional access logging. - - - - - -NJS variables access. - - - - - -$request_id variable contains a string that is formed using random data and -can be used as a unique request identifier. - - - - - -options to set control socket permissions. - - - - - -Ruby arrays in response headers, improving compatibility with Rack v3.0. - - - - - -Python bytearray response bodies for ASGI applications. - - - - - -router could crash while sending large files. Thanks to rustedsword. - - - - - -serving static files from a network filesystem could lead to error. - - - - - -"uidmap" and "gidmap" isolation options validation. - - - - - -abstract UNIX socket name could be corrupted during configuration validation. -Thanks to Alejandro Colomar. - - - - - -HTTP header field value encoding could be misinterpreted in Python module. - - - - - -Node.js http.createServer() accepts and ignores the "options" argument, -improving compatibility with strapi applications, among others. - - - - - -ServerRequest.flushHeaders() implemented in Node.js module to make it compatible -with Next.js. - - - - - -ServerRequest.httpVersion variable format in Node.js module. - - - - - -Node.js module handles standard library imports prefixed with "node:", making it -possible to run newer Nuxt applications, among others. - - - - - -Node.js tarball location changed to avoid build/install errors. - - - - - -Go module sets environment variables necessary for building on macOS/arm64 -systems. - - - - - - - - - -NGINX Unit updated to 1.31.1. - - - - - - - - - - -allow to set the HTTP response status in Wasm module. - - - - - -allow uploads larger than 4GiB in Wasm module. - - - - - -application process could crash while rewriting URLs with query strings. - - - - - -requests larger than about 64MiB could cause error in Wasm module. - - - - - -when using many headers in Java module some of them could be -corrupted due to memory realocation issue. - - - - - -ServerRequest.destroy() implemented in Node.js module to make it compatible -with some frameworks that might use it. - - - - - -chunk argument of ServerResponse.write() can now be a Uint8Array to improve -compatibility with Node.js 15.0.0 and above. - - - - - -Node.JS unit-http NPM module now has appropriate default paths for macOS/arm64 -systems. - - - - - -build on musl libc with clang. - - - - - - - - - - -NGINX Unit updated to 1.31.0. - - - - - - - - - - -if building with njs, version 0.8.0 or later is now required. - - - - - -technology preview of WebAssembly application module. - - - - - -"response_headers" option to manage headers in the action and fallback. - - - - - -HTTP response header variables. - - - - - -ASGI lifespan state support. Thanks to synodriver. - - - - - -ensure that $uri variable is not cached. - - - - - -deprecated options were unavailable. - - - - - -ASGI applications inaccessible over IPv6. - - - - - - - - - - -Initial release of WASM module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.30.0. - - - - - - - - - - -Initial release of Java 20 module for NGINX Unit. - - - - - - - - - - -remove Unix domain listen sockets upon reconfiguration. - - - - - -basic URI rewrite support. - - - - - -NJS loadable modules support. - - - - - -per-application logging. - - - - - -conditional logging of route selection. - - - - - -support the keys API on the request objects in NJS. - - - - - -default values for 'make install' pathnames such as prefix; -this allows to './configure && make && sudo make install'. - - - - - -"server_version" setting to omit the version token from "Server" header field. - - - - - -request header field values could be corrupted in some cases; the bug had -appeared in 1.29.0. - - - - - -PHP error handling (added missing 403 and 404 errors). - - - - - -Perl applications crash on second responder call. - - - - - - - - - - -NGINX Unit updated to 1.29.1. - - - - - - - - - - -stop creating world-writeable directories. - - - - - -memory leak related to NJS. - - - - - -path parsing in PHP applications. - - - - - -enabled UTF-8 for Python config by default to avoid applications failing -in some cases. - - - - - -using asyncio.get_running_loop() instead of asyncio.get_event_loop() -when it's available to prevent errors in some Python ASGI applications. - - - - - -applications that make use of various low level APIs such as pthreads could -fail to work correctly. - - - - - -websocket endianness detection for obscure operating systems. - - - - - - - - - - -NGINX Unit updated to 1.29.0. - - - - - - - - - - -Initial release of Java 19 module for NGINX Unit. - - - - - - - - - - -Initial release of Python 3.11 module for NGINX Unit. - - - - - - - - - - -removed $uri auto-append for "share" when loading configuration. - - - - - -prefer system crypto policy instead of hardcoding a default. - - - - - -njs support with the basic syntax of JS template literals. - - - - - -support per-application cgroups on Linux. - - - - - -the $request_time variable contains the request processing time. - - - - - -"prefix" option in Python applications to set WSGI "SCRIPT_NAME" -and ASGI root-path variables. - - - - - -compatibility with Python 3.11. - - - - - -compatibility with OpenSSL 3. - - - - - -compatibility with PHP 8.2. - - - - - -compatibility with Node.js 19.0. - - - - - -Ruby Rack v3 support. - - - - - -fix error in connection statistics when using proxy. - - - - - -fix HTTP cookie parsing when the value contains an equals sign. - - - - - -PHP directory URLs without a trailing '/' would give a 503 error (fixed with -a 301 re-direct). - - - - - -missing error checks in the C API. - - - - - -report the regex status in configure summary. - - - - - - - - - - -NGINX Unit updated to 1.28.0. - - - - - - - - - - -increased the applications' startup timeout. - - - - - -disallowed abstract Unix domain socket syntax in non-Linux systems. - - - - - -basic statistics API. - - - - - -customizable access log format. - - - - - -more HTTP variables support. - - - - - -forwarded header to replace client address and protocol. - - - - - -ability to get dynamic variables. - - - - - -support for abstract Unix sockets. - - - - - -support for Unix sockets in address matching. - - - - - -the $dollar variable translates to a literal "$" during variable substitution. - - - - - -router process could crash if index file didn't contain an extension. - - - - - -force SCRIPT_NAME in Ruby to always be an empty string. - - - - - -when isolated PID numbers reach the prototype process host PID, -the prototype crashed. - - - - - -the Ruby application process could crash on SIGTERM. - - - - - -the Ruby application process could crash on SIGINT. - - - - - -mutex leak in the C API. - - - - - - - - - - -NGINX Unit updated to 1.27.0. - - - - - - - - - - -ability to specify a custom index file name when serving static files. - - - - - -variables support in the "location" option of the "return" action. - - - - - -support empty strings in the "location" option of the "return" action. - - - - - -added a new variable, $request_uri, that includes both the path and the query -parts as per RFC 3986, sections 3-4. - - - - - -Ruby Rack environment parameter "SCRIPT_NAME" support. - - - - - -compatibility with GCC 12. - - - - - -Ruby Sinatra applications don't work without custom logging. - - - - - -the controller process could crash when a chain of more than four -certificates was uploaded. - - - - - -some Perl applications failed to process the request body, notably with Plack. - - - - - -some Spring Boot applications failed to start, notably with Grails. - - - - - -incorrect Python protocol auto detection (ASGI or WSGI) for native callable -object, notably with Falcon. - - - - - -ECMAScript modules did not work with the recent Node.js versions. - - - - - - - - - - -NGINX Unit updated to 1.26.1. - - - - - - - - - - -occasionally, the Unit daemon was unable to fully terminate; the bug had -appeared in 1.26.0. - - - - - -a prototype process could crash on an application process exit; the bug had -appeared in 1.26.0. - - - - - -the router process crashed on reconfiguration if "access_log" was configured -without listeners. - - - - - -a segmentation fault occurred in the PHP module if chdir() or -fastcgi_finish_request() was called in the OPcache preloading script. - - - - - -fatal errors on DragonFly BSD; the bug had appeared in 1.26.0. - - - - - - - - - - -Initial release of Java 18 module for NGINX Unit. - - - - - - - - - - -Initial release of Python 3.10 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.26.0. - - - - - - - - - - -the "share" option now specifies the entire path to the files it serves, -rather than a document root directory to be prepended to the request URI. - - - - - -automatic adjustment of existing configurations to the new "share" behavior -when updating from previous versions. - - - - - -variables support in the "share" option. - - - - - -multiple paths in the "share" option. - - - - - -variables support in the "chroot" option. - - - - - -PHP opcache is shared between application processes. - - - - - -request routing by the query string. - - - - - -the router and app processes could crash when the requests limit was reached -by asynchronous or multithreaded apps. - - - - - -established WebSocket connections could stop reading frames from the client -after the corresponding listener had been reconfigured. - - - - - -fixed building with glibc 2.34, notably Fedora 35. - - - - - - - - - - -NGINX Unit updated to 1.25.0. - - - - - - - - - - -client IP address replacement from a specified HTTP header field. - - - - - -TLS sessions cache. - - - - - -TLS session tickets. - - - - - -application restart control. - - - - - -process and thread lifecycle hooks in Ruby. - - - - - -the router process could crash on TLS connection open when multiple listeners -with TLS certificates were configured; the bug had appeared in 1.23.0. - - - - - -TLS connections were rejected for configurations with multiple certificate -bundles in a listener if the client did not use SNI. - - - - - -the router process could crash with frequent multithreaded application -reconfiguration. - - - - - -compatibility issues with some Python ASGI apps, notably based on the Starlette -framework. - - - - - -a descriptor and memory leak occurred in the router process when an app process -stopped or crashed. - - - - - -the controller or router process could crash if the configuration contained -a full-form IPv6 in a listener address. - - - - - -the router process crashed when a request was passed to an empty "routes" -or "upstreams" using a variable "pass" option. - - - - - -the router process crashed while matching a request to an empty array of source -or destination address patterns. - - - - - - - - - - -Initial release of Java 17 module for NGINX Unit. - - - - - - - - - - -Initial release of Java 16 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.24.0. - - - - - - - - - - -PHP added to the default MIME type list. - - - - - -arbitrary configuration of TLS connections via OpenSSL commands. - - - - - -the ability to limit static file serving by MIME types. - - - - - -support for chrooting, rejecting symlinks, and rejecting mount -point traversal on a per-request basis when serving static files. - - - - - -a loader for automatically overriding the "http" and "websocket" modules in -Node.js. - - - - - -multiple "targets" in Python applications. - - - - - -compatibility with Ruby 3.0. - - - - - -the router process could crash while closing a TLS connection. - - - - - -a segmentation fault might have occurred in the PHP module if -fastcgi_finish_request() was used with the "auto_globals_jit" option enabled. - - - - - - - - - - -NGINX Unit updated to 1.23.0. - - - - - - - - - - -support for multiple certificate bundles on a listener via the Server Name -Indication (SNI) TLS extension. - - - - - -"--mandir" ./configure option to specify the directory for man page -installation. - - - - - -the router process could crash on premature TLS connection close; the bug had -appeared in 1.17.0. - - - - - -a connection leak occurred on premature TLS connection close; the bug had -appeared in 1.6. - - - - - -a descriptor and memory leak occurred in the router process when processing -small WebSocket frames from a client; the bug had appeared in 1.19.0. - - - - - -a descriptor leak occurred in the router process when removing or -reconfiguring an application; the bug had appeared in 1.19.0. - - - - - -persistent storage of certificates might've not worked with some filesystems in -Linux, and all uploaded certificate bundles were forgotten after restart. - - - - - -the controller process could crash while requesting information about a -certificate with a non-DNS SAN entry. - - - - - -the controller process could crash on manipulations with a certificate -containing a SAN and no standard name attributes in subject or issuer. - - - - - -the Ruby module didn't respect the user locale for defaults in the Encoding -class. - - - - - -the PHP 5 module failed to build with thread safety enabled; the bug had -appeared in 1.22.0. - - - - - - - - - - -Initial release of Python 3.9 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.22.0. - - - - - - - - - - -the ServerRequest and ServerResponse objects of Node.js module are now -compliant with Stream API. - - - - - -support for specifying multiple directories in the "path" option of Python -apps. - - - - - -a memory leak occurred in the router process when serving files larger than -128K; the bug had appeared in 1.13.0. - - - - - -apps could stop processing new requests under high load; the bug had -appeared in 1.19.0. - - - - - -app processes could terminate unexpectedly under high load; the bug had -appeared in 1.19.0. - - - - - -invalid HTTP responses were generated for some unusual status codes. - - - - - -the PHP_AUTH_USER, PHP_AUTH_PW, and PHP_AUTH_DIGEST server variables were -missing in the PHP module. - - - - - -the router process could crash with multithreaded apps under high load. - - - - - -Ruby apps with multithreading configured could crash on start under load. - - - - - -mount points weren't unmounted when the "mount" namespace isolation was used; -the bug had appeared in 1.21.0. - - - - - -the router process could crash while removing or reconfiguring an app that used -WebSocket. - - - - - -a memory leak occurring in the router process when removing or reconfiguring -an application; the bug had appeared in 1.19.0. - - - - - - - - - - -Initial release of Java 15 module for NGINX Unit. - - - - - - - - - - -Initial release of Java 14 module for NGINX Unit. - - - - - - - - - - -Initial release of Java 13 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.21.0. - - - - - - - - - - -procfs is mounted by default for all languages when "rootfs" isolation is used. - - - - - -any characters valid according to RFC 7230 are now allowed in HTTP header field -names. - - - - - -HTTP header fields with underscores ("_") are now discarded from requests by -default. - - - - - -optional multithreaded request processing for Java, Python, Perl, and Ruby apps. - - - - - -regular expressions in route matching patterns. - - - - - -compatibility with Python 3.9. - - - - - -the Python module now supports ASGI 2.0 legacy applications. - - - - - -the "protocol" option in Python applications aids choice between ASGI and WSGI. - - - - - -the fastcgi_finish_request() PHP function that finalizes request processing and -continues code execution without holding onto the client connection. - - - - - -the "discard_unsafe_fields" HTTP option that enables discarding request header -fields with irregular (but still valid) characters in the field name. - - - - - -the "procfs" and "tmpfs" automount isolation options to disable automatic -mounting of eponymous filesystems. - - - - - -the router process could crash when running Go applications under high load; -the bug had appeared in 1.19.0. - - - - - -some language dependencies could remain mounted after using "rootfs" isolation. - - - - - -various compatibility issues in Java applications. - - - - - -the Java module built with the musl C library couldn't run applications that -use "rootfs" isolation. - - - - - - - - - - -NGINX Unit updated to 1.20.0. - - - - - - - - - - -the PHP module is now initialized before chrooting; this enables loading all -extensions from the host system. - - - - - -AVIF and APNG image formats added to the default MIME type list. - - - - - -functional tests migrated to the pytest framework. - - - - - -the Python module now fully supports applications that use the ASGI 3.0 server -interface. - - - - - -the Python module now has a built-in WebSocket server implementation for -applications, compatible with the HTTP & WebSocket ASGI Message Format 2.1 -specification. - - - - - -automatic mounting of an isolated "/tmp" file system into chrooted application -environments. - - - - - -the $host variable contains a normalized "Host" request value. - - - - - -the "callable" option sets Python application callable names. - - - - - -compatibility with PHP 8 RC 1. Thanks to Remi Collet. - - - - - -the "automount" option in the "isolation" object allows to turn off the -automatic mounting of language module dependencies. - - - - - -"pass"-ing requests to upstreams from a route was broken; the bug had appeared -in 1.19.0. Thanks to 洪志道 (Hong Zhi Dao) for discovering and fixing it. - - - - - -the router process could crash during reconfiguration. - - - - - -a memory leak occurring in the router process; the bug had appeared in 1.18.0. - - - - - -the "!" (non-empty) pattern was matched incorrectly; -the bug had appeared in 1.19.0. - - - - - -fixed building on platforms without sendfile() support, notably NetBSD; -the bug had appeared in 1.16.0. - - - - - - - - - - -NGINX Unit updated to 1.19.0. - - - - - - - - - - -reworked IPC between the router process and the applications to lower latencies, -increase performance, and improve scalability. - - - - - -support for an arbitrary number of wildcards in route matching patterns. - - - - - -chunked transfer encoding in proxy responses. - - - - - -basic variables support in the "pass" option. - - - - - -compatibility with PHP 8 Beta 1. -Thanks to Remi Collet. - - - - - -the router process could crash while passing requests to an application under -high load. - - - - - -a number of language modules failed to build on some systems; -the bug had appeared in 1.18.0. - - - - - -time in error log messages from PHP applications could lag. - - - - - -reconfiguration requests could hang if an application had failed to start; -the bug had appeared in 1.18.0. - - - - - -memory leak during reconfiguration. - - - - - -the daemon didn't start without language modules; -the bug had appeared in 1.18.0. - - - - - -the router process could crash at exit. - - - - - -Node.js applications could crash at exit. - - - - - -the Ruby module could be linked against a wrong library version. - - - - - - - - - - -NGINX Unit updated to 1.18.0. - - - - - - - - - - -the "rootfs" isolation option for changing root filesystem for an application. - - - - - -multiple "targets" in PHP applications. - - - - - -support for percent-encoding in the "uri" and "arguments" matching options -and in the "pass" option. - - - - - - - - - - -NGINX Unit updated to 1.17.0. - - - - - - - - - - -a "return" action with optional "location" for immediate responses and external -redirection. - - - - - -fractional weights support for upstream servers. - - - - - -accidental 502 "Bad Gateway" errors might have occurred in applications under -high load. - - - - - -memory leak in the router; the bug had appeared in 1.13.0. - - - - - -segmentation fault might have occurred in the router process when reaching -open connections limit. - - - - - -"close() failed (9: Bad file descriptor)" alerts might have appeared in the log -while processing large request bodies; the bug had appeared in 1.16.0. - - - - - -existing application processes didn't reopen the log file. - - - - - -incompatibility with some Node.js applications. - - - - - -broken build on DragonFly BSD; the bug had appeared in 1.16.0. - - - - - - - - - - -NGINX Unit updated to 1.16.0. - - - - - - - - - - -basic load-balancing support with round-robin. - - - - - -a "fallback" option that performs an alternative action if a request can't be -served from the "share" directory. - - - - - -reduced memory consumption by dumping large request bodies to disk. - - - - - -stripping UTF-8 BOM and JavaScript-style comments from uploaded JSON. - - - - - -negative address matching in router might work improperly in combination with -non-negative patterns. - - - - - -Java Spring applications failed to run; the bug had appeared in 1.10.0. - - - - - -PHP 7.4 was broken if it was built with thread safety enabled. - - - - - -compatibility issues with some Python applications. - - - - - - - - - - -NGINX Unit updated to 1.15.0. - - - - - - - - - - -extensions of dynamically requested PHP scripts were restricted to ".php". - - - - - -compatibility with Ruby 2.7. - - - - - -segmentation fault might have occurred in the router process with multiple -application processes under load; the bug had appeared in 1.14.0. - - - - - -receiving request body over TLS connection might have stalled. - - - - - - - - - - -NGINX Unit updated to 1.14.0. - - - - - - - - - - -the Go package import name changed to "unit.nginx.org/go". - - - - - -Go package now links to libunit instead of including library sources. - - - - - -ability to change user and group for isolated applications when Unit daemon -runs as an unprivileged user. - - - - - -request routing by source and destination addresses and ports. - - - - - -memory bloat on large responses. - - - - - - - - - - -Initial release of Go 1.13 module for NGINX Unit. - - - - - - - - - - -Initial release of Go 1.12 module for NGINX Unit. - - - - - - - - - - -Initial release of Python 3.8 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.13.0. - - - - - - - - - - -basic support for HTTP reverse proxying. - - - - - -compatibility with Python 3.8. - - - - - -memory leak in Python application processes when the close handler was used. - - - - - -threads in Python applications might not work correctly. - - - - - -Ruby on Rails applications might not work on Ruby 2.6. - - - - - -backtraces for uncaught exceptions in Python 3 might be logged with significant -delays. - - - - - -explicit setting a namespaces isolation option to false might have enabled it. - - - - - - - - - - -NGINX Unit updated to 1.12.0. - - - - - - - - - - -compatibility with PHP 7.4. - - - - - -descriptors leak on process creation; the bug had appeared in 1.11.0. - - - - - -TLS connection might be closed prematurely while sending response. - - - - - -segmentation fault might have occurred if an irregular file was requested. - - - - - - - - - - - -NGINX Unit updated to 1.11.0. - - - - - - - - - - -basic support for serving static files. - - - - - -isolation of application processes with Linux namespaces. - - - - - -built-in WebSocket server implementation for Java Servlet Containers. - - - - - -direct addressing of API configuration options containing slashes "/" -using URI encoding (%2F). - - - - - -segmentation fault might have occurred in Go applications under high load. - - - - - -WebSocket support was broken if Unit was built with some linkers other than -GNU ld (e.g. gold or LLD). - - - - - - - - - - -missed header files added to unit development package. - - - - - - - - - - -NGINX Unit updated to 1.10.0. - - - - - - - - - - -matching of cookies in routes made case sensitive. - - - - - -decreased log level of common errors when clients close connections. - - - - - -removed the Perl module's "--include=" ./configure option. - - - - - -built-in WebSocket server implementation for Node.js module. - - - - - -splitting PATH_INFO from request URI in PHP module. - - - - - -request routing by scheme (HTTP or HTTPS). - - - - - -support for multipart requests body in Java module. - - - - - -improved API compatibility with Node.js 11.10 or later. - - - - - -reconfiguration failed if "listeners" or "applications" objects were missing. - - - - - -applying a large configuration might have failed. - - - - - - - - - - -Initial release of Go 1.11 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.9.0. - - - - - - - - - - -request routing by arguments, headers, and cookies. - - - - - -route matching patterns allow a wildcard in the middle. - - - - - -POST operation for appending elements to arrays in configuration. - - - - - -support for changing credentials using CAP_SETUID and CAP_SETGID capabilities -on Linux without running main process as privileged user. - - - - - -memory leak in the router process might have happened when a client -prematurely closed the connection. - - - - - -applying a large configuration might have failed. - - - - - -PUT and DELETE operations on array elements in configuration did not work. - - - - - -request schema in applications did not reflect TLS connections. - - - - - -restored compatibility with Node.js applications that use -ServerResponse._implicitHeader() function; the bug had appeared in 1.7. - - - - - -various compatibility issues with Node.js applications. - - - - - - - - - - -Initial release of Java common packages for NGINX Unit. - - - - - - - - - - -Initial release of Java 8 module for NGINX Unit. - - - - - - - - - - -Initial release of Java 10 module for NGINX Unit. - - - - - - - - - - -Initial release of Java 11 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.8.0. - - - - - - - - - - -now three numbers are always used for versioning: major, minor, -and patch versions. - - - - - -now QUERY_STRING is always defined even if the request does not include -the query component. - - - - - -basic internal request routing by Host, URI, and method. - - - - - -experimental support for Java Servlet Containers. - - - - - -segmentation fault might have occurred in the router process. - - - - - -various potential memory leaks. - - - - - -TLS connections might have stalled. - - - - - -some Perl applications might have failed to send the response body. - - - - - -some compilers with specific flags might have produced non-functioning builds; -the bug had appeared in 1.5. - - - - - -Node.js package had wrong version number when installed from sources. - - - - - - - - - - -NGINX Unit updated to 1.7.1. - - - - - - - - - - -a heap memory buffer overflow might have been caused in the router process by -a specially crafted request, potentially resulting in a segmentation fault or -other unspecified behavior (CVE-2019-7401). - - - - - -install of Go module failed without prior building of Unit daemon; -the bug had appeared in 1.7. - - - - - - - - - - -Initial release of Python 3.7 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.7. - - - - - - - - - - -now rpath is set in Ruby module only if the library was not found in default -search paths; this allows to meet packaging restrictions on some systems. - - - - - -"disable_functions" and "disable_classes" PHP options set via Control API -did not work. - - - - - -Promises on request data in Node.js were not triggered. - - - - - -various compatibility issues with Node.js applications. - - - - - -a segmentation fault occurred in Node.js module if application tried to read -request body after request.end() was called. - - - - - -a segmentation fault occurred in Node.js module if application attempted to -send header twice. - - - - - -names of response header fields in Node.js module were erroneously treated as -case-sensitive. - - - - - -uncatched exceptions in Node.js were not logged. - - - - - -global install of Node.js module from sources was broken on some systems; -the bug had appeared in 1.6. - - - - - -traceback for exceptions during initialization of Python applications might not -be logged. - - - - - -PHP module build failed if PHP interpreter was built with thread safety -enabled. - - - - - - - - - - -NGINX Unit updated to 1.6. - - - - - - - - - - -"make install" now installs Node.js module as well if it was configured. - - - - - -"--local" ./configure option to install Node.js module locally. - - - - - -Node.js module might have crashed due to broken reference counting. - - - - - -asynchronous operations in Node.js might not have worked. - - - - - -various compatibility issues with Node.js applications. - - - - - -"freed pointer is out of pool" alerts might have appeared in log. - - - - - -module discovery did not work on 64-bit big-endian systems like IBM/S390x. - - - - - - - - - - -NGINX Unit updated to 1.5. - - - - - - - - - - -the "type" of application object for Go was changed to "external". - - - - - -initial version of Node.js package with basic HTTP request-response support. - - - - - -compatibility with LibreSSL. - - - - - ---libdir and --incdir ./configure options to install libunit headers -and static library. - - - - - -connection might be closed prematurely while sending response; -the bug had appeared in 1.3. - - - - - -application processes might have stopped handling requests, producing -"last message send failed: Resource temporarily unavailable" alerts in log; -the bug had appeared in 1.4. - - - - - -Go applications did not work when Unit was built with musl C library. - - - - - - - - - - -corrected instructions for launching sample application. - - - - - - - - - - -the "saveconfig" and "loadconfig" action scripts were removed. - - - - - - - - - - -NGINX Unit updated to 1.4. - - - - - - - - - - -the control API maps the configuration object only at "/config/". - - - - - -TLS support for client connections. - - - - - -TLS certificates storage control API. - - - - - -Unit library (libunit) to streamline language module integration. - - - - - -"408 Request Timeout" responses while closing HTTP keep-alive connections. - - - - - -improvements in OpenBSD support. -Thanks to David Carlier. - - - - - -a segmentation fault might have occurred after reconfiguration. - - - - - -building on systems with non-default locale might be broken. - - - - - -"header_read_timeout" might not work properly. - - - - - -header fields values with non-ASCII bytes might be handled incorrectly -in Python 3 module. - - - - - - - - - - -NGINX Unit updated to 1.3. - - - - - - - - - - -UTF-8 characters are now allowed in request header field values. - - - - - -configuration of the request body size limit. - - - - - -configuration of various HTTP connection timeouts. - - - - - -Ruby module now automatically uses Bundler where possible. - - - - - -http.Flusher interface in Go module. - - - - - -various issues in HTTP connection errors handling. - - - - - -requests with body data might be handled incorrectly in PHP module. - - - - - -individual PHP configuration options specified via control API were reset -to previous values after the first request in application process. - - - - - - - - - - -NGINX Unit updated to 1.2. - - - - - - - - - - -configuration of environment variables for application processes. - - - - - -customization of php.ini path. - - - - - -setting of individual PHP configuration options. - - - - - -configuration of execution arguments for Go applications. - - - - - -keep-alive connections might hang after reconfiguration. - - - - - - - - - - -Initial release of Go 1.10 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 1.1. - - - - - - - - - - -Python applications that use the write() callable did not work. - - - - - -virtual environments created with Python 3.3 or above might not have worked. - - - - - -the request.Read() function in Go applications did not produce EOF -when the whole body was read. - - - - - -a segmentation fault might have occurred while access log reopening. - - - - - -in parsing of IPv6 control socket addresses. - - - - - -loading of application modules was broken on OpenBSD. - - - - - -a segmentation fault might have occurred when there were two modules -with the same type and version; the bug had appeared in 1.0. - - - - - -alerts "freed pointer points to non-freeble page" might have appeared in log -on 32-bit platforms. - - - - - - - - - - -NGINX Unit updated to 1.0. - - - - - - - - - - -configuration object moved into "/config/" path. - - - - - -basic access logging. - - - - - -503 error occurred if Go application did not write response header or body. - - - - - -Ruby applications that use encoding conversions might not have worked. - - - - - -various stability issues. - - - - - - - - - - -NGINX Unit updated to 0.7. - - - - - - - - - - -Initial release of Ruby module for NGINX Unit. - - - - - - - - - - -Ruby application module. - - - - - -in discovering modules. - - - - - -various race conditions on reconfiguration and during shutting down. - - - - - -tabs and trailing spaces were not allowed in header fields values. - - - - - -a segmentation fault occurred in Python module if start_response() was called -outside of WSGI callable. - - - - - -a segmentation fault might have occurred in PHP module if there was an error -while initialization. - - - - - - - - - - -NGINX Unit updated to 0.6. - - - - - - - - - - -the main process died when the "type" application option contained version; -the bug had appeared in 0.5. - - - - - - - - - - -NGINX Unit updated to 0.5. - - - - - - - - - - -Initial release of Perl module for NGINX Unit. - - - - - - - - - - -the "workers" application option was removed, the "processes" -application option should be used instead. - - - - - -the "processes" application option with prefork and dynamic -process management support. - - - - - -Perl application module. - - - - - -in reading client request body; the bug had appeared in 0.3. - - - - - -some Python applications might not have worked due to missing -"wsgi.errors" environ variable. - - - - - -HTTP chunked responses might be encoded incorrectly on 32-bit -platforms. - - - - - -infinite looping in HTTP parser. - - - - - -segmentation fault in router. - - - - - - - - - - -NGINX Unit updated to 0.4. - - - - - - - - - - -compatibility with DragonFly BSD. - - - - - -"configure php --lib-static" option. - - - - - -HTTP request body was not passed to application; -the bug had appeared in 0.3. - - - - - -HTTP large header buffers allocation and deallocation fixed; -the bug had appeared in 0.3. - - - - - -some PHP applications might not have worked with relative "root" path. - - - - - - - - - - -Initial release of Go 1.9 module for NGINX Unit. - - - - - - - - - - -Initial release of Python 3.6 module for NGINX Unit. - - - - - - - - - - -NGINX Unit updated to 0.3. - - - - - - - - - - -the Go package name changed to "nginx/unit". - - - - - -in the "limits.timeout" application option: application start time and -time in queue now are not accounted. - - - - - -the "limits.requests" application option. - - - - - -application request processing latency optimization. - - - - - -HTTP keep-alive connections support. - - - - - -the "home" Python virtual environment configuration option. - - - - - -Python atexit hook support. - - - - - -various Go package improvements. - - - - - -various crashes fixed. - - - - - - - - - - -Initial release of Go module for NGINX Unit. - - - - - - - - - - -Initial release of Go 1.7 module for NGINX Unit. - - - - - - - - - - -Initial release of Go 1.8 module for NGINX Unit. - - - - - - - - - - -Initial release of Python module for NGINX Unit. - - - - - - - - - - -Initial release of Python 2.7 module for NGINX Unit. - - - - - - - - - - -Initial release of Python 3.4 module for NGINX Unit. - - - - - - - - - - -Initial release of Python 3.5 module for NGINX Unit. - - - - - - - - - - -Initial release of PHP module for NGINX Unit. - - - - - - - - - - -configuration persistence. - - - - - -improved handling of configuration errors. - - - - - -application "timeout" property. - - - - - -POST request for PHP were handled incorrectly. - - - - - -the router exited abnormally if all listeners had been deleted. - - - - - -the router crashed under load. - - - - - -memory leak in the router. - - - - - - - - - - -First public release. - - - - - - - diff --git a/docs/changes.xsls b/docs/changes.xsls deleted file mode 100644 index 9ff6a7e2..00000000 --- a/docs/changes.xsls +++ /dev/null @@ -1,289 +0,0 @@ -X:stylesheet { - -X:output method="text"; - -X:param format="'generic'"; -X:param pkgname="'unit'"; -X:param configuration="'change_log_conf.xml'"; -X:param curdate; -X:param curtime; - -X:var conf = "document($configuration)/configuration"; - -X:var start = { - X:choose { - X:when "$format='rpm'" { - !{$conf/rpm/start} - } - X:when "$format='deb'" { - !{$conf/deb/start} - } - X:when "$format='generic'" { - !{$conf/generic/start} - } - } -} - -X:var indent = { - X:choose { - X:when "$format='rpm'" { - !{$conf/rpm/indent} - } - X:when "$format='deb'" { - !{$conf/deb/indent} - } - X:when "$format='generic'" { - !{$conf/generic/indent} - } - } -} - -X:var max = { - X:choose { - X:when "$format='rpm'" { - !{$conf/rpm/length} - } - X:when "$format='deb'" { - !{$conf/deb/length} - } - X:when "$format='generic'" { - !{$conf/generic/length} - } - } -} - -X:var br = {<br>} - - -X:template = "/" { !! "change_log"; } -X:template = "change_log" { !! "changes"; } - - -X:template = "changes" { - X:var date_ = { !getdate(date="@date", curdate="$curdate") } - X:var time_ = { !gettime(time="@time", curtime="$curtime") } - X:var pday = { !padded_day(date="$date_") } - X:var dow = { !day_of_week(date="$date_") } - X:var apply = { !string_in_list(list="@apply", string="$pkgname") } - X:var pkgname_ = { !beautify(pkgname="$pkgname") } - - X:choose { - X:when "$pkgname='unit' and $format='generic' and @rev!=1" {} - X:otherwise { - X:if "$apply=$pkgname" { - - X:if "$format='generic'" { - X:text { } - - !{substring(concat($conf/changes/title, - $pkgname_, - ' ', @ver, - ' '), - 1, $conf/changes/length)} - - !{substring($date_, 9, 2)} - !{$conf/changes/month[number(substring($date_, 6, 2))]} - !{substring($date_, 1, 4)} - } - - X:if "$format='rpm'" { - !{concat('* ', $conf/changes/day[number($dow)], - $conf/changes/month[number(substring($date_, 6, 2))], - $pday, ' ', - substring($date_, 1, 4), ' ', @packager, ' - ', - @ver, '-', @rev, '%{?dist}.ngx')} - } - - X:if "$format='deb'" { - !{concat($pkgname, ' (', @ver, '-', @rev, - '~%%CODENAME%%) %%CODENAME%%; urgency=low')} - - X:text { } - } - - X:text { } - - !! "change"; - - X:text { } - - X:if "$format='deb'" { - !{concat(' -- ', @packager, ' ', - $conf/changes/day[number($dow)], ', ', - $pday, - $conf/changes/month[number(substring($date_, 6, 2))], - substring($date_, 1, 4), ' ', $time_)} - - X:text { } - X:text { } - } - } - } - } -} - - -X:template = "change" { - X:var prefix = "$conf/changes/*[local-name(.)=current()/@type]" - - X:var postfix = { X:if "$prefix" { X:text {: } } } - - !! "para" (prefix = "concat($start, $prefix, $postfix)"); -} - - -X:template para(prefix) = "para" { - X:var text = { !!; } - - X:if "$format='generic'" { - X:text { } - } - - !wrap(text = "normalize-space($text)", - prefix = { X:if "position() = 1" { !{$prefix} } else { !{$indent} } }) -} - - -X:template wrap(text, prefix) { - X:if "$text" { - X:var offset = { - X:choose { - X:when "starts-with($text, concat($br, ' '))" { - !{string-length($br) + 2} - } - X:when "starts-with($text, $br)" { - !{string-length($br) + 1} - } - X:otherwise { - 1 - } - } - } - - X:var length = { - !length(text = "substring($text, $offset)", - prefix = "string-length($prefix)", - length = "$max") - } - - !{$prefix} - - !{normalize-space(translate(substring($text, $offset, $length), - ' ', ' '))} - - X:text { } - - !wrap(text = "substring($text, $length + $offset)", prefix = "$indent") - } -} - - -X:template length(text, prefix, length) { - X:var break = "substring-before(substring($text, 1, - $length - $prefix + string-length($br)), - $br)" - - X:choose { - X:when "$break" { !{string-length($break)} } - - X:when "$length = 0" { !{$max - $prefix} } - - X:when "string-length($text) + $prefix <= $length" { - !{$length - $prefix} - } - - X:when "substring($text, $length - $prefix + 1, 1) = ' '" { - !{$length - $prefix + 1} - } - - X:otherwise { - !length(text = "$text", prefix = "$prefix", length = "$length - 1") - } - } -} - - -X:template day_of_week(date) { - X:param year = "substring-before($date, '-')"; - X:param month = "substring-before(substring-after($date, '-'), '-')"; - X:param day = "substring-after(substring-after($date, '-'), '-')"; - - X:var a = "floor((14 - $month) div 12)"; - - X:var y = "$year - $a"; - - X:var m = "$month + 12 * $a - 2"; - - !{($day + $y + floor($y div 4) - floor($y div 100) - + floor($y div 400) + floor((31 * $m) div 12)) mod 7 + 1} -} - - -X:template padded_day(date) { - !{substring(concat(' ', format-number(substring($date, 9, 2), '##')), - 1 + string-length(format-number(substring($date, 9, 2), '##')))} -} - - -X:template string_in_list(list, string) { - X:choose { - X:when "contains($list, ' ')" { - X:var str = "substring-before($list, ' ')"; - X:choose { - X:when "$str=$string" { - !{$string} - } - X:otherwise { - !string_in_list(list="substring-after($list, ' ')", - string="$string") - } - } - } - X:otherwise { - X:if "$list=$string" { !{$string} } - X:if "$list='*'" { !{$string} } - } - } -} - - -X:template beautify(pkgname) { - X:choose { - X:when "$pkgname='unit'" {Unit} - X:otherwise { - !{$pkgname} - } - } -} - - -X:template getdate(date, curdate) { - X:choose { - X:when "$date=''" { - !{$curdate} - } - X:otherwise { - !{$date} - } - } -} - - -X:template gettime(time, curtime) { - X:choose { - X:when "$time=''" { - !{$curtime} - } - X:otherwise { - !{$time} - } - } -} - - -X:template = "at" {@} -X:template = "br" { !{$br} } -X:template = "nobr" { !{translate(., ' ', ' ')} } - - -} diff --git a/docs/changes.xslt b/docs/changes.xslt deleted file mode 100644 index 08f2f800..00000000 --- a/docs/changes.xslt +++ /dev/null @@ -1,281 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - : - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Unit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@ - - - - - diff --git a/docs/man/man8/unitd.8.in b/docs/man/man8/unitd.8.in deleted file mode 100644 index 70371cdf..00000000 --- a/docs/man/man8/unitd.8.in +++ /dev/null @@ -1,129 +0,0 @@ -.\" (C) 2017-2024 NGINX, Inc. -.\" (C) 2017-2024 Andrei Zeliankou -.\" (C) 2018-2024 Konstantin Pavlov -.\" (C) 2021-2024 Zhidao Hong -.\" (C) 2022-2024 Andrew Clayton -.\" (C) 2022-2024 Liam Crilly -.\" (C) 2023-2024 Dan Callahan -.\" (C) 2023-2024 Danielle De Leo -.\" (C) 2023-2024 Dylan Arbour -.\" (C) 2023-2024 Gabor Javorszky -.\" (C) 2023-2024 Igor Ippolitov -.\" (C) 2023-2024 Taryn Musgrave -.\" (C) 2021-2023 Alejandro Colomar -.\" (C) 2017-2022 Valentin V. Bartenev -.\" (C) 2017-2022 Max Romanov -.\" (C) 2021-2022 Oisín Canty -.\" (C) 2017-2021 Igor Sysoev -.\" (C) 2017-2021 Andrei Belov -.\" (C) 2019-2021 Tiago Natel de Moura -.\" (C) 2019-2020 Axel Duch -.\" (C) 2018-2019 Alexander Borisov -.\" -.Dd 2023-04-26 -.Dt unitd 8 -.Os NGINX Unit -.Sh Name -.Nm unitd -.Nd "runs the NGINX Unit daemon" -.Sh Synopsis -.Nm -.Op Fl Fl no-daemon -.Op Fl Fl control Ar socket -.Op Fl Fl control-mode Ar mode -.Op Fl Fl control-user Ar user -.Op Fl Fl control-group Ar group -.Op Fl Fl group Ar name -.Op Fl Fl user Ar name -.Op Fl Fl log Ar file -.Op Fl Fl modulesdir Ar directory -.Op Fl Fl pid Ar file -.Op Fl Fl statedir Ar directory -.Nm -.Op Fl h | Fl Fl help | Fl Fl version -.Sh Description -NGINX Unit is a polyglot app server, a reverse proxy, and a static file server -for UNIX-like systems. -It was built by -.Xr nginx 8 -team members from -scratch to be highly efficient and fully configurable at runtime. -.Sh Options -.Bl -tag -width indent -.It Fl h , Fl Fl help -Displays a summary of Unit's command-line options and their -compile-time defaults. -.It Fl Fl version -Displays Unit's version and the -.Pa ./configure -settings it was built with. -.It Fl Fl no-daemon -Runs Unit in non-daemon mode. -.It Fl Fl control Ar socket -Overrides the control API's socket address in IPv4, IPv6, -or UNIX-domain format. -.It Fl Fl control-mode Ar mode -Sets the permission of the UNIX-domain control socket. -.It Fl Fl control-user Ar user -Sets the owner of the UNIX-domain control socket. -.It Fl Fl control-group Ar group -Sets the group of the UNIX-domain control socket. -.It Fl Fl group Ar name , Fl Fl user Ar name -Override group name and user name used to run Unit's non-privileged processes. -.It Fl Fl log Ar file -Overrides the pathname for Unit's log. -.It Fl Fl modulesdir Ar directory -Overrides the directory path for Unit's language modules -.Po Pa *.unit.so -.Pc files . -.It Fl Fl pid Ar file -Overrides the pathname for the PID file of Unit's main process. -.It Fl Fl statedir Ar directory -Overrides the directory path for Unit's state storage. -.El -.Sh Exit status -Exit status is 0 on success, or 1 if the daemon encounters an error. -.Sh Files -.Bl -tag -width indent -.It Pa %%PID_PATH%% -The PID file of Unit's main process. -.It Pa %%ERROR_LOG_PATH%% -A general-purpose log for diagnostics and troubleshooting. -.El -.Sh Sockets -.Bl -tag -width indent -.It Pa %%SOCKET_PATH%% -The socket address of Unit's control API. -.El -.Sh Copyright -.nf -(C) 2017-2024 NGINX, Inc. -(C) 2017-2024 Andrei Zeliankou -(C) 2018-2024 Konstantin Pavlov -(C) 2021-2024 Zhidao Hong -(C) 2022-2024 Andrew Clayton -(C) 2022-2024 Liam Crilly -(C) 2023-2024 Dan Callahan -(C) 2023-2024 Danielle De Leo -(C) 2023-2024 Dylan Arbour -(C) 2023-2024 Gabor Javorszky -(C) 2023-2024 Igor Ippolitov -(C) 2023-2024 Taryn Musgrave -(C) 2021-2023 Alejandro Colomar -(C) 2017-2022 Valentin V. Bartenev -(C) 2017-2022 Max Romanov -(C) 2021-2022 Oisín Canty -(C) 2017-2021 Igor Sysoev -(C) 2017-2021 Andrei Belov -(C) 2019-2021 Tiago Natel de Moura -(C) 2019-2020 Axel Duch -(C) 2018-2019 Alexander Borisov -.fi -.Pp -SPDX-License-Identifier: Apache-2.0 -.Sh See also -.Lk https://unit.nginx.org Website -.Pp -.Lk https://mailman.nginx.org/mailman/listinfo/unit "User mailing list" -.Pp -.Lk https://github.com/nginx/unit GitHub diff --git a/docs/unit-openapi.yaml b/docs/unit-openapi.yaml deleted file mode 100644 index 2eeb9cbb..00000000 --- a/docs/unit-openapi.yaml +++ /dev/null @@ -1,6389 +0,0 @@ -openapi: 3.0.0 -info: - title: "NGINX Unit 1.32.1" - description: "NGINX Unit is a lightweight and versatile application runtime - that provides the essential components for your web application as a - single open-source server: running application code, serving static assets, - handling TLS and request routing. - - \n\n**Important**: Unit's API is designed to expose any part of its - configuration as an addressable endpoint. Suppose a JSON - object is stored at `/config/listeners/`:\n\n - - ```json - { - \"*:8080\": { - \"pass\": \"applications/wp_emea_dev\" - } - } - ```\n - - Here, `/config/listeners/*:8080` and `/config/listeners/*:8080/pass` - are also endpoints. Generally, object options are addressable by - their names, array items—by their indexes (`/array/0/`). - - - \n\n**Note**: By default, Unit is configured through a UNIX domain - socket. To use this specification with OpenAPI tools interactively, - [start](https://unit.nginx.org/howto/source/#source-startup) Unit - with a TCP port as the control socket." - - contact: - name: "Unit project" - email: "unit-owner@nginx.org" - url: "https://unit.nginx.org/" - - license: - name: "Apache 2.0" - url: "https://www.apache.org/licenses/LICENSE-2.0.html" - - version: 0.2.0 - -servers: - - url: http://{server}:{port} - variables: - server: - default: "localhost" - - port: - default: "8080" - -# -- PATHS -- - -paths: - /certificates: - summary: "Endpoint for the `certificates` object" - get: - operationId: getCerts - summary: "Retrieve the certificates object" - description: "Retrieves the entire `/certificates` section that represents - Unit's [stored certificates](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - responses: - "200": - description: "OK; the `certificates` object exists in - the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/cert" - - examples: - example1: - $ref: "#/components/examples/cert" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}: - summary: "Endpoint for the certificate bundle object" - get: - operationId: getCertBundle - summary: "Retrieve the certificate bundle object" - description: "Retrieves the bundle description that represents - Unit's [stored certificate bundle] - (https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate bundle object exists in - the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/certBundle" - - examples: - example1: - $ref: "#/components/examples/certBundle" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: putCertBundle - summary: "Create or overwrite the actual certificate bundle" - description: "Creates or overwrites the [stored certificate bundle] - (https://unit.nginx.org/certificates/) in Unit." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/bundleName" - - requestBody: - required: true - content: - application/octet-stream: - schema: - type: string - format: binary - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - /certificates/{bundleName}/key: - summary: "Endpoint for the certificate bundle key" - get: - operationId: getCertBundleKey - summary: "Retrieve the certificate bundle key type" - description: "Retrieves the bundle key type from a - [stored certificate bundle](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate bundle key type exists in - the configuration." - - content: - application/json: - schema: - type: string - - examples: - Key: - value: "RSA (4096 bits)" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain: - summary: "Endpoint for the certificate bundle chain" - get: - operationId: getCertBundleChain - summary: "Retrieve the certificate bundle chain" - description: "Retrieves the bundle chain from a - [stored certificate bundle](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate bundle chain exists in - the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/certBundleChain" - - examples: - example1: - $ref: "#/components/examples/certBundleChain" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}: - summary: "Endpoint for the certificate object in the chain array" - get: - operationId: getCertBundleChainCert - summary: "Retrieve certificate object from the chain array" - description: "Retrieves the individual certificate from a - [stored certificate bundle](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/certBundleChainCert" - - examples: - example1: - $ref: "#/components/examples/certBundleChainCert" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/subject: - summary: "Endpoint for the certificate subject object" - get: - operationId: getCertBundleChainCertSubj - summary: "Retrieve the subject from the certificate object" - description: "Retrieves the subject from a - [stored certificate](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate subject exists in - the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/certBundleChainCertSubj" - - examples: - example1: - $ref: "#/components/examples/certBundleChainCertSubj" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/subject/common_name: - summary: "Endpoint for the certificate's common name" - get: - operationId: getCertBundleChainCertSubjCN - summary: "Retrieve the common name from the certificate subject" - description: "Retrieves the common name from a - [stored certificate's subject](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate subject's common name exists in - the configuration." - - content: - application/json: - schema: - type: string - - examples: - CN: - value: "example.com" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/subject/country: - summary: "Endpoint for the certificate's country of issue" - get: - operationId: getCertBundleChainCertSubjCountry - summary: "Retrieve the country code from the certificate subject" - description: "Retrieves the country code from a - [stored certificate's subject](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate subject's country code exists in - the configuration." - - content: - application/json: - schema: - type: string - - examples: - Country: - value: "US" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/subject/state_or_province: - summary: "Endpoint for the certificate's state or province of issue" - get: - operationId: getCertBundleChainCertSubjState - summary: "Retrieve the state or province code from the - certificate subject" - - description: "Retrieves the state or province code from a - [stored certificate's subject](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate subject's state or province code - exists in the configuration." - - content: - application/json: - schema: - type: string - - examples: - StateProvince: - value: "CA" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/subject/organization: - summary: "Endpoint for the certificate's designated organization" - get: - operationId: getCertBundleChainCertSubjOrg - summary: "Retrieve the organization name from the certificate subject" - description: "Retrieves the organization name from a - [stored certificate's subject](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate subject's organization name exists - in the configuration." - - content: - application/json: - schema: - type: string - - examples: - Org: - value: "Acme, Inc." - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/subject/alt_names: - summary: "Endpoint for the certificate's alternative names" - get: - operationId: getCertBundleChainCertSubjAltArray - summary: "Retrieve the alternative names array from the - certificate subject" - - description: "Retrieves the alternative names array from a - [stored certificate's subject](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate subject's alternative names array - exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/stringArray" - - examples: - AltNames: - value: - - "example.com" - - "www.example.com" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/subject/alt_names/{arrayIndex2}: - summary: "Endpoint for the certificate's alternative name" - get: - operationId: getCertBundleChainCertSubjAlt - summary: "Retrieve an alternative name from the certificate subject" - description: "Retrieves an alternative name from a - [stored certificate's subject](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/arrayIndex2" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate subject's alternative name exists - in the configuration." - - content: - application/json: - schema: - type: string - - examples: - AltName: - value: "example.com" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/issuer: - summary: "Endpoint for the certificate issuer object" - get: - operationId: getCertBundleChainCertIssuer - summary: "Retrieve the issuer object from the certificate object" - description: "Retrieves the issuer object from a - [stored certificate](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate issuer object exists in - the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/certBundleChainCertIssuer" - - examples: - example1: - $ref: "#/components/examples/certBundleChainCertIssuer" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/issuer/common_name: - summary: "Endpoint for the certificate issuer's common name" - get: - operationId: getCertBundleChainCertIssuerCN - summary: "Retrieve the common name from the certificate issuer" - description: "Retrieves the common name from a - [stored certificate's issuer](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate issuer's common name exists in - the configuration." - - content: - application/json: - schema: - type: string - - examples: - CN: - value: "intermediate.ca.example.com" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/issuer/country: - summary: "Endpoint for the certificate issuer's country of issue" - get: - operationId: getCertBundleChainCertissuerCountry - summary: "Retrieve the country code from the certificate issuer" - description: "Retrieves the country code from a - [stored certificate's issuer](https://unit.nginx.org/certificates/)." - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate issuer's country code exists in - the configuration." - - content: - application/json: - schema: - type: string - - examples: - Country: - value: "US" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/issuer/state_or_province: - summary: "Endpoint for the certificate issuer's state or province of issue" - get: - operationId: getCertBundleChainCertIssuerState - summary: "Retrieve the state or province code from the certificate issuer" - description: "Retrieves the state or province code from a - [stored certificate's issuer](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate issuer's state or province code - exists in the configuration." - - content: - application/json: - schema: - type: string - - examples: - StateProvince: - value: "CA" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/issuer/organization: - summary: "Endpoint for the certificate issuer's designated organization" - get: - operationId: getCertBundleChainCertIssuerOrg - summary: "Retrieve the organization name from the certificate issuer" - description: "Retrieves the organization name from a - [stored certificate's issuer](https://unit.nginx.org/certificates/)." - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate issuer's organization name exists in - the configuration." - - content: - application/json: - schema: - type: string - - examples: - Org: - value: "Acme Certification Authority" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/validity: - summary: "Endpoint for the certificate validity object" - get: - operationId: getCertBundleChainCertValid - summary: "Retrieve the validity object from the certificate object" - description: "Retrieves the validity object from a - [stored certificate](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the certificate validity object exists in - the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/certBundleChainCertValidity" - - examples: - example1: - $ref: "#/components/examples/certBundleChainCertValidity" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/validity/since: - summary: "Endpoint for the certificate validity's starting time" - get: - operationId: getCertBundleChainCertValidSince - summary: "Retrieve the starting time of certificate validity" - description: "Retrieves the starting time of a - [stored certificate's validity](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the starting time of certificate validity exists - in the configuration." - - content: - application/json: - schema: - type: string - - examples: - DateTime: - value: "Sep 18 19:46:19 2022 GMT" - - "404": - $ref: "#/components/responses/responseNotFound" - - /certificates/{bundleName}/chain/{arrayIndex}/validity/until: - summary: "Endpoint for the certificate validity's ending time" - get: - operationId: getCertBundleChainCertValidUntil - summary: "Retrieve the ending time of certificate validity" - description: "Retrieves the ending time of a - [stored certificate's validity](https://unit.nginx.org/certificates/)." - - tags: - - certificates - - parameters: - - $ref: "#/components/parameters/arrayIndex" - - $ref: "#/components/parameters/bundleName" - - responses: - "200": - description: "OK; the ending time of certificate validity exists - in the configuration." - - content: - application/json: - schema: - type: string - - examples: - DateTime: - value: "Sep 18 19:46:19 2022 GMT" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config: - summary: "Endpoint for the `config` object" - get: - operationId: getConfig - summary: "Retrieve the config" - description: "Retrieves the `config` object that represents Unit's - [configuration](https://unit.nginx.org/configuration)." - - tags: - - config - - responses: - "200": - description: "OK; the `config` object exists in the - configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/config" - - examples: - example1: - $ref: "#/components/examples/config" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateConfig - summary: "Create or overwrite the config" - description: "Creates or overwrites the entire `config` object." - tags: - - config - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/config" - - examples: - example1: - $ref: "#/components/examples/config" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteConfig - summary: "Delete the config object" - description: "Deletes the entire `config` object." - tags: - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/access_log: - summary: "Endpoint for the `access_log` object" - get: - operationId: getAccessLog - summary: "Retrieve the access log" - description: "Retrieves the `access_log` entity that represents Unit's - [access log](https://unit.nginx.org/configuration/#access-log)." - - tags: - - access log - - config - - responses: - "200": - description: "OK; the `access_log` entity exists in the - configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configAccessLog" - - examples: - example1: - $ref: "#/components/examples/configAccessLogBasic" - - example2: - $ref: "#/components/examples/configAccessLogComplex" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateAccessLog - summary: "Create or overwrite the access log" - description: "Creates or overwrites the entire `access_log` entity." - tags: - - access log - - config - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configAccessLog" - - examples: - example1: - $ref: "#/components/examples/configAccessLogBasic" - - example2: - $ref: "#/components/examples/configAccessLogComplex" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteAccessLog - summary: "Delete the access log" - description: "Deletes the entire `access_log` section." - tags: - - access log - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/access_log/format: - summary: "Endpoint for the `format` access log option" - get: - operationId: getAccessLogFormat - summary: "Retrieve the access log format option" - description: "Retrieves the `format` option that represents Unit's - [access log format](https://unit.nginx.org/configuration/#access-log) - in the `access_log` object." - - tags: - - access log - - config - - responses: - "200": - description: "OK; the `format` option exists in the configuration." - - content: - application/json: - schema: - type: string - - examples: - format: - value: '$remote_addr - - [$time_local] "$request_line" $status - $body_bytes_sent "$header_referer" "$header_user_agent"' - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateAccessLogFormat - summary: "Create or overwrite the access log format" - description: "Creates or overwrites the `format` option in the - `access_log` object." - - tags: - - access log - - config - - requestBody: - required: true - content: - application/json: - schema: - type: string - - examples: - format: - value: '$remote_addr - - [$time_local] "$request_line" $status - $body_bytes_sent "$header_referer" "$header_user_agent"' - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteAccessLogFormat - summary: "Delete the access log format" - description: "Deletes the `format` option from the `access_log` object." - tags: - - access log - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/access_log/path: - summary: "Endpoint for the `path` access log option" - get: - operationId: getAccessLogPath - summary: "Retrieve the access log path option" - description: "Retrieves the `path` option that represents Unit's - [access log path](https://unit.nginx.org/configuration/#access-log) - in the `access_log` object." - - tags: - - access log - - config - - responses: - "200": - description: "OK; the `path` option exists in the configuration." - - content: - application/json: - schema: - type: string - - examples: - path: - value: "/var/log/unit/access.log" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateAccessLogPath - summary: "Create or overwrite the access log path" - description: "Creates or overwrites the `path` option in the `access_log` - object." - - tags: - - access log - - config - - requestBody: - required: true - content: - application/json: - schema: - type: string - - examples: - path: - value: "/var/log/unit/access.log" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteAccessLogPath - summary: "Delete the access log path" - description: "Deletes the `path` option from the `access_log` object." - tags: - - access log - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/applications: - summary: "Endpoint for the `applications` object in the configuration" - get: - operationId: getApplications - summary: "Retrieve the applications object" - description: "Retrieves the `applications` object that represents Unit's - [applications](https://unit.nginx.org/configuration/#applications)." - tags: - - applications - - config - - responses: - "200": - description: "OK; the `applications` object exists in the - configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configApplications" - - examples: - example1: - $ref: "#/components/examples/configApplications" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateApplications - summary: "Overwrite the applications object" - description: "Overwrites the `applications` object in the configuration." - tags: - - applications - - config - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configApplications" - - examples: - example1: - $ref: "#/components/examples/configApplications" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteApplications - summary: "Delete the applications object" - description: "Deletes the `applications` object from the configuration." - tags: - - applications - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/applications/{appName}: - summary: "Endpoint for an application object in the configuration" - - parameters: - - $ref: "#/components/parameters/appName" - - get: - operationId: getApplication - summary: "Retrieve an application object" - description: "Retrieves the `{appName}` object that represents an - [application](https://unit.nginx.org/configuration/#applications) - in Unit's control API." - - tags: - - applications - - config - - responses: - "200": - description: "OK; the `{appName}` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configApplication" - - examples: - example1: - $ref: "#/components/examples/configApplication" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateApplication - summary: "Create or overwrite the application object" - description: "Creates or overwrites the `{appName}` object in the - configuration." - - tags: - - applications - - config - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configApplication" - - examples: - example1: - $ref: "#/components/examples/configApplication" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteApplication - summary: "Delete the application object" - description: "Deletes the `{appName}` object from the configuration." - tags: - - applications - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /control/applications/{appName}/restart: - summary: "Endpoint for the `applications/{appName}/restart` option" - get: - operationId: getAppRestart - summary: "Restart the {appName} application" - description: "Tells Unit to [restart] - (https://unit.nginx.org/configuration/#process-management) - the application identified by `{appName}`." - - tags: - - apps - - control - - parameters: - - $ref: "#/components/parameters/appName" - - responses: - "200": - description: "OK; the `{appName}` application was gracefully - restarted." - - content: - application/json: - schema: - $ref: "#/components/schemas/jsonSuccessMessage" - - example: - success: "Ok" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners: - summary: "Endpoint for the `listeners` object" - get: - operationId: getListeners - summary: "Retrieve all the listeners" - description: "Retrieves the `listeners` object whose options represent - individual [listeners](https://unit.nginx.org/configuration/#listeners); - each is a unique combination of a host IP address (or a `*` wildcard to - match any host IP addresses) and a port." - - tags: - - listeners - - config - - responses: - "200": - description: "OK; the `listeners` object exists in the configuration." - content: - application/json: - schema: - $ref: "#/components/schemas/configListeners" - - examples: - example1: - $ref: "#/components/examples/configListeners" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListeners - summary: "Create or overwrite all the listeners" - description: "Creates or overwrites the entire `listeners` section with - an object whose options represent individual listeners; each is a unique - combination of a host IP address (or a `*` wildcard to match any host IP - addresses) and a port." - - tags: - - listeners - - config - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configListeners" - - examples: - example1: - $ref: "#/components/examples/configListenerSimple" - - example2: - $ref: "#/components/examples/configListeners" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListeners - summary: "Delete all the listeners" - description: "Deletes the entire `listeners` section." - tags: - - listeners - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}: - summary: "Endpoint for a `listeners/{listenerName}` object that - represents a listener" - - get: - operationId: getListener - summary: "Retrieve a listener object" - description: "Retrieves the `{listenerName}` object that configures a - [listener](https://unit.nginx.org/configuration/#listeners)." - - tags: - - listeners - - config - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `{listenerName}` object exists in - the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configListener" - - examples: - example1: - $ref: "#/components/examples/configListenerSimple" - - example2: - $ref: "#/components/examples/configListenerComplex" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListener - summary: "Create or overwrite a listener object" - description: "Creates or overwrites the `{listenerName}` object." - tags: - - listeners - - config - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configListener" - - examples: - example1: - $ref: "#/components/examples/configListenerSimple" - - example2: - $ref: "#/components/examples/configListenerComplex" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListener - summary: "Delete a listener object" - description: "Deletes the `{listenerName}` object." - tags: - - listeners - - config - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/pass: - summary: "Endpoint for the `listeners/{listenerName}/pass` option" - get: - operationId: getListenerPass - summary: "Retrieve the pass option in a listener" - description: "Retrieves the `pass` option that configures the destination - where the `{listenerName}` listener object - [passes its requests](https://unit.nginx.org/configuration/#listeners)." - - tags: - - listeners - - config - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `pass` option exists in the configuration." - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerPassApp" - - example2: - $ref: "#/components/examples/configListenerPassRoute" - - example3: - $ref: "#/components/examples/configListenerPassAppTarget" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerPass - summary: "Update the pass option in a listener" - description: "Overwrites the `pass` option." - tags: - - listeners - - config - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerPassApp" - - example2: - $ref: "#/components/examples/configListenerPassRoute" - - example3: - $ref: "#/components/examples/configListenerPassAppTarget" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - /config/listeners/{listenerName}/tls: - summary: "Endpoint for the `listeners/{listenerName}/tls` object" - get: - operationId: getListenerTls - summary: "Retrieve the tls object in a listener" - description: "Retrieves the `tls` object that configures [TLS settings] - (https://unit.nginx.org/configuration/#ssl-tls-configuration) - for the `{listenerName}` listener." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `tls` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configListenerTls" - - examples: - example1: - $ref: "#/components/examples/configListenerTls" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerTls - summary: "Create or overwrite the tls object in a listener" - description: "Creates or overwrites the entire `tls` object." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configListenerTls" - - examples: - example1: - $ref: "#/components/examples/configListenerTls" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerTls - summary: "Delete the tls object in a listener" - description: "Deletes the `tls` object." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/tls/conf_commands: - summary: "Endpoint for the `listeners/{listenerName}/tls/conf_commands` - object" - - get: - operationId: listListenerTlsConfCommands - summary: "Retrieve the conf_commands object in a listener" - description: "Retrieves the `conf_commands` object that sets - [TLS configuration commands] - (https://unit.nginx.org/configuration/#ssl-tls-configuration) - for the `{listenerName}` listener." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `conf_commands` object exists in the - configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configListenerTlsConfCommands" - - examples: - example1: - $ref: "#/components/examples/configListenerTlsConfCommands" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerTlsConfCommands - summary: "Create or overwrite the conf_commands object in a listener" - description: "Creates or overwrites the entire `conf_commands` object." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configListenerTlsConfCommands" - - examples: - example1: - $ref: "#/components/examples/configListenerTlsConfCommands" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerTlsConfCommands - summary: "Delete the conf_commands object in a listener" - description: "Deletes the `conf_commands` object." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/tls/session: - summary: "Endpoint for the `listeners/{listenerName}/tls/session` object" - get: - operationId: getListenerTlsSession - summary: "Retrieve the session object in a listener" - description: "Retrieves the `session` object that configures - [TLS session settings] - (https://unit.nginx.org/configuration/#ssl-tls-configuration) - for the `{listenerName}` listener." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `session` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configListenerTlsSession" - - examples: - example1: - $ref: "#/components/examples/configListenerTlsSession" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerTlsSession - summary: "Create or overwrite the session object in a listener" - description: "Creates or overwrites the entire `session` object." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configListenerTlsSession" - - examples: - example1: - $ref: "#/components/examples/configListenerTlsSession" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerTlsSession - summary: "Delete the session object in a listener" - description: "Deletes the `session` object." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/tls/session/tickets: - summary: "Endpoint for the `listeners/{listenerName}/session/tickets` - object" - - get: - operationId: listListenerTlsSessionTickets - summary: "Retrieve the tickets option in a listener" - description: "Retrieves the `tickets` option that lists - [TLS session ticket keys] - (https://unit.nginx.org/configuration/#ssl-tls-configuration) - used with the `{listenerName}` listener." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `tickets` option exists in the configuration." - - content: - application/jsons: - schema: - $ref: "#/components/schemas/configListenerTlsSessionTickets" - - examples: - example1: - $ref: "#/components/examples/configListenerTlsSessionTicketsBool" - - example2: - $ref: "#/components/examples/configListenerTlsSessionTicketsString" - - example3: - $ref: "#/components/examples/configListenerTlsSessionTicketsArray" - - "404": - $ref: "#/components/responses/responseNotFound" - - post: - operationId: insertListenerTlsSessionTicket - summary: "Add a new tickets array item in a listener" - description: "Adds a new session ticket key to the end of the `tickets` - string array that lists [session ticket keys] - (https://unit.nginx.org/configuration/#ssl-tls-configuration) - configured earlier." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerTlsSessionTicketsString" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - put: - operationId: updateListenerTlsSessionTickets - summary: "Create or overwrite the tickets option in a listener" - description: "Creates or overwrites the entire `tickets` option with a - boolean, string, or string array that configures [session ticket keys] - (https://unit.nginx.org/configuration/#ssl-tls-configuration) - used with the `{listenerName}` listener." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configListenerTlsSessionTickets" - - examples: - example1: - $ref: "#/components/examples/configListenerTlsSessionTicketsBool" - - example2: - $ref: "#/components/examples/configListenerTlsSessionTicketsString" - - example3: - $ref: "#/components/examples/configListenerTlsSessionTicketsArray" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerTlsSessionTickets - summary: "Delete the tickets option in a listener" - description: "Deletes the `tickets` option." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/tls/session/tickets/{arrayIndex}: - summary: "Endpoint for the `listeners/{listenerName}/tls/certificate` - object" - - get: - operationId: getListenerTlsSessionTicket - summary: "Retrieve a ticket array item in a listener" - description: "Retrieves the `{arrayIndex}`th item from the `tickets` - string array." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - $ref: "#/components/parameters/arrayIndex" - - responses: - "200": - description: "OK; the ticket key at `{arrayIndex}` exists in the - configuration." - - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerTlsSessionTicketsString" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerTlsSessionTicket - summary: "Create or overwrite a ticket array item in a listener" - description: "Overwrites a single `tickets` string array item identified - by `{arrayIndex}`." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - $ref: "#/components/parameters/arrayIndex" - - requestBody: - required: true - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerTlsSessionTicketsString" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerTlsSessionTicket - summary: "Delete a ticket array item in a listener" - description: "Deletes an item from the `tickets` string array." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - $ref: "#/components/parameters/arrayIndex" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/tls/certificate: - summary: "Endpoint for the `listeners/{listenerName}/tls/certificate` - object" - - get: - operationId: listListenerTlsCertificates - summary: "Retrieve the certificate option in a listener" - description: "Retrieves the `certificate` option that lists [certificate - bundles](https://unit.nginx.org/configuration/#certificate-management) - used with the `{listenerName}` listener." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `certificate` option exists in the - configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configListenerTlsCertificate" - - examples: - example1: - $ref: "#/components/examples/configListenerTlsCertificateArray" - - example2: - $ref: "#/components/examples/configListenerTlsCertificateString" - - "404": - $ref: "#/components/responses/responseNotFound" - - post: - operationId: insertListenerTlsCertificate - summary: "Add a new certificate array item in a listener" - description: "Adds a new certificate bundle name to the end of the - `certificate` string array." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerTlsCertificateString" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - put: - operationId: updateListenerTlsCertificates - summary: "Create or overwrite the certificate option in a listener" - description: "Creates or overwrites the entire `certificate` option." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/stringOrStringArray" - - examples: - example1: - $ref: "#/components/examples/configListenerTlsCertificateArray" - - example2: - $ref: "#/components/examples/configListenerTlsCertificateString" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerTlsCertificates - summary: "Delete the certificate option in a listener" - description: "Deletes the `certificate` option." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/tls/certificate/{arrayIndex}: - summary: "Endpoint for the `listeners/{listenerName}/tls/certificate` - string array item" - - get: - operationId: getListenerTlsCertificate - summary: "Retrieve a certificate array item in a listener" - description: "Retrieves the `{arrayIndex}`th item from the `certificate` - string array." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - $ref: "#/components/parameters/arrayIndex" - - responses: - "200": - description: "OK; the certificate bundle at `{arrayIndex}` exists in - the configuration." - - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerTlsCertificateString" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerTlsCertificate - summary: "Update a certificate array item in a listener" - description: "Overwrites a single `certificate` string array item - identified by `{arrayIndex}`." - - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - $ref: "#/components/parameters/arrayIndex" - - requestBody: - required: true - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerTlsCertificateString" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerTlsCertificate - summary: "Delete a certificate array item in a listener" - description: "Deletes an item from the `certificate` string array." - tags: - - listeners - - config - - tls - - parameters: - - $ref: "#/components/parameters/listenerName" - - $ref: "#/components/parameters/arrayIndex" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/forwarded: - summary: "Endpoint for the `listeners/{listenerName}/forwarded` object" - get: - operationId: getListenerForwarded - summary: "Retrieve the forwarded object in a listener" - description: "Retrieves the `forwarded` object that configures - [originating IP identification] - (https://unit.nginx.org/configuration/#ip-protocol-forwarding) - for the `{listenerName}` listener." - - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `forwarded` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configListenerForwarded" - - examples: - example1: - $ref: "#/components/examples/configListenerForwarded" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerForwarded - summary: "Create or overwrite the forwarded object in a listener" - description: "Creates or overwrites the entire `forwarded` object." - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configListenerForwarded" - - examples: - example1: - $ref: "#/components/examples/configListenerForwarded" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerForwared - summary: "Delete the forwarded object in a listener" - description: "Deletes the `forwarded` object." - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/forwarded/client_ip: - summary: "Endpoint for the `listeners/{listenerName}/forwarded/client_ip` - option" - - get: - operationId: getListenerForwardedClientIp - summary: "Retrieve the client_ip option in a listener" - description: "Retrieves the `client_ip` option that configures the headers - expected by the `{listenerName}` listener for - [originating IP identification] - (https://unit.nginx.org/configuration/#originating-ip-identification)." - - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `client_ip` option exists in the configuration." - - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerForwardedClientIp" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerForwardedClientIp - summary: "Create or overwrite the client_ip option in a listener" - description: "Creates or overwrites the `client_ip` option." - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerForwardedClientIp" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - /config/listeners/{listenerName}/forwarded/protocol: - summary: "Endpoint for the `listeners/{listenerName}/forwarded/protocol` - option" - - get: - operationId: getListenerForwardedProtocol - summary: "Retrieve the protocol option in a listener" - description: "Retrieves the `protocol` option that configures the protocol - expected by the `{listenerName}` listener for - [originating IP identification] - (https://unit.nginx.org/configuration/#originating-ip-identification)." - - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `protocol` option exists in the configuration." - - content: - application/json: - schema: - type: string - enum: - - "http" - - "https" - - "on" - - examples: - example1: - $ref: "#/components/examples/configListenerForwardedProtocol" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerForwardedProtocol - summary: "Create or overwrite the protocol option in a listener" - description: "Creates or overwrites the `protocol` option." - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - type: string - enum: - - "http" - - "https" - - "on" - - examples: - example1: - $ref: "#/components/examples/configListenerForwardedProtocol" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - /config/listeners/{listenerName}/forwarded/recursive: - summary: "Endpoint for the `listeners/{listenerName}/forwarded/recursive` - option" - - get: - operationId: getListenerForwardedRecursive - summary: "Retrieve the recursive option in a listener" - description: "Retrieves the `recursive` option that controls how the - `{listenerName}` listener uses [originating IP identification] - (https://unit.nginx.org/configuration/#originating-ip-identification)." - - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `recursive` option exists in the configuration." - - content: - application/json: - schema: - type: boolean - - examples: - example1: - summary: "Enables recursive header field traversal" - value: true - - example2: - summary: "Disables recursive header field traversal" - value: false - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerForwardedRecursive - summary: "Create or overwrite the recursive option in a listener" - description: "Creates or overwrites the `recursive` option." - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - type: boolean - - examples: - example1: - summary: "Enables recursive header field traversal" - value: true - - example2: - summary: "Disables recursive header field traversal" - value: false - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerForwardedRecursive - summary: "Delete the recursive object in a listener" - description: "Deletes the `recursive` object." - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/forwarded/source: - summary: "Endpoint for the `listeners/{listenerName}/forwarded/source` - object" - - get: - operationId: listListenerForwardedSources - summary: "Retrieve the source option in a listener" - description: "Retrieves the `source` option that defines address patterns - for trusted addresses, used by the `{listenerName}` listener for - [originating IP identification] - (https://unit.nginx.org/configuration/#originating-ip-identification)." - - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - description: "OK; the `source` option exists in the configuration." - content: - application/json: - schema: - $ref: "#/components/schemas/stringOrStringArray" - - examples: - example1: - $ref: "#/components/examples/configListenerForwardedSourceArray" - - example2: - $ref: "#/components/examples/configListenerForwardedSourceString" - - "404": - $ref: "#/components/responses/responseNotFound" - - post: - operationId: insertListenerForwardedSource - summary: "Add a new source array item in a listener" - description: "Adds a new source bundle name to the end of the `source` - string array defines address patterns for trusted addresses, used by - the `{listenerName}` listener for [originating IP identification] - (https://unit.nginx.org/configuration/#originating-ip-identification)." - - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerForwardedSourceString" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - put: - operationId: updateListenerForwardedSources - summary: "Create or overwrite the source option in a listener" - description: "Creates or overwrites the entire `source` option." - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/stringOrStringArray" - - examples: - example1: - $ref: "#/components/examples/configListenerForwardedSourceArray" - - example2: - $ref: "#/components/examples/configListenerForwardedSourceString" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerForwardedSources - summary: "Delete the source option in a listener" - description: "Deletes the `source` option." - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/listeners/{listenerName}/forwarded/source/{arrayIndex}: - summary: "Endpoint for the `listeners/{listenerName}/forwarded/source` - string array item" - - get: - operationId: getListenerForwardedSource - summary: "Retrieve a source array item in a listener" - description: "Retrieves the `{arrayIndex}`th item from the `source` - string array." - - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - $ref: "#/components/parameters/arrayIndex" - - responses: - "200": - description: "OK; the address pattern at `{arrayIndex}` exists in the - configuration." - - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerForwardedSourceString" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateListenerForwardedSource - summary: "Update a source array item in a listener" - description: "Overwrites a single `source` string array item identified - by `{arrayIndex}`." - - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - $ref: "#/components/parameters/arrayIndex" - - requestBody: - required: true - content: - application/json: - schema: - type: string - - examples: - example1: - $ref: "#/components/examples/configListenerForwardedSourceString" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteListenerForwardedSource - summary: "Delete a source array item in a listener" - description: "Deletes an item from the `source` string array." - tags: - - listeners - - config - - xff - - parameters: - - $ref: "#/components/parameters/listenerName" - - $ref: "#/components/parameters/arrayIndex" - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/routes: - summary: "Endpoint for the `routes` entity in the configuration" - get: - operationId: getRoutes - summary: "Retrieve the routes entity" - description: "Retrieves the `routes` entity that represents Unit's - [routes](https://unit.nginx.org/configuration/#routes)." - - tags: - - config - - routes - - responses: - "200": - description: "OK; the `routes` entity exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configRoutes" - - examples: - example1: - $ref: "#/components/examples/configRoutes" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateRoutes - summary: "Overwrite the routes entity" - description: "Overwrites the `routes` entity in the configuration." - tags: - - config - - routes - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configRoutes" - - examples: - example1: - $ref: "#/components/examples/configRoutes" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteRoutes - summary: "Delete the routes entity" - description: "Deletes the `routes` entity from the configuration." - tags: - - config - - routes - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings: - summary: "Endpoint for the `settings` object in the configuration" - get: - operationId: getSettings - summary: "Retrieve the settings object" - description: "Retrieves the `settings` object that represents Unit's - [global settings](https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `settings` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configSettings" - - examples: - example1: - $ref: "#/components/examples/configSettings" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettings - summary: "Create or overwrite the settings object" - description: "Creates or overwrites the `settings` object in the - configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configSettings" - - examples: - example1: - $ref: "#/components/examples/configSettings" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettings - summary: "Delete the settings object" - description: "Deletes the `settings` object from the configuration." - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http: - summary: "Endpoint for the `http` object in `settings`" - - get: - operationId: getSettingsHttp - summary: "Retrieve the http object from settings" - description: "Retrieves the `http` object that represents Unit's - [HTTP settings](https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `http` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configSettingsHttp" - - examples: - example1: - $ref: "#/components/examples/configSettingsHttp" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsHttp - summary: "Create or overwrite the http object" - description: "Creates or overwrites the `http` object in the - configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configSettingsHttp" - - examples: - example1: - $ref: "#/components/examples/configSettingsHttp" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsHttp - summary: "Delete the http object" - description: "Deletes the `http` object from the configuration." - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/body_read_timeout: - summary: "Endpoint for the `body_read_timeout` option in `http`" - get: - operationId: getSettingsHttpBodyReadTimeout - summary: "Retrieve the body_read_timeout option from http settings" - description: "Retrieves the `body_read_timeout` option that represents - Unit's [request body read timeout] - (https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `body_read_timeout` option exists in the - configuration." - - content: - application/json: - schema: - type: integer - - examples: - BodyReadTimeout: - value: 30 - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsHttpBodyReadTimeout - summary: "Create or overwrite the body_read_timeout option" - description: "Creates or overwrites the `body_read_timeout` option in - the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - type: integer - - examples: - BodyReadTimeout: - value: 30 - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsHttpBodyReadTimeout - summary: "Delete the body_read_timeout option" - description: "Deletes the `body_read_timeout` option from the - configuration." - - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/discard_unsafe_fields: - summary: "Endpoint for the `discard_unsafe_fields` option in `http`" - get: - operationId: getSettingsDiscardUnsafeFields - summary: "Retrieve the discard_unsafe_fields option from http settings" - description: "Retrieves the `discard_unsafe_fields` option that represents - Unit's [header processing behavior] - (https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `discard_unsafe_fields` option exists in - the configuration." - - content: - application/json: - schema: - type: boolean - - examples: - DiscardUnsafeFields: - value: true - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsDiscardUnsafeFields - summary: "Create or overwrite the discard_unsafe_fields option" - description: "Creates or overwrites the `discard_unsafe_fields` option - in the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - type: boolean - - examples: - DiscardUnsafeFields: - value: true - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsDiscardUnsafeFields - summary: "Delete the discard_unsafe_fields option" - description: "Deletes the `discard_unsafe_fields` option from - the configuration." - - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/header_read_timeout: - summary: "Endpoint for the `header_read_timeout` option in `http`" - get: - operationId: getSettingsHttpHeaderReadTimeout - summary: "Retrieve the header_read_timeout option from http settings" - description: "Retrieves the `header_read_timeout` option that represents - Unit's [request headers read timeout] - (https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `header_read_timeout` option exists in - the configuration." - - content: - application/json: - schema: - type: integer - - examples: - HeaderReadTimeout: - value: 30 - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsHttpHeaderReadTimeout - summary: "Create or overwrite the header_read_timeout option" - description: "Creates or overwrites the `header_read_timeout` option - in the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - type: integer - - examples: - HeaderReadTimeout: - value: 30 - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsHttpHeaderReadTimeout - summary: "Delete the header_read_timeout option" - description: "Deletes the `header_read_timeout` option from - the configuration." - - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/idle_timeout: - summary: "Endpoint for the `idle_timeout` option in `http`" - get: - operationId: getSettingsHttpIdleTimeout - summary: "Retrieve the idle_timeout option from http settings" - description: "Retrieves the `idle_timeout` option that represents - Unit's [keep-alive idling timeout] - (https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `idle_timeout` option exists in - the configuration." - - content: - application/json: - schema: - type: integer - - examples: - IdleTimeout: - value: 180 - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsHttpIdleTimeout - summary: "Create or overwrite the idle_timeout option" - description: "Creates or overwrites the `idle_timeout` option in - the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - type: integer - - examples: - IdleTimeout: - value: 180 - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsHttpIdleTimeout - summary: "Delete the idle_timeout option" - description: "Deletes the `idle_timeout` option from the configuration." - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/log_route: - summary: "Endpoint for the `log_route` option in `http`" - get: - operationId: getSettingsLogRoute - summary: "Retrieve the log_route option from http settings" - description: "Retrieves the `log_route` option that controls - Unit's [router logging] - (https://unit.nginx.org/troubleshooting/#router-log)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `log_route` option exists in - the configuration." - - content: - application/json: - schema: - type: boolean - - examples: - LogRoute: - value: true - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsLogRoute - summary: "Create or overwrite the log_route option" - description: "Creates or overwrites the `log_route` option - in the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - type: boolean - - examples: - LogRoute: - value: true - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsLogRoute - summary: "Delete the log_route option" - description: "Deletes the `log_route` option from - the configuration." - - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/max_body_size: - summary: "Endpoint for the `max_body_size` option in `http`" - get: - operationId: getSettingsHttpMaxBodySize - summary: "Retrieve the max_body_size option from http settings" - description: "Retrieves the `max_body_size` option that represents - Unit's [request body size limit] - (https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `max_body_size` option exists in - the configuration." - - content: - application/json: - schema: - type: integer - - examples: - MaxBodySize: - value: 8388608 - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsHttpMaxBodySize - summary: "Create or overwrite the max_body_size option" - description: "Creates or overwrites the `max_body_size` option in - the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - type: integer - - examples: - MaxBodySize: - value: 8388608 - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsHttpMaxBodySize - summary: "Delete the max_body_size option" - description: "Deletes the `max_body_size` option from the configuration." - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/send_timeout: - summary: "Endpoint for the `send_timeout` option in `http`" - get: - operationId: getSettingsHttpSendTimeout - summary: "Retrieve the send_timeout option from http settings" - description: "Retrieves the `send_timeout` option that represents - Unit's [response send timeout] - (https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `send_timeout` option exists in - the configuration." - - content: - application/json: - schema: - type: integer - - examples: - SendTimeout: - value: 30 - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsHttpSendTimeout - summary: "Create or overwrite the send_timeout option" - description: "Creates or overwrites the `send_timeout` option in - the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - type: integer - - examples: - SendTimeout: - value: 30 - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsHttpSendTimeout - summary: "Delete the send_timeout option" - description: "Deletes the `send_timeout` option from the configuration." - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/server_version: - summary: "Endpoint for the `server_version` option in `http`" - get: - operationId: getSettingsServerVersion - summary: "Retrieve the server_version option from http settings" - description: "Retrieves the `server_version` option that controls - Unit's [Server header field versioning] - (https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `server_version` option exists in - the configuration." - - content: - application/json: - schema: - type: boolean - - examples: - ServerVersion: - value: true - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsServerVersion - summary: "Create or overwrite the server_version option" - description: "Creates or overwrites the `server_version` option - in the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - type: boolean - - examples: - ServerVersion: - value: true - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsServerVersion - summary: "Delete the server_version option" - description: "Deletes the `server_version` option from - the configuration." - - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/static: - summary: "Endpoint for the `static` object in `http`" - get: - operationId: getSettingsHttpStatic - summary: "Retrieve the static object from http settings" - description: "Retrieves the `static` object that represents - Unit's [static content settings] - (https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `static` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configSettingsHttpStatic" - - examples: - example1: - $ref: "#/components/examples/configSettingsHttpStatic" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsHttpStatic - summary: "Create or overwrite the static object" - description: "Creates or overwrites the `static` object in - the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configSettingsHttpStatic" - - examples: - example1: - $ref: "#/components/examples/configSettingsHttpStatic" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsHttpStatic - summary: "Delete the static object" - description: "Deletes the `static` object from the configuration." - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/static/mime_types: - summary: "Endpoint for the `mime_types` object in `static`" - get: - operationId: getSettingsHttpStaticMimeTypes - summary: "Retrieve the mime_types object from static settings" - description: "Retrieves the `mime_types` object that represents Unit's - [MIME type settings](https://unit.nginx.org/configuration/#settings)." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the `mime_types` object exists in - the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configSettingsHttpStaticMimeTypes" - - examples: - example1: - $ref: "#/components/examples/configSettingsHttpStaticMimeTypes" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsHttpStaticMimeTypes - summary: "Create or overwrite the mime_types object" - description: "Creates or overwrites the `mime_types` object in - the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configSettingsHttpStaticMimeTypes" - - examples: - example1: - $ref: "#/components/examples/configSettingsHttpStaticMimeTypes" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsHttpStaticMimeTypes - summary: "Delete the mime_types object" - description: "Deletes the `mime_types` object from the configuration." - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /config/settings/http/static/mime_types/{mimeType}: - summary: "Endpoint for a MIME type option in `mime_types`" - parameters: - - $ref: "#/components/parameters/mimeType" - - get: - operationId: getSettingsHttpStaticMimeType - summary: "Retrieve the MIME type option from MIME type settings" - description: "Retrieves the MIME type option that represents a - [MIME type](https://unit.nginx.org/configuration/#settings) - supported by Unit." - - tags: - - settings - - config - - responses: - "200": - description: "OK; the MIME type option exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/configSettingsHttpStaticMimeType" - - examples: - example1: - $ref: "#/components/examples/configSettingsHttpStaticMimeType" - - "404": - $ref: "#/components/responses/responseNotFound" - - put: - operationId: updateSettingsHttpStaticMimeType - summary: "Create or overwrite the MIME type option" - description: "Creates or overwrites the MIME type option in - the configuration." - - tags: - - settings - - config - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/configSettingsHttpStaticMimeType" - - examples: - example1: - $ref: "#/components/examples/configSettingsHttpStaticMimeType" - - responses: - "200": - $ref: "#/components/responses/responseOkUpdated" - - "400": - $ref: "#/components/responses/responseBadRequest" - - "404": - $ref: "#/components/responses/responseNotFound" - - "500": - $ref: "#/components/responses/responseInternalError" - - delete: - operationId: deleteSettingsHttpStaticMimeType - summary: "Delete the MIME type option" - description: "Deletes the MIME type option from the configuration." - tags: - - settings - - config - - responses: - "200": - $ref: "#/components/responses/responseOkDeleted" - - "404": - $ref: "#/components/responses/responseNotFound" - - /status: - summary: "Endpoint for the `status` object" - get: - operationId: getStatus - summary: "Retrieve the status object" - description: "Retrieves the entire `/status` section that represents - Unit's [usage statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - responses: - "200": - description: "OK; the `status` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/status" - - examples: - example1: - $ref: "#/components/examples/status" - - /status/connections: - summary: "Endpoint for the `connections` status object" - get: - operationId: getStatusConnections - summary: "Retrieve the connections status object" - description: "Retrieves the `connections` status object that represents - Unit's [connection statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - responses: - "200": - description: "OK; the `connections` object exists in - the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/statusConnections" - - examples: - example1: - $ref: "#/components/examples/statusConnections" - - /status/connections/accepted: - summary: "Endpoint for the `accepted` connections number" - get: - operationId: getStatusConnectionsAccepted - summary: "Retrieve the accepted connections number" - description: "Retrieves the `accepted` connections number that represents - Unit's [connection statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - responses: - "200": - description: "OK; the `active` number exists in the configuration." - - content: - application/json: - schema: - type: integer - - examples: - Accepted: - value: 1067 - - /status/connections/active: - summary: "Endpoint for the `active` connections number" - get: - operationId: getStatusConnectionsActive - summary: "Retrieve the active connections number" - description: "Retrieves the `active` connections number that represents - Unit's [connection statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - responses: - "200": - description: "OK; the `active` number exists in the configuration." - - content: - application/json: - schema: - type: integer - - examples: - Active: - value: 13 - - /status/connections/idle: - summary: "Endpoint for the `idle` connections number" - get: - operationId: getStatusConnectionsIdle - summary: "Retrieve the idle connections number" - description: "Retrieves the `idle` connections number that represents - Unit's [connection statistics](https://unit.nginx.org/usagestats/)." - tags: - - status - - responses: - "200": - description: "OK; the `idle` number exists in the configuration." - - content: - application/json: - schema: - type: integer - - examples: - Idle: - value: 4 - - /status/connections/closed: - summary: "Endpoint for the `closed` connections number" - get: - operationId: getStatusConnectionsClosed - summary: "Retrieve the closed connections number" - description: "Retrieves the `closed` connections number that represents - Unit's [connection statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - responses: - "200": - description: "OK; the `closed` number exists in the configuration." - - content: - application/json: - schema: - type: integer - - examples: - Closed: - value: 4 - - /status/requests: - summary: "Endpoint for the `requests` status object" - get: - operationId: getStatusRequests - summary: "Retrieve the requests status object" - description: "Retrieves the `requests` status object that represents - Unit's instance [request statistics] - (https://unit.nginx.org/usagestats/)." - - tags: - - status - - responses: - "200": - description: "OK; the `requests` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/statusRequests" - - examples: - example1: - $ref: "#/components/examples/statusRequests" - - /status/requests/total: - summary: "Endpoint for the `total` requests number" - get: - operationId: getStatusRequestsTotal - summary: "Retrieve the total requests number" - description: "Retrieves the `total` requests number that represents Unit's - instance [request statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - responses: - "200": - description: "OK; the `total` number exists in the configuration." - - content: - application/json: - schema: - type: integer - - examples: - Closed: - value: 1307 - - /status/applications: - summary: "Endpoint for the `applications` status object" - get: - operationId: getStatusApplications - summary: "Retrieve the applications status object" - description: "Retrieves the `applications` status object that represents - Unit's per-app - [process and request statistics](https://unit.nginx.org/usagestats/)." - tags: - - status - - responses: - "200": - description: "OK; the `applications` object exists in - the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/statusApplications" - - examples: - example1: - $ref: "#/components/examples/statusApplications" - - /status/applications/{appName}: - summary: "Endpoint for the app status object" - get: - operationId: getStatusApplicationsApp - summary: "Retrieve the app status object" - description: "Retrieves the app status object that represents - Unit's per-app - [process and request statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - parameters: - - $ref: "#/components/parameters/appName" - - responses: - "200": - description: "OK; the app object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/statusApplicationsApp" - - examples: - example1: - $ref: "#/components/examples/statusApplicationsApp" - - "404": - $ref: "#/components/responses/responseNotFound" - - /status/applications/{appName}/processes: - summary: "Endpoint for the `processes` app status object" - get: - operationId: getStatusApplicationsAppProcesses - summary: "Retrieve the processes app status object" - description: "Retrieves the `processes` app status object that represents - Unit's per-app - [process statistics](https://unit.nginx.org/usagestats/)." - tags: - - status - - parameters: - - $ref: "#/components/parameters/appName" - - responses: - "200": - description: "OK; the `processes` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/statusApplicationsAppProcesses" - - examples: - example1: - $ref: "#/components/examples/statusApplicationsAppProcesses" - - "404": - $ref: "#/components/responses/responseNotFound" - - /status/applications/{appName}/processes/running: - summary: "Endpoint for the `running` processes number" - get: - operationId: getStatusApplicationsAppProcessesRunning - summary: "Retrieve the running processes app status number" - description: "Retrieves the `running` processes number that represents - Unit's per-app - [process statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - parameters: - - $ref: "#/components/parameters/appName" - - responses: - "200": - description: "OK; the `running` number exists in the configuration." - - content: - application/json: - schema: - type: integer - - examples: - Running: - value: 9 - - "404": - $ref: "#/components/responses/responseNotFound" - - /status/applications/{appName}/processes/starting: - summary: "Endpoint for the `starting` processes number" - get: - operationId: getStatusApplicationsAppProcessesStarting - summary: "Retrieve the starting processes app status number" - description: "Retrieves the `starting` processes number that represents - Unit's per-app - [process statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - parameters: - - $ref: "#/components/parameters/appName" - - responses: - "200": - description: "OK; the `starting` number exists in the configuration." - - content: - application/json: - schema: - type: integer - - examples: - Starting: - value: 1 - - "404": - $ref: "#/components/responses/responseNotFound" - - /status/applications/{appName}/processes/idle: - summary: "Endpoint for the `idle` processes number" - get: - operationId: getStatusApplicationsAppProcessesIdle - summary: "Retrieve the idle processes app status number" - description: "Retrieves the `idle` processes number that represents - Unit's per-app - [process statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - parameters: - - $ref: "#/components/parameters/appName" - - responses: - "200": - description: "OK; the `idle` number exists in the configuration." - content: - application/json: - schema: - type: integer - - examples: - Idle: - value: 0 - - "404": - $ref: "#/components/responses/responseNotFound" - - /status/applications/{appName}/requests: - summary: "Endpoint for the `requests` app status object" - get: - operationId: getStatusApplicationsAppRequests - summary: "Retrieve the requests app status object" - description: "Retrieves the `requests` app status object that represents - Unit's per-app - [request statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - parameters: - - $ref: "#/components/parameters/appName" - - responses: - "200": - description: "OK; the `requests` object exists in the configuration." - - content: - application/json: - schema: - $ref: "#/components/schemas/statusApplicationsAppRequests" - - examples: - example1: - $ref: "#/components/examples/statusApplicationsAppRequests" - - /status/applications/{appName}/requests/active: - summary: "Endpoint for the `active` requests number" - get: - operationId: getStatusApplicationsAppRequestsActive - summary: "Retrieve the active requests app status number" - description: "Retrieves the `active` requests number that represents - Unit's per-app - [request statistics](https://unit.nginx.org/usagestats/)." - - tags: - - status - - parameters: - - $ref: "#/components/parameters/appName" - - responses: - "200": - description: "OK; the `active` number exists in the configuration." - - content: - application/json: - schema: - type: integer - - examples: - Idle: - value: 15 - - "404": - $ref: "#/components/responses/responseNotFound" - -components: - # -- PARAMETERS -- - - parameters: - appName: - in: path - description: "An application's name in the configuration." - name: appName - required: true - schema: - type: string - - arrayIndex: - in: path - description: "A zero-based index in a configuration array." - name: arrayIndex - required: true - schema: - type: integer - - arrayIndex2: - in: path - description: "A zero-based index in a configuration array." - name: arrayIndex2 - required: true - schema: - type: integer - - bundleName: - in: path - description: "A certificate bundle's name" - name: bundleName - required: true - schema: - type: string - - listenerName: - in: path - description: "Listener name; a unique combination of a host IP address - (or a `*` wildcard to match any host IP addresses), followed by a colon - and a port number, such as `127.0.0.1:80` or `*:443`." - - name: listenerName - required: true - schema: - type: string - - mimeType: - in: path - description: "A MIME type name, such as `text/x-code` or - `application/json`." - name: mimeType - required: true - schema: - type: string - - # -- EXAMPLES -- - - examples: - # -- RESPONSE EXAMPLES -- - - errorInvalidJson: - summary: "400 error response" - value: - error: "Invalid JSON." - detail: 'A valid JSON value is expected here. It must be either a - literal (null, true, or false), a number, a string (in double quotes - ""), an array (with brackets []), or an object (with braces {}).' - - location: - offset: 0 - line: 1 - column: 0 - - errorValueDoesntExist: - summary: "404 error response" - value: - error: "Value doesn't exist." - - errorInternalError: - summary: "500 error response" - value: - error: "Failed to apply new configuration." - - successReconfigurationDone: - summary: "Success response" - value: - success: "Reconfiguration done." - - # -- CONFIGURATION EXAMPLES -- - - # /certificates - cert: - summary: "Certificate bundle or bundles" - value: - bundle: - key: "RSA (4096 bits)" - chain: - - subject: - common_name: "example.com" - country: "US" - state_or_province: "CA" - organization: "Acme, Inc." - alt_names: - - "example.com" - - "www.example.com" - - issuer: - common_name: "intermediate.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme, Inc." - - validity: - since: "Feb 22 22:45:55 2023 GMT" - until: "Feb 21 22:45:55 2016 GMT" - - - subject: - common_name: "intermediate.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme Certification Authority" - - issuer: - common_name: "root.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme Certification Authority" - - validity: - since: "Sep 18 19:46:19 2022 GMT" - until: "Jun 15 19:46:19 2025 GMT" - - # /certificates/{bundleName} - certBundle: - summary: "Single certificate bundle" - value: - key: "RSA (4096 bits)" - chain: - - subject: - common_name: "example.com" - country: "US" - state_or_province: "CA" - organization: "Acme, Inc." - alt_names: - - "example.com" - - "www.example.com" - - issuer: - common_name: "intermediate.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme, Inc." - - validity: - since: "Feb 22 22:45:55 2023 GMT" - until: "Feb 21 22:45:55 2016 GMT" - - - subject: - common_name: "intermediate.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme Certification Authority" - - issuer: - common_name: "root.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme Certification Authority" - - validity: - since: "Sep 18 19:46:19 2022 GMT" - until: "Jun 15 19:46:19 2025 GMT" - - # /certificates/{bundleName}/chain - certBundleChain: - summary: "Certificate chain" - value: - - subject: - common_name: "example.com" - country: "US" - state_or_province: "CA" - organization: "Acme, Inc." - alt_names: - - "example.com" - - "www.example.com" - - issuer: - common_name: "intermediate.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme, Inc." - - validity: - since: "Feb 22 22:45:55 2023 GMT" - until: "Feb 21 22:45:55 2016 GMT" - - - subject: - common_name: "intermediate.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme Certification Authority" - - issuer: - common_name: "root.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme Certification Authority" - - validity: - since: "Sep 18 19:46:19 2022 GMT" - until: "Jun 15 19:46:19 2025 GMT" - - # /certificates/{bundleName}/chain/{arrayIndex} - certBundleChainCert: - summary: "Single certificate" - value: - subject: - common_name: "example.com" - country: "US" - state_or_province: "CA" - organization: "Acme, Inc." - alt_names: - - "example.com" - - "www.example.com" - - issuer: - common_name: "intermediate.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme, Inc." - - validity: - since: "Feb 22 22:45:55 2023 GMT" - until: "Feb 21 22:45:55 2016 GMT" - - # /certificates/{bundleName}/chain/{arrayIndex}/issuer - certBundleChainCertIssuer: - summary: "Certificate's issuer" - value: - common_name: "intermediate.ca.example.com" - country: "US" - state_or_province: "CA" - organization: "Acme, Inc." - - # /certificates/{bundleName}/chain/{arrayIndex}/subject - certBundleChainCertSubj: - summary: "Certificate's subject" - value: - common_name: "example.com" - country: "US" - state_or_province: "CA" - organization: "Acme, Inc." - alt_names: - - "example.com" - - "www.example.com" - - # /certificates/{bundleName}/chain/{arrayIndex}/validity - certBundleChainCertValidity: - summary: "Certificate's validity" - value: - since: "Feb 22 22:45:55 2023 GMT" - until: "Feb 21 22:45:55 2016 GMT" - - # /config - config: - summary: "The entire /config section of the API" - value: - access_log: "/var/log/unit/access.log" - - applications: - nodejsapp: - type: "external" - working_directory: "/www/app/node-app/" - executable: "app.js" - user: "www" - group: "www" - arguments: - - "--tmp-files" - - "/tmp/node-cache" - - pythonapp: - type: "python 3.11" - processes: 16 - working_directory: "/www/app/python-app/" - path: "blog" - module: "blog.wsgi" - user: "www" - group: "www" - stderr: "stderr.log" - isolation: - rootfs: "/www/" - - routes: - local: - - action: - share: "/www/local/" - - global: - - match: - host: "backend.example.com" - - action: - pass: "applications/pythonapp" - - - action: - pass: "applications/nodejsapp" - - listeners: - 127.0.0.1:8080: - pass: "routes/local" - - "*:443": - pass: "routes/global" - tls: - certificate: "bundle" - conf_commands: - ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" - minprotocol: "TLSv1.3" - - session: - cache_size: 10240 - timeout: 60 - tickets: - - "IAMkP16P8OBuqsijSDGKTpmxrzfFNPP4EdRovXH2mqstXsodPC6MqIce5NlMzHLP" - - "Ax4bv/JvMWoQG+BfH0feeM9Qb32wSaVVKOj1+1hmyU8ORMPHnf3Tio8gLkqm2ifC" - - forwarded: - client_ip: "X-Forwarded-For" - recursive: false - source: - - "192.0.2.0/24" - - "198.51.100.0/24" - - settings: - http: - body_read_timeout: 30 - discard_unsafe_fields: true - header_read_timeout: 30 - idle_timeout: 180 - log_route: true - max_body_size: 8388608 - send_timeout: 30 - server_version: false - - # /config/access_log - configAccessLogBasic: - summary: "Basic access_log string" - value: "/var/log/unit/access.log" - - # /config/access_log - configAccessLogComplex: - summary: "Complex access_log object" - value: - path: "/var/log/unit/access.log" - format: '$remote_addr - - [$time_local] "$request_line" $status - $body_bytes_sent "$header_referer" "$header_user_agent"' - - # /config/applications/{appName} - configApplication: - summary: "Individual Unit application" - value: - type: "python 3.11" - processes: 16 - working_directory: "/www/app/python-app/" - path: "blog" - module: "blog.wsgi" - user: "www" - group: "www" - stderr: "stderr.log" - stdout: "stdout.log" - isolation: - rootfs: "/www/" - - # /config/applications - configApplications: - summary: "Entire Unit applications section" - value: - nodejsapp: - type: "external" - working_directory: "/www/app/node-app/" - executable: "app.js" - user: "www" - group: "www" - arguments: - - "--tmp-files" - - "/tmp/node-cache" - - pythonapp: - type: "python 3.11" - processes: 16 - working_directory: "/www/app/python-app/" - path: "blog" - module: "blog.wsgi" - user: "www" - group: "www" - stderr: "stderr.log" - isolation: - rootfs: "/www/" - - # /config/listeners - configListeners: - summary: "Multiple listeners" - value: - 127.0.0.1:8080: - pass: "applications/wp_emea_dev" - "*:443": - pass: "applications/php_app/target" - tls: - certificate: "bundle" - conf_commands: - ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" - minprotocol: "TLSv1.3" - session: - cache_size: 10240 - timeout: 60 - tickets: - - "IAMkP16P8OBuqsijSDGKTpmxrzfFNPP4EdRovXH2mqstXsodPC6MqIce5NlMzHLP" - - "Ax4bv/JvMWoQG+BfH0feeM9Qb32wSaVVKOj1+1hmyU8ORMPHnf3Tio8gLkqm2ifC" - forwarded: - client_ip: "X-Forwarded-For" - recursive: false - source: - - "192.0.2.0/24" - - "198.51.100.0/24" - - # /config/listeners/{listenerName} - configListenerSimple: - summary: "Simple listener object" - value: - pass: "applications/wp_emea_dev" - - # /config/listeners/{listenerName} - configListenerComplex: - summary: "Elaborate listener object" - value: - pass: "applications/php_app/target" - tls: - certificate: "bundle" - conf_commands: - ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" - minprotocol: "TLSv1.3" - session: - cache_size: 10240 - timeout: 60 - tickets: - - "IAMkP16P8OBuqsijSDGKTpmxrzfFNPP4EdRovXH2mqstXsodPC6MqIce5NlMzHLP" - - "Ax4bv/JvMWoQG+BfH0feeM9Qb32wSaVVKOj1+1hmyU8ORMPHnf3Tio8gLkqm2ifC" - forwarded: - client_ip: "X-Forwarded-For" - recursive: false - protocol: "http" - source: - - "192.0.2.0/24" - - "198.51.100.0/24" - - # /config/listeners/{listenerName}/forwarded - configListenerForwarded: - summary: "Originating IP identification configuration object" - value: - client_ip: "X-Forwarded-For" - recursive: false - source: - - "192.0.2.0/24" - - "198.51.100.0/24" - - # /config/listeners/{listenerName}/forwarded/source - configListenerForwardedSourceArray: - summary: "Array of source address patterns" - value: - - "192.0.2.0/24" - - "198.51.100.0/24" - - # /config/listeners/{listenerName}/forwarded/source - configListenerForwardedSourceString: - summary: "Single source address pattern" - value: "192.0.2.0/24" - - # /config/listeners/{listenerName}/forwarded/client_ip - configListenerForwardedClientIp: - summary: "Client IP headers expected by a listener" - value: "X-Forwarded-For" - - # /config/listeners/{listenerName}/forwarded/protocol - configListenerForwardedProtocol: - summary: "Protocol header expected by a listener" - value: "http" - - # /config/listeners/{listenerName}/pass - configListenerPassApp: - summary: "Application destination in a listener" - value: "applications/wp_emea_dev" - - # /config/listeners/{listenerName}/pass - configListenerPassRoute: - summary: "Route destination in a listener" - value: "routes/staticsite" - - # /config/listeners/{listenerName}/pass - configListenerPassAppTarget: - summary: "App target destination in a listener" - value: "applications/php_app/index_target" - - # /config/listeners/{listenerName}/tls - configListenerTls: - summary: "TLS object in a listener" - value: - certificate: "bundle" - conf_commands: - ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" - minprotocol: "TLSv1.3" - session: - cache_size: 10240 - timeout: 60 - tickets: - - "IAMkP16P8OBuqsijSDGKTpmxrzfFNPP4EdRovXH2mqstXsodPC6MqIce5NlMzHLP" - - "Ax4bv/JvMWoQG+BfH0feeM9Qb32wSaVVKOj1+1hmyU8ORMPHnf3Tio8gLkqm2ifC" - - # /config/listeners/{listenerName}/tls/certificate - configListenerTlsCertificateArray: - summary: "Array of certificate bundle names" - value: - - bundle_old - - bundle_new - - # /config/listeners/{listenerName}/tls/certificate - configListenerTlsCertificateString: - summary: "Single certificate bundle name" - value: bundle - - # /config/listeners/{listenerName}/tls/conf_commands - configListenerTlsConfCommands: - summary: "TLS configuration commands in an object" - value: - ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" - minprotocol: "TLSv1.3" - - # /config/listeners/{listenerName}/tls/session - configListenerTlsSession: - summary: "Session settings object" - value: - cache_size: 10240 - timeout: 60 - tickets: - - "IAMkP16P8OBuqsijSDGKTpmxrzfFNPP4EdRovXH2mqstXsodPC6MqIce5NlMzHLP" - - "Ax4bv/JvMWoQG+BfH0feeM9Qb32wSaVVKOj1+1hmyU8ORMPHnf3Tio8gLkqm2ifC" - - # /config/listeners/{listenerName}/tls/session/tickets - configListenerTlsSessionTicketsBool: - summary: "Boolean value that enables or disables random tickets" - value: true - - # /config/listeners/{listenerName}/tls/session/tickets - configListenerTlsSessionTicketsString: - summary: "Single session ticket key" - value: "IAMkP16P8OBuqsijSDGKTpmxrzfFNPP4EdRovXH2mqstXsodPC6MqIce5NlMzHLP" - - # /config/listeners/{listenerName}/tls/session/tickets - configListenerTlsSessionTicketsArray: - summary: "Multiple session ticket keys" - value: - - "IAMkP16P8OBuqsijSDGKTpmxrzfFNPP4EdRovXH2mqstXsodPC6MqIce5NlMzHLP" - - "Ax4bv/JvMWoQG+BfH0feeM9Qb32wSaVVKOj1+1hmyU8ORMPHnf3Tio8gLkqm2ifC" - - # /config/routes - configRoutes: - summary: "Routes array" - value: - - action: - pass: "applications/${host}_php_handler" - - match: - arguments: - mode: "strict" - fullAccess: "true" - - uri: "~^/data/www/.*\\.php(/.*)?$" - - - action: - share: "/www/data$uri" - - match: - headers: - - User-Agent: "curl*" - - source: - - "!192.168.1.1" - - "!10.1.1.0/16" - - "192.168.1.0/24" - - "2001:0db8::/32" - - - action: - return: 301 - location: "https://www.example.com" - - # /config/settings - configSettings: - summary: "Global settings" - value: - http: - body_read_timeout: 30 - discard_unsafe_fields: true - header_read_timeout: 30 - idle_timeout: 180 - log_route: true - max_body_size: 8388608 - send_timeout: 30 - server_version: false - static: - mime_types: - "text/x-code": - - ".c" - - ".h" - - # /config/settings/http - configSettingsHttp: - summary: "HTTP settings" - value: - body_read_timeout: 30 - discard_unsafe_fields: true - header_read_timeout: 30 - idle_timeout: 180 - log_route: true - max_body_size: 8388608 - send_timeout: 30 - server_version: false - static: - mime_types: - "text/x-code": - - ".c" - - ".h" - - # /config/settings/http/static - configSettingsHttpStatic: - summary: "Static content settings" - value: - mime_types: - "text/x-code": - - ".c" - - ".h" - - # /config/settings/http/static/mime_types/{optionName} - configSettingsHttpStaticMimeType: - summary: "Individual MIME type" - value: - - ".c" - - ".h" - - # /config/settings/http/static/mime_types - configSettingsHttpStaticMimeTypes: - summary: "MIME types recognized by Unit" - value: - "text/x-code": - - ".c" - - ".h" - - # /status - status: - summary: "Regular status object" - value: - connections: - accepted: 1067 - active: 13 - idle: 4 - closed: 1050 - requests: - total: 1307 - applications: - wp: - processes: - running: 9 - starting: 1 - idle: 0 - requests: - active: 15 - - # /status/connections - statusConnections: - summary: "Regular connections status object" - value: - accepted: 1067 - active: 13 - idle: 4 - closed: 1050 - - # /status/applications - statusApplications: - summary: "Regular applications status object" - value: - wp: - processes: - running: 9 - starting: 1 - idle: 0 - requests: - active: 15 - - # /status/applications/{appName} - statusApplicationsApp: - summary: "Regular app status object" - value: - processes: - running: 9 - starting: 1 - idle: 0 - requests: - active: 15 - - # /status/applications/{appName}/processes - statusApplicationsAppProcesses: - summary: "Regular app processes status object" - value: - running: 9 - starting: 1 - idle: 0 - - # /status/applications/{appName}/requests - statusApplicationsAppRequests: - summary: "Regular app requests status object" - value: - active: 15 - - # /status/requests - statusRequests: - summary: "Regular requests status object" - value: - total: 1307 - - # -- RESPONSES -- - - responses: - responseOkDeleted: - description: "OK; the value was deleted." - content: - application/json: - schema: - $ref: "#/components/schemas/jsonSuccessMessage" - - examples: - example1: - $ref: "#/components/examples/successReconfigurationDone" - - responseOkUpdated: - description: "OK; the value was updated." - content: - application/json: - schema: - $ref: "#/components/schemas/jsonSuccessMessage" - - examples: - example1: - $ref: "#/components/examples/successReconfigurationDone" - - responseBadRequest: - description: "Bad Request; invalid JSON payload was provided. - This may occur if the payload supplied doesn't match the JSON schema for - the respective configuration section." - - content: - application/json: - schema: - $ref: "#/components/schemas/jsonErrorMessage" - - examples: - example1: - $ref: "#/components/examples/errorInvalidJson" - - responseNotFound: - description: "Not Found; the value does not exist in the configuration. - This may occur if any part of the path is non-existent." - - content: - application/json: - schema: - $ref: "#/components/schemas/jsonErrorMessage" - - examples: - example1: - $ref: "#/components/examples/errorValueDoesntExist" - - responseInternalError: - description: "Internal server error; the configuration wasn't applied. - This may occur with misconfigured paths, wrong permissions, etc." - - content: - application/json: - schema: - $ref: "#/components/schemas/jsonErrorMessage" - - examples: - example1: - $ref: "#/components/examples/errorInternalError" - - # -- SCHEMAS -- - - schemas: - # -- GENERIC REUSABLE OBJECTS -- - - stringArray: - type: array - description: "An array of strings." - items: - type: string - - stringOrStringArray: - description: "A string or an array of strings." - oneOf: - - type: string - - $ref: "#/components/schemas/stringArray" - - jsonSuccessMessage: - type: object - description: "JSON message on success." - additionalProperties: - type: string - - jsonErrorMessage: - type: object - description: "JSON message on error." - additionalProperties: - type: string - - # Configuration sections as data types; hugely reliant on each other - - # /certificates - cert: - type: object - description: "An object whose options represent certificate bundles." - additionalProperties: - $ref: "#/components/schemas/certBundle" - - # /certificates/{bundleName} - certBundle: - type: object - description: "An object whose options represent a certificate bundle." - properties: - key: - type: string - description: "Certificate bundle's key type, i. e. RSA, ECDSA, etc." - - chain: - $ref: "#/components/schemas/certBundleChain" - - # /certificates/{bundleName}/chain - certBundleChain: - type: array - description: "An array whose items represent certificates in a bundle." - items: - $ref: "#/components/schemas/certBundleChainCert" - - # /certificates/{bundleName}/chain/{certIndex} - certBundleChainCert: - type: object - description: "An object that represents an individual certificate." - properties: - subject: - $ref: "#/components/schemas/certBundleChainCertSubj" - - issuer: - $ref: "#/components/schemas/certBundleChainCertIssuer" - - validity: - $ref: "#/components/schemas/certBundleChainCertValidity" - - # /certificates/{bundleName}/chain/{certIndex}/subject - certBundleChainCertSubj: - type: object - description: "An object that represents a certificate's subject." - properties: - common_name: - type: string - - country: - type: string - - state_or_province: - type: string - - organization: - type: string - - alt_names: - $ref: "#/components/schemas/stringArray" - - # /certificates/{bundleName}/chain/{certIndex}/issuer - certBundleChainCertIssuer: - type: object - description: "An object that represents a certificate's issuer." - properties: - common_name: - type: string - - country: - type: string - - state_or_province: - type: string - - organization: - type: string - - # /certificates/{bundleName}/chain/{certIndex}/validity - certBundleChainCertValidity: - type: object - description: "An object that represents the validity of a certificate." - properties: - since: - type: string - - until: - type: string - - # /config - config: - type: object - description: "The entire /config section of the API." - properties: - access_log: - $ref: "#/components/schemas/configAccessLog" - - applications: - $ref: "#/components/schemas/configApplications" - - routes: - $ref: "#/components/schemas/configRoutes" - - listeners: - $ref: "#/components/schemas/configListeners" - - settings: - $ref: "#/components/schemas/configSettings" - - # /config/access_log - configAccessLog: - description: "Configures the access log." - anyOf: - - type: string - - $ref: "#/components/schemas/configAccessLogObject" - - # /config/access_log - configAccessLogObject: - description: "Configures the access log." - type: object - properties: - format: - type: string - description: "Sets the log format. Besides arbitrary text, can contain - any variables Unit supports." - - default: '$remote_addr - - [$time_local] "$request_line" $status - $body_bytes_sent "$header_referer" "$header_user_agent"' - - path: - type: string - description: "Pathname of the access log file." - - # /config/applications - configApplications: - type: object - description: "An object whose options define individual applications." - additionalProperties: - $ref: "#/components/schemas/configApplication" - - # /config/applications/{appName} - configApplication: - type: object - description: "An object that defines an individual application." - anyOf: - - $ref: "#/components/schemas/configApplicationExternal" - - $ref: "#/components/schemas/configApplicationJava" - - $ref: "#/components/schemas/configApplicationPerl" - - $ref: "#/components/schemas/configApplicationPHP" - - $ref: "#/components/schemas/configApplicationPython" - - $ref: "#/components/schemas/configApplicationRuby" - - discriminator: - propertyName: type - mapping: - external: "#/components/schemas/configApplicationExternal" - java: "#/components/schemas/configApplicationJava" - perl: "#/components/schemas/configApplicationPerl" - php: "#/components/schemas/configApplicationPHP" - python: "#/components/schemas/configApplicationPython" - ruby: "#/components/schemas/configApplicationRuby" - - # ABSTRACT BASE SCHEMA, NOT PRESENT IN THE CONFIGURATION; STORES COMMON OPTIONS - configApplicationCommon: - type: object - description: "Common application object options." - required: - - type - - properties: - type: - type: string - description: "Application type and language version." - enum: [external, java, perl, php, python, ruby] - - environment: - type: object - description: "Environment variables to be passed to the app." - additionalProperties: - type: string - - group: - type: string - description: "Group name that runs the app process." - - isolation: - type: object - description: "Manages the isolation of an application process." - properties: - automount: - type: object - description: "Controls mount behavior if rootfs is enabled." - properties: - language_deps: - type: boolean - description: "Controls whether the language runtime - dependencies are automounted." - - default: true - - procfs: - type: boolean - description: "Controls whether the procfs is automounted." - default: true - - tmpfs: - type: boolean - description: "Controls whether the tmpfs is automounted." - default: true - - cgroup: - type: object - description: "Defines the app’s cgroup." - required: - - path - - properties: - path: - type: string - description: "Configures absolute or relative path of the app - in the cgroups v2 hierarchy." - - gidmap: - type: array - description: "Array of group ID mapping objects." - items: - type: object - description: "Group ID mapping object." - required: - - container - - host - - size - - properties: - container: - type: integer - description: "Starts the group ID mapping range in the - app’s namespace." - - host: - type: integer - description: "Starts the group ID mapping range in the - OS namespace." - - size: - type: integer - description: "Size of the ID range in both namespaces." - - namespaces: - type: object - properties: - cgroup: - type: boolean - description: "Creates a new cgroup namespace for the app." - default: false - - credential: - type: boolean - description: "Creates a new user namespace for the app." - default: false - - mount: - type: boolean - description: "Creates a new mount namespace for the app." - default: false - - network: - type: boolean - description: "Creates a new network namespace for the app." - default: false - - pid: - type: boolean - description: "Creates a new PID namespace for the app." - default: false - - uname: - type: boolean - description: "Creates a new UTS namespace for the app." - default: false - - rootfs: - type: string - description: "pathname of the directory to be used as the new - file system root for the app." - - uidmap: - type: array - description: "Array of user ID mapping objects." - items: - type: object - description: "User ID mapping object." - required: - - container - - host - - size - - properties: - container: - type: integer - description: "Starts the user ID mapping range in the - app’s namespace." - - host: - type: integer - description: "Starts the user ID mapping range in the - OS namespace." - - size: - type: integer - description: "Size of the ID range in both namespaces." - - limits: - type: object - description: "Governs the life cycle of an application process." - properties: - requests: - type: integer - description: "Maximum number of requests an app process - can serve." - - timeout: - type: integer - description: "Request timeout in seconds." - - processes: - description: "Governs the behavior of app processes." - anyOf: - - type: integer - - type: object - properties: - idle_timeout: - type: integer - description: "Number of seconds Unit waits for before - terminating an idle process that exceeds `spare`." - - max: - type: integer - description: "Maximum number of application processes that - Unit maintains (busy and idle)." - - default: 1 - - idle: - type: integer - description: "Minimum number of idle processes that Unit tries - to maintain for an app." - - default: 1 - - user: - type: string - description: "Username that runs the app process." - - stderr: - type: string - description: "Filename where Unit redirects the app's stderr stream." - - stdout: - type: string - description: "Filename where Unit redirects the app's stdout stream." - - working_directory: - type: string - description: "The app’s working directory." - - configApplicationExternal: - description: "Go or Node.js application on Unit." - allOf: - - $ref: "#/components/schemas/configApplicationCommon" - - type: object - required: - - executable - - properties: - executable: - type: string - description: "Pathname of the app, absolute or relative - to `working_directory`." - - arguments: - description: "Command-line arguments to be passed to the app." - $ref: "#/components/schemas/stringArray" - - configApplicationJava: - description: "Java application on Unit." - allOf: - - $ref: "#/components/schemas/configApplicationCommon" - - type: object - required: - - webapp - - properties: - webapp: - type: string - description: "Pathname of the application’s .war file - (packaged or unpackaged)." - - classpath: - description: "Paths to your app’s required libraries - (may point to directories or individual .jar files)." - - $ref: "#/components/schemas/stringArray" - - options: - desription: "JVM runtime options." - $ref: "#/components/schemas/stringArray" - - thread_stack_size: - type: integer - description: "Stack size of a worker thread in bytes." - - threads: - type: integer - description: "Number of worker threads per app process." - default: 1 - - configApplicationPerl: - description: "Perl application on Unit." - allOf: - - $ref: "#/components/schemas/configApplicationCommon" - - type: object - required: - - script - - properties: - script: - type: string - description: "PSGI script path." - - thread_stack_size: - type: integer - description: "Stack size of a worker thread in bytes." - - threads: - type: integer - description: "Number of worker threads per app process." - default: 1 - - configApplicationPHP: - description: "PHP application on Unit." - allOf: - - $ref: "#/components/schemas/configApplicationCommon" - - type: object - required: - - root - - properties: - root: - type: string - description: "Base directory of the app’s file structure." - - index: - type: string - description: "Filename added to URI paths that point to - directories if no `script` is set." - - default: "index.php" - - options: - type: object - description: "Defines the php.ini location and options." - properties: - admin: - type: object - description: "Extra directives set in PHP_INI_SYSTEM mode." - - additionalProperties: - type: string - - file: - type: string - description: "Pathname of the php.ini file." - - user: - type: object - description: "Extra directives set in PHP_INI_USER mode." - additionalProperties: - type: string - - script: - type: string - description: "Filename of a `root`-based PHP script that serves - all requests to the app." - - targets: - type: object - description: "Application sections with custom `root`, `script`, - and `index` values." - - additionalProperties: - type: object - required: - - root - - properties: - root: - type: string - description: "Base directory of the target’s - file structure." - - index: - type: string - description: "Filename added to URI paths that point to - directories if no `script` is set." - - default: "index.php" - - script: - type: string - description: "Filename of a `root`-based PHP script that - serves all requests to the target." - - configApplicationPython: - description: "Python application on Unit." - allOf: - - $ref: "#/components/schemas/configApplicationCommon" - - type: object - required: - - module - - properties: - module: - type: string - description: "App’s module name." - - callable: - type: string - description: "Name of the `module`-based callable that Unit runs - as the app." - - default: "application" - - home: - type: string - description: "Path to the app’s virtual environment, absolute or - relative to `working_directory`." - - path: - description: "Additional Python module lookup paths." - anyOf: - - type: string - - $ref: "#/components/schemas/stringArray" - - prefix: - type: string - description: "SCRIPT_NAME context value for WSGI or the - root_path context value for ASGI." - - protocol: - description: "Hints Unit that the app uses a certain interface." - enum: - - "asgi" - - "wsgi" - - targets: - type: object - description: "App sections with custom `module` and - `callable` values." - - additionalProperties: - type: object - required: - - module - - properties: - module: - type: string - description: "Target's module name." - - callable: - type: string - description: "Name of the `module`-based callable that Unit - runs as the target." - - default: "application" - - prefix: - type: string - description: "SCRIPT_NAME context value for WSGI or the - root_path context value for ASGI." - - thread_stack_size: - type: integer - description: "Stack size of a worker thread in bytes." - - threads: - type: integer - description: "Number of worker threads per app process." - default: 1 - - configApplicationRuby: - description: "Ruby application on Unit." - allOf: - - $ref: "#/components/schemas/configApplicationCommon" - - type: object - required: - - script - - properties: - script: - type: string - description: "Rack script pathname, including the .ru extension." - - hooks: - type: string - description: "Pathname of the .rb file setting the event hooks - invoked during the app’s lifecycle." - - threads: - type: integer - description: "Number of worker threads per app process." - default: 1 - - #/config/routes - configRoutes: - description: "Configures the routes." - anyOf: - - $ref: "#/components/schemas/configRouteArray" - - $ref: "#/components/schemas/configRoutesObject" - - #/config/routes/{routeName} or /config/routes - configRouteArray: - type: array - description: "An array whose items define individual route steps." - items: - $ref: "#/components/schemas/configRouteStep" - - #/config/routes - configRoutesObject: - type: object - description: "An object whose options define individual routes." - additionalProperties: - description: "Individual route arrays." - $ref: "#/components/schemas/configRouteArray" - - #/config/routes/{stepIndex} - #/config/routes/{routeName}/{stepIndex} - configRouteStep: - type: object - description: "An object whose options define a step's - conditions and action." - - required: - - action - - properties: - action: - description: "Defines how matching requests are handled." - $ref: "#/components/schemas/configRouteStepAction" - - match: - description: "Defines the step’s conditions to be matched." - $ref: "#/components/schemas/configRouteStepMatch" - - #/config/routes/{stepIndex}/match - #/config/routes/{routeName}/{stepIndex}/match - configRouteStepMatch: - type: object - description: "An object whose options define a step's conditions." - properties: - arguments: - description: "Arguments supplied with the request’s query string." - anyOf: - - $ref: "#/components/schemas/configRouteStepMatchObject" - - $ref: "#/components/schemas/configRouteStepMatchObjectArray" - - cookies: - description: "Cookies supplied with the request." - anyOf: - - $ref: "#/components/schemas/configRouteStepMatchObject" - - $ref: "#/components/schemas/configRouteStepMatchObjectArray" - - destination: - description: "Target IP address and optional port of the request." - $ref: "#/components/schemas/stringOrStringArray" - - headers: - description: "Header fields supplied with the request." - anyOf: - - $ref: "#/components/schemas/configRouteStepMatchObject" - - $ref: "#/components/schemas/configRouteStepMatchObjectArray" - - host: - description: "Host header field." - $ref: "#/components/schemas/stringOrStringArray" - - method: - description: "Method from the request line." - $ref: "#/components/schemas/stringOrStringArray" - - query: - description: "Query string." - $ref: "#/components/schemas/stringOrStringArray" - - scheme: - description: "URI scheme. Accepts only two patterns, - either `http` or `https`." - - enum: - - "http" - - "https" - - source: - description: "Source IP address and optional port of the request." - $ref: "#/components/schemas/stringOrStringArray" - - uri: - description: "Request target." - $ref: "#/components/schemas/stringOrStringArray" - - #/config/routes/{stepIndex}/match/[arguments|cookies|headers] - #/config/routes/{routeName}/{stepIndex}/match/[arguments|cookies|headers] - configRouteStepMatchObject: - type: object - description: "An object whose options define a set of conditions." - additionalProperties: - $ref: "#/components/schemas/stringOrStringArray" - - #/config/routes/{stepIndex}/match/[arguments|cookies|headers] - #/config/routes/{routeName}/{stepIndex}/match/[arguments|cookies|headers] - configRouteStepMatchObjectArray: - type: array - description: "An array whose items define sets of conditions." - items: - $ref: "#/components/schemas/configRouteStepMatchObject" - - #/config/routes/{stepIndex}/action - #/config/routes/{routeName}/{stepIndex}/action - configRouteStepAction: - type: object - description: "An object whose options define a step's action." - oneOf: - - $ref: "#/components/schemas/configRouteStepActionPass" - - $ref: "#/components/schemas/configRouteStepActionProxy" - - $ref: "#/components/schemas/configRouteStepActionReturn" - - $ref: "#/components/schemas/configRouteStepActionShare" - - #/config/routes/{stepIndex}/action/pass - #/config/routes/{routeName}/{stepIndex}/action/pass - configRouteStepActionPass: - type: object - description: "An object whose single option defines a step's pass action." - required: - - pass - properties: - pass: - type: string - description: "Destination to which the action passes - incoming requests." - - rewrite: - $ref: "#/components/schemas/configRouteStepActionRewrite" - - response_headers: - $ref: "#/components/schemas/configRouteStepActionResponseHeaders" - - #/config/routes/{stepIndex}/action/proxy - #/config/routes/{routeName}/{stepIndex}/action/proxy - configRouteStepActionProxy: - type: object - description: "An object whose single option defines a step's proxy - action." - required: - - proxy - properties: - proxy: - type: string - description: "Socket address of an HTTP server to where the request - is proxied." - - rewrite: - $ref: "#/components/schemas/configRouteStepActionRewrite" - - response_headers: - $ref: "#/components/schemas/configRouteStepActionResponseHeaders" - - #/config/routes/{stepIndex}/action/return - #/config/routes/{routeName}/{stepIndex}/action/return - configRouteStepActionReturn: - type: object - description: "An object whose single option defines a step's - return action." - - required: - - return - - properties: - return: - type: integer - description: "Defines the HTTP response status code to be returned." - - location: - type: string - description: "URI; used if the return value implies redirection." - - rewrite: - $ref: "#/components/schemas/configRouteStepActionRewrite" - - response_headers: - $ref: "#/components/schemas/configRouteStepActionResponseHeaders" - - #/config/routes/{stepIndex}/action/share - #/config/routes/{routeName}/{stepIndex}/action/share - configRouteStepActionShare: - type: object - description: "An object whose single option defines a step's - share action." - - required: - - share - - properties: - share: - description: "Lists file paths that are tried until a file is found." - $ref: "#/components/schemas/stringOrStringArray" - - index: - type: string - description: "Filename; tried if share is a directory." - default: "index.html" - - fallback: - description: "Used if the request can’t be served by share or index." - $ref: "#/components/schemas/configRouteStepAction" - - types: - description: "Used to filter the shared files." - $ref: "#/components/schemas/stringArray" - - chroot: - type: string - description: "Directory pathname that restricts the shareable paths." - - follow_symlinks: - type: boolean - description: "Turns on and off symbolic link resolution." - default: true - - traverse_mounts: - type: boolean - description: "Turns on and off mount point resolution." - default: true - - rewrite: - $ref: "#/components/schemas/configRouteStepActionRewrite" - - response_headers: - $ref: "#/components/schemas/configRouteStepActionResponseHeaders" - - #/config/routes/{stepIndex}/action/rewrite - #/config/routes/{routeName}/{stepIndex}/action/rewrite - configRouteStepActionRewrite: - type: string - description: "Updates the URI of the incoming request before the action - is applied." - - #/config/routes/{stepIndex}/action/response_headers - #/config/routes/{routeName}/{stepIndex}/action/response_headers - configRouteStepActionResponseHeaders: - type: object - description: "Updates the header fields of Unit’s response before the - action is taken." - additionalProperties: - type: string - - # /config/listeners/ - configListeners: - type: object - description: "An object whose options are listeners." - additionalProperties: - $ref: "#/components/schemas/configListener" - - # /config/listeners/{listenerName} - configListener: - type: object - description: "An individual listener." - properties: - tls: - $ref: "#/components/schemas/configListenerTls" - forwarded: - $ref: "#/components/schemas/configListenerForwarded" - pass: - type: string - description: "Destination to which the listener passes - incoming requests." - - # /config/listeners/{listenerName}/tls/certificate - configListenerTlsCertificate: - description: "Refers to one or more certificate bundles uploaded earlier." - anyOf: - - type: string - - $ref: "#/components/schemas/stringArray" - - # /config/listeners/{listenerName}/tls/conf_commands - configListenerTlsConfCommands: - type: object - description: "Defines the SSL configuration commands to be set for - the listener." - additionalProperties: - type: string - - # /config/listeners/{listenerName}/tls - configListenerTls: - type: object - description: "Defines SSL/TLS settings for the listener." - required: - - certificate - - properties: - conf_commands: - $ref: "#/components/schemas/configListenerTlsConfCommands" - - session: - $ref: "#/components/schemas/configListenerTlsSession" - - certificate: - $ref: "#/components/schemas/configListenerTlsCertificate" - - # /config/listeners/{listenerName}/tls/session - configListenerTlsSession: - type: object - description: "Configures the TLS session cache and tickets for - the listener." - - properties: - cache_size: - type: integer - description: "Number of sessions in the TLS session cache." - default: 0 - - timeout: - type: integer - description: "Session timeout for the TLS session cache in seconds." - default: 300 - - tickets: - $ref: "#/components/schemas/configListenerTlsSessionTickets" - - # /config/listeners/{listenerName}/tls/session/tickets - configListenerTlsSessionTickets: - description: "Configures TLS session tickets." - anyOf: - - type: boolean - - type: string - - $ref: "#/components/schemas/stringArray" - - default: false - - # /config/listeners/{listenerName}/forwarded - configListenerForwarded: - type: object - description: "Configures client IP address and protocol replacement." - required: - - source - - properties: - client_ip: - type: string - description: "Defines the HTTP header fields to expect in the request; - uses the `X-Forwarded-For` format." - - source: - description: "Defines address-based patterns for trusted addresses." - anyOf: - - type: string - - $ref: "#/components/schemas/stringArray" - - recursive: - type: boolean - description: "Controls how the `client_ip` fields are traversed." - default: false - - protocol: - description: "Defines the relevant HTTP header field to expect in the - request; uses the `X-Forwarded-Proto` format." - - enum: - - "http" - - "https" - - "on" - - # /config/settings - configSettings: - type: object - description: "An object whose single option represents global - Unit settings." - - properties: - http: - description: "Represents global HTTP settings in Unit." - $ref: "#/components/schemas/configSettingsHttp" - - # /config/settings/http - configSettingsHttp: - type: object - description: "An object whose options represent global HTTP settings - in Unit." - - properties: - body_read_timeout: - type: integer - description: "Maximum number of seconds to read data from the body of - a client’s request." - - default: 30 - - discard_unsafe_fields: - type: boolean - description: "If `true`, Unit only processes header names made of - alphanumerics and hyphens." - - default: true - - header_read_timeout: - type: integer - description: "Maximum number of seconds to read the header of a - client’s request." - - default: 30 - - idle_timeout: - type: integer - description: "Maximum number of seconds between requests in a - keep-alive connection." - - default: 180 - - log_route: - type: boolean - description: "Enables or disables router logging." - default: false - - max_body_size: - type: integer - description: "Maximum number of bytes in the body of a - client’s request." - - default: 8388608 - - send_timeout: - type: integer - description: "Maximum number of seconds to transmit data as a - response to the client." - default: 30 - - server_version: - type: boolean - description: "Enables or disables version numbers in Unit's `Server` - header fields." - - default: true - - static: - description: "Configures static asset handling." - $ref: "#/components/schemas/configSettingsHttpStatic" - - # /config/settings/http/static - configSettingsHttpStatic: - type: object - description: "An object whose single option defines specific MIME types." - properties: - mime_types: - $ref: "#/components/schemas/configSettingsHttpStaticMimeTypes" - - # /config/settings/http/static/mime_types - configSettingsHttpStaticMimeTypes: - type: object - description: "An object whose options define individual MIME types." - additionalProperties: - $ref: "#/components/schemas/configSettingsHttpStaticMimeType" - - # /config/settings/http/static/mime_types/{mimeType} - configSettingsHttpStaticMimeType: - description: "An entity that defines an individual MIME type by - listing file extensions." - - anyOf: - - type: string - - $ref: "#/components/schemas/stringArray" - - # /status - status: - description: "Represents Unit's usage statistics." - type: object - properties: - connections: - $ref: "#/components/schemas/statusConnections" - - requests: - $ref: "#/components/schemas/statusRequests" - - applications: - $ref: "#/components/schemas/statusApplications" - - # /status/applications - statusApplications: - description: "Lists Unit's application process and request statistics." - type: object - additionalProperties: - $ref: "#/components/schemas/statusApplicationsApp" - - # /status/applications/{appName} - statusApplicationsApp: - description: "Represents Unit's per-app process and request statistics." - type: object - properties: - processes: - $ref: "#/components/schemas/statusApplicationsAppProcesses" - - requests: - $ref: "#/components/schemas/statusApplicationsAppRequests" - - # /status/applications/{appName}/processes - statusApplicationsAppProcesses: - description: "Represents Unit's per-app process statistics." - type: object - properties: - running: - type: integer - description: "Current running app processes." - - starting: - type: integer - description: "Current starting app processes." - - idle: - type: integer - description: "Current idle app processes." - - # /status/applications/{appName}/requests - statusApplicationsAppRequests: - description: "Represents Unit's per-app request statistics." - type: object - properties: - active: - type: integer - description: "Active app requests." - - # /status/requests - statusRequests: - description: "Represents Unit's per-instance request statistics." - type: object - properties: - total: - type: integer - description: "Total non-API requests during the instance’s lifetime." - - # /status/connections - statusConnections: - description: "Represents Unit's per-instance connection statistics." - type: object - properties: - accepted: - type: integer - description: "Total accepted connections during the - instance’s lifetime." - - active: - type: integer - description: "Current active connections for the instance." - - idle: - type: integer - description: "Current idle connections for the instance." - - closed: - type: integer - description: "Total closed connections during - the instance’s lifetime." - -# -- TAGS -- - -tags: - - name: access log - description: Everything about the access log in the /config section - externalDocs: - url: https://unit.nginx.org/configuration/#access-log - - - name: apps - description: Everything about applications - externalDocs: - url: https://unit.nginx.org/configuration/#applications - - - name: certificates - description: - Everything about the /certificates section in Unit's control API - in Unit's control API - externalDocs: - url: https://unit.nginx.org/certificates/ - - - name: config - description: Everything about the /config section in Unit's control API - externalDocs: - url: https://unit.nginx.org/configuration/ - - - name: control - description: Everything about the /control section in Unit's control API - externalDocs: - url: https://unit.nginx.org/controlapi/ - - - name: listeners - description: Everything about listeners in the /config section - externalDocs: - url: https://unit.nginx.org/configuration/#listeners - - - name: routes - description: Everything about routes in the /config section - externalDocs: - url: https://unit.nginx.org/configuration/#routes - - - name: settings - description: Everything about the global settings in the /config section - externalDocs: - url: https://unit.nginx.org/configuration/#settings - - - name: status - description: Everything about the /status section in Unit's control API - externalDocs: - url: https://unit.nginx.org/usagestats/ - - - name: tls - description: Everything about SSL/TLS in Unit's control API - externalDocs: - url: https://unit.nginx.org/certificates/ - - - name: xff - description: Everything about X-Forwarded-* handling in Unit's control API - externalDocs: - url: https://unit.nginx.org/configuration/#ip-protocol-forwarding - -externalDocs: - description: "Find us on GitHub" - url: "https://github.com/nginx/unit" diff --git a/docs/unitlogo.svg b/docs/unitlogo.svg deleted file mode 100644 index a8b87b18..00000000 --- a/docs/unitlogo.svg +++ /dev/null @@ -1,305 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/go/go.mod b/go/go.mod deleted file mode 100644 index 2c0431db..00000000 --- a/go/go.mod +++ /dev/null @@ -1 +0,0 @@ -module unit.nginx.org/go diff --git a/go/ldflags-darwin.go b/go/ldflags-darwin.go deleted file mode 100644 index 77114ee4..00000000 --- a/go/ldflags-darwin.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build darwin -// +build darwin - -/* - * Copyright (C) Danielle De Leo - * Copyright (C) NGINX, Inc. - */ - -package unit - -/* -#cgo LDFLAGS: -L/opt/homebrew/lib -#cgo CFLAGS: -I/opt/homebrew/include -*/ -import "C" diff --git a/go/ldflags-lrt.go b/go/ldflags-lrt.go deleted file mode 100644 index 68a29145..00000000 --- a/go/ldflags-lrt.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build linux || netbsd -// +build linux netbsd - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -package unit - -/* -#cgo LDFLAGS: -lrt -*/ -import "C" diff --git a/go/ldflags.go b/go/ldflags.go deleted file mode 100644 index 68f2ab78..00000000 --- a/go/ldflags.go +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (C) NGINX, Inc. - */ - -package unit - -/* -#cgo LDFLAGS: -lunit -*/ -import "C" diff --git a/go/nxt_cgo_lib.c b/go/nxt_cgo_lib.c deleted file mode 100644 index ca9fc3ab..00000000 --- a/go/nxt_cgo_lib.c +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -#include "_cgo_export.h" - -#include -#include - - -static ssize_t nxt_cgo_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - const void *buf, size_t buf_size, const void *oob, size_t oob_size); -static ssize_t nxt_cgo_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - void *buf, size_t buf_size, void *oob, size_t *oob_size); - -int -nxt_cgo_run(uintptr_t handler) -{ - int rc; - nxt_unit_ctx_t *ctx; - nxt_unit_init_t init; - - memset(&init, 0, sizeof(init)); - - init.callbacks.request_handler = nxt_go_request_handler; - init.callbacks.add_port = nxt_go_add_port; - init.callbacks.remove_port = nxt_go_remove_port; - init.callbacks.port_send = nxt_cgo_port_send; - init.callbacks.port_recv = nxt_cgo_port_recv; - init.callbacks.shm_ack_handler = nxt_go_shm_ack_handler; - init.callbacks.ready_handler = nxt_go_ready; - - init.data = (void *) handler; - - ctx = nxt_unit_init(&init); - if (ctx == NULL) { - return NXT_UNIT_ERROR; - } - - rc = nxt_unit_run_ctx(ctx); - - nxt_unit_done(ctx); - - return rc; -} - - -static ssize_t -nxt_cgo_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - const void *buf, size_t buf_size, const void *oob, size_t oob_size) -{ - return nxt_go_port_send(port->id.pid, port->id.id, - (void *) buf, buf_size, (void *) oob, oob_size); -} - - -static ssize_t -nxt_cgo_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - void *buf, size_t buf_size, void *oob, size_t *oob_size) -{ - return nxt_go_port_recv(port->id.pid, port->id.id, - buf, buf_size, oob, oob_size); -} - - -ssize_t -nxt_cgo_response_write(nxt_unit_request_info_t *req, uintptr_t start, - uint32_t len) -{ - return nxt_unit_response_write_nb(req, (void *) start, len, 0); -} - - -ssize_t -nxt_cgo_request_read(nxt_unit_request_info_t *req, uintptr_t dst, - uint32_t dst_len) -{ - return nxt_unit_request_read(req, (void *) dst, dst_len); -} - - -void -nxt_cgo_warn(const char *msg, uint32_t msg_len) -{ - nxt_unit_warn(NULL, "%.*s", (int) msg_len, (char *) msg); -} - - -void -nxt_cgo_alert(const char *msg, uint32_t msg_len) -{ - nxt_unit_alert(NULL, "%.*s", (int) msg_len, (char *) msg); -} diff --git a/go/nxt_cgo_lib.h b/go/nxt_cgo_lib.h deleted file mode 100644 index 3705d1ef..00000000 --- a/go/nxt_cgo_lib.h +++ /dev/null @@ -1,32 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_CGO_LIB_H_INCLUDED_ -#define _NXT_CGO_LIB_H_INCLUDED_ - - -#include -#include -#include -#include -#include - -enum { - NXT_FIELDS_OFFSET = offsetof(nxt_unit_request_t, fields) -}; - -int nxt_cgo_run(uintptr_t handler); - -ssize_t nxt_cgo_response_write(nxt_unit_request_info_t *req, - uintptr_t src, uint32_t len); - -ssize_t nxt_cgo_request_read(nxt_unit_request_info_t *req, - uintptr_t dst, uint32_t dst_len); - -void nxt_cgo_warn(const char *msg, uint32_t msg_len); -void nxt_cgo_alert(const char *msg, uint32_t msg_len); - -#endif /* _NXT_CGO_LIB_H_INCLUDED_ */ diff --git a/go/observable.go b/go/observable.go deleted file mode 100644 index 9a38802c..00000000 --- a/go/observable.go +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) NGINX, Inc. - */ - -package unit - -import ( - "sync" -) - -type observable struct { - sync.Mutex - observers []chan int -} - -func (o *observable) attach(c chan int) { - o.Lock() - defer o.Unlock() - - o.observers = append(o.observers, c) -} - -func (o *observable) notify(e int) { - o.Lock() - defer o.Unlock() - - for _, v := range o.observers { - v <- e - } - - o.observers = nil -} diff --git a/go/port.go b/go/port.go deleted file mode 100644 index 6635e87c..00000000 --- a/go/port.go +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -package unit - -/* -#include "nxt_cgo_lib.h" -*/ -import "C" - -import ( - "io" - "net" - "os" - "sync" - "unsafe" -) - -type port_key struct { - pid int - id int -} - -type port struct { - key port_key - rcv *net.UnixConn - snd *net.UnixConn -} - -type port_registry struct { - sync.RWMutex - m map[port_key]*port -} - -var port_registry_ port_registry - -func find_port(key port_key) *port { - port_registry_.RLock() - res := port_registry_.m[key] - port_registry_.RUnlock() - - return res -} - -func add_port(p *port) { - - port_registry_.Lock() - if port_registry_.m == nil { - port_registry_.m = make(map[port_key]*port) - } - - old := port_registry_.m[p.key] - - if old == nil { - port_registry_.m[p.key] = p - } - - port_registry_.Unlock() -} - -func (p *port) Close() { - if p.rcv != nil { - p.rcv.Close() - } - - if p.snd != nil { - p.snd.Close() - } -} - -func getUnixConn(fd int) *net.UnixConn { - if fd < 0 { - return nil - } - - f := os.NewFile(uintptr(fd), "sock") - defer f.Close() - - c, err := net.FileConn(f) - if err != nil { - nxt_go_alert("FileConn error %s", err) - return nil - } - - uc, ok := c.(*net.UnixConn) - if !ok { - nxt_go_alert("Not a Unix-domain socket %d", fd) - return nil - } - - return uc -} - -//export nxt_go_add_port -func nxt_go_add_port(ctx *C.nxt_unit_ctx_t, p *C.nxt_unit_port_t) C.int { - - new_port := &port{ - key: port_key{ - pid: int(p.id.pid), - id: int(p.id.id), - }, - rcv: getUnixConn(int(p.in_fd)), - snd: getUnixConn(int(p.out_fd)), - } - - add_port(new_port) - - p.in_fd = -1 - p.out_fd = -1 - - return C.NXT_UNIT_OK -} - -//export nxt_go_ready -func nxt_go_ready(ctx *C.nxt_unit_ctx_t) C.int { - go func(ctx *C.nxt_unit_ctx_t) { - C.nxt_unit_run_shared(ctx) - }(ctx) - - return C.NXT_UNIT_OK -} - -//export nxt_go_remove_port -func nxt_go_remove_port(unit *C.nxt_unit_t, ctx *C.nxt_unit_ctx_t, - p *C.nxt_unit_port_t) { - - key := port_key{ - pid: int(p.id.pid), - id: int(p.id.id), - } - - port_registry_.Lock() - if port_registry_.m != nil { - delete(port_registry_.m, key) - } - - port_registry_.Unlock() -} - -//export nxt_go_port_send -func nxt_go_port_send(pid C.int, id C.int, buf unsafe.Pointer, buf_size C.int, - oob unsafe.Pointer, oob_size C.int) C.ssize_t { - - key := port_key{ - pid: int(pid), - id: int(id), - } - - p := find_port(key) - - if p == nil { - nxt_go_alert("port %d:%d not found", pid, id) - return 0 - } - - n, oobn, err := p.snd.WriteMsgUnix(GoBytes(buf, buf_size), - GoBytes(oob, oob_size), nil) - - if err != nil { - nxt_go_warn("write result %d (%d), %s", n, oobn, err) - - n = -1 - } - - return C.ssize_t(n) -} - -//export nxt_go_port_recv -func nxt_go_port_recv(pid C.int, id C.int, buf unsafe.Pointer, buf_size C.int, - oob unsafe.Pointer, oob_size *C.size_t) C.ssize_t { - - key := port_key{ - pid: int(pid), - id: int(id), - } - - p := find_port(key) - - if p == nil { - nxt_go_alert("port %d:%d not found", pid, id) - return 0 - } - - n, oobn, _, _, err := p.rcv.ReadMsgUnix(GoBytes(buf, buf_size), - GoBytes(oob, C.int(*oob_size))) - - if err != nil { - if nerr, ok := err.(*net.OpError); ok { - if nerr.Err == io.EOF { - return 0 - } - } - - nxt_go_warn("read result %d (%d), %s", n, oobn, err) - - n = -1 - - } else { - *oob_size = C.size_t(oobn) - } - - return C.ssize_t(n) -} diff --git a/go/request.go b/go/request.go deleted file mode 100644 index 7e2e848a..00000000 --- a/go/request.go +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -package unit - -/* -#include "nxt_cgo_lib.h" -*/ -import "C" - -import ( - "io" - "net/http" - "net/url" - "crypto/tls" - "unsafe" -) - -type request struct { - req http.Request - resp response - c_req *C.nxt_unit_request_info_t -} - -func (r *request) Read(p []byte) (n int, err error) { - res := C.nxt_cgo_request_read(r.c_req, buf_ref(p), C.uint32_t(len(p))) - - if res == 0 && len(p) > 0 { - return 0, io.EOF - } - - return int(res), nil -} - -func (r *request) Close() error { - return nil -} - -func new_request(c_req *C.nxt_unit_request_info_t) (r *request, err error) { - req := c_req.request - - uri := GoStringN(&req.target, C.int(req.target_length)) - - URL, err := url.ParseRequestURI(uri) - if err != nil { - return nil, err - } - - proto := GoStringN(&req.version, C.int(req.version_length)) - - r = &request{ - req: http.Request { - URL: URL, - Header: http.Header{}, - RequestURI: uri, - Method: GoStringN(&req.method, C.int(req.method_length)), - Proto: proto, - ProtoMajor: 1, - ProtoMinor: int(proto[7] - '0'), - ContentLength: int64(req.content_length), - Host: GoStringN(&req.server_name, C.int(req.server_name_length)), - RemoteAddr: GoStringN(&req.remote, C.int(req.remote_length)), - }, - resp: response{header: http.Header{}, c_req: c_req}, - c_req: c_req, - } - - r.req.Body = r - - if req.tls != 0 { - r.req.TLS = &tls.ConnectionState{ } - r.req.URL.Scheme = "https" - - } else { - r.req.URL.Scheme = "http" - } - - fields := get_fields(req) - - for i := 0; i < len(fields); i++ { - f := &fields[i] - - n := GoStringN(&f.name, C.int(f.name_length)) - v := GoStringN(&f.value, C.int(f.value_length)) - - r.req.Header.Add(n, v) - } - - return r, nil -} - -func get_fields(req *C.nxt_unit_request_t) []C.nxt_unit_field_t { - f := uintptr(unsafe.Pointer(req)) + uintptr(C.NXT_FIELDS_OFFSET) - - h := &slice_header{ - Data: unsafe.Pointer(f), - Len: int(req.fields_count), - Cap: int(req.fields_count), - } - - return *(*[]C.nxt_unit_field_t)(unsafe.Pointer(h)) -} - -//export nxt_go_request_handler -func nxt_go_request_handler(c_req *C.nxt_unit_request_info_t) { - - go func(c_req *C.nxt_unit_request_info_t, handler http.Handler) { - - ctx := c_req.ctx - - for { - r, err := new_request(c_req) - - if err == nil { - handler.ServeHTTP(&r.resp, &r.req) - - if !r.resp.header_sent { - r.resp.WriteHeader(http.StatusOK) - } - - C.nxt_unit_request_done(c_req, C.NXT_UNIT_OK) - - } else { - C.nxt_unit_request_done(c_req, C.NXT_UNIT_ERROR) - } - - c_req = C.nxt_unit_dequeue_request(ctx) - if c_req == nil { - break - } - } - - }(c_req, get_handler(uintptr(c_req.unit.data))) -} diff --git a/go/response.go b/go/response.go deleted file mode 100644 index a1af30b3..00000000 --- a/go/response.go +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -package unit - -/* -#include "nxt_cgo_lib.h" -*/ -import "C" - -import ( - "net/http" -) - -type response struct { - header http.Header - header_sent bool - c_req *C.nxt_unit_request_info_t - ch chan int -} - -func (r *response) Header() http.Header { - return r.header -} - -func (r *response) Write(p []byte) (n int, err error) { - if !r.header_sent { - r.WriteHeader(http.StatusOK) - } - - l := len(p) - written := int(0) - br := buf_ref(p) - - for written < l { - res := C.nxt_cgo_response_write(r.c_req, br, C.uint32_t(l - written)) - - written += int(res) - br += C.uintptr_t(res) - - if (written < l) { - if r.ch == nil { - r.ch = make(chan int, 2) - } - - wait_shm_ack(r.ch) - } - } - - return written, nil -} - -func (r *response) WriteHeader(code int) { - if r.header_sent { - nxt_go_warn("multiple response.WriteHeader calls") - return - } - r.header_sent = true - - // Set a default Content-Type - if _, hasType := r.header["Content-Type"]; !hasType { - r.header.Add("Content-Type", "text/html; charset=utf-8") - } - - fields := 0 - fields_size := 0 - - for k, vv := range r.header { - for _, v := range vv { - fields++ - fields_size += len(k) + len(v) - } - } - - C.nxt_unit_response_init(r.c_req, C.uint16_t(code), C.uint32_t(fields), - C.uint32_t(fields_size)) - - for k, vv := range r.header { - for _, v := range vv { - C.nxt_unit_response_add_field(r.c_req, str_ref(k), C.uint8_t(len(k)), - str_ref(v), C.uint32_t(len(v))) - } - } - - C.nxt_unit_response_send(r.c_req) -} - -func (r *response) Flush() { - if !r.header_sent { - r.WriteHeader(http.StatusOK) - } -} - -var observer_registry_ observable - -func wait_shm_ack(c chan int) { - observer_registry_.attach(c) - - _ = <-c -} - -//export nxt_go_shm_ack_handler -func nxt_go_shm_ack_handler(ctx *C.nxt_unit_ctx_t) { - observer_registry_.notify(1) -} diff --git a/go/unit.go b/go/unit.go deleted file mode 100644 index b5dd4f6c..00000000 --- a/go/unit.go +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -package unit - -/* -#include "nxt_cgo_lib.h" -*/ -import "C" - -import ( - "fmt" - "net/http" - "sync" - "unsafe" -) - -type cbuf struct { - b C.uintptr_t - s C.size_t -} - -func buf_ref(buf []byte) C.uintptr_t { - if len(buf) == 0 { - return 0 - } - - return C.uintptr_t(uintptr(unsafe.Pointer(&buf[0]))) -} - -type string_header struct { - Data unsafe.Pointer - Len int -} - -func str_ref(s string) *C.char { - header := (*string_header)(unsafe.Pointer(&s)) - - return (*C.char)(header.Data) -} - -func (buf *cbuf) init_bytes(b []byte) { - buf.b = buf_ref(b) - buf.s = C.size_t(len(b)) -} - -type slice_header struct { - Data unsafe.Pointer - Len int - Cap int -} - -func (buf *cbuf) GoBytes() []byte { - if buf == nil { - var b [0]byte - return b[:0] - } - - header := &slice_header{ - Data: unsafe.Pointer(uintptr(buf.b)), - Len: int(buf.s), - Cap: int(buf.s), - } - - return *(*[]byte)(unsafe.Pointer(header)) -} - -func GoBytes(buf unsafe.Pointer, size C.int) []byte { - bytesHeader := &slice_header{ - Data: buf, - Len: int(size), - Cap: int(size), - } - - return *(*[]byte)(unsafe.Pointer(bytesHeader)) -} - -func GoStringN(sptr *C.nxt_unit_sptr_t, l C.int) string { - p := unsafe.Pointer(sptr) - b := uintptr(p) + uintptr(*(*C.uint32_t)(p)) - - return C.GoStringN((*C.char)(unsafe.Pointer(b)), l) -} - -func nxt_go_warn(format string, args ...interface{}) { - str := fmt.Sprintf("[go] " + format, args...) - - C.nxt_cgo_warn(str_ref(str), C.uint32_t(len(str))) -} - -func nxt_go_alert(format string, args ...interface{}) { - str := fmt.Sprintf("[go] " + format, args...) - - C.nxt_cgo_alert(str_ref(str), C.uint32_t(len(str))) -} - -type handler_registry struct { - sync.RWMutex - next uintptr - m map[uintptr]*http.Handler -} - -var handler_registry_ handler_registry - -func set_handler(handler *http.Handler) uintptr { - - handler_registry_.Lock() - if handler_registry_.m == nil { - handler_registry_.m = make(map[uintptr]*http.Handler) - handler_registry_.next = 1 - } - - h := handler_registry_.next - handler_registry_.next += 1 - handler_registry_.m[h] = handler - - handler_registry_.Unlock() - - return h -} - -func get_handler(h uintptr) http.Handler { - handler_registry_.RLock() - defer handler_registry_.RUnlock() - - return *handler_registry_.m[h] -} - -func reset_handler(h uintptr) { - - handler_registry_.Lock() - if handler_registry_.m != nil { - delete(handler_registry_.m, h) - } - - handler_registry_.Unlock() -} - -func ListenAndServe(addr string, handler http.Handler) error { - if handler == nil { - handler = http.DefaultServeMux - } - - h := set_handler(&handler) - - rc := C.nxt_cgo_run(C.uintptr_t(h)) - - reset_handler(h) - - if rc != 0 { - return http.ListenAndServe(addr, handler) - } - - return nil -} diff --git a/pkg/Makefile b/pkg/Makefile deleted file mode 100644 index ad12efb7..00000000 --- a/pkg/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/make - -include ../version -include shasum.mak - -VERSION ?= $(NXT_VERSION) -RELEASE ?= 1 - -default: - @echo "available targets: dist rpm deb docker npm" - -dist: - rm -f unit-$(VERSION).tar.gz - cd .. && git archive \ - --output pkg/unit-$(VERSION).tar.gz \ - --prefix unit-$(VERSION)/ \ - --worktree-attributes \ - $(VERSION) ./ - $(SHA512SUM) unit-$(VERSION).tar.gz > unit-$(VERSION).tar.gz.sha512 - -rpm: - @cd rpm && VERSION=$(VERSION) RELEASE=$(RELEASE) make all - -deb: - @cd deb && VERSION=$(VERSION) RELEASE=$(RELEASE) make all - -docker: - @cd docker && VERSION=$(VERSION) RELEASE=$(RELEASE) make all - -npm: - @cd npm && VERSION=$(VERSION) RELEASE=$(RELEASE) make all - -njs: - @cd contrib && make .njs - -clean: - @cd rpm && make clean - @cd deb && make clean - @cd docker && make clean - @cd npm && make clean - @cd contrib && make clean - rm -f unit-$(VERSION).tar.gz - rm -f unit-$(VERSION).tar.gz.sha512 - -.PHONY: default rpm deb docker npm clean diff --git a/pkg/contrib/Makefile b/pkg/contrib/Makefile deleted file mode 100644 index 7e3b8b97..00000000 --- a/pkg/contrib/Makefile +++ /dev/null @@ -1,140 +0,0 @@ -all: install - -TOPSRC := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -SRC := $(TOPSRC)/src -TARBALLS := $(TOPSRC)/tarballs -VPATH := $(TARBALLS) -PREFIX = $(TOPSRC)/local -PREFIX := $(abspath $(PREFIX)) - -PKGS_ALL := $(patsubst $(SRC)/%/Makefile,%,$(wildcard $(SRC)/*/Makefile)) - -# Common download locations -CONTRIB_NGINX := https://packages.nginx.org/contrib - -# -# Tools -# -NPROC := $(shell getconf _NPROCESSORS_ONLN) -_SMP_MFLAGS := -j$(NPROC) - -ifndef GIT -ifeq ($(shell git --version >/dev/null 2>&1 || echo FAIL),) -GIT = git -endif -endif -GIT ?= $(error git not found) - -ifeq ($(shell curl --version >/dev/null 2>&1 || echo FAIL),) -download = curl -f -L -- "$(1)" > "$@" -else ifeq ($(shell wget --version >/dev/null 2>&1 || echo FAIL),) -download = (rm -f $@.tmp && \ - wget --passive -c -p -O $@.tmp "$(1)" && \ - touch $@.tmp && \ - mv $@.tmp $@ ) -else ifeq ($(which fetch >/dev/null 2>&1 || echo FAIL),) -download = (rm -f $@.tmp && \ - fetch -p -o $@.tmp "$(1)" && \ - touch $@.tmp && \ - mv $@.tmp $@) -else -download = $(error Neither curl nor wget found) -endif - -download_pkg = $(call download,$(CONTRIB_NGINX)/$(2)/$(lastword $(subst /, ,$(@)))) || \ - ( $(call download,$(1)) && echo "Please upload $(lastword $(subst /, ,$(@))) to $(CONTRIB_NGINX)" ) - -ifeq ($(shell which xz >/dev/null 2>&1 || echo FAIL),) -XZ = xz -else -XZ ?= $(error XZ (LZMA) compressor not found) -endif - -ifeq ($(shell sha512sum --version >/dev/null 2>&1 || echo FAIL),) -SHA512SUM = sha512sum --check -else ifeq ($(shell shasum --version >/dev/null 2>&1 || echo FAIL),) -SHA512SUM = shasum -a 512 --check -else ifeq ($(shell openssl version >/dev/null 2>&1 || echo FAIL),) -SHA512SUM = openssl dgst -sha512 -else -SHA512SUM = $(error SHA-512 checksumming not found) -endif - -# -# Common helpers -# -download_git = \ - rm -Rf -- "$(@:.tar.xz=)" && \ - $(GIT) init --bare "$(@:.tar.xz=)" && \ - (cd "$(@:.tar.xz=)" && \ - $(GIT) remote add origin "$(1)" && \ - $(GIT) fetch origin "$(2)") && \ - (cd "$(@:.tar.xz=)" && \ - $(GIT) archive --prefix="$(notdir $(@:.tar.xz=))/" \ - --format=tar "$(3)") > "$(@:.xz=)" && \ - echo "$(3) $(@)" > "$(@:.tar.xz=.githash)" && \ - rm -Rf -- "$(@:.tar.xz=)" && \ - $(XZ) --stdout "$(@:.xz=)" > "$@.tmp" && \ - rm -f "$(@:.xz=)" && \ - mv -f -- "$@.tmp" "$@" -check_githash = \ - h=`sed -e "s,^\([0-9a-fA-F]\{40\}\) .*/$(notdir $<),\1,g" \ - < "$(<:.tar.xz=.githash)"` && \ - test "$$h" = "$1" - -checksum = \ - $(foreach f,$(filter $(TARBALLS)/%,$^), \ - grep -- " $(f:$(TARBALLS)/%=%)$$" \ - "$(SRC)/$(patsubst $(3)%,%,$@)/$(2)SUMS" |) \ - (cd $(TARBALLS) && $(1)) -CHECK_SHA512 = $(call checksum,$(SHA512SUM),SHA512,.sum-) -UNPACK = $(RM) -R $@ \ - $(foreach f,$(filter %.tar.gz %.tgz,$^), && tar xvzfo $(f)) \ - $(foreach f,$(filter %.tar.bz2,$^), && tar xvjfo $(f)) \ - $(foreach f,$(filter %.tar.xz,$^), && tar xvJfo $(f)) \ - $(foreach f,$(filter %.zip,$^), && unzip $(f)) -UNPACK_DIR = $(patsubst %.tar,%,$(basename $(notdir $<))) -APPLY = (cd $(UNPACK_DIR) && patch -fp1) < -MOVE = mv $(UNPACK_DIR) $@ && touch $@ - -# Per-package build rules -include $(SRC)/*/Makefile - -# Targets -PKGS_DEPS := $(sort $(foreach p,$(PKGS),$(DEPS_$(p)))) - -fetch: $(PKGS:%=.sum-%) -install: $(PKGS:%=.%) - -clean: - -$(RM) $(foreach p,$(PKGS),.$(p) .sum-$(p) .dep-$(p)) - -$(RM) -R $(foreach p,$(PKGS),$(p)) - -$(RM) -R "$(PREFIX)" - -$(RM) $(TARBALLS)/*.* - -list: - @echo Packages: - @echo ' $(PKGS)' | tr " " "\n" | sort | tr "\n" " " |fmt - @echo Depended-on packages: - @echo ' $(PKGS_DEPS)' | tr " " "\n" | sort | tr "\n" " " |fmt - -.PHONY: all fetch install clean list - -# Default pattern rules -.sum-%: $(SRC)/%/SHA512SUMS - $(CHECK_SHA512) - touch $@ - -.sum-%: - $(error Download and check target not defined for $*) - -# Real dependency on missing packages -$(patsubst %,.dep-%,$(PKGS)): .dep-%: .% - touch -r $< $@ - -.SECONDEXPANSION: - -# Dependency propagation (convert 'DEPS_foo = bar' to '.foo: .bar') -$(foreach p,$(PKGS),.$(p)): .%: $$(foreach d,$$(DEPS_$$*),.dep-$$(d)) - -.DELETE_ON_ERROR: diff --git a/pkg/contrib/src/libunit-wasm/Makefile b/pkg/contrib/src/libunit-wasm/Makefile deleted file mode 100644 index 51c24456..00000000 --- a/pkg/contrib/src/libunit-wasm/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# libunit-wasm - -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/version -LIBUNIT_WASM_URL := https://github.com/nginx/unit-wasm.git - -PKGS += libunit-wasm - -DEPS_libunit-wasm = wasi-sysroot $(DEPS_wasi-sysroot) - -$(TARBALLS)/libunit-wasm-$(LIBUNIT_WASM_GITHASH).tar.xz: - $(call download_git,$(LIBUNIT_WASM_URL),,$(LIBUNIT_WASM_GITHASH)) - -.sum-libunit-wasm: libunit-wasm-$(LIBUNIT_WASM_GITHASH).tar.xz - $(call check_githash,$(LIBUNIT_WASM_GITHASH)) - touch $@ - -libunit-wasm: libunit-wasm-$(LIBUNIT_WASM_GITHASH).tar.xz - $(UNPACK) - $(MOVE) - -.libunit-wasm: libunit-wasm - cd $< && CFLAGS= make WASI_SYSROOT=$(TOPSRC)wasi-sysroot V=1 libunit-wasm - touch $@ diff --git a/pkg/contrib/src/libunit-wasm/version b/pkg/contrib/src/libunit-wasm/version deleted file mode 100644 index 60577d0e..00000000 --- a/pkg/contrib/src/libunit-wasm/version +++ /dev/null @@ -1,2 +0,0 @@ -LIBUNIT_WASM_VERSION := 0.3.0 -LIBUNIT_WASM_GITHASH := 01c43784ec53aa1ff22aca7e7ae6f18b4591b514 diff --git a/pkg/contrib/src/njs/Makefile b/pkg/contrib/src/njs/Makefile deleted file mode 100644 index 6a4fdf9d..00000000 --- a/pkg/contrib/src/njs/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# njs - -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/version -NJS_URL := https://hg.nginx.org/njs/archive/$(NJS_VERSION).tar.gz - -PKGS += njs - -$(TARBALLS)/njs-$(NJS_VERSION).tar.gz: - $(call download_pkg,$(NJS_URL),njs) - -.sum-njs: njs-$(NJS_VERSION).tar.gz - -njs: njs-$(NJS_VERSION).tar.gz .sum-njs - $(UNPACK) - $(MOVE) - -.njs: njs - cd $< && ./configure \ - --no-libxml2 \ - --no-zlib \ - && $(MAKE) libnjs - touch $@ diff --git a/pkg/contrib/src/njs/SHA512SUMS b/pkg/contrib/src/njs/SHA512SUMS deleted file mode 100644 index 43766487..00000000 --- a/pkg/contrib/src/njs/SHA512SUMS +++ /dev/null @@ -1 +0,0 @@ -cc3110a0c6866dfc03d19c58745e5b75aa9792999db45bc55a752f7b04db8ae51322bfe0156b873109c8477c6c1a030c851c770697cf6791c6e89fb2fed0a2c5 njs-0.8.2.tar.gz diff --git a/pkg/contrib/src/njs/version b/pkg/contrib/src/njs/version deleted file mode 100644 index 00453419..00000000 --- a/pkg/contrib/src/njs/version +++ /dev/null @@ -1 +0,0 @@ -NJS_VERSION := 0.8.2 diff --git a/pkg/contrib/src/wasi-sysroot/Makefile b/pkg/contrib/src/wasi-sysroot/Makefile deleted file mode 100644 index fcfb8df3..00000000 --- a/pkg/contrib/src/wasi-sysroot/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# wasi-sysroot - -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/version -WASI_SYSROOT_URL := https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WASI_SYSROOT_VERSION_MAJOR)/wasi-sysroot-$(WASI_SYSROOT_VERSION_MAJOR).$(WASI_SYSROOT_VERSION_MINOR).tar.gz - -PKGS += wasi-sysroot - -$(TARBALLS)/wasi-sysroot-$(WASI_SYSROOT_VERSION_MAJOR).$(WASI_SYSROOT_VERSION_MINOR).tar.gz: - $(call download_pkg,$(WASI_SYSROOT_URL),wasi-sysroot) - -.sum-wasi-sysroot: wasi-sysroot-$(WASI_SYSROOT_VERSION_MAJOR).$(WASI_SYSROOT_VERSION_MINOR).tar.gz - -wasi-sysroot: wasi-sysroot-$(WASI_SYSROOT_VERSION_MAJOR).$(WASI_SYSROOT_VERSION_MINOR).tar.gz .sum-wasi-sysroot - $(UNPACK) - -.wasi-sysroot: wasi-sysroot - touch $@ diff --git a/pkg/contrib/src/wasi-sysroot/SHA512SUMS b/pkg/contrib/src/wasi-sysroot/SHA512SUMS deleted file mode 100644 index a1e71fff..00000000 --- a/pkg/contrib/src/wasi-sysroot/SHA512SUMS +++ /dev/null @@ -1 +0,0 @@ -ad4ad629d02f01f3d2eb977dd0bc43091b0f11ed1b5dd9fdb3580e4cf49c132f6cb4982ae80eabf638f0d08d0c4c7df40cceb2be8f9d2c29abc35b8564ffda42 wasi-sysroot-20.0.tar.gz diff --git a/pkg/contrib/src/wasi-sysroot/version b/pkg/contrib/src/wasi-sysroot/version deleted file mode 100644 index 919c7098..00000000 --- a/pkg/contrib/src/wasi-sysroot/version +++ /dev/null @@ -1,2 +0,0 @@ -WASI_SYSROOT_VERSION_MAJOR := 20 -WASI_SYSROOT_VERSION_MINOR := 0 diff --git a/pkg/contrib/src/wasmtime/Makefile b/pkg/contrib/src/wasmtime/Makefile deleted file mode 100644 index 11797fee..00000000 --- a/pkg/contrib/src/wasmtime/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# wasmtime - -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/version -WASMTIME_URL := https://github.com/bytecodealliance/wasmtime/releases/download/v$(WASMTIME_VERSION)/wasmtime-v$(WASMTIME_VERSION)-src.tar.gz - -PKGS += wasmtime - -ifeq ($(shell which cargo >/dev/null 2>&1 || echo FAIL),) -CARGO = cargo -else -CARGO = $(error Cargo (Rust package manager) not found) -endif - -ifeq ($(shell uname -s),Linux) -WASMTIME_ARGS=-Clink-arg=-Wl,-soname,libwasmtime.so -endif - -$(TARBALLS)/wasmtime-v$(WASMTIME_VERSION)-src.tar.gz: - $(call download_pkg,$(WASMTIME_URL),wasmtime) - -.sum-wasmtime: wasmtime-v$(WASMTIME_VERSION)-src.tar.gz - -wasmtime: wasmtime-v$(WASMTIME_VERSION)-src.tar.gz .sum-wasmtime - $(UNPACK) - $(MOVE) - -.wasmtime: wasmtime - cd $< && $(CARGO) rustc --release -p wasmtime-c-api -- $(WASMTIME_ARGS) - cp $ - -SRCDIR= unit-$(VERSION) - -CODENAME = $(shell lsb_release -cs) - -BUILD_DEPENDS_unit = build-essential debhelper devscripts fakeroot libxml2-utils lintian lsb-release xsltproc libssl-dev -BUILD_DEPENDS = $(BUILD_DEPENDS_unit) - -MODULES= - -# Ubuntu 23.10 -ifeq ($(CODENAME),mantic) -include Makefile.php -include Makefile.python311 -include Makefile.python312 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc11 -include Makefile.jsc17 -include Makefile.jsc19 -include Makefile.jsc20 -include Makefile.jsc21 -include Makefile.wasm -endif - -# Ubuntu 23.04 -ifeq ($(CODENAME),lunar) -include Makefile.php -include Makefile.python311 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc11 -include Makefile.jsc17 -include Makefile.jsc18 -include Makefile.jsc19 -include Makefile.jsc20 -include Makefile.wasm -endif - -# Ubuntu 22.10 -ifeq ($(CODENAME),kinetic) -include Makefile.php -include Makefile.python27 -include Makefile.python310 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc11 -include Makefile.jsc17 -include Makefile.jsc18 -include Makefile.jsc19 -include Makefile.wasm -endif - -# Ubuntu 22.04 -ifeq ($(CODENAME),jammy) -include Makefile.php -include Makefile.python27 -include Makefile.python310 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc11 -include Makefile.jsc17 -include Makefile.jsc18 -include Makefile.wasm -endif - -# Ubuntu 21.10 -ifeq ($(CODENAME),impish) -include Makefile.php -include Makefile.python27 -include Makefile.python39 -include Makefile.python310 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc11 -include Makefile.jsc16 -include Makefile.jsc17 -include Makefile.jsc18 -include Makefile.wasm -endif - -# Ubuntu 20.04 -ifeq ($(CODENAME),focal) -include Makefile.php -include Makefile.python27 -include Makefile.python38 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc11 -include Makefile.wasm -endif - -# Ubuntu 18.04 -ifeq ($(CODENAME),bionic) -include Makefile.php -include Makefile.python27 -include Makefile.python36 -include Makefile.python37 -include Makefile.python38 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc8 -include Makefile.jsc11 -include Makefile.wasm -endif - -# Debian 12 -ifeq ($(CODENAME),bookworm) -include Makefile.php -include Makefile.python311 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc17 -include Makefile.wasm -endif - -# Debian 11 -ifeq ($(CODENAME),bullseye) -include Makefile.php -include Makefile.python27 -include Makefile.python39 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc11 -include Makefile.wasm -endif - -# Debian 10 -ifeq ($(CODENAME),buster) -include Makefile.php -include Makefile.python27 -include Makefile.python37 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc11 -include Makefile.wasm -endif - -CONFIGURE_ARGS_COMMON=\ - --prefix=/usr \ - --statedir=/var/lib/unit \ - --control="unix:/var/run/control.unit.sock" \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --tests \ - --openssl - -CONFIGURE_ARGS=\ - $(CONFIGURE_ARGS_COMMON) \ - --njs - -export CR=\\n - -default: - @echo "valid targets: all modules unit $(addprefix unit-, $(MODULES)) test test-debug clean" - -all: check-build-depends-all unit modules - -modules: $(addprefix unit-, $(MODULES)) - -check-build-depends-%: - @{ \ - case "$*" in \ - all) pkgs="$(BUILD_DEPENDS)" ;; \ - unit) pkgs="$(BUILD_DEPENDS_unit)" ;; \ - *) pkgs="$(BUILD_DEPENDS_unit) $(BUILD_DEPENDS_$*)" ;; \ - esac ; \ - not_installed= ; \ - for pkg in $${pkgs}; do \ - dpkg-query -W $${pkg} >/dev/null 2>&1 ; \ - if [ $$? -ne 0 ]; then \ - not_installed="$${not_installed} $${pkg}" ; \ - fi ; \ - done ; \ - if test -n "$${not_installed}" ; then \ - echo "" >&2 ; \ - echo "The following packages are required in order to proceed:" >&2 ; \ - echo "" >&2 ; \ - echo $${not_installed} >&2 ; \ - echo "" >&2 ; \ - exit 1 ; \ - fi \ - } - touch $@ - -debuild/$(SRCDIR)/debian: - @{ \ - set -e ; \ - mkdir -p debuild/$(SRCDIR) ; \ - cp -pr debian debuild/$(SRCDIR) ; \ - echo '11' > debuild/$(SRCDIR)/debian/compat ; \ - mkdir -p debuild/$(SRCDIR)/debian/source ; \ - echo '3.0 (quilt)' > debuild/$(SRCDIR)/debian/source/format ; \ - cat debian/control.in | sed \ - -e "s#%%PACKAGE_VENDOR%%#$(PACKAGE_VENDOR)#g" \ - -e "s#%%UNIT_VERSION%%#$(VERSION)#g" \ - > debuild/$(SRCDIR)/debian/control ; \ - cat debian/rules.in | sed \ - -e "s#%%CONFIGURE_ARGS%%#$(CONFIGURE_ARGS)#g" \ - > debuild/$(SRCDIR)/debian/rules ; \ - chmod +x debuild/$(SRCDIR)/debian/rules ; \ - } - -debuild/$(SRCDIR)/debian/changelog: ../../docs/changes.xml | debuild/$(SRCDIR)/debian - cd ../../docs && make ../build/unit.deb-changelog -ifneq ($(DEFAULT_VERSION)$(DEFAULT_RELEASE), $(VERSION)$(RELEASE)) - cat ../../build/unit.deb-changelog | sed \ - -e "s/unit ($(DEFAULT_VERSION)-$(DEFAULT_RELEASE)~/unit ($(VERSION)-$(RELEASE)~/" \ - -e "s#%%CODENAME%%#$(CODENAME)#g" \ - > debuild/$(SRCDIR)/debian/changelog -else - cat ../../build/unit.deb-changelog | sed \ - -e "s#%%CODENAME%%#$(CODENAME)#g" \ - > debuild/$(SRCDIR)/debian/changelog -endif - -debuild/unit_$(VERSION).orig.tar.gz: | debuild/$(SRCDIR)/debian - cd ../.. && tar -czf pkg/deb/debuild/$(SRCDIR).tar.gz \ - --transform "s#^#$(SRCDIR)/#" \ - LICENSE NOTICE CHANGES README.md CONTRIBUTING.md configure auto src \ - test tools version go pkg/contrib docs/man/man8/unitd.8.in - mv debuild/$(SRCDIR).tar.gz debuild/unit_$(VERSION).orig.tar.gz - cd debuild && tar zxf unit_$(VERSION).orig.tar.gz - -unit: check-build-depends-unit debuild/unit_$(VERSION).orig.tar.gz debuild/$(SRCDIR)/debian/changelog - @echo "===> Building $@ package" - cd debuild/$(SRCDIR) && debuild --preserve-envvar PATH --preserve-envvar RUSTUP_HOME -us -uc - mkdir -p debs - find debuild/ -maxdepth 1 -type f -exec cp {} debs/ \; - ln -s debuild/$(SRCDIR)/build $@ - -debuild-%: debuild/unit_$(VERSION).orig.tar.gz ../../docs/changes.xml - mkdir $@ - cp debuild/unit_$(VERSION).orig.tar.gz debuild-$*/unit-$(MODULE_SUFFIX_$*)_$(VERSION).orig.tar.gz - cd $@ && tar zxf unit-$(MODULE_SUFFIX_$*)_$(VERSION).orig.tar.gz - mkdir $@/$(SRCDIR)/debian - echo '11' > $@/$(SRCDIR)/debian/compat - mkdir $@/$(SRCDIR)/debian/source - echo '3.0 (quilt)' > $@/$(SRCDIR)/debian/source/format - cd ../../docs && make ../build/unit-$(MODULE_SUFFIX_$*).deb-changelog -ifneq ($(DEFAULT_VERSION)$(DEFAULT_RELEASE), $(VERSION)$(RELEASE)) - cat ../../build/unit-$(MODULE_SUFFIX_$*).deb-changelog | sed \ - -e "s/unit-$* ($(DEFAULT_VERSION)-$(DEFAULT_RELEASE)~/unit-$* ($(VERSION)-$(RELEASE)~/" \ - -e "s#%%CODENAME%%#$(CODENAME)#g" \ - > $@/$(SRCDIR)/debian/changelog -else - cat ../../build/unit-$(MODULE_SUFFIX_$*).deb-changelog | sed \ - -e "s#%%CODENAME%%#$(CODENAME)#g" \ - > $@/$(SRCDIR)/debian/changelog -endif - if [ -f debian.module/copyright.unit-$(MODULE_SUFFIX_$*) ]; then \ - cp debian.module/copyright.unit-$(MODULE_SUFFIX_$*) debuild-$*/$(SRCDIR)/debian/copyright ; \ - else \ - cp debian/copyright debuild-$*/$(SRCDIR)/debian/ ; \ - fi - @{ \ - set -e ; \ - for src in $(MODULE_SOURCES_$*); do \ - cp debian.module/$${src} $@/$(SRCDIR)/debian/ ; \ - done ; \ - definitions=`echo "$$MODULE_DEFINITIONS_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - prebuild=`echo "$$MODULE_PREBUILD_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - preinstall=`echo "$$MODULE_PREINSTALL_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - postinstall=`echo "$$MODULE_POSTINSTALL_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - post=`echo "$$MODULE_POST_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - cat debian.module/$(if $(MODULE_NOARCH_$*),control-noarch.in,control.in) | sed \ - -e "s#%%NAME%%#unit-$(MODULE_SUFFIX_$*)#g" \ - -e "s#%%SUMMARY%%#$(MODULE_SUMMARY_$*)#g" \ - -e "s#%%CODENAME%%#$(CODENAME)#g" \ - -e "s#%%UNIT_VERSION%%#$(VERSION)#g" \ - -e "s#%%UNIT_RELEASE%%#$(RELEASE)#g" \ - -e "s#%%VERSION%%#$(MODULE_VERSION_$*)#g" \ - -e "s#%%RELEASE%%#$(MODULE_RELEASE_$*)#g" \ - -e "s#%%PACKAGE_VENDOR%%#$(PACKAGE_VENDOR)#g" \ - -e "s#%%MODULE_BUILD_DEPENDS%%#$(MODULE_BUILD_DEPENDS_$*)#g" \ - -e "s#%%MODULE_DEPENDS%%#$(MODULE_DEPENDS_$*)#g" \ - > $@/$(SRCDIR)/debian/control ; \ - cat debian.module/$(if $(MODULE_NOARCH_$*),rules-noarch.in,rules.in) | sed \ - -e "s#%%NAME%%#unit-$(MODULE_SUFFIX_$*)#g" \ - -e "s#%%CODENAME%%#$(CODENAME)#g" \ - -e "s#%%UNIT_VERSION%%#$(VERSION)#g" \ - -e "s#%%UNIT_RELEASE%%#$(RELEASE)#g" \ - -e "s#%%CONFIGURE_ARGS%%#$(CONFIGURE_ARGS_COMMON)#g" \ - -e "s#%%MODULE_CONFARGS%%#$(MODULE_CONFARGS_$*)#g" \ - -e "s#%%MODULE_MAKEARGS%%#$(MODULE_MAKEARGS_$*)#g" \ - -e "s#%%MODULE_INSTARGS%%#$(MODULE_INSTARGS_$*)#g" \ - -e "s#%%MODULE_DEFINITIONS%%#$${definitions}#g" \ - -e "s#%%MODULE_PREBUILD%%#$${prebuild}#g" \ - -e "s#%%MODULE_PREINSTALL%%#$${preinstall}#g" \ - -e "s#%%MODULE_POSTINSTALL%%#$${postinstall}#g" \ - > $@/$(SRCDIR)/debian/rules ; \ - cat debian.module/preinst.in | sed \ - -e "s#%%MODULE_POST%%#$$post#g" \ - > $@/$(SRCDIR)/debian/preinst ; \ - chmod +x $@/$(SRCDIR)/debian/rules ; \ - } - -unit-%: check-build-depends-% | debuild-% - @echo "===> Building $@ package" - cd debuild-$*/$(SRCDIR) && debuild --preserve-envvar PATH --preserve-envvar RUSTUP_HOME -us -uc - mkdir -p debs - find debuild-$*/ -maxdepth 1 -type f -exec cp {} debs/ \; - ln -s debuild-$*/$(SRCDIR)/build $@ - -test: unit modules - @{ \ - for so in `find debuild-*/unit-$(VERSION)/debian/build-unit/ -type f \( -name "*.so" -o -name "*.jar" \)`; do \ - soname=`basename $${so}` ; \ - test "$${soname}" = "java.unit.so" && continue ; \ - test -h debuild/unit-$(VERSION)/debian/build-unit/build/lib/$${soname} || \ - ln -fs `pwd`/$${so} debuild/unit-$(VERSION)/debian/build-unit/build/lib/$${soname} ; \ - done ; \ - ( cd debuild/unit-$(VERSION)/debian/build-unit && env python3 -m pytest --user=nobody $(PYTEST_ARGS) ) ; \ - } - -test-debug: unit modules - @{ \ - for so in `find debuild-*/unit-$(VERSION)/debian/build-unit-debug/ -type f \( -name "*.so" -o -name "*.jar" \)`; do \ - soname=`basename $${so}` ; \ - test "$${soname}" = "java.unit.so" && continue ; \ - test -h debuild/unit-$(VERSION)/debian/build-unit-debug/build/lib/$${soname} || \ - ln -fs `pwd`/$${so} debuild/unit-$(VERSION)/debian/build-unit-debug/build/lib/$${soname} ; \ - done ; \ - ( cd debuild/unit-$(VERSION)/debian/build-unit-debug && env python3 -m pytest --user=nobody $(PYTEST_ARGS) ) ; \ - } - -clean: - rm -rf debuild debuild-* debs ../../build - rm -f check-build-depends-* - find . -maxdepth 1 -type l -delete - -.PHONY: default all modules test test-debug clean - -.SECONDARY: $(addprefix check-build-depends-, $(MODULES)) $(addprefix debuild-, $(MODULES)) diff --git a/pkg/deb/Makefile.go b/pkg/deb/Makefile.go deleted file mode 100644 index b9463076..00000000 --- a/pkg/deb/Makefile.go +++ /dev/null @@ -1,50 +0,0 @@ -MODULES+= go -MODULE_SUFFIX_go= go - -MODULE_SUMMARY_go= Go module for NGINX Unit - -MODULE_VERSION_go= $(VERSION) -MODULE_RELEASE_go= 1 - -MODULE_CONFARGS_go= go --go-path=/usr/share/gocode -MODULE_MAKEARGS_go= go -MODULE_INSTARGS_go= go-install-src - -MODULE_SOURCES_go= unit.example-go-app \ - unit.example-go-config - -BUILD_DEPENDS_go= golang -BUILD_DEPENDS+= $(BUILD_DEPENDS_go) - -MODULE_BUILD_DEPENDS_go=,golang -MODULE_DEPENDS_go=,golang,unit-dev (= $(VERSION)-$(RELEASE)~$(CODENAME)) - -MODULE_NOARCH_go= true - -define MODULE_PREINSTALL_go - mkdir -p debian/unit-go/usr/share/doc/unit-go/examples/go-app - install -m 644 -p debian/unit.example-go-app debian/unit-go/usr/share/doc/unit-go/examples/go-app/let-my-people.go - install -m 644 -p debian/unit.example-go-config debian/unit-go/usr/share/doc/unit-go/examples/unit.config -endef -export MODULE_PREINSTALL_go - -define MODULE_POST_go -cat <= 11), - linux-libc-dev%%MODULE_BUILD_DEPENDS%% -Standards-Version: 4.1.4 -Homepage: https://unit.nginx.org - -Package: %%NAME%% -Section: admin -Architecture: all -Depends: lsb-base, - ${misc:Depends}, - unit (= %%UNIT_VERSION%%-%%UNIT_RELEASE%%~%%CODENAME%%)%%MODULE_DEPENDS%% -Description: %%SUMMARY%% - NGINX Unit is a runtime and delivery environment for modern distributed - applications. It runs the application code in multiple languages - (PHP, Python, Go, etc.), and tightly couples it with traffic delivery - in and out of the application. Take this application server and proxy - directly in the cloud / container environments and fully control your app - dynamically via an API. - This package contains %%SUMMARY%%. diff --git a/pkg/deb/debian.module/control.in b/pkg/deb/debian.module/control.in deleted file mode 100644 index f82362d1..00000000 --- a/pkg/deb/debian.module/control.in +++ /dev/null @@ -1,34 +0,0 @@ -Source: %%NAME%% -Section: admin -Priority: extra -Maintainer: %%PACKAGE_VENDOR%% -Build-Depends: debhelper (>= 11), - linux-libc-dev, - libssl-dev, - libpcre2-dev%%MODULE_BUILD_DEPENDS%% -Standards-Version: 4.1.4 -Homepage: https://unit.nginx.org - -Package: %%NAME%% -Section: admin -Architecture: any -Depends: lsb-base, - ${misc:Depends}, ${shlibs:Depends}, - unit-r%%UNIT_VERSION%%%%MODULE_DEPENDS%% -Description: %%SUMMARY%% - NGINX Unit is a runtime and delivery environment for modern distributed - applications. It runs the application code in multiple languages - (PHP, Python, Go, etc.), and tightly couples it with traffic delivery - in and out of the application. Take this application server and proxy - directly in the cloud / container environments and fully control your app - dynamically via an API. - This package contains %%SUMMARY%%. - -Package: %%NAME%%-dbg -Section: debug -Architecture: any -Priority: extra -Depends: %%NAME%% (= ${binary:Version}), - ${misc:Depends} -Description: %%SUMMARY%% (debug symbols) - This package contains the debugging symbols for %%NAME%% diff --git a/pkg/deb/debian.module/copyright.unit-jsc-common b/pkg/deb/debian.module/copyright.unit-jsc-common deleted file mode 100644 index accb1834..00000000 --- a/pkg/deb/debian.module/copyright.unit-jsc-common +++ /dev/null @@ -1,872 +0,0 @@ - -The unit-jsc-common package includes supplementary Java archives (JARs) -required by Java servlet container module for NGINX Unit. - -Java is a registered trademark of Oracle and/or its affiliates. - -The following software components distributed under corresponding licenses: - - * classgraph-4.4.11.jar: MIT - * ecj-3.13.102.jar: EPL 1.0 - * jetty-http-9.4.12.v20180830.jar: Apache 2.0 + EPL 1.0 - * jetty-server-9.4.12.v20180830.jar: Apache 2.0 + EPL 1.0 - * jetty-util-9.4.12.v20180830.jar: Apache 2.0 + EPL 1.0 - * tomcat-api-9.0.13.jar: Apache 2.0 - * tomcat-el-api-9.0.13.jar: Apache 2.0 - * tomcat-jasper-9.0.13.jar: Apache 2.0 - * tomcat-jasper-el-9.0.13.jar: Apache 2.0 - * tomcat-jsp-api-9.0.13.jar: Apache 2.0 - * tomcat-juli-9.0.13.jar: Apache 2.0 - * tomcat-servlet-api-9.0.13.jar: Apache 2.0 + CDDL 1.0 - * tomcat-util-9.0.13.jar: Apache 2.0 - * tomcat-util-scan-9.0.13.jar: Apache 2.0 - -Licenses could be found by the following links and below in this file: - - - MIT (The MIT License): - http://www.opensource.org/licenses/MIT - - - EPL (Eclipse Public License) v1.0: - https://www.eclipse.org/legal/epl-v10.html - - - Apache 2.0: - http://www.apache.org/licenses/LICENSE-2.0.html - - - CDDL (Common Development and Distribution License) v1.0: - https://opensource.org/licenses/CDDL-1.0 - - -====[ MIT license - begin ]=================================================== - -The MIT License (MIT) - -Copyright (c) 2015 Luke Hutchison - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -====[ MIT license - end ]===================================================== - - -====[ EPL license - begin ]=================================================== - -Eclipse Public License - v1.0 - -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC -LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM -CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation -distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are -distributed by that particular Contributor. A Contribution 'originates' from a -Contributor if it was added to the Program by such Contributor itself or -anyone acting on such Contributor's behalf. Contributions do not include -additions to the Program which: (i) are separate modules of software -distributed in conjunction with the Program under their own license agreement, -and (ii) are not derivative works of the Program. "Contributor" means any -person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are -necessarily infringed by the use or sale of its Contribution alone or when -combined with the Program. - -"Program" means the Contributions distributed in accordance with this -Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, -including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free copyright license to -reproduce, prepare derivative works of, publicly display, publicly perform, -distribute and sublicense the Contribution of such Contributor, if any, and -such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free patent license under -Licensed Patents to make, use, sell, offer to sell, import and otherwise -transfer the Contribution of such Contributor, if any, in source code and -object code form. This patent license shall apply to the combination of the -Contribution and the Program if, at the time the Contribution is added by the -Contributor, such addition of the Contribution causes such combination to be -covered by the Licensed Patents. The patent license shall not apply to any -other combinations which include the Contribution. No hardware per se is -licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to -its Contributions set forth herein, no assurances are provided by any -Contributor that the Program does not infringe the patent or other -intellectual property rights of any other entity. Each Contributor disclaims -any liability to Recipient for claims brought by any other entity based on -infringement of intellectual property rights or otherwise. As a condition to -exercising the rights and licenses granted hereunder, each Recipient hereby -assumes sole responsibility to secure any other intellectual property rights -needed, if any. For example, if a third party patent license is required to -allow Recipient to distribute the Program, it is Recipient's responsibility to -acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient -copyright rights in its Contribution, if any, to grant the copyright license -set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under -its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and -conditions, express and implied, including warranties or conditions of title -and non-infringement, and implied warranties or conditions of merchantability -and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for -damages, including direct, indirect, special, incidental and consequential -damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered -by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such -Contributor, and informs licensees how to obtain it in a reasonable manner on -or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within -the Program. - -Each Contributor must identify itself as the originator of its Contribution, -if any, in a manner that reasonably allows subsequent Recipients to identify -the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with -respect to end users, business partners and the like. While this license is -intended to facilitate the commercial use of the Program, the Contributor who -includes the Program in a commercial product offering should do so in a manner -which does not create potential liability for other Contributors. Therefore, -if a Contributor includes the Program in a commercial product offering, such -Contributor ("Commercial Contributor") hereby agrees to defend and indemnify -every other Contributor ("Indemnified Contributor") against any losses, -damages and costs (collectively "Losses") arising from claims, lawsuits and -other legal actions brought by a third party against the Indemnified -Contributor to the extent caused by the acts or omissions of such Commercial -Contributor in connection with its distribution of the Program in a commercial -product offering. The obligations in this section do not apply to any claims -or Losses relating to any actual or alleged intellectual property -infringement. In order to qualify, an Indemnified Contributor must: a) -promptly notify the Commercial Contributor in writing of such claim, and b) -allow the Commercial Contributor to control, and cooperate with the Commercial -Contributor in, the defense and any related settlement negotiations. The -Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product -offering, Product X. That Contributor is then a Commercial Contributor. If -that Commercial Contributor then makes performance claims, or offers -warranties related to Product X, those performance claims and warranties are -such Commercial Contributor's responsibility alone. Under this section, the -Commercial Contributor would have to defend claims against the other -Contributors related to those performance claims and warranties, and if a -court requires any other Contributor to pay any damages as a result, the -Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR -IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, -NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each -Recipient is solely responsible for determining the appropriateness of using -and distributing the Program and assumes all risks associated with its -exercise of rights under this Agreement , including but not limited to the -risks and costs of program errors, compliance with applicable laws, damage to -or loss of data, programs or equipment, and unavailability or interruption of -operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY -CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION -LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE -EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under -applicable law, it shall not affect the validity or enforceability of the -remainder of the terms of this Agreement, and without further action by the -parties hereto, such provision shall be reformed to the minimum extent -necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Program itself -(excluding combinations of the Program with other software or hardware) -infringes such Recipient's patent(s), then such Recipient's rights granted -under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to -comply with any of the material terms or conditions of this Agreement and does -not cure such failure in a reasonable period of time after becoming aware of -such noncompliance. If all Recipient's rights under this Agreement terminate, -Recipient agrees to cease use and distribution of the Program as soon as -reasonably practicable. However, Recipient's obligations under this Agreement -and any licenses granted by Recipient relating to the Program shall continue -and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in -order to avoid inconsistency the Agreement is copyrighted and may only be -modified in the following manner. The Agreement Steward reserves the right to -publish new versions (including revisions) of this Agreement from time to -time. No one other than the Agreement Steward has the right to modify this -Agreement. The Eclipse Foundation is the initial Agreement Steward. The -Eclipse Foundation may assign the responsibility to serve as the Agreement -Steward to a suitable separate entity. Each new version of the Agreement will -be given a distinguishing version number. The Program (including -Contributions) may always be distributed subject to the version of the -Agreement under which it was received. In addition, after a new version of the -Agreement is published, Contributor may elect to distribute the Program -(including its Contributions) under the new version. Except as expressly -stated in Sections 2(a) and 2(b) above, Recipient receives no rights or -licenses to the intellectual property of any Contributor under this Agreement, -whether expressly, by implication, estoppel or otherwise. All rights in the -Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the -intellectual property laws of the United States of America. No party to this -Agreement will bring a legal action under this Agreement more than one year -after the cause of action arose. Each party waives its rights to a jury trial -in any resulting litigation. - -====[ EPL license - begin ]=================================================== - - -====[ Apache 2.0 license - begin ]============================================ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -====[ Apache 2.0 license - end ]============================================== - - -====[ CDDL v1.0 license - start ]============================================= - -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0 - -1. Definitions. - - 1.1. "Contributor" means each individual or entity that creates - or contributes to the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Software, prior Modifications used by a Contributor (if any), - and the Modifications made by that particular Contributor. - - 1.3. "Covered Software" means (a) the Original Software, or (b) - Modifications, or (c) the combination of files containing - Original Software with files containing Modifications, in - each case including portions thereof. - - 1.4. "Executable" means the Covered Software in any form other - than Source Code. - - 1.5. "Initial Developer" means the individual or entity that first - makes Original Software available under this License. - - 1.6. "Larger Work" means a work which combines Covered Software or - portions thereof with code not governed by the terms of this - License. - - 1.7. "License" means this document. - - 1.8. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed - herein. - - 1.9. "Modifications" means the Source Code and Executable form of - any of the following: - - A. Any file that results from an addition to, deletion from or - modification of the contents of a file containing Original - Software or previous Modifications; - - B. Any new file that contains any part of the Original - Software or previous Modifications; or - - C. Any new file that is contributed or otherwise made - available under the terms of this License. - - 1.10. "Original Software" means the Source Code and Executable - form of computer software code that is originally released - under this License. - - 1.11. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, - process, and apparatus claims, in any patent Licensable by - grantor. - - 1.12. "Source Code" means (a) the common form of computer software - code in which modifications are made and (b) associated - documentation included in or with such code. - - 1.13. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms - of, this License. For legal entities, "You" includes any - entity which controls, is controlled by, or is under common - control with You. For purposes of this definition, - "control" means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by - contract or otherwise, or (b) ownership of more than fifty - percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants. - - 2.1. The Initial Developer Grant. - - Conditioned upon Your compliance with Section 3.1 below and - subject to third party intellectual property claims, the Initial - Developer hereby grants You a world-wide, royalty-free, - non-exclusive license: - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer, to use, - reproduce, modify, display, perform, sublicense and - distribute the Original Software (or portions thereof), - with or without Modifications, and/or as part of a Larger - Work; and - - (b) under Patent Claims infringed by the making, using or - selling of Original Software, to make, have made, use, - practice, sell, and offer for sale, and/or otherwise - dispose of the Original Software (or portions thereof). - - (c) The licenses granted in Sections 2.1(a) and (b) are - effective on the date Initial Developer first distributes - or otherwise makes the Original Software available to a - third party under the terms of this License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: (1) for code that You delete from the Original - Software, or (2) for infringements caused by: (i) the - modification of the Original Software, or (ii) the - combination of the Original Software with other software - or devices. - - 2.2. Contributor Grant. - - Conditioned upon Your compliance with Section 3.1 below and - subject to third party intellectual property claims, each - Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor to use, reproduce, - modify, display, perform, sublicense and distribute the - Modifications created by such Contributor (or portions - thereof), either on an unmodified basis, with other - Modifications, as Covered Software and/or as part of a - Larger Work; and - - (b) under Patent Claims infringed by the making, using, or - selling of Modifications made by that Contributor either - alone and/or in combination with its Contributor Version - (or portions of such combination), to make, use, sell, - offer for sale, have made, and/or otherwise dispose of: - (1) Modifications made by that Contributor (or portions - thereof); and (2) the combination of Modifications made by - that Contributor with its Contributor Version (or portions - of such combination). - - (c) The licenses granted in Sections 2.2(a) and 2.2(b) are - effective on the date Contributor first distributes or - otherwise makes the Modifications available to a third - party. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: (1) for any code that Contributor has deleted - from the Contributor Version; (2) for infringements caused - by: (i) third party modifications of Contributor Version, - or (ii) the combination of Modifications made by that - Contributor with other software (except as part of the - Contributor Version) or other devices; or (3) under Patent - Claims infringed by Covered Software in the absence of - Modifications made by that Contributor. - -3. Distribution Obligations. - - 3.1. Availability of Source Code. - - Any Covered Software that You distribute or otherwise make - available in Executable form must also be made available in Source - Code form and that Source Code form must be distributed only under - the terms of this License. You must include a copy of this - License with every copy of the Source Code form of the Covered - Software You distribute or otherwise make available. You must - inform recipients of any such Covered Software in Executable form - as to how they can obtain such Covered Software in Source Code - form in a reasonable manner on or through a medium customarily - used for software exchange. - - 3.2. Modifications. - - The Modifications that You create or to which You contribute are - governed by the terms of this License. You represent that You - believe Your Modifications are Your original creation(s) and/or - You have sufficient rights to grant the rights conveyed by this - License. - - 3.3. Required Notices. - - You must include a notice in each of Your Modifications that - identifies You as the Contributor of the Modification. You may - not remove or alter any copyright, patent or trademark notices - contained within the Covered Software, or any notices of licensing - or any descriptive text giving attribution to any Contributor or - the Initial Developer. - - 3.4. Application of Additional Terms. - - You may not offer or impose any terms on any Covered Software in - Source Code form that alters or restricts the applicable version - of this License or the recipients' rights hereunder. You may - choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of - Covered Software. However, you may do so only on Your own behalf, - and not on behalf of the Initial Developer or any Contributor. - You must make it absolutely clear that any such warranty, support, - indemnity or liability obligation is offered by You alone, and You - hereby agree to indemnify the Initial Developer and every - Contributor for any liability incurred by the Initial Developer or - such Contributor as a result of warranty, support, indemnity or - liability terms You offer. - - 3.5. Distribution of Executable Versions. - - You may distribute the Executable form of the Covered Software - under the terms of this License or under the terms of a license of - Your choice, which may contain terms different from this License, - provided that You are in compliance with the terms of this License - and that the license for the Executable form does not attempt to - limit or alter the recipient's rights in the Source Code form from - the rights set forth in this License. If You distribute the - Covered Software in Executable form under a different license, You - must make it absolutely clear that any terms which differ from - this License are offered by You alone, not by the Initial - Developer or Contributor. You hereby agree to indemnify the - Initial Developer and every Contributor for any liability incurred - by the Initial Developer or such Contributor as a result of any - such terms You offer. - - 3.6. Larger Works. - - You may create a Larger Work by combining Covered Software with - other code not governed by the terms of this License and - distribute the Larger Work as a single product. In such a case, - You must make sure the requirements of this License are fulfilled - for the Covered Software. - -4. Versions of the License. - - 4.1. New Versions. - - Sun Microsystems, Inc. is the initial license steward and may - publish revised and/or new versions of this License from time to - time. Each version will be given a distinguishing version number. - Except as provided in Section 4.3, no one other than the license - steward has the right to modify this License. - - 4.2. Effect of New Versions. - - You may always continue to use, distribute or otherwise make the - Covered Software available under the terms of the version of the - License under which You originally received the Covered Software. - If the Initial Developer includes a notice in the Original - Software prohibiting it from being distributed or otherwise made - available under any subsequent version of the License, You must - distribute and make the Covered Software available under the terms - of the version of the License under which You originally received - the Covered Software. Otherwise, You may also choose to use, - distribute or otherwise make the Covered Software available under - the terms of any subsequent version of the License published by - the license steward. - - 4.3. Modified Versions. - - When You are an Initial Developer and You want to create a new - license for Your Original Software, You may create and use a - modified version of this License if You: (a) rename the license - and remove any references to the name of the license steward - (except to note that the license differs from this License); and - (b) otherwise make it clear that the license contains terms which - differ from this License. - -5. DISCLAIMER OF WARRANTY. - - COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" - BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, - INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED - SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR - PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND - PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY - COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE - INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY - NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF - WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF - ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS - DISCLAIMER. - -6. TERMINATION. - - 6.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to - cure such breach within 30 days of becoming aware of the breach. - Provisions which, by their nature, must remain in effect beyond - the termination of this License shall survive. - - 6.2. If You assert a patent infringement claim (excluding - declaratory judgment actions) against Initial Developer or a - Contributor (the Initial Developer or Contributor against whom You - assert such claim is referred to as "Participant") alleging that - the Participant Software (meaning the Contributor Version where - the Participant is a Contributor or the Original Software where - the Participant is the Initial Developer) directly or indirectly - infringes any patent, then any and all rights granted directly or - indirectly to You by such Participant, the Initial Developer (if - the Initial Developer is not the Participant) and all Contributors - under Sections 2.1 and/or 2.2 of this License shall, upon 60 days - notice from Participant terminate prospectively and automatically - at the expiration of such 60 day notice period, unless if within - such 60 day period You withdraw Your claim with respect to the - Participant Software against such Participant either unilaterally - or pursuant to a written agreement with Participant. - - 6.3. In the event of termination under Sections 6.1 or 6.2 above, - all end user licenses that have been validly granted by You or any - distributor hereunder prior to termination (excluding licenses - granted to You by any distributor) shall survive termination. - -7. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE - INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF - COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE - LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR - CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT - LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK - STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER - COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN - INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF - LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL - INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT - APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO - NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR - CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT - APPLY TO YOU. - -8. U.S. GOVERNMENT END USERS. - - The Covered Software is a "commercial item," as that term is - defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 - C.F.R. 252.227-7014(a)(1)) and "commercial computer software - documentation" as such terms are used in 48 C.F.R. 12.212 - (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 - C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all - U.S. Government End Users acquire Covered Software with only those - rights set forth herein. This U.S. Government Rights clause is in - lieu of, and supersedes, any other FAR, DFAR, or other clause or - provision that addresses Government rights in computer software - under this License. - -9. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed - by the law of the jurisdiction specified in a notice contained - within the Original Software (except to the extent applicable law, - if any, provides otherwise), excluding such jurisdiction's - conflict-of-law provisions. Any litigation relating to this - License shall be subject to the jurisdiction of the courts located - in the jurisdiction and venue specified in a notice contained - within the Original Software, with the losing party responsible - for costs, including, without limitation, court costs and - reasonable attorneys' fees and expenses. The application of the - United Nations Convention on Contracts for the International Sale - of Goods is expressly excluded. Any law or regulation which - provides that the language of a contract shall be construed - against the drafter shall not apply to this License. You agree - that You alone are responsible for compliance with the United - States export administration regulations (and the export control - laws and regulation of any other countries) when You use, - distribute or otherwise make available any Covered Software. - -10. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or - indirectly, out of its utilization of rights under this License - and You agree to work with Initial Developer and Contributors to - distribute such responsibility on an equitable basis. Nothing - herein is intended or shall be deemed to constitute any admission - of liability. - --------------------------------------------------------------------- - -NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND -DISTRIBUTION LICENSE (CDDL) - -For Covered Software in this distribution, this License shall -be governed by the laws of the State of California (excluding -conflict-of-law provisions). - -Any litigation relating to this License shall be subject to the -jurisdiction of the Federal Courts of the Northern District of -California and the state courts of the State of California, with -venue lying in Santa Clara County, California. - -====[ CDDL v1.0 license - end ]=============================================== diff --git a/pkg/deb/debian.module/copyright.unit-jsc11 b/pkg/deb/debian.module/copyright.unit-jsc11 deleted file mode 100644 index 6e512e86..00000000 --- a/pkg/deb/debian.module/copyright.unit-jsc11 +++ /dev/null @@ -1,42 +0,0 @@ - - NGINX Unit. - - Copyright 2017-2024 NGINX, Inc. - Copyright 2017-2024 Andrei Zeliankou - Copyright 2018-2024 Konstantin Pavlov - Copyright 2021-2024 Zhidao Hong - Copyright 2022-2024 Andrew Clayton - Copyright 2022-2024 Liam Crilly - Copyright 2023-2024 Dan Callahan - Copyright 2023-2024 Danielle De Leo - Copyright 2023-2024 Dylan Arbour - Copyright 2023-2024 Gabor Javorszky - Copyright 2023-2024 Igor Ippolitov - Copyright 2023-2024 Taryn Musgrave - Copyright 2021-2023 Alejandro Colomar - Copyright 2017-2022 Valentin V. Bartenev - Copyright 2017-2022 Max Romanov - Copyright 2021-2022 Oisín Canty - Copyright 2017-2021 Igor Sysoev - Copyright 2017-2021 Andrei Belov - Copyright 2019-2021 Tiago Natel de Moura - Copyright 2019-2020 Axel Duch - Copyright 2018-2019 Alexander Borisov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - /usr/share/common-licenses/Apache-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - The unit-jsc11 package provides Java servlet container module - for NGINX Unit. - - Java is a registered trademark of Oracle and/or its affiliates. diff --git a/pkg/deb/debian.module/copyright.unit-jsc8 b/pkg/deb/debian.module/copyright.unit-jsc8 deleted file mode 100644 index 60da2dfa..00000000 --- a/pkg/deb/debian.module/copyright.unit-jsc8 +++ /dev/null @@ -1,42 +0,0 @@ - - NGINX Unit. - - Copyright 2017-2024 NGINX, Inc. - Copyright 2017-2024 Andrei Zeliankou - Copyright 2018-2024 Konstantin Pavlov - Copyright 2021-2024 Zhidao Hong - Copyright 2022-2024 Andrew Clayton - Copyright 2022-2024 Liam Crilly - Copyright 2023-2024 Dan Callahan - Copyright 2023-2024 Danielle De Leo - Copyright 2023-2024 Dylan Arbour - Copyright 2023-2024 Gabor Javorszky - Copyright 2023-2024 Igor Ippolitov - Copyright 2023-2024 Taryn Musgrave - Copyright 2021-2023 Alejandro Colomar - Copyright 2017-2022 Valentin V. Bartenev - Copyright 2017-2022 Max Romanov - Copyright 2021-2022 Oisín Canty - Copyright 2017-2021 Igor Sysoev - Copyright 2017-2021 Andrei Belov - Copyright 2019-2021 Tiago Natel de Moura - Copyright 2019-2020 Axel Duch - Copyright 2018-2019 Alexander Borisov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - /usr/share/common-licenses/Apache-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - The unit-jsc8 package provides Java servlet container module - for NGINX Unit. - - Java is a registered trademark of Oracle and/or its affiliates. diff --git a/pkg/deb/debian.module/preinst.in b/pkg/deb/debian.module/preinst.in deleted file mode 100644 index 51bdfc93..00000000 --- a/pkg/deb/debian.module/preinst.in +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -set -e - -case "$1" in - install) -%%MODULE_POST%% - ;; - upgrade) - ;; - abort-upgrade) - ;; - *) - echo "preinst called with unknown argument \`$1'" >&2 - exit 0 - ;; -esac - -#DEBHELPER# - -exit 0 diff --git a/pkg/deb/debian.module/rules-noarch.in b/pkg/deb/debian.module/rules-noarch.in deleted file mode 100644 index e56e06bc..00000000 --- a/pkg/deb/debian.module/rules-noarch.in +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/make -f - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -export DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie -export DEB_CFLAGS_MAINT_APPEND=-Wp,-D_FORTIFY_SOURCE=2 -fPIC -DPKG_EXPORT_BUILDFLAGS = 1 -include /usr/share/dpkg/buildflags.mk - -BUILDDIR_unit = $(CURDIR)/debian/build-unit -BUILDDIR_unit_debug = $(CURDIR)/debian/build-unit-debug -INSTALLDIR = $(CURDIR)/debian/%%NAME%% -BASEDIR = $(CURDIR) - -%%MODULE_DEFINITIONS%% - -config.env.%: - dh_testdir - mkdir -p $(BUILDDIR_$*) - cp -Pa $(CURDIR)/auto $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/configure $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/src $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/test $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/version $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/CHANGES $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/LICENSE $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/NOTICE $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/README.md $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/CONTRIBUTING.md $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/go $(BUILDDIR_$*)/ - touch $@ - -configure.unit: config.env.unit - cd $(BUILDDIR_unit) && \ - CFLAGS= ./configure \ - %%CONFIGURE_ARGS%% \ - --modulesdir=/usr/lib/unit/modules \ - --cc-opt="$(CFLAGS)" && \ - ./configure %%MODULE_CONFARGS%% - touch $@ - -configure.unit_debug: config.env.unit_debug - cd $(BUILDDIR_unit_debug) && \ - CFLAGS= ./configure \ - %%CONFIGURE_ARGS%% \ - --modulesdir=/usr/lib/unit/debug-modules \ - --cc-opt="$(CFLAGS)" \ - --debug && \ - ./configure %%MODULE_CONFARGS%% - touch $@ - -build-arch.%: configure.% - dh_testdir - $(MAKE) -C $(BUILDDIR_$*) %%MODULE_MAKEARGS%% - touch $@ - -build-indep: - dh_testdir - touch $@ - -build-arch: build-arch.unit build-arch.unit_debug - dh_testdir - touch $@ - -build: build-arch build-indep - dh_testdir - touch $@ - -clean: - dh_testdir - dh_testroot - dh_clean - find $(CURDIR) -maxdepth 1 -size 0 -delete - rm -rf $(BUILDDIR_unit) $(BUILDDIR_unit_debug) - -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs - dh_installinit - dh_installlogrotate -%%MODULE_PREINSTALL%% - cd $(BUILDDIR_unit) && \ - DESTDIR=$(INSTALLDIR) make %%MODULE_INSTARGS%% - cd $(BUILDDIR_unit_debug) && \ - DESTDIR=$(INSTALLDIR) make %%MODULE_INSTARGS%% -%%MODULE_POSTINSTALL%% - -binary-indep: build install - dh_testdir - dh_testroot - dh_installdocs - dh_installchangelogs - dh_link - dh_compress - dh_fixperms - dh_installdeb - dh_perl - dh_gencontrol - dh_md5sums - dh_builddeb - -binary-arch: install - -binary: binary-indep binary-arch - -.PHONY: clean binary-indep binary-arch binary install build diff --git a/pkg/deb/debian.module/rules.in b/pkg/deb/debian.module/rules.in deleted file mode 100755 index 7814fbfd..00000000 --- a/pkg/deb/debian.module/rules.in +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/make -f - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -export DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie -export DEB_CFLAGS_MAINT_APPEND=-Wp,-D_FORTIFY_SOURCE=2 -fPIC -DPKG_EXPORT_BUILDFLAGS = 1 -include /usr/share/dpkg/buildflags.mk - -BUILDDIR_unit = $(CURDIR)/debian/build-unit -BUILDDIR_unit_debug = $(CURDIR)/debian/build-unit-debug -INSTALLDIR = $(CURDIR)/debian/%%NAME%% -BASEDIR = $(CURDIR) - -%%MODULE_DEFINITIONS%% - -config.env.%: - dh_testdir -%%MODULE_PREBUILD%% - mkdir -p $(BUILDDIR_$*) - cp -Pa $(CURDIR)/auto $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/configure $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/src $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/test $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/version $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/CHANGES $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/LICENSE $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/NOTICE $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/README.md $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/CONTRIBUTING.md $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/go $(BUILDDIR_$*)/ - touch $@ - -configure.unit: config.env.unit - cd $(BUILDDIR_unit) && \ - CFLAGS= ./configure \ - %%CONFIGURE_ARGS%% \ - --modulesdir=/usr/lib/unit/modules \ - --cc-opt="$(CFLAGS)" && \ - ./configure %%MODULE_CONFARGS%% - touch $@ - -configure.unit_debug: config.env.unit_debug - cd $(BUILDDIR_unit_debug) && \ - CFLAGS= ./configure \ - %%CONFIGURE_ARGS%% \ - --modulesdir=/usr/lib/unit/debug-modules \ - --cc-opt="$(CFLAGS)" \ - --debug && \ - ./configure %%MODULE_CONFARGS%% - touch $@ - -build-arch.%: configure.% - dh_testdir - $(MAKE) -C $(BUILDDIR_$*) %%MODULE_MAKEARGS%% - touch $@ - -build-indep: - dh_testdir - touch $@ - -build-arch: build-arch.unit build-arch.unit_debug - dh_testdir - touch $@ - -build: build-arch build-indep - dh_testdir - touch $@ - -clean: - dh_testdir - dh_testroot - dh_clean - find $(CURDIR) -maxdepth 1 -size 0 -delete - rm -rf $(BUILDDIR_unit) $(BUILDDIR_unit_debug) - -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs - dh_installinit - dh_installlogrotate -%%MODULE_PREINSTALL%% - cd $(BUILDDIR_unit) && \ - DESTDIR=$(INSTALLDIR) make %%MODULE_INSTARGS%% - cd $(BUILDDIR_unit_debug) && \ - DESTDIR=$(INSTALLDIR) make %%MODULE_INSTARGS%% -%%MODULE_POSTINSTALL%% - -binary-indep: build install - dh_testdir - dh_testroot - dh_installdocs - dh_installchangelogs - dh_link - dh_strip --dbg-package=%%NAME%%-dbg - dh_shlibdeps - dh_compress - dh_fixperms - dh_installdeb - dh_perl - dh_gencontrol - dh_md5sums - dh_builddeb - -binary-arch: install - -binary: binary-indep binary-arch - -.PHONY: clean binary-indep binary-arch binary install build diff --git a/pkg/deb/debian.module/unit.example-go-app b/pkg/deb/debian.module/unit.example-go-app deleted file mode 100644 index 6eec1dbb..00000000 --- a/pkg/deb/debian.module/unit.example-go-app +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - "unit.nginx.org/go" -) - -func handler(w http.ResponseWriter, r *http.Request) { - w.Header().Add("Content-Type", "text/plain"); - - fmt.Fprintf(w, "Method : %s\n", r.Method) - fmt.Fprintf(w, "URL : %s\n", r.URL.Path) - fmt.Fprintf(w, "Host : %s\n", r.Host) -} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe("8000", nil) -} diff --git a/pkg/deb/debian.module/unit.example-go-config b/pkg/deb/debian.module/unit.example-go-config deleted file mode 100644 index 8aa65939..00000000 --- a/pkg/deb/debian.module/unit.example-go-config +++ /dev/null @@ -1,14 +0,0 @@ -{ - "applications": { - "example_go": { - "type": "external", - "executable": "/tmp/go-app" - } - }, - - "listeners": { - "*:8500": { - "pass": "applications/example_go" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-jsc-app b/pkg/deb/debian.module/unit.example-jsc-app deleted file mode 100644 index be01e123..00000000 --- a/pkg/deb/debian.module/unit.example-jsc-app +++ /dev/null @@ -1,12 +0,0 @@ -<%@ page contentType="text/plain"%><%@ page import="java.util.*" %>This is plain text response for "<%= request.getMethod() %> <%= request.getRequestURI() %>". -Here is the list of all system properties: -<% - Properties p = System.getProperties(); - Enumeration keys = p.keys(); - while (keys.hasMoreElements()) { - String key = (String) keys.nextElement(); - String value = (String) p.get(key); - out.println(" " + key + " : " + value); - } -%> -<% response.addHeader("X-Unit-JSP", "ok"); %> diff --git a/pkg/deb/debian.module/unit.example-jsc11-config b/pkg/deb/debian.module/unit.example-jsc11-config deleted file mode 100644 index 3f7dd518..00000000 --- a/pkg/deb/debian.module/unit.example-jsc11-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java11": { - "processes": 1, - "type": "java 11", - "webapp": "/usr/share/doc/unit-jsc11/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java11" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-jsc16-config b/pkg/deb/debian.module/unit.example-jsc16-config deleted file mode 100644 index 0b10a44d..00000000 --- a/pkg/deb/debian.module/unit.example-jsc16-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java16": { - "processes": 1, - "type": "java 16", - "webapp": "/usr/share/doc/unit-jsc16/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java16" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-jsc17-config b/pkg/deb/debian.module/unit.example-jsc17-config deleted file mode 100644 index 28b13e4d..00000000 --- a/pkg/deb/debian.module/unit.example-jsc17-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java17": { - "processes": 1, - "type": "java 17", - "webapp": "/usr/share/doc/unit-jsc17/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java17" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-jsc18-config b/pkg/deb/debian.module/unit.example-jsc18-config deleted file mode 100644 index 08f9f596..00000000 --- a/pkg/deb/debian.module/unit.example-jsc18-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java18": { - "processes": 1, - "type": "java 18", - "webapp": "/usr/share/doc/unit-jsc18/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java18" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-jsc19-config b/pkg/deb/debian.module/unit.example-jsc19-config deleted file mode 100644 index 106b694b..00000000 --- a/pkg/deb/debian.module/unit.example-jsc19-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java19": { - "processes": 1, - "type": "java 19", - "webapp": "/usr/share/doc/unit-jsc19/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java19" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-jsc20-config b/pkg/deb/debian.module/unit.example-jsc20-config deleted file mode 100644 index 57865a45..00000000 --- a/pkg/deb/debian.module/unit.example-jsc20-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java20": { - "processes": 1, - "type": "java 20", - "webapp": "/usr/share/doc/unit-jsc20/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java20" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-jsc21-config b/pkg/deb/debian.module/unit.example-jsc21-config deleted file mode 100644 index a20cff8f..00000000 --- a/pkg/deb/debian.module/unit.example-jsc21-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java21": { - "processes": 1, - "type": "java 21", - "webapp": "/usr/share/doc/unit-jsc21/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java21" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-jsc8-config b/pkg/deb/debian.module/unit.example-jsc8-config deleted file mode 100644 index 4d79112f..00000000 --- a/pkg/deb/debian.module/unit.example-jsc8-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java8": { - "processes": 1, - "type": "java 1.8.0", - "webapp": "/usr/share/doc/unit-jsc8/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java8" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-perl-app b/pkg/deb/debian.module/unit.example-perl-app deleted file mode 100644 index 33be1d3e..00000000 --- a/pkg/deb/debian.module/unit.example-perl-app +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env perl - -use Data::Dumper; - -my $app = sub { - my $env = shift; - return [ - '200', - [ 'Content-Type' => 'text/plain' ], - [ "Hello from Unit, Perl $^V, environment:\n\n", Dumper($env) ], - ]; -}; diff --git a/pkg/deb/debian.module/unit.example-perl-config b/pkg/deb/debian.module/unit.example-perl-config deleted file mode 100644 index 2182fc46..00000000 --- a/pkg/deb/debian.module/unit.example-perl-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_perl": { - "type": "perl", - "processes": 1, - "working_directory": "/usr/share/doc/unit-perl/examples/perl-app", - "script": "/usr/share/doc/unit-perl/examples/perl-app/index.pl" - } - }, - - "listeners": { - "*:8600": { - "pass": "applications/example_perl" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-php-app b/pkg/deb/debian.module/unit.example-php-app deleted file mode 100644 index 147cebcd..00000000 --- a/pkg/deb/debian.module/unit.example-php-app +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pkg/deb/debian.module/unit.example-php-config b/pkg/deb/debian.module/unit.example-php-config deleted file mode 100644 index 9673385f..00000000 --- a/pkg/deb/debian.module/unit.example-php-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_php": { - "type": "php", - "processes": 2, - "root": "/usr/share/doc/unit-php/examples/phpinfo-app", - "index": "index.php" - } - }, - - "listeners": { - "*:8300": { - "pass": "applications/example_php" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-python-app b/pkg/deb/debian.module/unit.example-python-app deleted file mode 100644 index 4146fb52..00000000 --- a/pkg/deb/debian.module/unit.example-python-app +++ /dev/null @@ -1,16 +0,0 @@ -import os -import datetime -import sys - -def application(environ, start_response): - output = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p") - output += "\n\nPython: " - output += sys.version - output += "\n\nENV Variables:\n\n" - for param in os.environ.keys(): - output += param - output += "\t" - output += os.environ[param] - output += "\n" - start_response('200 OK', [('Content-type', 'text/plain')]) - return [s.encode('utf8') for s in output] diff --git a/pkg/deb/debian.module/unit.example-python2.7-config b/pkg/deb/debian.module/unit.example-python2.7-config deleted file mode 100644 index 4f1d16c9..00000000 --- a/pkg/deb/debian.module/unit.example-python2.7-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 2.7", - "processes": 2, - "path": "/usr/share/doc/unit-python2.7/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-python3.10-config b/pkg/deb/debian.module/unit.example-python3.10-config deleted file mode 100644 index eaeb6103..00000000 --- a/pkg/deb/debian.module/unit.example-python3.10-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.10", - "processes": 2, - "path": "/usr/share/doc/unit-python3.10/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-python3.11-config b/pkg/deb/debian.module/unit.example-python3.11-config deleted file mode 100644 index 39b31b57..00000000 --- a/pkg/deb/debian.module/unit.example-python3.11-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.11", - "processes": 2, - "path": "/usr/share/doc/unit-python3.11/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-python3.12-config b/pkg/deb/debian.module/unit.example-python3.12-config deleted file mode 100644 index 37b65f1f..00000000 --- a/pkg/deb/debian.module/unit.example-python3.12-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.12", - "processes": 2, - "path": "/usr/share/doc/unit-python3.12/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-python3.6-config b/pkg/deb/debian.module/unit.example-python3.6-config deleted file mode 100644 index 543024ff..00000000 --- a/pkg/deb/debian.module/unit.example-python3.6-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.6", - "processes": 2, - "path": "/usr/share/doc/unit-python3.6/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-python3.7-config b/pkg/deb/debian.module/unit.example-python3.7-config deleted file mode 100644 index e7b8dbc3..00000000 --- a/pkg/deb/debian.module/unit.example-python3.7-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.7", - "processes": 2, - "path": "/usr/share/doc/unit-python3.7/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-python3.8-config b/pkg/deb/debian.module/unit.example-python3.8-config deleted file mode 100644 index dc649e30..00000000 --- a/pkg/deb/debian.module/unit.example-python3.8-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.8", - "processes": 2, - "path": "/usr/share/doc/unit-python3.8/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-python3.9-config b/pkg/deb/debian.module/unit.example-python3.9-config deleted file mode 100644 index fdb7e9db..00000000 --- a/pkg/deb/debian.module/unit.example-python3.9-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.9", - "processes": 2, - "path": "/usr/share/doc/unit-python3.9/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/deb/debian.module/unit.example-ruby-app b/pkg/deb/debian.module/unit.example-ruby-app deleted file mode 100644 index 69b015b7..00000000 --- a/pkg/deb/debian.module/unit.example-ruby-app +++ /dev/null @@ -1,7 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'Content-Type' => 'text/plain', - }, ["Hello from Unit running with Ruby #{RUBY_VERSION}!\n\n"]] -end - -run app diff --git a/pkg/deb/debian.module/unit.example-ruby-config b/pkg/deb/debian.module/unit.example-ruby-config deleted file mode 100644 index 930aa987..00000000 --- a/pkg/deb/debian.module/unit.example-ruby-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_ruby": { - "type": "ruby", - "processes": 2, - "script": "/usr/share/doc/unit-ruby/examples/ruby-app.ru" - } - }, - - "listeners": { - "*:8700": { - "pass": "applications/example_ruby" - } - } -} diff --git a/pkg/deb/debian/control.in b/pkg/deb/debian/control.in deleted file mode 100644 index bc757233..00000000 --- a/pkg/deb/debian/control.in +++ /dev/null @@ -1,45 +0,0 @@ -Source: unit -Section: admin -Priority: extra -Maintainer: %%PACKAGE_VENDOR%% -Build-Depends: debhelper (>= 11), - linux-libc-dev, - libssl-dev, - libpcre2-dev, - pkg-config, - clang, - llvm -Standards-Version: 4.1.4 -Homepage: https://unit.nginx.org - -Package: unit -Section: admin -Architecture: any -Depends: lsb-base, - ${misc:Depends}, ${shlibs:Depends} -Provides: unit-r%%UNIT_VERSION%% -Description: NGINX Unit - NGINX Unit is a runtime and delivery environment for modern distributed - applications. It runs the application code in multiple languages - (PHP, Python, Go, etc.), and tightly couples it with traffic delivery - in and out of the application. Take this application server and proxy - directly in the cloud / container environments and fully control your app - dynamically via an API. - -Package: unit-dbg -Section: debug -Architecture: any -Priority: extra -Depends: unit (= ${binary:Version}), - ${misc:Depends} -Description: NGINX Unit (debug symbols) - This package contains the debugging symbols for NGINX Unit. - -Package: unit-dev -Section: libdevel -Priority: optional -Architecture: any -Depends: unit (= ${binary:Version}), - ${misc:Depends} -Description: NGINX Unit (development files) - Library and include files required for NGINX Unit modules development. diff --git a/pkg/deb/debian/copyright b/pkg/deb/debian/copyright deleted file mode 100644 index dbc37146..00000000 --- a/pkg/deb/debian/copyright +++ /dev/null @@ -1,38 +0,0 @@ - - NGINX Unit. - - Copyright 2017-2024 NGINX, Inc. - Copyright 2017-2024 Andrei Zeliankou - Copyright 2018-2024 Konstantin Pavlov - Copyright 2021-2024 Zhidao Hong - Copyright 2022-2024 Andrew Clayton - Copyright 2022-2024 Liam Crilly - Copyright 2023-2024 Dan Callahan - Copyright 2023-2024 Danielle De Leo - Copyright 2023-2024 Dylan Arbour - Copyright 2023-2024 Gabor Javorszky - Copyright 2023-2024 Igor Ippolitov - Copyright 2023-2024 Taryn Musgrave - Copyright 2021-2023 Alejandro Colomar - Copyright 2017-2022 Valentin V. Bartenev - Copyright 2017-2022 Max Romanov - Copyright 2021-2022 Oisín Canty - Copyright 2017-2021 Igor Sysoev - Copyright 2017-2021 Andrei Belov - Copyright 2019-2021 Tiago Natel de Moura - Copyright 2019-2020 Axel Duch - Copyright 2018-2019 Alexander Borisov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - /usr/share/common-licenses/Apache-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/pkg/deb/debian/dirs b/pkg/deb/debian/dirs deleted file mode 100644 index 552cdf7c..00000000 --- a/pkg/deb/debian/dirs +++ /dev/null @@ -1,5 +0,0 @@ -usr/bin -usr/sbin -usr/lib/unit -usr/include/unit -var/lib/unit diff --git a/pkg/deb/debian/rules.in b/pkg/deb/debian/rules.in deleted file mode 100644 index 55a4ebec..00000000 --- a/pkg/deb/debian/rules.in +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/make -f - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -export DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie -export DEB_CFLAGS_MAINT_APPEND=-Wp,-D_FORTIFY_SOURCE=2 -fPIC -export DEB_LDFLAGS_MAINT_APPEND=-Wl,--as-needed -pie -DPKG_EXPORT_BUILDFLAGS = 1 -include /usr/share/dpkg/buildflags.mk - -DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) -CODENAME := $(shell lsb_release -cs) - -BUILDDIR_unit = $(CURDIR)/debian/build-unit -BUILDDIR_unit_debug = $(CURDIR)/debian/build-unit-debug -INSTALLDIR = $(CURDIR)/debian/unit -INSTALLDIR_dev = $(CURDIR)/debian/unit-dev -BASEDIR = $(CURDIR) - -DOTESTS = 0 - -njs: - dh_testdir - cd pkg/contrib && make .njs - touch $@ - -libunit-wasm: - dh_testdir - cd pkg/contrib && make .libunit-wasm - touch $@ - -config.env.%: njs - dh_testdir - mkdir -p $(BUILDDIR_$*) - cp -Pa $(CURDIR)/auto $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/configure $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/src $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/test $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/tools $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/version $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/CHANGES $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/LICENSE $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/NOTICE $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/README.md $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/CONTRIBUTING.md $(BUILDDIR_$*)/ - cp -Pa $(CURDIR)/go $(BUILDDIR_$*)/ - mkdir -p $(BUILDDIR_$*)/docs/man/man8 - cp -Pa $(CURDIR)/docs/man/man8/unitd.8.in $(BUILDDIR_$*)/docs/man/man8/ - touch $@ - -configure.unit: config.env.unit - cd $(BUILDDIR_unit) && \ - PKG_CONFIG_PATH=$(CURDIR)/pkg/contrib/njs/build \ - CFLAGS= ./configure \ - %%CONFIGURE_ARGS%% \ - --modulesdir=/usr/lib/unit/modules \ - --libdir=/usr/lib/$(DEB_HOST_MULTIARCH) \ - --cc-opt="$(CFLAGS)" \ - --ld-opt="$(LDFLAGS)" - touch $@ - -configure.unit_debug: config.env.unit_debug - cd $(BUILDDIR_unit_debug) && \ - PKG_CONFIG_PATH=$(CURDIR)/pkg/contrib/njs/build \ - CFLAGS= ./configure \ - %%CONFIGURE_ARGS%% \ - --modulesdir=/usr/lib/unit/debug-modules \ - --libdir=/usr/lib/$(DEB_HOST_MULTIARCH) \ - --cc-opt="$(CFLAGS)" \ - --ld-opt="$(LDFLAGS)" \ - --debug - touch $@ - -build-arch.%: configure.% - dh_testdir - $(MAKE) -C $(BUILDDIR_$*) - $(MAKE) -C $(BUILDDIR_$*) build/lib/libunit.a -ifeq ($(DOTESTS), 1) - $(MAKE) -C $(BUILDDIR_$*) tests -endif - touch $@ - -do.tests: build - dh_testdir -ifeq ($(DOTESTS), 1) - cd $(BUILDDIR_unit) && ./build/tests - cd $(BUILDDIR_unit_debug) && ./build/tests -endif - touch $@ - -build-indep: - dh_testdir - touch $@ - -build-arch: build-arch.unit build-arch.unit_debug - dh_testdir - touch $@ - -build: build-arch build-indep libunit-wasm - dh_testdir - touch $@ - -clean: - dh_testdir - dh_testroot - dh_clean - find $(CURDIR) -maxdepth 1 -size 0 -delete - rm -rf $(BUILDDIR_unit) $(BUILDDIR_unit_debug) - -install: build do.tests - dh_testdir - dh_testroot - dh_prep - dh_installdirs - dh_installsystemd -punit --name=unit unit.service - dh_installsystemd -punit --name=unit-debug --no-start --no-enable unit-debug.service - dh_installlogrotate - cd $(BUILDDIR_unit) && DESTDIR=$(INSTALLDIR) make install - cd $(BUILDDIR_unit) && DESTDIR=$(INSTALLDIR_dev) make libunit-install - install -m 755 $(BUILDDIR_unit)/tools/unitc $(INSTALLDIR)/usr/bin/unitc - install -m 755 $(BUILDDIR_unit)/tools/setup-unit $(INSTALLDIR)/usr/bin/setup-unit - install -m 755 $(BUILDDIR_unit_debug)/build/sbin/unitd $(INSTALLDIR)/usr/sbin/unitd-debug - install -m 644 $(BUILDDIR_unit_debug)/build/lib/libunit.a $(INSTALLDIR_dev)/usr/lib/$(DEB_HOST_MULTIARCH)/libunit-debug.a - mkdir -p $(INSTALLDIR)/usr/share/doc/unit/examples - install -m 644 debian/unit.example.config $(INSTALLDIR)/usr/share/doc/unit/examples/example.config - install -m 644 CHANGES $(INSTALLDIR)/usr/share/doc/unit/changelog - install -m 644 README.md $(INSTALLDIR)/usr/share/doc/unit/ - install -m 644 CONTRIBUTING.md $(INSTALLDIR)/usr/share/doc/unit/ - install -m 644 NOTICE $(INSTALLDIR)/usr/share/doc/unit/ - mkdir -p $(INSTALLDIR_dev)/usr/include/unit - install -m644 $(CURDIR)/pkg/contrib/libunit-wasm/src/c/libunit-wasm.a $(INSTALLDIR_dev)/usr/lib/$(DEB_HOST_MULTIARCH)/libunit-wasm.a - install -m644 $(CURDIR)/pkg/contrib/libunit-wasm/src/c/include/unit/unit-wasm.h $(INSTALLDIR_dev)/usr/include/unit/ - -binary-indep: build install - dh_testdir - dh_testroot - dh_installdocs - dh_installchangelogs - dh_link - dh_strip --dbg-package=unit-dbg - dh_shlibdeps - dh_compress - dh_fixperms - dh_installdeb - dh_perl - dh_gencontrol - dh_md5sums - dh_builddeb - -binary-arch: install - -binary: binary-indep binary-arch - -.PHONY: clean binary-indep binary-arch binary install build diff --git a/pkg/deb/debian/unit-debug.service b/pkg/deb/debian/unit-debug.service deleted file mode 100644 index 252d8451..00000000 --- a/pkg/deb/debian/unit-debug.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=NGINX Unit -Wants=network-online.target -After=network-online.target - -[Service] -Type=forking -PIDFile=/var/run/unit.pid -EnvironmentFile=-/etc/default/unit -ExecStart=/usr/sbin/unitd-debug $DAEMON_ARGS -ExecReload= - -[Install] -WantedBy=multi-user.target diff --git a/pkg/deb/debian/unit.default b/pkg/deb/debian/unit.default deleted file mode 100644 index 8aff8bfe..00000000 --- a/pkg/deb/debian/unit.default +++ /dev/null @@ -1 +0,0 @@ -DAEMON_ARGS="--log /var/log/unit.log --pid /var/run/unit.pid" diff --git a/pkg/deb/debian/unit.example-go-app b/pkg/deb/debian/unit.example-go-app deleted file mode 100644 index 6eec1dbb..00000000 --- a/pkg/deb/debian/unit.example-go-app +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - "unit.nginx.org/go" -) - -func handler(w http.ResponseWriter, r *http.Request) { - w.Header().Add("Content-Type", "text/plain"); - - fmt.Fprintf(w, "Method : %s\n", r.Method) - fmt.Fprintf(w, "URL : %s\n", r.URL.Path) - fmt.Fprintf(w, "Host : %s\n", r.Host) -} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe("8000", nil) -} diff --git a/pkg/deb/debian/unit.example-php-app b/pkg/deb/debian/unit.example-php-app deleted file mode 100644 index 147cebcd..00000000 --- a/pkg/deb/debian/unit.example-php-app +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pkg/deb/debian/unit.example-python-app b/pkg/deb/debian/unit.example-python-app deleted file mode 100644 index 756de77e..00000000 --- a/pkg/deb/debian/unit.example-python-app +++ /dev/null @@ -1,16 +0,0 @@ -import os -import datetime -import sys - -def application(environ, start_response): - output = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p") - output += "\n\nPython: " - output += sys.version - output += "\n\nENV Variables:\n\n" - for param in os.environ.keys(): - output += param - output += "\t" - output += os.environ[param] - output += "\n" - start_response('200 OK', [('Content-type', 'text/plain')]) - return output.encode('utf8') diff --git a/pkg/deb/debian/unit.example.config b/pkg/deb/debian/unit.example.config deleted file mode 100644 index 66695327..00000000 --- a/pkg/deb/debian/unit.example.config +++ /dev/null @@ -1,47 +0,0 @@ -{ - "applications": { - "example_php": { - "type": "php", - "processes": 2, - "root": "/usr/share/doc/unit/examples/php-app", - "index": "index.php" - }, - - "example_python": { - "type": "python", - "processes": 2, - "path": "/usr/share/doc/unit/examples/python-app", - "module": "wsgi" - }, - - "example_go": { - "type": "external", - "executable": "/tmp/go-app" - }, - - "example_perl": { - "type": "perl", - "processes": 1, - "working_directory": "/usr/share/doc/unit-perl/examples/perl-app", - "script": "/usr/share/doc/unit-perl/examples/perl-app/index.pl" - } - }, - - "listeners": { - "*:8300": { - "pass": "applications/example_php" - }, - - "*:8400": { - "pass": "applications/example_python" - }, - - "*:8500": { - "pass": "applications/example_go" - }, - - "*:8600": { - "pass": "applications/example_perl" - } - } -} diff --git a/pkg/deb/debian/unit.init b/pkg/deb/debian/unit.init deleted file mode 100644 index 900e97fd..00000000 --- a/pkg/deb/debian/unit.init +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/sh -# -# unitd NGINX Unit -# -### BEGIN INIT INFO -# Provides: unitd -# Required-Start: $network $remote_fs -# Required-Stop: $network $remote_fs -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: NGINX Unit -# Description: NGINX Unit -### END INIT INFO -PATH=/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/sbin/unitd -NAME=unit -DESC=unitd - -#includes lsb functions -. /lib/lsb/init-functions - -test -f $DAEMON || exit 0 - -umask 022 - -# Read configuration variable file if it is present -[ -r /etc/default/$NAME ] && . /etc/default/$NAME - -case "$1" in - start) - log_daemon_msg "Starting $DESC" "$NAME" - if start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ - --exec $DAEMON -- $DAEMON_ARGS; then - log_end_msg 0 - else - log_end_msg 1 - fi - ;; - status) - status_of_proc -p "$PIDFILE" "$DAEMON" "$NAME" && exit 0 || exit $? - ;; - stop) - log_daemon_msg "Stopping $DESC" "$NAME" - if start-stop-daemon --oknodo --stop --quiet --pidfile /var/run/$NAME.pid \ - --exec $DAEMON; then - log_end_msg 0 - else - log_end_msg 1 - fi - ;; - reload|force-reload) - echo "Not implemented." >&2 - exit 1 - ;; - restart) - log_action_begin_msg "Restarting $DESC" "$NAME" - - start-stop-daemon --stop --quiet --pidfile \ - /var/run/$NAME.pid --exec $DAEMON || true - sleep 1 - if start-stop-daemon --start --quiet --pidfile \ - /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_ARGS; then - log_end_msg 0 - else - log_end_msg 1 - fi - ;; - *) - echo "Usage: /etc/init.d/$NAME {start|status|stop|restart|reload|force-reload}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/pkg/deb/debian/unit.logrotate b/pkg/deb/debian/unit.logrotate deleted file mode 100644 index 416947ca..00000000 --- a/pkg/deb/debian/unit.logrotate +++ /dev/null @@ -1,15 +0,0 @@ -/var/log/unit.log { - daily - missingok - rotate 7 - compress - delaycompress - nocreate - notifempty - su root root - postrotate - if [ -f /var/run/unit.pid ]; then - /bin/kill -SIGUSR1 `cat /var/run/unit.pid` - fi - endscript -} diff --git a/pkg/deb/debian/unit.postinst b/pkg/deb/debian/unit.postinst deleted file mode 100755 index 44301f2d..00000000 --- a/pkg/deb/debian/unit.postinst +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -set -e - -if [ "$1" != "configure" ]; then - exit 0 -fi - -if [ -n "$2" ]; then - if dpkg --compare-versions "${2%%-*}" le "1.21.0"; then - cat </dev/null; then - groupadd --system unit >/dev/null -fi - -if ! getent passwd unit >/dev/null; then - useradd \ - --system \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit >/dev/null -fi - -#DEBHELPER# - -exit 0 diff --git a/pkg/deb/debian/unit.preinst b/pkg/deb/debian/unit.preinst deleted file mode 100644 index bd513788..00000000 --- a/pkg/deb/debian/unit.preinst +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -set -e - -case "$1" in - install) - cat <&2 - exit 0 - ;; -esac - -#DEBHELPER# - -exit 0 diff --git a/pkg/deb/debian/unit.service b/pkg/deb/debian/unit.service deleted file mode 100644 index d07a06d3..00000000 --- a/pkg/deb/debian/unit.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=NGINX Unit -Wants=network-online.target -After=network-online.target - -[Service] -Type=forking -PIDFile=/var/run/unit.pid -EnvironmentFile=-/etc/default/unit -ExecStart=/usr/sbin/unitd $DAEMON_ARGS -ExecReload= - -[Install] -WantedBy=multi-user.target diff --git a/pkg/docker/Dockerfile.go1.21 b/pkg/docker/Dockerfile.go1.21 deleted file mode 100644 index 637e0c79..00000000 --- a/pkg/docker/Dockerfile.go1.21 +++ /dev/null @@ -1,89 +0,0 @@ -FROM golang:1.21-bullseye - -LABEL org.opencontainers.image.title="Unit (go1.21)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && /bin/true \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure go --go-path=$GOPATH \ - && make -j $NCPU go-install-src libunit-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure go --go-path=$GOPATH \ - && make -j $NCPU go-install-src libunit-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && /bin/true \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.go1.22 b/pkg/docker/Dockerfile.go1.22 deleted file mode 100644 index 7794353b..00000000 --- a/pkg/docker/Dockerfile.go1.22 +++ /dev/null @@ -1,89 +0,0 @@ -FROM golang:1.22-bullseye - -LABEL org.opencontainers.image.title="Unit (go1.22)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && /bin/true \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure go --go-path=$GOPATH \ - && make -j $NCPU go-install-src libunit-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure go --go-path=$GOPATH \ - && make -j $NCPU go-install-src libunit-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && /bin/true \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.jsc11 b/pkg/docker/Dockerfile.jsc11 deleted file mode 100644 index fb3bdea0..00000000 --- a/pkg/docker/Dockerfile.jsc11 +++ /dev/null @@ -1,89 +0,0 @@ -FROM eclipse-temurin:11-jdk-jammy - -LABEL org.opencontainers.image.title="Unit (jsc11)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && /bin/true \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure java --jars=/usr/share/unit-jsc-common/ \ - && make -j $NCPU java-shared-install java-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure java --jars=/usr/share/unit-jsc-common/ \ - && make -j $NCPU java-shared-install java-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && rm -rf /root/.m2 \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.minimal b/pkg/docker/Dockerfile.minimal deleted file mode 100644 index a50df863..00000000 --- a/pkg/docker/Dockerfile.minimal +++ /dev/null @@ -1,89 +0,0 @@ -FROM debian:bullseye-slim - -LABEL org.opencontainers.image.title="Unit (minimal)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && /bin/true \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure \ - && make -j $NCPU version \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure \ - && make -j $NCPU version \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && /bin/true \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.node20 b/pkg/docker/Dockerfile.node20 deleted file mode 100644 index 6c1518a3..00000000 --- a/pkg/docker/Dockerfile.node20 +++ /dev/null @@ -1,89 +0,0 @@ -FROM node:20-bullseye - -LABEL org.opencontainers.image.title="Unit (node20)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && npm -g install node-gyp \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure nodejs --node-gyp=/usr/local/bin/node-gyp \ - && make -j $NCPU node node-install libunit-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure nodejs --node-gyp=/usr/local/bin/node-gyp \ - && make -j $NCPU node node-install libunit-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && rm -rf /root/.cache/ && rm -rf /root/.npm \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.node21 b/pkg/docker/Dockerfile.node21 deleted file mode 100644 index 9ff49215..00000000 --- a/pkg/docker/Dockerfile.node21 +++ /dev/null @@ -1,89 +0,0 @@ -FROM node:21-bullseye - -LABEL org.opencontainers.image.title="Unit (node21)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && npm -g install node-gyp \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure nodejs --node-gyp=/usr/local/bin/node-gyp \ - && make -j $NCPU node node-install libunit-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure nodejs --node-gyp=/usr/local/bin/node-gyp \ - && make -j $NCPU node node-install libunit-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && rm -rf /root/.cache/ && rm -rf /root/.npm \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.perl5.36 b/pkg/docker/Dockerfile.perl5.36 deleted file mode 100644 index f25ec048..00000000 --- a/pkg/docker/Dockerfile.perl5.36 +++ /dev/null @@ -1,89 +0,0 @@ -FROM perl:5.36-bullseye - -LABEL org.opencontainers.image.title="Unit (perl5.36)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && /bin/true \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure perl \ - && make -j $NCPU perl-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure perl \ - && make -j $NCPU perl-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && /bin/true \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.perl5.38 b/pkg/docker/Dockerfile.perl5.38 deleted file mode 100644 index 852bfbb7..00000000 --- a/pkg/docker/Dockerfile.perl5.38 +++ /dev/null @@ -1,89 +0,0 @@ -FROM perl:5.38-bullseye - -LABEL org.opencontainers.image.title="Unit (perl5.38)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && /bin/true \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure perl \ - && make -j $NCPU perl-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure perl \ - && make -j $NCPU perl-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && /bin/true \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.php8.2 b/pkg/docker/Dockerfile.php8.2 deleted file mode 100644 index 96999b3b..00000000 --- a/pkg/docker/Dockerfile.php8.2 +++ /dev/null @@ -1,89 +0,0 @@ -FROM php:8.2-cli-bullseye - -LABEL org.opencontainers.image.title="Unit (php8.2)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && /bin/true \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure php \ - && make -j $NCPU php-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure php \ - && make -j $NCPU php-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && ldconfig \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.php8.3 b/pkg/docker/Dockerfile.php8.3 deleted file mode 100644 index 2b87fe74..00000000 --- a/pkg/docker/Dockerfile.php8.3 +++ /dev/null @@ -1,89 +0,0 @@ -FROM php:8.3-cli-bullseye - -LABEL org.opencontainers.image.title="Unit (php8.3)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && /bin/true \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure php \ - && make -j $NCPU php-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure php \ - && make -j $NCPU php-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && ldconfig \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.ruby3.2 b/pkg/docker/Dockerfile.ruby3.2 deleted file mode 100644 index 95bcdfa7..00000000 --- a/pkg/docker/Dockerfile.ruby3.2 +++ /dev/null @@ -1,89 +0,0 @@ -FROM ruby:3.2-bullseye - -LABEL org.opencontainers.image.title="Unit (ruby3.2)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && /bin/true \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure ruby \ - && make -j $NCPU ruby-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure ruby \ - && make -j $NCPU ruby-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && gem install rack && rm -rf /root/.local \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.ruby3.3 b/pkg/docker/Dockerfile.ruby3.3 deleted file mode 100644 index 55f8a7d8..00000000 --- a/pkg/docker/Dockerfile.ruby3.3 +++ /dev/null @@ -1,89 +0,0 @@ -FROM ruby:3.3-bullseye - -LABEL org.opencontainers.image.title="Unit (ruby3.3)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && /bin/true \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure ruby \ - && make -j $NCPU ruby-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure ruby \ - && make -j $NCPU ruby-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && gem install rack && rm -rf /root/.local \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Dockerfile.wasm b/pkg/docker/Dockerfile.wasm deleted file mode 100644 index 0fe8ed14..00000000 --- a/pkg/docker/Dockerfile.wasm +++ /dev/null @@ -1,110 +0,0 @@ -FROM debian:bullseye-slim - -LABEL org.opencontainers.image.title="Unit (wasm)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="1.32.1" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b 1.32.1-1 https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && apt-get install --no-install-recommends --no-install-suggests -y libclang-dev \ - && export RUST_VERSION=1.76.0 \ - && export RUSTUP_HOME=/usr/src/unit/rustup \ - && export CARGO_HOME=/usr/src/unit/cargo \ - && export PATH=/usr/src/unit/cargo/bin:$PATH \ - && dpkgArch="$(dpkg --print-architecture)" \ - && case "${dpkgArch##*-}" in \ - amd64) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db" ;; \ - arm64) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="673e336c81c65e6b16dcdede33f4cc9ed0f08bde1dbe7a935f113605292dc800" ;; \ - *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ - esac \ - && url="https://static.rust-lang.org/rustup/archive/1.26.0/${rustArch}/rustup-init" \ - && curl -L -O "$url" \ - && echo "${rustupSha256} *rustup-init" | sha256sum -c - \ - && chmod +x rustup-init \ - && ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch} \ - && rm rustup-init \ - && rustup --version \ - && cargo --version \ - && rustc --version \ - && make -C pkg/contrib .wasmtime \ - && install -pm 755 pkg/contrib/wasmtime/target/release/libwasmtime.so /usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)/ \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure wasm --include-path=`pwd`/pkg/contrib/wasmtime/crates/c-api/include --lib-path=/usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)/ && ./configure wasm-wasi-component \ - && make -j $NCPU wasm-install wasm-wasi-component-install \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure wasm --include-path=`pwd`/pkg/contrib/wasmtime/crates/c-api/include --lib-path=/usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)/ && ./configure wasm-wasi-component \ - && make -j $NCPU wasm-install wasm-wasi-component-install \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && /bin/true \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/docker/Makefile b/pkg/docker/Makefile deleted file mode 100644 index d8c53021..00000000 --- a/pkg/docker/Makefile +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/make - -include ../../version -include ../shasum.mak - -DEFAULT_VERSION := $(NXT_VERSION) - -VERSION ?= $(DEFAULT_VERSION) -PATCHLEVEL ?= 1 - -MODULES ?= go jsc node perl php python ruby wasm - -VARIANT ?= bullseye - -VERSIONS_minimal ?= -CONTAINER_minimal ?= debian:$(VARIANT)-slim -CONFIGURE_minimal ?= -INSTALL_minimal ?= version -RUN_minimal ?= /bin/true -MODULE_PREBUILD_minimal ?= /bin/true - -VERSIONS_go ?= 1.21 1.22 -VARIANT_go ?= $(VARIANT) -$(foreach goversion, $(VERSIONS_go), $(eval CONTAINER_go$(goversion) = golang:$(goversion)-$(VARIANT_go))) -CONFIGURE_go ?= go --go-path=$$GOPATH -INSTALL_go ?= go-install-src libunit-install -RUN_go ?= /bin/true -MODULE_PREBUILD_go ?= /bin/true - -VERSIONS_jsc ?= 11 -VARIANT_jsc ?= jammy -$(foreach jscversion, $(VERSIONS_jsc), $(eval CONTAINER_jsc$(jscversion) = eclipse-temurin:$(jscversion)-jdk-$(VARIANT_jsc))) -CONFIGURE_jsc ?= java --jars=/usr/share/unit-jsc-common/ -INSTALL_jsc ?= java-shared-install java-install -RUN_jsc ?= rm -rf /root/.m2 -MODULE_PREBUILD_jsc ?= /bin/true - -VERSIONS_node ?= 20 21 -VARIANT_node ?= $(VARIANT) -$(foreach nodeversion, $(VERSIONS_node), $(eval CONTAINER_node$(nodeversion) = node:$(nodeversion)-$(VARIANT_node))) -CONFIGURE_node ?= nodejs --node-gyp=/usr/local/bin/node-gyp -INSTALL_node ?= node node-install libunit-install -RUN_node ?= rm -rf /root/.cache/ \&\& rm -rf /root/.npm -MODULE_PREBUILD_node ?= npm -g install node-gyp - -VERSIONS_perl ?= 5.36 5.38 -VARIANT_perl ?= $(VARIANT) -$(foreach perlversion, $(VERSIONS_perl), $(eval CONTAINER_perl$(perlversion) = perl:$(perlversion)-$(VARIANT_perl))) -CONFIGURE_perl ?= perl -INSTALL_perl ?= perl-install -RUN_perl ?= /bin/true -MODULE_PREBUILD_perl ?= /bin/true - -VERSIONS_php ?= 8.2 8.3 -VARIANT_php ?= cli-$(VARIANT) -$(foreach phpversion, $(VERSIONS_php), $(eval CONTAINER_php$(phpversion) = php:$(phpversion)-$(VARIANT_php))) -CONFIGURE_php ?= php -INSTALL_php ?= php-install -RUN_php ?= ldconfig -MODULE_PREBUILD_php ?= /bin/true - -VERSIONS_python ?= 3.11 3.12 -VARIANT_python ?= $(VARIANT) -$(foreach pythonversion, $(VERSIONS_python), $(eval CONTAINER_python$(pythonversion) = python:$(pythonversion)-$(VARIANT_python))) -CONFIGURE_python ?= python --config=/usr/local/bin/python3-config -INSTALL_python ?= python3-install -RUN_python ?= /bin/true -MODULE_PREBUILD_python ?= /bin/true - -VERSIONS_ruby ?= 3.2 3.3 -VARIANT_ruby ?= $(VARIANT) -$(foreach rubyversion, $(VERSIONS_ruby), $(eval CONTAINER_ruby$(rubyversion) = ruby:$(rubyversion)-$(VARIANT_ruby))) -CONFIGURE_ruby ?= ruby -INSTALL_ruby ?= ruby-install -RUN_ruby ?= gem install rack \&\& rm -rf /root/.local -MODULE_PREBUILD_ruby ?= /bin/true - -VERSIONS_wasm ?= -CONTAINER_wasm ?= debian:$(VARIANT)-slim -CONFIGURE_wasm ?= wasm --include-path=\`pwd\`/pkg/contrib/wasmtime/crates/c-api/include --lib-path=/usr/lib/\$$(dpkg-architecture -q DEB_HOST_MULTIARCH)/ \&\& ./configure wasm-wasi-component -INSTALL_wasm ?= wasm-install wasm-wasi-component-install -RUN_wasm ?= /bin/true - -define MODULE_PREBUILD_wasm -apt-get install --no-install-recommends --no-install-suggests -y libclang-dev \\\n \ -\ \ \ \&\& export RUST_VERSION=1.76.0 \\\n \ -\ \ \ \&\& export RUSTUP_HOME=/usr/src/unit/rustup \\\n \ -\ \ \ \&\& export CARGO_HOME=/usr/src/unit/cargo \\\n \ -\ \ \ \&\& export PATH=/usr/src/unit/cargo/bin:\$$PATH \\\n \ -\ \ \ \&\& dpkgArch="\$$\(dpkg --print-architecture\)" \\\n \ -\ \ \ \&\& case "\$${dpkgArch##*-}" in \\\n \ -\ \ \ \ \ \ amd64\) rustArch="x86_64-unknown-linux-gnu"; rustupSha256="0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db" ;; \\\n \ -\ \ \ \ \ \ arm64\) rustArch="aarch64-unknown-linux-gnu"; rustupSha256="673e336c81c65e6b16dcdede33f4cc9ed0f08bde1dbe7a935f113605292dc800" ;; \\\n \ -\ \ \ \ \ \ *\) echo \>\&2 "unsupported architecture: \$${dpkgArch}"; exit 1 ;; \\\n \ -\ \ \ \esac \\\n \ -\ \ \ \&\& url="https://static.rust-lang.org/rustup/archive/1.26.0/\$${rustArch}/rustup-init" \\\n \ -\ \ \ \&\& curl -L -O "\$$url" \\\n \ -\ \ \ \&\& echo "\$${rustupSha256} *rustup-init" | sha256sum -c - \\\n \ -\ \ \ \&\& chmod +x rustup-init \\\n \ -\ \ \ \&\& ./rustup-init -y --no-modify-path --profile minimal --default-toolchain \$$RUST_VERSION --default-host \$${rustArch} \\\n \ -\ \ \ \&\& rm rustup-init \\\n \ -\ \ \ \&\& rustup --version \\\n \ -\ \ \ \&\& cargo --version \\\n \ -\ \ \ \&\& rustc --version \\\n \ -\ \ \ \&\& make -C pkg/contrib .wasmtime \\\n \ -\ \ \ \&\& install -pm 755 pkg/contrib/wasmtime/target/release/libwasmtime.so /usr/lib/\$$\(dpkg-architecture -q DEB_HOST_MULTIARCH\)/ -endef - -default: - @echo "valid targets: all build dockerfiles library clean" - -MODVERSIONS = $(foreach module, $(MODULES), $(foreach modversion, $(shell for v in $(VERSIONS_$(module)); do echo $$v; done | sort -r), $(module)$(modversion))) wasm minimal - -modname = $(shell echo $1 | /usr/bin/tr -d '.01234567890-') - -dockerfiles: $(addprefix Dockerfile., $(MODVERSIONS)) -build: $(addprefix build-, $(MODVERSIONS)) - -Dockerfile.%: ../../version template.Dockerfile - @echo "===> Building $@" - cat template.Dockerfile | sed \ - -e 's,@@VERSION@@,$(VERSION),g' \ - -e 's,@@PATCHLEVEL@@,$(PATCHLEVEL),g' \ - -e 's,@@CONTAINER@@,$(CONTAINER_$*),g' \ - -e 's,@@CONFIGURE@@,$(CONFIGURE_$(call modname, $*)),g' \ - -e 's,@@INSTALL@@,$(INSTALL_$(call modname, $*)),g' \ - -e 's,@@RUN@@,$(RUN_$(call modname, $*)),g' \ - -e 's,@@MODULE_PREBUILD@@,$(MODULE_PREBUILD_$(call modname, $*)),g' \ - -e 's,@@MODULE@@,$*,g' \ - > $@ - -build-%: Dockerfile.% - docker pull $(CONTAINER_$*) - docker build --no-cache -t unit:$(VERSION)-$* -f Dockerfile.$* . - -library: - @echo "# this file is generated via https://github.com/nginx/unit/blob/$(shell git describe --always --abbrev=0 HEAD)/pkg/docker/Makefile" - @echo "" - @echo "Maintainers: Unit Docker Maintainers (@nginx)" - @echo "GitRepo: https://github.com/nginx/unit.git" - @previous=""; \ - for mod in $(MODVERSIONS); do \ - echo ""; \ - modname="$$( echo $$mod | tr -d '.0123456789-' )"; \ - TAGS="$$mod $${mod%%.*} $$modname" ; \ - TAGS="$$(echo $$TAGS | tr " " "\n" | sort -u -r | tr "\n" "," | sed "s/,/, /g")"; \ - if [ "$$previous" = "$$modname" ]; then \ - echo "Tags: $(VERSION)-$$mod, $$mod"; \ - else \ - if [ "$$mod" = "minimal" ]; then \ - echo "Tags: $(VERSION)-$$mod, $${TAGS%, }, latest"; \ - else \ - echo "Tags: $(VERSION)-$$mod, $${TAGS%, }"; \ - fi; \ - fi; \ - echo "Architectures: amd64, arm64v8"; \ - echo "GitFetch: refs/heads/branches/packaging"; \ - echo "GitCommit: $(shell git describe --always --abbrev=0 HEAD)"; \ - echo "Directory: pkg/docker"; \ - echo "File: Dockerfile.$$mod"; \ - previous=$$(echo $$mod | tr -d '.0123456789-'); \ - done - -diff: $(addprefix diff-, $(MODVERSIONS)) - -diff-%: - @echo container-diff diff --type file daemon://$(CONTAINER_$*) daemon://unit:$(VERSION)-$* - -all: $(addprefix Dockerfile., $(MODVERSIONS)) - -clean: - rm -f Dockerfile.* - -.PHONY: default build dockerfiles clean library diff --git a/pkg/docker/template.Dockerfile b/pkg/docker/template.Dockerfile deleted file mode 100644 index edf9ba75..00000000 --- a/pkg/docker/template.Dockerfile +++ /dev/null @@ -1,89 +0,0 @@ -FROM @@CONTAINER@@ - -LABEL org.opencontainers.image.title="Unit (@@MODULE@@)" -LABEL org.opencontainers.image.description="Official build of Unit for Docker." -LABEL org.opencontainers.image.url="https://unit.nginx.org" -LABEL org.opencontainers.image.source="https://github.com/nginx/unit" -LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" -LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers " -LABEL org.opencontainers.image.version="@@VERSION@@" - -RUN set -ex \ - && savedAptMark="$(apt-mark showmanual)" \ - && apt-get update \ - && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git build-essential libssl-dev libpcre2-dev curl pkg-config \ - && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ - && mkdir -p /usr/src/unit \ - && cd /usr/src/unit \ - && git clone --depth 1 -b @@VERSION@@-@@PATCHLEVEL@@ https://github.com/nginx/unit \ - && cd unit \ - && NCPU="$(getconf _NPROCESSORS_ONLN)" \ - && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ - && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ - && LD_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_LDFLAGS_MAINT_APPEND="-Wl,--as-needed -pie" dpkg-buildflags --get LDFLAGS)" \ - && CONFIGURE_ARGS_MODULES="--prefix=/usr \ - --statedir=/var/lib/unit \ - --control=unix:/var/run/control.unit.sock \ - --runstatedir=/var/run \ - --pid=/var/run/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --openssl \ - --libdir=/usr/lib/$DEB_HOST_MULTIARCH" \ - && CONFIGURE_ARGS="$CONFIGURE_ARGS_MODULES \ - --njs" \ - && make -j $NCPU -C pkg/contrib .njs \ - && export PKG_CONFIG_PATH=$(pwd)/pkg/contrib/njs/build \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd-debug \ - && make clean \ - && ./configure $CONFIGURE_ARGS --cc-opt="$CC_OPT" --ld-opt="$LD_OPT" --modulesdir=/usr/lib/unit/modules \ - && make -j $NCPU unitd \ - && install -pm755 build/sbin/unitd /usr/sbin/unitd \ - && make clean \ - && @@MODULE_PREBUILD@@ \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/debug-modules --debug \ - && ./configure @@CONFIGURE@@ \ - && make -j $NCPU @@INSTALL@@ \ - && make clean \ - && ./configure $CONFIGURE_ARGS_MODULES --cc-opt="$CC_OPT" --modulesdir=/usr/lib/unit/modules \ - && ./configure @@CONFIGURE@@ \ - && make -j $NCPU @@INSTALL@@ \ - && cd \ - && rm -rf /usr/src/unit \ - && for f in /usr/sbin/unitd /usr/lib/unit/modules/*.unit.so; do \ - ldd $f | awk '/=>/{print $(NF-1)}' | while read n; do dpkg-query -S $n; done | sed 's/^\([^:]\+\):.*$/\1/' | sort | uniq >> /requirements.apt; \ - done \ - && apt-mark showmanual | xargs apt-mark auto > /dev/null \ - && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ - && @@RUN@@ \ - && mkdir -p /var/lib/unit/ \ - && mkdir -p /docker-entrypoint.d/ \ - && groupadd --gid 999 unit \ - && useradd \ - --uid 999 \ - --gid unit \ - --no-create-home \ - --home /nonexistent \ - --comment "unit user" \ - --shell /bin/false \ - unit \ - && apt-get update \ - && apt-get --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \ - && apt-get purge -y --auto-remove build-essential \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /requirements.apt \ - && ln -sf /dev/stderr /var/log/unit.log - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY welcome.* /usr/share/unit/welcome/ - -STOPSIGNAL SIGTERM - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -EXPOSE 80 -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/pkg/npm/Makefile b/pkg/npm/Makefile deleted file mode 100644 index ef8ef7b5..00000000 --- a/pkg/npm/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/make - -include ../../version - -VERSION ?= $(NXT_VERSION) -VERNUM ?= $(NXT_VERNUM) -NPM ?= npm - -default: - @echo "valid targets: all publish clean" - -copy: - cp -rp ../../src/nodejs/unit-http . - echo '#define NXT_NODE_VERNUM ${VERNUM}' > unit-http/version.h - mv unit-http/binding_pub.gyp unit-http/binding.gyp - sed -e 's/"version"\s*:.*/"version": "${VERSION}",/' \ - unit-http/package.json > unit-http/package.json.tmp - mv unit-http/package.json.tmp unit-http/package.json - -publish: copy - cd unit-http && $(NPM) publish - -all: copy - -clean: - rm -rf unit-http - -.PHONY: default all copy publish clean diff --git a/pkg/rpm/Makefile b/pkg/rpm/Makefile deleted file mode 100644 index 1f3bbd58..00000000 --- a/pkg/rpm/Makefile +++ /dev/null @@ -1,307 +0,0 @@ -#!/usr/bin/make - -include ../../version - -DEFAULT_VERSION := $(NXT_VERSION) -DEFAULT_RELEASE := 1 - -VERSION ?= $(DEFAULT_VERSION) -RELEASE ?= $(DEFAULT_RELEASE) - -PACKAGE_VENDOR = NGINX Packaging - -ifeq ($(shell test `rpm --eval '0%{?rhel} -eq 7 -a 0%{?amzn} -eq 0'`; echo $$?), 0) -OSVER = centos7 -else ifeq ($(shell rpm --eval "%{?rhel}"), 8) -OSVER = centos8 -else ifeq ($(shell rpm --eval "%{?rhel}"), 9) -OSVER = centos9 -else ifeq ($(shell rpm --eval "%{?amzn}"), 2) -OSVER = amazonlinux2 -else ifeq ($(shell rpm --eval "%{?amzn}"), 2023) -OSVER = amazonlinux2023 -else ifeq ($(shell test `rpm --eval '0%{?fedora} -ge 35 -a 0%{?fedora} -le 36'`; echo $$?),0) -OSVER = fedora -else ifeq ($(shell test `rpm --eval '0%{?fedora} -ge 37 -a 0%{?fedora} -le 38'`; echo $$?),0) -OSVER = fedora37 -else ifeq ($(shell test `rpm --eval '0%{?fedora} -ge 39'`; echo $$?),0) -OSVER = fedora39 -endif - -BUILD_DEPENDS_unit = gcc rpm-build rpmlint - -ifeq ($(OSVER), centos7) -BUILD_DEPENDS_unit += which -endif - -ifneq (,$(findstring $(OSVER),amazonlinux2)) -BUILD_DEPENDS_unit += libxml2 libxslt openssl11-devel -else -BUILD_DEPENDS_unit += libxml2 libxslt openssl-devel -endif - -BUILD_DEPENDS = $(BUILD_DEPENDS_unit) - -MODULES= - -ifeq ($(OSVER), centos7) -include Makefile.php -include Makefile.python27 -include Makefile.python36 -include Makefile.go -include Makefile.perl -include Makefile.jsc-common -include Makefile.jsc8 -include Makefile.jsc11 -endif - -ifeq ($(OSVER), centos8) -include Makefile.php -include Makefile.python27 -include Makefile.python36 -include Makefile.python38 -include Makefile.python39 -include Makefile.go -include Makefile.perl -include Makefile.jsc-common -include Makefile.jsc8 -include Makefile.jsc11 -include Makefile.wasm -endif - -ifeq ($(OSVER), centos9) -include Makefile.php -include Makefile.python39 -include Makefile.go -include Makefile.perl -include Makefile.jsc-common -include Makefile.jsc8 -include Makefile.jsc11 -include Makefile.wasm -endif - -ifeq ($(OSVER), amazonlinux2) -include Makefile.php -include Makefile.python27 -include Makefile.python37 -include Makefile.go -include Makefile.perl -include Makefile.jsc-common -include Makefile.jsc8 -include Makefile.wasm -endif - -ifeq ($(OSVER), amazonlinux2023) -include Makefile.php -include Makefile.python39 -include Makefile.python311 -include Makefile.go -include Makefile.perl -include Makefile.jsc-common -include Makefile.jsc17 -include Makefile.wasm -endif - -ifeq ($(OSVER), fedora) -include Makefile.php -include Makefile.python310 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc8 -include Makefile.jsc11 -include Makefile.wasm -endif - -ifeq ($(OSVER), fedora37) -include Makefile.php -include Makefile.python311 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc8 -include Makefile.jsc11 -include Makefile.wasm -endif - -ifeq ($(OSVER), fedora39) -include Makefile.php -include Makefile.python312 -include Makefile.go -include Makefile.perl -include Makefile.ruby -include Makefile.jsc-common -include Makefile.jsc17 -include Makefile.wasm -endif - - -CONFIGURE_ARGS_COMMON=\ - --prefix=/usr \ - --statedir=%{_sharedstatedir}/unit \ - --control="unix:/var/run/unit/control.sock" \ - --runstatedir=/var/run \ - --pid=/var/run/unit/unit.pid \ - --logdir=/var/log \ - --log=/var/log/unit/unit.log \ - --tmpdir=/var/tmp \ - --user=unit \ - --group=unit \ - --tests \ - --openssl - -CONFIGURE_ARGS=\ - $(CONFIGURE_ARGS_COMMON) \ - --njs - -export CR=\\n - -default: - @echo "valid targets: all modules unit $(addprefix unit-, $(MODULES)) rpmlint specs test test-debug clean" - -all: check-build-depends-all unit modules - -modules: $(addprefix unit-, $(MODULES)) - -specs: rpmbuild/SPECS/unit.spec $(addsuffix .spec, $(addprefix rpmbuild/SPECS/unit-, $(MODULES))) - -check-build-depends-%: - @{ \ - case "$*" in \ - all) pkgs="$(BUILD_DEPENDS)" ;; \ - unit) pkgs="$(BUILD_DEPENDS_unit)" ;; \ - *) pkgs="$(BUILD_DEPENDS_unit) $(BUILD_DEPENDS_$*)" ;; \ - esac ; \ - not_installed= ; \ - for pkg in $${pkgs}; do \ - rpm -qi --whatprovides $${pkg} >/dev/null 2>&1 ; \ - if [ $$? -ne 0 ]; then \ - not_installed="$${not_installed} $${pkg}" ; \ - fi ; \ - done ; \ - if test -n "$${not_installed}" ; then \ - echo "" >&2 ; \ - echo "The following packages are required in order to proceed:" >&2 ; \ - echo "" >&2 ; \ - echo $${not_installed} >&2 ; \ - echo "" >&2 ; \ - exit 1 ; \ - fi \ - } - touch $@ - -rpmbuild/SPECS: - mkdir -p rpmbuild/SPECS - -rpmbuild/SPECS/unit.spec: unit.spec.in ../../docs/changes.xml | rpmbuild/SPECS - cat unit.spec.in | \ - sed -e "s#%%VERSION%%#$(VERSION)#g" \ - -e "s#%%RELEASE%%#$(RELEASE)#g" \ - -e "s#%%CONFIGURE_ARGS%%#$(CONFIGURE_ARGS)#g" \ - -e "s#%%PACKAGE_VENDOR%%#$(PACKAGE_VENDOR)#g" \ - > rpmbuild/SPECS/unit.spec - cd ../../docs && make ../build/unit.rpm-changelog -ifneq ($(DEFAULT_VERSION)$(DEFAULT_RELEASE), $(VERSION)$(RELEASE)) - cat ../../build/unit.rpm-changelog | sed -e \ - "s/> - $(DEFAULT_VERSION)-$(DEFAULT_RELEASE)/> - $(VERSION)-$(RELEASE)/" \ - >> rpmbuild/SPECS/unit.spec -else - cat ../../build/unit.rpm-changelog >> rpmbuild/SPECS/unit.spec -endif - -rpmbuild/SOURCES/unit-$(VERSION).tar.gz: - cd ../.. && tar -czf pkg/rpm/rpmbuild/SOURCES/unit-$(VERSION).tar.gz \ - --transform "s#^#unit-$(VERSION)/#" \ - LICENSE NOTICE CHANGES README.md CONTRIBUTING.md configure auto src \ - test tools version go pkg/contrib docs/man/man8/unitd.8.in - -unit: check-build-depends-unit rpmbuild/SPECS/unit.spec rpmbuild/SOURCES/unit-$(VERSION).tar.gz - @echo "===> Building $@ package" ; \ - rpmbuild -D "_topdir `pwd`/rpmbuild" -ba --noclean rpmbuild/SPECS/unit.spec && \ - ln -s rpmbuild/BUILD/$@-$(VERSION)/build $@ - -rpmlint: - find rpmbuild/ -name "*.rpm" -print -exec rpmlint {} \; - -rpmbuild/SPECS/unit-%.spec: unit.module.spec.in ../../docs/changes.xml | rpmbuild/SPECS - @echo "===> Creating $@" - @{ \ - set -e ; \ - i=100 ; \ - sources= ; \ - for src in $(MODULE_SOURCES_$*); do \ - s="`printf "Source%d: %s\n" $${i} $${src}`" ; \ - sources="$${sources}\n$${s}" ; \ - i=$$(($${i}+1)) ; \ - done ; \ - pkgname=$(shell echo $@ | cut -d '/' -f 3 | tr '_' '-' | cut -d '.' -f 1) ; \ - definitions=`echo "$$MODULE_DEFINITIONS_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - prebuild=`echo "$$MODULE_PREBUILD_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - preinstall=`echo "$$MODULE_PREINSTALL_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - postinstall=`echo "$$MODULE_POSTINSTALL_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - files=`echo "$$MODULE_FILES_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - post=`echo "$$MODULE_POST_$*" | sed -e ':a' -e 'N' -e '$$!ba' -e "s/\n/\$$CR/g"` ; \ - cat unit.module.spec.in | sed \ - -e "s#%%NAME%%#$${pkgname}#g" \ - -e "s#%%SUMMARY%%#$(MODULE_SUMMARY_$*)#g" \ - -e "s#%%VERSION%%#$(MODULE_VERSION_$*)#g" \ - -e "s#%%RELEASE%%#$(MODULE_RELEASE_$*)#g" \ - -e "s#%%UNIT_VERSION%%#$(VERSION)#g" \ - -e "s#%%UNIT_RELEASE%%#$(RELEASE)#g" \ - -e "s#%%PACKAGE_VENDOR%%#$(PACKAGE_VENDOR)#g" \ - -e "s#%%MODULE_SOURCES%%#$${sources}#g" \ - -e "s#%%CONFIGURE_ARGS%%#$(CONFIGURE_ARGS_COMMON)#g" \ - -e "s#%%MODULE_CONFARGS%%#$(MODULE_CONFARGS_$*)#g" \ - -e "s#%%MODULE_MAKEARGS%%#$(MODULE_MAKEARGS_$*)#g" \ - -e "s#%%MODULE_INSTARGS%%#$(MODULE_INSTARGS_$*)#g" \ - -e "s#%%MODULE_DEFINITIONS%%#$${definitions}#g" \ - -e "s#%%MODULE_PREBUILD%%#$${prebuild}#g" \ - -e "s#%%MODULE_PREINSTALL%%#$${preinstall}#g" \ - -e "s#%%MODULE_POSTINSTALL%%#$${postinstall}#g" \ - -e "s#%%MODULE_FILES%%#$${files}#g" \ - -e "s#%%MODULE_POST%%#$${post}#g" \ - > $@.tmp ; \ - } - cd ../../docs && make ../build/unit-$(MODULE_SUFFIX_$*).rpm-changelog - cat ../../build/unit-$(MODULE_SUFFIX_$*).rpm-changelog | sed -e \ - "s/> - $(DEFAULT_VERSION)-$(DEFAULT_RELEASE)/> - $(MODULE_VERSION_$*)-$(MODULE_RELEASE_$*)/" \ - >> $@.tmp - mv $@.tmp $@ - -unit-%: check-build-depends-% rpmbuild/SPECS/unit-%.spec rpmbuild/SOURCES/unit-$(VERSION).tar.gz - @echo "===> Building $(subst _,-,$@) package" ; \ - rpmbuild -D "_topdir `pwd`/rpmbuild" -ba --noclean rpmbuild/SPECS/$@.spec && \ - ln -s rpmbuild/BUILD/$(subst _,-,$@)-$(VERSION)/build $@ - -test: unit modules - @{ \ - for so in `find rpmbuild/BUILD/*/build-nodebug/ -type f \( -name "*.so" -o -name "*.jar" \)`; do \ - soname=`basename $${so}` ; \ - test "$${soname}" = "java.unit.so" && continue ; \ - test -h rpmbuild/BUILD/unit-$(VERSION)/build-nodebug/$${soname} || \ - ln -fs `pwd`/$${so} rpmbuild/BUILD/unit-$(VERSION)/build-nodebug/$${soname} ; \ - done ; \ - ( cd rpmbuild/BUILD/unit-$(VERSION) && rm -f build && ln -s build-nodebug build && env python3 -m pytest --user=nobody $(PYTEST_ARGS) ) ; \ - } - -test-debug: unit modules - @{ \ - for so in `find rpmbuild/BUILD/*/build-debug/ -type f \( -name "*.so" -o -name "*.jar" \)`; do \ - soname=`basename $${so}` ; \ - test "$${soname}" = "java.unit.so" && continue ; \ - test -h rpmbuild/BUILD/unit-$(VERSION)/build-debug/$${soname} || \ - ln -fs `pwd`/$${so} rpmbuild/BUILD/unit-$(VERSION)/build-debug/$${soname} ; \ - done ; \ - ( cd rpmbuild/BUILD/unit-$(VERSION) && rm -f build && ln -s build-debug build && env python3 -m pytest --user=nobody $(PYTEST_ARGS) ) ; \ - } - -clean: - rm -rf rpmbuild/SPECS rpmbuild/BUILD rpmbuild/BUILDROOT rpmbuild/RPMS rpmbuild/SRPMS ../../build - rm -f rpmbuild/SOURCES/unit-*.tar.gz check-build-depends-* - find . -maxdepth 1 -type l -delete - -.PHONY: default all modules specs rpmlint test test-debug clean - -.SECONDARY: $(addprefix check-build-depends-, $(MODULES)) diff --git a/pkg/rpm/Makefile.go b/pkg/rpm/Makefile.go deleted file mode 100644 index aacbe2b9..00000000 --- a/pkg/rpm/Makefile.go +++ /dev/null @@ -1,68 +0,0 @@ -MODULES+= go -MODULE_SUFFIX_go= go - -MODULE_SUMMARY_go= Go module for NGINX Unit - -MODULE_VERSION_go= $(VERSION) -MODULE_RELEASE_go= 1 - -MODULE_CONFARGS_go= go --go-path=%{gopath} -MODULE_MAKEARGS_go= go -MODULE_INSTARGS_go= go-install-src - -MODULE_SOURCES_go= unit.example-go-app \ - unit.example-go-config - -ifeq ($(OSVER), centos6) -BUILD_DEPENDS_go= epel-release golang -else -BUILD_DEPENDS_go= golang -endif - -BUILD_DEPENDS+= $(BUILD_DEPENDS_go) - -define MODULE_DEFINITIONS_go -BuildArch: noarch -Requires: unit-devel == $(VERSION)-$(RELEASE)%{?dist}.ngx -BuildRequires: $(BUILD_DEPENDS_go) -endef -export MODULE_DEFINITIONS_go - -define MODULE_PREINSTALL_go -QA_SKIP_BUILD_ROOT=1 -export QA_SKIP_BUILD_ROOT - -%{__mkdir} -p %{buildroot}%{_datadir}/doc/unit-go/examples/go-app -%{__install} -m 644 -p %{SOURCE100} \ - %{buildroot}%{_datadir}/doc/unit-go/examples/go-app/let-my-people.go -%{__install} -m 644 -p %{SOURCE101} \ - %{buildroot}%{_datadir}/doc/unit-go/examples/unit.config -endef -export MODULE_PREINSTALL_go - -define MODULE_FILES_go -%dir %{gopath}/src/unit.nginx.org/go -%{gopath}/src/unit.nginx.org/go/* -endef -export MODULE_FILES_go - -define MODULE_POST_go -cat <&1 | grep -F -e os.arch | sed -e 's/^.*= //') - -ifeq ($(OSVER),amazonlinux2023) -MODULE_CONFARGS_jsc_common= java --home=/usr/lib/jvm/java-17-amazon-corretto --lib-path=/usr/lib/jvm/java-17-amazon-corretto/lib --jars=/usr/share/unit-jsc-common/ -else ifeq ($(OSVER),fedora39) -MODULE_CONFARGS_jsc_common= java --home=/usr/lib/jvm/java-17-openjdk --lib-path=/usr/lib/jvm/java-17-openjdk/lib --jars=/usr/share/unit-jsc-common/ -else -MODULE_CONFARGS_jsc_common= java --home=/usr/lib/jvm/java-1.8.0 --lib-path=/usr/lib/jvm/jre-1.8.0/lib/$(JAVA_ARCH_jsc_common) --jars=/usr/share/unit-jsc-common/ -endif -MODULE_INSTARGS_jsc_common= java-shared-install - -MODULE_SOURCES_jsc_common= COPYRIGHT.unit-jsc-common - -ifeq ($(OSVER),amazonlinux2023) -BUILD_DEPENDS_jsc_common= java-17-amazon-corretto-devel curl -else ifeq ($(OSVER),fedora39) -BUILD_DEPENDS_jsc_common= java-17-openjdk-devel curl -else -BUILD_DEPENDS_jsc_common= java-1.8.0-openjdk-devel curl -endif -BUILD_DEPENDS+= $(BUILD_DEPENDS_jsc_common) - -define MODULE_DEFINITIONS_jsc_common -BuildArch: noarch -endef -export MODULE_DEFINITIONS_jsc_common - -define MODULE_FILES_jsc_common -%dir %{_datadir}/unit-jsc-common -%{_datadir}/unit-jsc-common/* -endef -export MODULE_FILES_jsc_common - -define MODULE_POST_jsc_common -cat <= 39) -Requires: java-17-openjdk-headless -%endif -endef -export MODULE_DEFINITIONS_jsc17 - -define MODULE_PREINSTALL_jsc17 -%{__mkdir} -p %{buildroot}%{_datadir}/doc/unit-jsc17/examples/jsc-app -%{__install} -m 644 -p %{SOURCE100} \ - %{buildroot}%{_datadir}/doc/unit-jsc17/examples/jsc-app/index.jsp -%{__install} -m 644 -p %{SOURCE101} \ - %{buildroot}%{_datadir}/doc/unit-jsc17/examples/unit.config -%{__install} -m 644 -p %{bdir}/src/java/README.JSR-340 \ - %{buildroot}%{_datadir}/doc/unit-jsc17/ -endef -export MODULE_PREINSTALL_jsc17 - -define MODULE_POSTINSTALL_jsc17 -DESTDIR=%{buildroot} make java-shared-uninstall -endef -export MODULE_POSTINSTALL_jsc17 - -define MODULE_FILES_jsc17 -%{_libdir}/unit/modules/* -%{_libdir}/unit/debug-modules/* -%dir %{_datadir}/doc/unit-jsc17 -%{_datadir}/doc/unit-jsc17/* -%{_datadir}/unit-jsc-common/* -endef -export MODULE_FILES_jsc17 - -define MODULE_POST_jsc17 -cat <&1 | grep -F -e os.arch | sed -e 's/^.*= //') - -MODULE_CONFARGS_jsc8= java --module=java8 --home=/usr/lib/jvm/java-1.8.0 --lib-path=/usr/lib/jvm/jre-1.8.0/lib/$(JAVA_ARCH_jsc8) --jars=/usr/share/unit-jsc-common/ -MODULE_MAKEARGS_jsc8= java8 -MODULE_INSTARGS_jsc8= java8-install - -MODULE_SOURCES_jsc8= unit.example-jsc-app \ - unit.example-jsc8-config - -BUILD_DEPENDS_jsc8= java-1.8.0-openjdk-devel -BUILD_DEPENDS+= $(BUILD_DEPENDS_jsc8) - -define MODULE_DEFINITIONS_jsc8 -Requires: unit-jsc-common == $(MODULE_VERSION_jsc_common)-$(MODULE_RELEASE_jsc_common)%{?dist}.ngx -Requires: java-1.8.0-headless -endef -export MODULE_DEFINITIONS_jsc8 - -define MODULE_PREINSTALL_jsc8 -%{__mkdir} -p %{buildroot}%{_datadir}/doc/unit-jsc8/examples/jsc-app -%{__install} -m 644 -p %{SOURCE100} \ - %{buildroot}%{_datadir}/doc/unit-jsc8/examples/jsc-app/index.jsp -%{__install} -m 644 -p %{SOURCE101} \ - %{buildroot}%{_datadir}/doc/unit-jsc8/examples/unit.config -%{__install} -m 644 -p %{bdir}/src/java/README.JSR-340 \ - %{buildroot}%{_datadir}/doc/unit-jsc8/ -endef -export MODULE_PREINSTALL_jsc8 - -define MODULE_POSTINSTALL_jsc8 -DESTDIR=%{buildroot} make java-shared-uninstall -endef -export MODULE_POSTINSTALL_jsc8 - -define MODULE_FILES_jsc8 -%{_libdir}/unit/modules/* -%{_libdir}/unit/debug-modules/* -%dir %{_datadir}/doc/unit-jsc8 -%{_datadir}/doc/unit-jsc8/* -%{_datadir}/unit-jsc-common/* -endef -export MODULE_FILES_jsc8 - -define MODULE_POST_jsc8 -cat <<%@ page import="java.util.*" %>This is plain text response for "<%= request.getMethod() %> <%= request.getRequestURI() %>". -Here is the list of all system properties: -<% - Properties p = System.getProperties(); - Enumeration keys = p.keys(); - while (keys.hasMoreElements()) { - String key = (String) keys.nextElement(); - String value = (String) p.get(key); - out.println(" " + key + " : " + value); - } -%> -<% response.addHeader("X-Unit-JSP", "ok"); %> diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-jsc11-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-jsc11-config deleted file mode 100644 index 3f7dd518..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-jsc11-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java11": { - "processes": 1, - "type": "java 11", - "webapp": "/usr/share/doc/unit-jsc11/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java11" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-jsc17-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-jsc17-config deleted file mode 100644 index 28b13e4d..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-jsc17-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java17": { - "processes": 1, - "type": "java 17", - "webapp": "/usr/share/doc/unit-jsc17/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java17" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-jsc8-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-jsc8-config deleted file mode 100644 index 4d79112f..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-jsc8-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_java8": { - "processes": 1, - "type": "java 1.8.0", - "webapp": "/usr/share/doc/unit-jsc8/examples/jsc-app" - } - }, - - "listeners": { - "*:8800": { - "pass": "applications/example_java8" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-perl-app b/pkg/rpm/rpmbuild/SOURCES/unit.example-perl-app deleted file mode 100644 index 33be1d3e..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-perl-app +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env perl - -use Data::Dumper; - -my $app = sub { - my $env = shift; - return [ - '200', - [ 'Content-Type' => 'text/plain' ], - [ "Hello from Unit, Perl $^V, environment:\n\n", Dumper($env) ], - ]; -}; diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-perl-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-perl-config deleted file mode 100644 index 2182fc46..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-perl-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_perl": { - "type": "perl", - "processes": 1, - "working_directory": "/usr/share/doc/unit-perl/examples/perl-app", - "script": "/usr/share/doc/unit-perl/examples/perl-app/index.pl" - } - }, - - "listeners": { - "*:8600": { - "pass": "applications/example_perl" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-php-app b/pkg/rpm/rpmbuild/SOURCES/unit.example-php-app deleted file mode 100644 index 147cebcd..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-php-app +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-php-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-php-config deleted file mode 100644 index 9673385f..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-php-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_php": { - "type": "php", - "processes": 2, - "root": "/usr/share/doc/unit-php/examples/phpinfo-app", - "index": "index.php" - } - }, - - "listeners": { - "*:8300": { - "pass": "applications/example_php" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python-app b/pkg/rpm/rpmbuild/SOURCES/unit.example-python-app deleted file mode 100644 index 756de77e..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python-app +++ /dev/null @@ -1,16 +0,0 @@ -import os -import datetime -import sys - -def application(environ, start_response): - output = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p") - output += "\n\nPython: " - output += sys.version - output += "\n\nENV Variables:\n\n" - for param in os.environ.keys(): - output += param - output += "\t" - output += os.environ[param] - output += "\n" - start_response('200 OK', [('Content-type', 'text/plain')]) - return output.encode('utf8') diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-python-config deleted file mode 100644 index b3d3a2e5..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python", - "processes": 2, - "path": "/usr/share/doc/unit-python/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python27-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-python27-config deleted file mode 100644 index 094e6621..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python27-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 2.7", - "processes": 2, - "path": "/usr/share/doc/unit-python27/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python310-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-python310-config deleted file mode 100644 index 8a73ca53..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python310-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.10", - "processes": 2, - "path": "/usr/share/doc/unit-python310/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python311-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-python311-config deleted file mode 100644 index ee653db6..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python311-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.11", - "processes": 2, - "path": "/usr/share/doc/unit-python311/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python312-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-python312-config deleted file mode 100644 index 1de2eba6..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python312-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.12", - "processes": 2, - "path": "/usr/share/doc/unit-python312/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python34-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-python34-config deleted file mode 100644 index 15063c5e..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python34-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.4", - "processes": 2, - "path": "/usr/share/doc/unit-python34/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python36-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-python36-config deleted file mode 100644 index ef31c781..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python36-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.6", - "processes": 2, - "path": "/usr/share/doc/unit-python36/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python37-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-python37-config deleted file mode 100644 index 904af440..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python37-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.7", - "processes": 2, - "path": "/usr/share/doc/unit-python37/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python38-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-python38-config deleted file mode 100644 index c98d1a52..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python38-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.8", - "processes": 2, - "path": "/usr/share/doc/unit-python38/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-python39-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-python39-config deleted file mode 100644 index 61ed8568..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-python39-config +++ /dev/null @@ -1,16 +0,0 @@ -{ - "applications": { - "example_python": { - "type": "python 3.9", - "processes": 2, - "path": "/usr/share/doc/unit-python39/examples/python-app", - "module": "wsgi" - } - }, - - "listeners": { - "*:8400": { - "pass": "applications/example_python" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-ruby-app b/pkg/rpm/rpmbuild/SOURCES/unit.example-ruby-app deleted file mode 100644 index 69b015b7..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-ruby-app +++ /dev/null @@ -1,7 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'Content-Type' => 'text/plain', - }, ["Hello from Unit running with Ruby #{RUBY_VERSION}!\n\n"]] -end - -run app diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example-ruby-config b/pkg/rpm/rpmbuild/SOURCES/unit.example-ruby-config deleted file mode 100644 index 930aa987..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example-ruby-config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "applications": { - "example_ruby": { - "type": "ruby", - "processes": 2, - "script": "/usr/share/doc/unit-ruby/examples/ruby-app.ru" - } - }, - - "listeners": { - "*:8700": { - "pass": "applications/example_ruby" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.example.config b/pkg/rpm/rpmbuild/SOURCES/unit.example.config deleted file mode 100644 index 4855a954..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.example.config +++ /dev/null @@ -1,47 +0,0 @@ -{ - "applications": { - "example_php": { - "type": "php", - "processes": 2, - "root": "/usr/share/doc/unit-php/examples/phpinfo-app", - "index": "index.php" - }, - - "example_python": { - "type": "python", - "processes": 2, - "path": "/usr/share/doc/unit-python/examples/python-app", - "module": "wsgi" - }, - - "example_go": { - "type": "external", - "executable": "/tmp/go-app" - }, - - "example_perl": { - "type": "perl", - "processes": 1, - "working_directory": "/usr/share/doc/unit-perl/examples/perl-app", - "script": "/usr/share/doc/unit-perl/examples/perl-app/index.pl" - } - }, - - "listeners": { - "*:8300": { - "pass": "applications/example_php" - }, - - "*:8400": { - "pass": "applications/example_python" - }, - - "*:8500": { - "pass": "applications/example_go" - }, - - "*:8600": { - "pass": "applications/example_perl" - } - } -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.logrotate b/pkg/rpm/rpmbuild/SOURCES/unit.logrotate deleted file mode 100644 index 806e4594..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.logrotate +++ /dev/null @@ -1,14 +0,0 @@ -/var/log/unit/*.log { - daily - missingok - rotate 7 - compress - delaycompress - nocreate - notifempty - postrotate - if [ -f /var/run/unit/unit.pid ]; then - /bin/kill -SIGUSR1 `cat /var/run/unit/unit.pid` - fi - endscript -} diff --git a/pkg/rpm/rpmbuild/SOURCES/unit.service b/pkg/rpm/rpmbuild/SOURCES/unit.service deleted file mode 100644 index 6df00fbb..00000000 --- a/pkg/rpm/rpmbuild/SOURCES/unit.service +++ /dev/null @@ -1,26 +0,0 @@ -# Modifying this file in-place is not recommended, because changes -# will be overwritten during package upgrades. To customize the -# behaviour, run "systemctl edit unit" to create an override unit. - -# For example, to change options given to the unitd binary at startup, -# create an override unit (as is done by systemctl edit) and enter -# the following: - -# [Service] -# Environment="UNITD_OPTIONS=--log /var/log/unit/unit.log --pid /var/run/unit/unit.pid" - -[Unit] -Description=NGINX Unit -Wants=network-online.target -After=network-online.target - -[Service] -Type=simple -Environment="UNITD_OPTIONS=--log /var/log/unit/unit.log --pid /var/run/unit/unit.pid" -ExecStart=/usr/sbin/unitd $UNITD_OPTIONS --no-daemon -ExecReload= -RuntimeDirectory=unit -RuntimeDirectoryMode=0755 - -[Install] -WantedBy=multi-user.target diff --git a/pkg/rpm/unit.module.spec.in b/pkg/rpm/unit.module.spec.in deleted file mode 100644 index b3d5d94b..00000000 --- a/pkg/rpm/unit.module.spec.in +++ /dev/null @@ -1,117 +0,0 @@ -# distribution specific definitions -%define bdir %{_builddir}/%{name}-%{version} - -%if (0%{?rhel} == 7 && 0%{?amzn} == 0) -%define dist .el7 -%endif - -%%MODULE_DEFINITIONS%% - -%if 0%{?rhel}%{?fedora} -BuildRequires: gcc -%if 0%{?amzn2} -BuildRequires: openssl11-devel -%else -BuildRequires: openssl-devel -%endif -%endif - -%define unit_version %%UNIT_VERSION%% -%define unit_release %%UNIT_RELEASE%%%{?dist}.ngx - -%define CC_OPT %{optflags} - -%define CONFIGURE_ARGS $(echo "%%CONFIGURE_ARGS%%") - -Name: %%NAME%% -Summary: %%SUMMARY%% -Version: %%VERSION%% -Release: %%RELEASE%%%{?dist}.ngx -License: ASL 2.0 -Vendor: %%PACKAGE_VENDOR%% -URL: https://unit.nginx.org/ -Group: System Environment/Daemons - -Source0: unit-%{version}.tar.gz -%%MODULE_SOURCES%% - -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: pcre2-devel - -Requires: unit-r%%UNIT_VERSION%% - -%description -NGINX Unit is a runtime and delivery environment for modern distributed -applications. It runs the application code in multiple languages -(PHP, Python, Go, etc.), and tightly couples it with traffic delivery -in and out of the application. Take this application server and proxy -directly in the cloud / container environments and fully control your app -dynamically via an API. -This package contains %%SUMMARY%%. - -%if (0%{?fedora}) || (0%{?rhel} >= 8) -%define _debugsource_template %{nil} -%endif - -%prep -%setup -qcTn %{name}-%{unit_version} -tar --strip-components=1 -zxf %{SOURCE0} - -%build -%%MODULE_PREBUILD%% -./configure \ - %{CONFIGURE_ARGS} \ - --modulesdir=%{_libdir}/unit/debug-modules \ - --cc-opt="%{CC_OPT}" \ - --debug -./configure %%MODULE_CONFARGS%% -make %%MODULE_MAKEARGS%% -%{__mv} build build-debug -./configure \ - %{CONFIGURE_ARGS} \ - --modulesdir=%{_libdir}/unit/modules \ - --cc-opt="%{CC_OPT}" -./configure %%MODULE_CONFARGS%% -make %%MODULE_MAKEARGS%% -%{__mv} build build-nodebug - -%install -%{__rm} -rf %{buildroot} -%{__mkdir} -p %{buildroot}%{_datadir}/doc/%%NAME%% -if [ `basename %{SOURCE100}` == COPYRIGHT.%{name} ]; then -%{__install} -m 644 -p %{SOURCE100} \ - %{buildroot}%{_datadir}/doc/%%NAME%%/COPYRIGHT -else -%{__install} -m 644 -p NOTICE \ - %{buildroot}%{_datadir}/doc/%%NAME%%/COPYRIGHT -fi -%%MODULE_PREINSTALL%% -%{__ln_s} build-debug build -DESTDIR=%{buildroot} make %%MODULE_INSTARGS%% -%{__rm} -f build -%{__ln_s} build-nodebug build -DESTDIR=%{buildroot} make %%MODULE_INSTARGS%% -%%MODULE_POSTINSTALL%% - -%check -%{__rm} -rf %{buildroot}/usr/src -cd %{bdir} -grep -v 'usr/src' debugfiles.list > debugfiles.list.new && mv debugfiles.list.new debugfiles.list -cat /dev/null > debugsources.list - -%clean -%{__rm} -rf %{buildroot} - -%post -if [ $1 -eq 1 ]; then -%%MODULE_POST%% -fi - -%files -%defattr(-,root,root,-) -%dir %{_datadir}/doc/%%NAME%% -%{_datadir}/doc/%%NAME%%/* -%%MODULE_FILES%% - -%changelog diff --git a/pkg/rpm/unit.spec.in b/pkg/rpm/unit.spec.in deleted file mode 100644 index 01323650..00000000 --- a/pkg/rpm/unit.spec.in +++ /dev/null @@ -1,244 +0,0 @@ -# distribution specific definitions -%define bdir %{_builddir}/%{name}-%{version} -%define dotests 0 - -%if 0%{?rhel}%{?fedora} -BuildRequires: gcc -%if 0%{?amzn2} -BuildRequires: openssl11-devel -%else -BuildRequires: openssl-devel -%endif -%endif - -%if 0%{?rhel} -%if 0%{?amzn} == 0 -%define dist .el%{?rhel} -%endif -%endif - -%define CC_OPT %{optflags} -fPIC -%define LD_OPT -Wl,-z,relro -Wl,-z,now -pie - -%define CONFIGURE_ARGS $(echo "%%CONFIGURE_ARGS%%") - -Provides: nginx-unit - -Name: unit -Summary: NGINX Unit -Version: %%VERSION%% -Release: %%RELEASE%%%{?dist}.ngx -License: ASL 2.0 -Vendor: %%PACKAGE_VENDOR%% -URL: https://unit.nginx.org/ -Group: System Environment/Daemons - -Source0: unit-%{version}.tar.gz -Source1: unit.service -Source2: unit-debug.service -Source3: unit.example.config -Source4: unit.logrotate - -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) -BuildRequires: systemd -Requires(post): systemd -Requires(preun): systemd -Requires(postun): systemd - -BuildRequires: pcre2-devel -BuildRequires: pkgconfig -BuildRequires: clang -BuildRequires: llvm - -Provides: unit-r%{version} - -%description -NGINX Unit is a runtime and delivery environment for modern distributed -applications. It runs the application code in multiple languages -(PHP, Python, Go, etc.), and tightly couples it with traffic delivery -in and out of the application. Take this application server and proxy -directly in the cloud / container environments and fully control your app -dynamically via an API. - -%if (0%{?fedora}) || (0%{?rhel} >= 8) -%define _debugsource_template %{nil} -%endif - -%package devel -Summary: NGINX Unit (development files) -Version: %%VERSION%% -Release: %%RELEASE%%%{?dist}.ngx -Group: Development/Libraries -Requires: unit == %%VERSION%%-%%RELEASE%%%{?dist}.ngx -%description devel -Library and include files required for NGINX Unit modules development. - -%prep -%setup -q - -%build -%{__make} %{?_smp_mflags} -C pkg/contrib .njs - -PKG_CONFIG_PATH=%{bdir}/pkg/contrib/njs/build \ -./configure \ - %{CONFIGURE_ARGS} \ - --modulesdir=%{_libdir}/unit/debug-modules \ - --libdir=%{_libdir} \ - --cc-opt="%{CC_OPT}" \ - --ld-opt="%{LD_OPT}" \ - --debug -%{__make} %{?_smp_mflags} -%{__make} %{?_smp_mflags} build/lib/libunit.a -%{__mv} build build-debug - -PKG_CONFIG_PATH=%{bdir}/pkg/contrib/njs/build \ -./configure \ - %{CONFIGURE_ARGS} \ - --modulesdir=%{_libdir}/unit/modules \ - --libdir=%{_libdir} \ - --cc-opt="%{CC_OPT}" \ - --ld-opt="%{LD_OPT}" -%{__make} %{?_smp_mflags} -%{__mv} build build-nodebug - -%if (0%{?fedora}) || (0%{?rhel} >= 8) || (0%{?amzn2}) -%{__make} %{?_smp_mflags} -C pkg/contrib .libunit-wasm -%endif - -%install -%{__rm} -rf %{buildroot} -%{__ln_s} build-nodebug build -DESTDIR=%{buildroot} make unitd-install libunit-install manpage-install -%{__mkdir} -p %{buildroot}%{_bindir} -%{__install} -m755 %{bdir}/tools/unitc \ - %{buildroot}%{_bindir}/unitc -%{__install} -m755 %{bdir}/tools/setup-unit \ - %{buildroot}%{_bindir}/setup-unit -%{__install} -m755 %{bdir}/build-debug/sbin/unitd \ - %{buildroot}%{_sbindir}/unitd-debug -%{__install} -m644 %{bdir}/build-debug/lib/libunit.a \ - %{buildroot}%{_libdir}/libunit-debug.a -%{__mkdir} -p %{buildroot}%{_libdir}/unit/modules -%{__mkdir} -p %{buildroot}%{_libdir}/unit/debug-modules -%{__mkdir} -p %{buildroot}%{_sharedstatedir}/unit -%{__mkdir} -p %{buildroot}%{_localstatedir}/log/unit -%{__mkdir} -p %{buildroot}%{_localstatedir}/run/unit -%{__mkdir} -p %{buildroot}%{_sysconfdir}/logrotate.d -%{__install} -m 644 -p %{SOURCE4} \ - %{buildroot}%{_sysconfdir}/logrotate.d/unit -%{__mkdir} -p %{buildroot}%{_datadir}/doc/unit/examples -%{__install} -m 644 -p %{SOURCE3} \ - %{buildroot}%{_datadir}/doc/unit/examples/example.config -%{__install} -m 644 -p CHANGES \ - %{buildroot}%{_datadir}/doc/unit/ -%{__install} -m 644 -p NOTICE \ - %{buildroot}%{_datadir}/doc/unit/COPYRIGHT -%{__install} -m 644 -p README.md \ - %{buildroot}%{_datadir}/doc/unit/ -%{__install} -m 644 -p CONTRIBUTING.md \ - %{buildroot}%{_datadir}/doc/unit/ - -%{__rm} -rf %{buildroot}%{_initrddir}/ -%{__install} -p -D -m 0644 %{SOURCE1} %{buildroot}%{_unitdir}/unit.service -%{__install} -p -D -m 0644 %{SOURCE2} %{buildroot}%{_unitdir}/unit-debug.service - -%if (0%{?fedora}) || (0%{?rhel} >= 8) || (0%{?amzn2}) -%{__mkdir} -p %{buildroot}%{_includedir}/unit/ -%{__install} -m 644 pkg/contrib/libunit-wasm/src/c/libunit-wasm.a %{buildroot}%{_libdir}/ -%{__install} -m 644 pkg/contrib/libunit-wasm/src/c/include/unit/unit-wasm.h %{buildroot}%{_includedir}/unit/ -%endif - -QA_SKIP_BUILD_ROOT=1 -export QA_SKIP_BUILD_ROOT - -%check -%if %{dotests} -cd %{bdir} && make tests && ./build/tests -%endif -%{__rm} -rf %{buildroot}/usr/src -cd %{bdir} -grep -v 'usr/src' debugfiles.list > debugfiles.list.new && mv debugfiles.list.new debugfiles.list -cat /dev/null > debugsources.list - -%clean -%{__rm} -rf %{buildroot} - -%post -getent group unit >/dev/null || groupadd -r unit -getent passwd unit >/dev/null || \ - useradd -r -g unit -s /sbin/nologin \ - -d /nonexistent -c "unit user" unit -if [ $1 -eq 1 ]; then - /usr/bin/systemctl preset unit.service >/dev/null 2>&1 ||: - /usr/bin/systemctl preset unit-debug.service >/dev/null 2>&1 ||: - cat </dev/null 2>&1 ||: - /usr/bin/systemctl stop unit.service >/dev/null 2>&1 ||: -fi - -%postun -/usr/bin/systemctl daemon-reload >/dev/null 2>&1 ||: -if [ $1 -ge 1 ]; then - /usr/bin/systemctl try-restart unit.service >/dev/null 2>&1 ||: -fi - -%triggerpostun -- unit < 1.22.0 -cat <= 8) || (0%{?amzn2}) -%{_libdir}/libunit-wasm.a -%dir %{_includedir}/unit -%{_includedir}/unit/*.h -%endif -%{_includedir}/nxt_*.h -%{_datadir}/pkgconfig/unit.pc - -%changelog diff --git a/pkg/shasum.mak b/pkg/shasum.mak deleted file mode 100644 index 39ec09e6..00000000 --- a/pkg/shasum.mak +++ /dev/null @@ -1,9 +0,0 @@ -ifeq ($(shell sha512sum --version >/dev/null 2>&1 || echo FAIL),) -SHA512SUM = sha512sum -else ifeq ($(shell shasum --version >/dev/null 2>&1 || echo FAIL),) -SHA512SUM = shasum -a 512 -else ifeq ($(shell openssl version >/dev/null 2>&1 || echo FAIL),) -SHA512SUM = openssl sha512 -else -SHA512SUM = $(error no SHA-512 tool found!) -endif diff --git a/src/java/README.JSR-340 b/src/java/README.JSR-340 deleted file mode 100644 index 0eb189a7..00000000 --- a/src/java/README.JSR-340 +++ /dev/null @@ -1,16 +0,0 @@ -NOTICE: - -This version of Unit code is made available in support of the open source -development process. This is an intermediate build made available for -testing purposes only. This Unit code is untested and presumed incompatible -with the JSR 340 Java Servlet 3.1 specification. You should not deploy or -write to this code. You should instead deploy and write production -applications on pre-built binaries that have been tested and certified -to meet the JSR-340 compatibility requirements such as certified binaries -published for the JSR-340 reference implementation available at -https://javaee.github.io/glassfish/. - -Redistribution of any Intermediate Build must retain this notice. - -Oracle and Java are registered trademarks of Oracle and/or its affiliates. -Other names may be trademarks of their respective owners. diff --git a/src/java/javax/websocket/ClientEndpoint.java b/src/java/javax/websocket/ClientEndpoint.java deleted file mode 100644 index ee984171..00000000 --- a/src/java/javax/websocket/ClientEndpoint.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import javax.websocket.ClientEndpointConfig.Configurator; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface ClientEndpoint { - String[] subprotocols() default {}; - Class[] decoders() default {}; - Class[] encoders() default {}; - public Class configurator() - default Configurator.class; -} diff --git a/src/java/javax/websocket/ClientEndpointConfig.java b/src/java/javax/websocket/ClientEndpointConfig.java deleted file mode 100644 index 13b6cba5..00000000 --- a/src/java/javax/websocket/ClientEndpointConfig.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public interface ClientEndpointConfig extends EndpointConfig { - - List getPreferredSubprotocols(); - - List getExtensions(); - - public Configurator getConfigurator(); - - public final class Builder { - - private static final Configurator DEFAULT_CONFIGURATOR = - new Configurator() {}; - - - public static Builder create() { - return new Builder(); - } - - - private Builder() { - // Hide default constructor - } - - private Configurator configurator = DEFAULT_CONFIGURATOR; - private List preferredSubprotocols = Collections.emptyList(); - private List extensions = Collections.emptyList(); - private List> encoders = - Collections.emptyList(); - private List> decoders = - Collections.emptyList(); - - - public ClientEndpointConfig build() { - return new DefaultClientEndpointConfig(preferredSubprotocols, - extensions, encoders, decoders, configurator); - } - - - public Builder configurator(Configurator configurator) { - if (configurator == null) { - this.configurator = DEFAULT_CONFIGURATOR; - } else { - this.configurator = configurator; - } - return this; - } - - - public Builder preferredSubprotocols( - List preferredSubprotocols) { - if (preferredSubprotocols == null || - preferredSubprotocols.size() == 0) { - this.preferredSubprotocols = Collections.emptyList(); - } else { - this.preferredSubprotocols = - Collections.unmodifiableList(preferredSubprotocols); - } - return this; - } - - - public Builder extensions( - List extensions) { - if (extensions == null || extensions.size() == 0) { - this.extensions = Collections.emptyList(); - } else { - this.extensions = Collections.unmodifiableList(extensions); - } - return this; - } - - - public Builder encoders(List> encoders) { - if (encoders == null || encoders.size() == 0) { - this.encoders = Collections.emptyList(); - } else { - this.encoders = Collections.unmodifiableList(encoders); - } - return this; - } - - - public Builder decoders(List> decoders) { - if (decoders == null || decoders.size() == 0) { - this.decoders = Collections.emptyList(); - } else { - this.decoders = Collections.unmodifiableList(decoders); - } - return this; - } - } - - - public class Configurator { - - /** - * Provides the client with a mechanism to inspect and/or modify the headers - * that are sent to the server to start the WebSocket handshake. - * - * @param headers The HTTP headers - */ - public void beforeRequest(Map> headers) { - // NO-OP - } - - /** - * Provides the client with a mechanism to inspect the handshake response - * that is returned from the server. - * - * @param handshakeResponse The response - */ - public void afterResponse(HandshakeResponse handshakeResponse) { - // NO-OP - } - } -} diff --git a/src/java/javax/websocket/CloseReason.java b/src/java/javax/websocket/CloseReason.java deleted file mode 100644 index ef88d135..00000000 --- a/src/java/javax/websocket/CloseReason.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -public class CloseReason { - - private final CloseCode closeCode; - private final String reasonPhrase; - - public CloseReason(CloseReason.CloseCode closeCode, String reasonPhrase) { - this.closeCode = closeCode; - this.reasonPhrase = reasonPhrase; - } - - public CloseCode getCloseCode() { - return closeCode; - } - - public String getReasonPhrase() { - return reasonPhrase; - } - - @Override - public String toString() { - return "CloseReason: code [" + closeCode.getCode() + - "], reason [" + reasonPhrase + "]"; - } - - public interface CloseCode { - int getCode(); - } - - public enum CloseCodes implements CloseReason.CloseCode { - - NORMAL_CLOSURE(1000), - GOING_AWAY(1001), - PROTOCOL_ERROR(1002), - CANNOT_ACCEPT(1003), - RESERVED(1004), - NO_STATUS_CODE(1005), - CLOSED_ABNORMALLY(1006), - NOT_CONSISTENT(1007), - VIOLATED_POLICY(1008), - TOO_BIG(1009), - NO_EXTENSION(1010), - UNEXPECTED_CONDITION(1011), - SERVICE_RESTART(1012), - TRY_AGAIN_LATER(1013), - TLS_HANDSHAKE_FAILURE(1015); - - private int code; - - CloseCodes(int code) { - this.code = code; - } - - public static CloseCode getCloseCode(final int code) { - if (code > 2999 && code < 5000) { - return new CloseCode() { - @Override - public int getCode() { - return code; - } - }; - } - switch (code) { - case 1000: - return CloseCodes.NORMAL_CLOSURE; - case 1001: - return CloseCodes.GOING_AWAY; - case 1002: - return CloseCodes.PROTOCOL_ERROR; - case 1003: - return CloseCodes.CANNOT_ACCEPT; - case 1004: - return CloseCodes.RESERVED; - case 1005: - return CloseCodes.NO_STATUS_CODE; - case 1006: - return CloseCodes.CLOSED_ABNORMALLY; - case 1007: - return CloseCodes.NOT_CONSISTENT; - case 1008: - return CloseCodes.VIOLATED_POLICY; - case 1009: - return CloseCodes.TOO_BIG; - case 1010: - return CloseCodes.NO_EXTENSION; - case 1011: - return CloseCodes.UNEXPECTED_CONDITION; - case 1012: - return CloseCodes.SERVICE_RESTART; - case 1013: - return CloseCodes.TRY_AGAIN_LATER; - case 1015: - return CloseCodes.TLS_HANDSHAKE_FAILURE; - default: - throw new IllegalArgumentException( - "Invalid close code: [" + code + "]"); - } - } - - @Override - public int getCode() { - return code; - } - } -} diff --git a/src/java/javax/websocket/ContainerProvider.java b/src/java/javax/websocket/ContainerProvider.java deleted file mode 100644 index 1727ca93..00000000 --- a/src/java/javax/websocket/ContainerProvider.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.util.Iterator; -import java.util.ServiceLoader; - -/** - * Use the {@link ServiceLoader} mechanism to provide instances of the WebSocket - * client container. - */ -public abstract class ContainerProvider { - - private static final String DEFAULT_PROVIDER_CLASS_NAME = - "nginx.unit.websocket.WsWebSocketContainer"; - - /** - * Create a new container used to create outgoing WebSocket connections. - * - * @return A newly created container. - */ - public static WebSocketContainer getWebSocketContainer() { - WebSocketContainer result = null; - - ServiceLoader serviceLoader = - ServiceLoader.load(ContainerProvider.class); - Iterator iter = serviceLoader.iterator(); - while (result == null && iter.hasNext()) { - result = iter.next().getContainer(); - } - - // Fall-back. Also used by unit tests - if (result == null) { - try { - @SuppressWarnings("unchecked") - Class clazz = - (Class) Class.forName( - DEFAULT_PROVIDER_CLASS_NAME); - result = clazz.getConstructor().newInstance(); - } catch (ReflectiveOperationException | IllegalArgumentException | - SecurityException e) { - // No options left. Just return null. - } - } - return result; - } - - protected abstract WebSocketContainer getContainer(); -} diff --git a/src/java/javax/websocket/DecodeException.java b/src/java/javax/websocket/DecodeException.java deleted file mode 100644 index 771cfa58..00000000 --- a/src/java/javax/websocket/DecodeException.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.nio.ByteBuffer; - -public class DecodeException extends Exception { - - private static final long serialVersionUID = 1L; - - private ByteBuffer bb; - private String encodedString; - - public DecodeException(ByteBuffer bb, String message, Throwable cause) { - super(message, cause); - this.bb = bb; - } - - public DecodeException(String encodedString, String message, - Throwable cause) { - super(message, cause); - this.encodedString = encodedString; - } - - public DecodeException(ByteBuffer bb, String message) { - super(message); - this.bb = bb; - } - - public DecodeException(String encodedString, String message) { - super(message); - this.encodedString = encodedString; - } - - public ByteBuffer getBytes() { - return bb; - } - - public String getText() { - return encodedString; - } -} diff --git a/src/java/javax/websocket/Decoder.java b/src/java/javax/websocket/Decoder.java deleted file mode 100644 index fad262e3..00000000 --- a/src/java/javax/websocket/Decoder.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.nio.ByteBuffer; - -public interface Decoder { - - abstract void init(EndpointConfig endpointConfig); - - abstract void destroy(); - - interface Binary extends Decoder { - - T decode(ByteBuffer bytes) throws DecodeException; - - boolean willDecode(ByteBuffer bytes); - } - - interface BinaryStream extends Decoder { - - T decode(InputStream is) throws DecodeException, IOException; - } - - interface Text extends Decoder { - - T decode(String s) throws DecodeException; - - boolean willDecode(String s); - } - - interface TextStream extends Decoder { - - T decode(Reader reader) throws DecodeException, IOException; - } -} diff --git a/src/java/javax/websocket/DefaultClientEndpointConfig.java b/src/java/javax/websocket/DefaultClientEndpointConfig.java deleted file mode 100644 index ce28cb26..00000000 --- a/src/java/javax/websocket/DefaultClientEndpointConfig.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -final class DefaultClientEndpointConfig implements ClientEndpointConfig { - - private final List preferredSubprotocols; - private final List extensions; - private final List> encoders; - private final List> decoders; - private final Map userProperties = new ConcurrentHashMap<>(); - private final Configurator configurator; - - - DefaultClientEndpointConfig(List preferredSubprotocols, - List extensions, - List> encoders, - List> decoders, - Configurator configurator) { - this.preferredSubprotocols = preferredSubprotocols; - this.extensions = extensions; - this.decoders = decoders; - this.encoders = encoders; - this.configurator = configurator; - } - - - @Override - public List getPreferredSubprotocols() { - return preferredSubprotocols; - } - - - @Override - public List getExtensions() { - return extensions; - } - - - @Override - public List> getEncoders() { - return encoders; - } - - - @Override - public List> getDecoders() { - return decoders; - } - - - @Override - public final Map getUserProperties() { - return userProperties; - } - - - @Override - public Configurator getConfigurator() { - return configurator; - } -} diff --git a/src/java/javax/websocket/DeploymentException.java b/src/java/javax/websocket/DeploymentException.java deleted file mode 100644 index 1678fd09..00000000 --- a/src/java/javax/websocket/DeploymentException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -public class DeploymentException extends Exception { - - private static final long serialVersionUID = 1L; - - public DeploymentException(String message) { - super(message); - } - - public DeploymentException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/java/javax/websocket/EncodeException.java b/src/java/javax/websocket/EncodeException.java deleted file mode 100644 index fdb536ac..00000000 --- a/src/java/javax/websocket/EncodeException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -public class EncodeException extends Exception { - - private static final long serialVersionUID = 1L; - - private Object object; - - public EncodeException(Object object, String message) { - super(message); - this.object = object; - } - - public EncodeException(Object object, String message, Throwable cause) { - super(message, cause); - this.object = object; - } - - public Object getObject() { - return this.object; - } -} diff --git a/src/java/javax/websocket/Encoder.java b/src/java/javax/websocket/Encoder.java deleted file mode 100644 index 42a107f0..00000000 --- a/src/java/javax/websocket/Encoder.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.nio.ByteBuffer; - -public interface Encoder { - - abstract void init(EndpointConfig endpointConfig); - - abstract void destroy(); - - interface Text extends Encoder { - - String encode(T object) throws EncodeException; - } - - interface TextStream extends Encoder { - - void encode(T object, Writer writer) - throws EncodeException, IOException; - } - - interface Binary extends Encoder { - - ByteBuffer encode(T object) throws EncodeException; - } - - interface BinaryStream extends Encoder { - - void encode(T object, OutputStream os) - throws EncodeException, IOException; - } -} diff --git a/src/java/javax/websocket/Endpoint.java b/src/java/javax/websocket/Endpoint.java deleted file mode 100644 index 9dfdbcce..00000000 --- a/src/java/javax/websocket/Endpoint.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -public abstract class Endpoint { - - /** - * Event that is triggered when a new session starts. - * - * @param session The new session. - * @param config The configuration with which the Endpoint was - * configured. - */ - public abstract void onOpen(Session session, EndpointConfig config); - - /** - * Event that is triggered when a session has closed. - * - * @param session The session - * @param closeReason Why the session was closed - */ - public void onClose(Session session, CloseReason closeReason) { - // NO-OP by default - } - - /** - * Event that is triggered when a protocol error occurs. - * - * @param session The session. - * @param throwable The exception. - */ - public void onError(Session session, Throwable throwable) { - // NO-OP by default - } -} diff --git a/src/java/javax/websocket/EndpointConfig.java b/src/java/javax/websocket/EndpointConfig.java deleted file mode 100644 index 0b6c9681..00000000 --- a/src/java/javax/websocket/EndpointConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.util.List; -import java.util.Map; - -public interface EndpointConfig { - - List> getEncoders(); - - List> getDecoders(); - - Map getUserProperties(); -} diff --git a/src/java/javax/websocket/Extension.java b/src/java/javax/websocket/Extension.java deleted file mode 100644 index b95b27b8..00000000 --- a/src/java/javax/websocket/Extension.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.util.List; - -public interface Extension { - String getName(); - List getParameters(); - - interface Parameter { - String getName(); - String getValue(); - } -} diff --git a/src/java/javax/websocket/HandshakeResponse.java b/src/java/javax/websocket/HandshakeResponse.java deleted file mode 100644 index 807192e8..00000000 --- a/src/java/javax/websocket/HandshakeResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.util.List; -import java.util.Map; - -public interface HandshakeResponse { - - /** - * Name of the WebSocket accept HTTP header. - */ - public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept"; - - Map> getHeaders(); -} diff --git a/src/java/javax/websocket/MessageHandler.java b/src/java/javax/websocket/MessageHandler.java deleted file mode 100644 index 2c30d997..00000000 --- a/src/java/javax/websocket/MessageHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -public interface MessageHandler { - - interface Partial extends MessageHandler { - - /** - * Called when part of a message is available to be processed. - * - * @param messagePart The message part - * @param last true if this is the last part of - * this message, else false - */ - void onMessage(T messagePart, boolean last); - } - - interface Whole extends MessageHandler { - - /** - * Called when a whole message is available to be processed. - * - * @param message The message - */ - void onMessage(T message); - } -} diff --git a/src/java/javax/websocket/OnClose.java b/src/java/javax/websocket/OnClose.java deleted file mode 100644 index 6ee61d36..00000000 --- a/src/java/javax/websocket/OnClose.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface OnClose { -} diff --git a/src/java/javax/websocket/OnError.java b/src/java/javax/websocket/OnError.java deleted file mode 100644 index ce431484..00000000 --- a/src/java/javax/websocket/OnError.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface OnError { -} diff --git a/src/java/javax/websocket/OnMessage.java b/src/java/javax/websocket/OnMessage.java deleted file mode 100644 index 564fa994..00000000 --- a/src/java/javax/websocket/OnMessage.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface OnMessage { - long maxMessageSize() default -1; -} diff --git a/src/java/javax/websocket/OnOpen.java b/src/java/javax/websocket/OnOpen.java deleted file mode 100644 index 9f0ea6e3..00000000 --- a/src/java/javax/websocket/OnOpen.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface OnOpen { -} diff --git a/src/java/javax/websocket/PongMessage.java b/src/java/javax/websocket/PongMessage.java deleted file mode 100644 index 7e9e3b6a..00000000 --- a/src/java/javax/websocket/PongMessage.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.nio.ByteBuffer; - -/** - * Represents a WebSocket Pong message and used by message handlers to enable - * applications to process the response to any Pings they send. - */ -public interface PongMessage { - /** - * Get the payload of the Pong message. - * - * @return The payload of the Pong message. - */ - ByteBuffer getApplicationData(); -} diff --git a/src/java/javax/websocket/RemoteEndpoint.java b/src/java/javax/websocket/RemoteEndpoint.java deleted file mode 100644 index 19c7a100..00000000 --- a/src/java/javax/websocket/RemoteEndpoint.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.nio.ByteBuffer; -import java.util.concurrent.Future; - - -public interface RemoteEndpoint { - - interface Async extends RemoteEndpoint { - - /** - * Obtain the timeout (in milliseconds) for sending a message - * asynchronously. The default value is determined by - * {@link WebSocketContainer#getDefaultAsyncSendTimeout()}. - * @return The current send timeout in milliseconds. A non-positive - * value means an infinite timeout. - */ - long getSendTimeout(); - - /** - * Set the timeout (in milliseconds) for sending a message - * asynchronously. The default value is determined by - * {@link WebSocketContainer#getDefaultAsyncSendTimeout()}. - * @param timeout The new timeout for sending messages asynchronously - * in milliseconds. A non-positive value means an - * infinite timeout. - */ - void setSendTimeout(long timeout); - - /** - * Send the message asynchronously, using the SendHandler to signal to the - * client when the message has been sent. - * @param text The text message to send - * @param completion Used to signal to the client when the message has - * been sent - */ - void sendText(String text, SendHandler completion); - - /** - * Send the message asynchronously, using the Future to signal to the - * client when the message has been sent. - * @param text The text message to send - * @return A Future that signals when the message has been sent. - */ - Future sendText(String text); - - /** - * Send the message asynchronously, using the Future to signal to the client - * when the message has been sent. - * @param data The text message to send - * @return A Future that signals when the message has been sent. - * @throws IllegalArgumentException if {@code data} is {@code null}. - */ - Future sendBinary(ByteBuffer data); - - /** - * Send the message asynchronously, using the SendHandler to signal to the - * client when the message has been sent. - * @param data The text message to send - * @param completion Used to signal to the client when the message has - * been sent - * @throws IllegalArgumentException if {@code data} or {@code completion} - * is {@code null}. - */ - void sendBinary(ByteBuffer data, SendHandler completion); - - /** - * Encodes object as a message and sends it asynchronously, using the - * Future to signal to the client when the message has been sent. - * @param obj The object to be sent. - * @return A Future that signals when the message has been sent. - * @throws IllegalArgumentException if {@code obj} is {@code null}. - */ - Future sendObject(Object obj); - - /** - * Encodes object as a message and sends it asynchronously, using the - * SendHandler to signal to the client when the message has been sent. - * @param obj The object to be sent. - * @param completion Used to signal to the client when the message has - * been sent - * @throws IllegalArgumentException if {@code obj} or - * {@code completion} is {@code null}. - */ - void sendObject(Object obj, SendHandler completion); - - } - - interface Basic extends RemoteEndpoint { - - /** - * Send the message, blocking until the message is sent. - * @param text The text message to send. - * @throws IllegalArgumentException if {@code text} is {@code null}. - * @throws IOException if an I/O error occurs during the sending of the - * message. - */ - void sendText(String text) throws IOException; - - /** - * Send the message, blocking until the message is sent. - * @param data The binary message to send - * @throws IllegalArgumentException if {@code data} is {@code null}. - * @throws IOException if an I/O error occurs during the sending of the - * message. - */ - void sendBinary(ByteBuffer data) throws IOException; - - /** - * Sends part of a text message to the remote endpoint. Once the first part - * of a message has been sent, no other text or binary messages may be sent - * until all remaining parts of this message have been sent. - * - * @param fragment The partial message to send - * @param isLast true if this is the last part of the - * message, otherwise false - * @throws IllegalArgumentException if {@code fragment} is {@code null}. - * @throws IOException if an I/O error occurs during the sending of the - * message. - */ - void sendText(String fragment, boolean isLast) throws IOException; - - /** - * Sends part of a binary message to the remote endpoint. Once the first - * part of a message has been sent, no other text or binary messages may be - * sent until all remaining parts of this message have been sent. - * - * @param partialByte The partial message to send - * @param isLast true if this is the last part of the - * message, otherwise false - * @throws IllegalArgumentException if {@code partialByte} is - * {@code null}. - * @throws IOException if an I/O error occurs during the sending of the - * message. - */ - void sendBinary(ByteBuffer partialByte, boolean isLast) throws IOException; - - OutputStream getSendStream() throws IOException; - - Writer getSendWriter() throws IOException; - - /** - * Encodes object as a message and sends it to the remote endpoint. - * @param data The object to be sent. - * @throws EncodeException if there was a problem encoding the - * {@code data} object as a websocket message. - * @throws IllegalArgumentException if {@code data} is {@code null}. - * @throws IOException if an I/O error occurs during the sending of the - * message. - */ - void sendObject(Object data) throws IOException, EncodeException; - - } - /** - * Enable or disable the batching of outgoing messages for this endpoint. If - * batching is disabled when it was previously enabled then this method will - * block until any currently batched messages have been written. - * - * @param batchingAllowed New setting - * @throws IOException If changing the value resulted in a call to - * {@link #flushBatch()} and that call threw an - * {@link IOException}. - */ - void setBatchingAllowed(boolean batchingAllowed) throws IOException; - - /** - * Obtains the current batching status of the endpoint. - * - * @return true if batching is enabled, otherwise - * false. - */ - boolean getBatchingAllowed(); - - /** - * Flush any currently batched messages to the remote endpoint. This method - * will block until the flush completes. - * - * @throws IOException If an I/O error occurs while flushing - */ - void flushBatch() throws IOException; - - /** - * Send a ping message blocking until the message has been sent. Note that - * if a message is in the process of being sent asynchronously, this method - * will block until that message and this ping has been sent. - * - * @param applicationData The payload for the ping message - * - * @throws IOException If an I/O error occurs while sending the ping - * @throws IllegalArgumentException if the applicationData is too large for - * a control message (max 125 bytes) - */ - void sendPing(ByteBuffer applicationData) - throws IOException, IllegalArgumentException; - - /** - * Send a pong message blocking until the message has been sent. Note that - * if a message is in the process of being sent asynchronously, this method - * will block until that message and this pong has been sent. - * - * @param applicationData The payload for the pong message - * - * @throws IOException If an I/O error occurs while sending the pong - * @throws IllegalArgumentException if the applicationData is too large for - * a control message (max 125 bytes) - */ - void sendPong(ByteBuffer applicationData) - throws IOException, IllegalArgumentException; -} - diff --git a/src/java/javax/websocket/SendHandler.java b/src/java/javax/websocket/SendHandler.java deleted file mode 100644 index 65b9a19a..00000000 --- a/src/java/javax/websocket/SendHandler.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -public interface SendHandler { - - void onResult(SendResult result); -} diff --git a/src/java/javax/websocket/SendResult.java b/src/java/javax/websocket/SendResult.java deleted file mode 100644 index a3797d5b..00000000 --- a/src/java/javax/websocket/SendResult.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -public final class SendResult { - private final Throwable exception; - private final boolean ok; - - public SendResult(Throwable exception) { - this.exception = exception; - this.ok = (exception == null); - } - - public SendResult() { - this (null); - } - - public Throwable getException() { - return exception; - } - - public boolean isOK() { - return ok; - } -} diff --git a/src/java/javax/websocket/Session.java b/src/java/javax/websocket/Session.java deleted file mode 100644 index eea15e5b..00000000 --- a/src/java/javax/websocket/Session.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.io.Closeable; -import java.io.IOException; -import java.net.URI; -import java.security.Principal; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public interface Session extends Closeable { - - /** - * Get the container that created this session. - * @return the container that created this session. - */ - WebSocketContainer getContainer(); - - /** - * Registers a {@link MessageHandler} for incoming messages. Only one - * {@link MessageHandler} may be registered for each message type (text, - * binary, pong). The message type will be derived at runtime from the - * provided {@link MessageHandler} instance. It is not always possible to do - * this so it is better to use - * {@link #addMessageHandler(Class, javax.websocket.MessageHandler.Partial)} - * or - * {@link #addMessageHandler(Class, javax.websocket.MessageHandler.Whole)}. - * - * @param handler The message handler for a incoming message - * - * @throws IllegalStateException If a message handler has already been - * registered for the associated message type - */ - void addMessageHandler(MessageHandler handler) throws IllegalStateException; - - Set getMessageHandlers(); - - void removeMessageHandler(MessageHandler listener); - - String getProtocolVersion(); - - String getNegotiatedSubprotocol(); - - List getNegotiatedExtensions(); - - boolean isSecure(); - - boolean isOpen(); - - /** - * Get the idle timeout for this session. - * @return The current idle timeout for this session in milliseconds. Zero - * or negative values indicate an infinite timeout. - */ - long getMaxIdleTimeout(); - - /** - * Set the idle timeout for this session. - * @param timeout The new idle timeout for this session in milliseconds. - * Zero or negative values indicate an infinite timeout. - */ - void setMaxIdleTimeout(long timeout); - - /** - * Set the current maximum buffer size for binary messages. - * @param max The new maximum buffer size in bytes - */ - void setMaxBinaryMessageBufferSize(int max); - - /** - * Get the current maximum buffer size for binary messages. - * @return The current maximum buffer size in bytes - */ - int getMaxBinaryMessageBufferSize(); - - /** - * Set the maximum buffer size for text messages. - * @param max The new maximum buffer size in characters. - */ - void setMaxTextMessageBufferSize(int max); - - /** - * Get the maximum buffer size for text messages. - * @return The maximum buffer size in characters. - */ - int getMaxTextMessageBufferSize(); - - RemoteEndpoint.Async getAsyncRemote(); - - RemoteEndpoint.Basic getBasicRemote(); - - /** - * Provides a unique identifier for the session. This identifier should not - * be relied upon to be generated from a secure random source. - * @return A unique identifier for the session. - */ - String getId(); - - /** - * Close the connection to the remote end point using the code - * {@link javax.websocket.CloseReason.CloseCodes#NORMAL_CLOSURE} and an - * empty reason phrase. - * - * @throws IOException if an I/O error occurs while the WebSocket session is - * being closed. - */ - @Override - void close() throws IOException; - - - /** - * Close the connection to the remote end point using the specified code - * and reason phrase. - * @param closeReason The reason the WebSocket session is being closed. - * - * @throws IOException if an I/O error occurs while the WebSocket session is - * being closed. - */ - void close(CloseReason closeReason) throws IOException; - - URI getRequestURI(); - - Map> getRequestParameterMap(); - - String getQueryString(); - - Map getPathParameters(); - - Map getUserProperties(); - - Principal getUserPrincipal(); - - /** - * Obtain the set of open sessions associated with the same local endpoint - * as this session. - * - * @return The set of currently open sessions for the local endpoint that - * this session is associated with. - */ - Set getOpenSessions(); - - /** - * Registers a {@link MessageHandler} for partial incoming messages. Only - * one {@link MessageHandler} may be registered for each message type (text - * or binary, pong messages are never presented as partial messages). - * - * @param The type of message that the given handler is intended - * for - * @param clazz The Class that implements T - * @param handler The message handler for a incoming message - * - * @throws IllegalStateException If a message handler has already been - * registered for the associated message type - * - * @since WebSocket 1.1 - */ - void addMessageHandler(Class clazz, MessageHandler.Partial handler) - throws IllegalStateException; - - /** - * Registers a {@link MessageHandler} for whole incoming messages. Only - * one {@link MessageHandler} may be registered for each message type (text, - * binary, pong). - * - * @param The type of message that the given handler is intended - * for - * @param clazz The Class that implements T - * @param handler The message handler for a incoming message - * - * @throws IllegalStateException If a message handler has already been - * registered for the associated message type - * - * @since WebSocket 1.1 - */ - void addMessageHandler(Class clazz, MessageHandler.Whole handler) - throws IllegalStateException; -} diff --git a/src/java/javax/websocket/SessionException.java b/src/java/javax/websocket/SessionException.java deleted file mode 100644 index 428b82ec..00000000 --- a/src/java/javax/websocket/SessionException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -public class SessionException extends Exception { - - private static final long serialVersionUID = 1L; - - private final Session session; - - - public SessionException(String message, Throwable cause, Session session) { - super(message, cause); - this.session = session; - } - - - public Session getSession() { - return session; - } -} diff --git a/src/java/javax/websocket/WebSocketContainer.java b/src/java/javax/websocket/WebSocketContainer.java deleted file mode 100644 index f2da3e43..00000000 --- a/src/java/javax/websocket/WebSocketContainer.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket; - -import java.io.IOException; -import java.net.URI; -import java.util.Set; - -public interface WebSocketContainer { - - /** - * Get the default timeout for sending a message asynchronously. - * @return The current default timeout in milliseconds. A non-positive value - * means an infinite timeout. - */ - long getDefaultAsyncSendTimeout(); - - /** - * Set the default timeout for sending a message asynchronously. - * @param timeout The new default timeout in milliseconds. A non-positive - * value means an infinite timeout. - */ - void setAsyncSendTimeout(long timeout); - - Session connectToServer(Object endpoint, URI path) - throws DeploymentException, IOException; - - Session connectToServer(Class annotatedEndpointClass, URI path) - throws DeploymentException, IOException; - - /** - * Creates a new connection to the WebSocket. - * - * @param endpoint - * The endpoint instance that will handle responses from the - * server - * @param clientEndpointConfiguration - * Used to configure the new connection - * @param path - * The full URL of the WebSocket endpoint to connect to - * - * @return The WebSocket session for the connection - * - * @throws DeploymentException If the connection cannot be established - * @throws IOException If an I/O occurred while trying to establish the - * connection - */ - Session connectToServer(Endpoint endpoint, - ClientEndpointConfig clientEndpointConfiguration, URI path) - throws DeploymentException, IOException; - - /** - * Creates a new connection to the WebSocket. - * - * @param endpoint - * An instance of this class will be created to handle responses - * from the server - * @param clientEndpointConfiguration - * Used to configure the new connection - * @param path - * The full URL of the WebSocket endpoint to connect to - * - * @return The WebSocket session for the connection - * - * @throws DeploymentException If the connection cannot be established - * @throws IOException If an I/O occurred while trying to establish the - * connection - */ - Session connectToServer(Class endpoint, - ClientEndpointConfig clientEndpointConfiguration, URI path) - throws DeploymentException, IOException; - - /** - * Get the current default session idle timeout. - * @return The current default session idle timeout in milliseconds. Zero or - * negative values indicate an infinite timeout. - */ - long getDefaultMaxSessionIdleTimeout(); - - /** - * Set the default session idle timeout. - * @param timeout The new default session idle timeout in milliseconds. Zero - * or negative values indicate an infinite timeout. - */ - void setDefaultMaxSessionIdleTimeout(long timeout); - - /** - * Get the default maximum buffer size for binary messages. - * @return The current default maximum buffer size in bytes - */ - int getDefaultMaxBinaryMessageBufferSize(); - - /** - * Set the default maximum buffer size for binary messages. - * @param max The new default maximum buffer size in bytes - */ - void setDefaultMaxBinaryMessageBufferSize(int max); - - /** - * Get the default maximum buffer size for text messages. - * @return The current default maximum buffer size in characters - */ - int getDefaultMaxTextMessageBufferSize(); - - /** - * Set the default maximum buffer size for text messages. - * @param max The new default maximum buffer size in characters - */ - void setDefaultMaxTextMessageBufferSize(int max); - - /** - * Get the installed extensions. - * @return The set of extensions that are supported by this WebSocket - * implementation. - */ - Set getInstalledExtensions(); -} diff --git a/src/java/javax/websocket/server/DefaultServerEndpointConfig.java b/src/java/javax/websocket/server/DefaultServerEndpointConfig.java deleted file mode 100644 index 7c3b8d7d..00000000 --- a/src/java/javax/websocket/server/DefaultServerEndpointConfig.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket.server; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import javax.websocket.Decoder; -import javax.websocket.Encoder; -import javax.websocket.Extension; - -/** - * Provides the default configuration for WebSocket server endpoints. - */ -final class DefaultServerEndpointConfig implements ServerEndpointConfig { - - private final Class endpointClass; - private final String path; - private final List subprotocols; - private final List extensions; - private final List> encoders; - private final List> decoders; - private final Configurator serverEndpointConfigurator; - private final Map userProperties = new ConcurrentHashMap<>(); - - DefaultServerEndpointConfig( - Class endpointClass, String path, - List subprotocols, List extensions, - List> encoders, - List> decoders, - Configurator serverEndpointConfigurator) { - this.endpointClass = endpointClass; - this.path = path; - this.subprotocols = subprotocols; - this.extensions = extensions; - this.encoders = encoders; - this.decoders = decoders; - this.serverEndpointConfigurator = serverEndpointConfigurator; - } - - @Override - public Class getEndpointClass() { - return endpointClass; - } - - @Override - public List> getEncoders() { - return this.encoders; - } - - @Override - public List> getDecoders() { - return this.decoders; - } - - @Override - public String getPath() { - return path; - } - - @Override - public Configurator getConfigurator() { - return serverEndpointConfigurator; - } - - @Override - public final Map getUserProperties() { - return userProperties; - } - - @Override - public final List getSubprotocols() { - return subprotocols; - } - - @Override - public final List getExtensions() { - return extensions; - } -} diff --git a/src/java/javax/websocket/server/HandshakeRequest.java b/src/java/javax/websocket/server/HandshakeRequest.java deleted file mode 100644 index f2e33273..00000000 --- a/src/java/javax/websocket/server/HandshakeRequest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket.server; - -import java.net.URI; -import java.security.Principal; -import java.util.List; -import java.util.Map; - -/** - * Represents the HTTP request that asked to be upgraded to WebSocket. - */ -public interface HandshakeRequest { - - static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key"; - static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol"; - static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version"; - static final String SEC_WEBSOCKET_EXTENSIONS= "Sec-WebSocket-Extensions"; - - Map> getHeaders(); - - Principal getUserPrincipal(); - - URI getRequestURI(); - - boolean isUserInRole(String role); - - /** - * Get the HTTP Session object associated with this request. Object is used - * to avoid a direct dependency on the Servlet API. - * @return The javax.servlet.http.HttpSession object associated with this - * request, if any. - */ - Object getHttpSession(); - - Map> getParameterMap(); - - String getQueryString(); -} diff --git a/src/java/javax/websocket/server/PathParam.java b/src/java/javax/websocket/server/PathParam.java deleted file mode 100644 index ff1d085e..00000000 --- a/src/java/javax/websocket/server/PathParam.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket.server; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Used to annotate method parameters on POJO endpoints the the {@link - * ServerEndpoint} has been defined with a {@link ServerEndpoint#value()} that - * uses a URI template. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface PathParam { - String value(); -} diff --git a/src/java/javax/websocket/server/ServerApplicationConfig.java b/src/java/javax/websocket/server/ServerApplicationConfig.java deleted file mode 100644 index b91f1c43..00000000 --- a/src/java/javax/websocket/server/ServerApplicationConfig.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket.server; - -import java.util.Set; - -import javax.websocket.Endpoint; - -/** - * Applications may provide an implementation of this interface to filter the - * discovered WebSocket endpoints that are deployed. Implementations of this - * class will be discovered via an ServletContainerInitializer scan. - */ -public interface ServerApplicationConfig { - - /** - * Enables applications to filter the discovered implementations of - * {@link ServerEndpointConfig}. - * - * @param scanned The {@link Endpoint} implementations found in the - * application - * @return The set of configurations for the endpoint the application - * wishes to deploy - */ - Set getEndpointConfigs( - Set> scanned); - - /** - * Enables applications to filter the discovered classes annotated with - * {@link ServerEndpoint}. - * - * @param scanned The POJOs annotated with {@link ServerEndpoint} found in - * the application - * @return The set of POJOs the application wishes to deploy - */ - Set> getAnnotatedEndpointClasses(Set> scanned); -} diff --git a/src/java/javax/websocket/server/ServerContainer.java b/src/java/javax/websocket/server/ServerContainer.java deleted file mode 100644 index 3243a07c..00000000 --- a/src/java/javax/websocket/server/ServerContainer.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket.server; - -import javax.websocket.DeploymentException; -import javax.websocket.WebSocketContainer; - -/** - * Provides the ability to deploy endpoints programmatically. - */ -public interface ServerContainer extends WebSocketContainer { - public abstract void addEndpoint(Class clazz) throws DeploymentException; - - public abstract void addEndpoint(ServerEndpointConfig sec) - throws DeploymentException; -} diff --git a/src/java/javax/websocket/server/ServerEndpoint.java b/src/java/javax/websocket/server/ServerEndpoint.java deleted file mode 100644 index 43b7dfa2..00000000 --- a/src/java/javax/websocket/server/ServerEndpoint.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket.server; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import javax.websocket.Decoder; -import javax.websocket.Encoder; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface ServerEndpoint { - - /** - * URI or URI-template that the annotated class should be mapped to. - * @return The URI or URI-template that the annotated class should be mapped - * to. - */ - String value(); - - String[] subprotocols() default {}; - - Class[] decoders() default {}; - - Class[] encoders() default {}; - - public Class configurator() - default ServerEndpointConfig.Configurator.class; -} diff --git a/src/java/javax/websocket/server/ServerEndpointConfig.java b/src/java/javax/websocket/server/ServerEndpointConfig.java deleted file mode 100644 index 5afdf79c..00000000 --- a/src/java/javax/websocket/server/ServerEndpointConfig.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.websocket.server; - -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.ServiceLoader; - -import javax.websocket.Decoder; -import javax.websocket.Encoder; -import javax.websocket.EndpointConfig; -import javax.websocket.Extension; -import javax.websocket.HandshakeResponse; - -/** - * Provides configuration information for WebSocket endpoints published to a - * server. Applications may provide their own implementation or use - * {@link Builder}. - */ -public interface ServerEndpointConfig extends EndpointConfig { - - Class getEndpointClass(); - - /** - * Returns the path at which this WebSocket server endpoint has been - * registered. It may be a path or a level 0 URI template. - * @return The registered path - */ - String getPath(); - - List getSubprotocols(); - - List getExtensions(); - - Configurator getConfigurator(); - - - public final class Builder { - - public static Builder create( - Class endpointClass, String path) { - return new Builder(endpointClass, path); - } - - - private final Class endpointClass; - private final String path; - private List> encoders = - Collections.emptyList(); - private List> decoders = - Collections.emptyList(); - private List subprotocols = Collections.emptyList(); - private List extensions = Collections.emptyList(); - private Configurator configurator = - Configurator.fetchContainerDefaultConfigurator(); - - - private Builder(Class endpointClass, - String path) { - this.endpointClass = endpointClass; - this.path = path; - } - - public ServerEndpointConfig build() { - return new DefaultServerEndpointConfig(endpointClass, path, - subprotocols, extensions, encoders, decoders, configurator); - } - - - public Builder encoders( - List> encoders) { - if (encoders == null || encoders.size() == 0) { - this.encoders = Collections.emptyList(); - } else { - this.encoders = Collections.unmodifiableList(encoders); - } - return this; - } - - - public Builder decoders( - List> decoders) { - if (decoders == null || decoders.size() == 0) { - this.decoders = Collections.emptyList(); - } else { - this.decoders = Collections.unmodifiableList(decoders); - } - return this; - } - - - public Builder subprotocols( - List subprotocols) { - if (subprotocols == null || subprotocols.size() == 0) { - this.subprotocols = Collections.emptyList(); - } else { - this.subprotocols = Collections.unmodifiableList(subprotocols); - } - return this; - } - - - public Builder extensions( - List extensions) { - if (extensions == null || extensions.size() == 0) { - this.extensions = Collections.emptyList(); - } else { - this.extensions = Collections.unmodifiableList(extensions); - } - return this; - } - - - public Builder configurator(Configurator serverEndpointConfigurator) { - if (serverEndpointConfigurator == null) { - this.configurator = Configurator.fetchContainerDefaultConfigurator(); - } else { - this.configurator = serverEndpointConfigurator; - } - return this; - } - } - - - public class Configurator { - - private static volatile Configurator defaultImpl = null; - private static final Object defaultImplLock = new Object(); - - private static final String DEFAULT_IMPL_CLASSNAME = - "nginx.unit.websocket.server.DefaultServerEndpointConfigurator"; - - public static void setDefault(Configurator def) { - synchronized (defaultImplLock) { - defaultImpl = def; - } - } - - static Configurator fetchContainerDefaultConfigurator() { - if (defaultImpl == null) { - synchronized (defaultImplLock) { - if (defaultImpl == null) { - defaultImpl = loadDefault(); - } - } - } - return defaultImpl; - } - - - private static Configurator loadDefault() { - Configurator result = null; - - ServiceLoader serviceLoader = - ServiceLoader.load(Configurator.class); - - Iterator iter = serviceLoader.iterator(); - while (result == null && iter.hasNext()) { - result = iter.next(); - } - - // Fall-back. Also used by unit tests - if (result == null) { - try { - @SuppressWarnings("unchecked") - Class clazz = - (Class) Class.forName( - DEFAULT_IMPL_CLASSNAME); - result = clazz.getConstructor().newInstance(); - } catch (ReflectiveOperationException | IllegalArgumentException | - SecurityException e) { - // No options left. Just return null. - } - } - return result; - } - - public String getNegotiatedSubprotocol(List supported, - List requested) { - return fetchContainerDefaultConfigurator().getNegotiatedSubprotocol(supported, requested); - } - - public List getNegotiatedExtensions(List installed, - List requested) { - return fetchContainerDefaultConfigurator().getNegotiatedExtensions(installed, requested); - } - - public boolean checkOrigin(String originHeaderValue) { - return fetchContainerDefaultConfigurator().checkOrigin(originHeaderValue); - } - - public void modifyHandshake(ServerEndpointConfig sec, - HandshakeRequest request, HandshakeResponse response) { - fetchContainerDefaultConfigurator().modifyHandshake(sec, request, response); - } - - public T getEndpointInstance(Class clazz) - throws InstantiationException { - return fetchContainerDefaultConfigurator().getEndpointInstance( - clazz); - } - } -} diff --git a/src/java/nginx/unit/Context.java b/src/java/nginx/unit/Context.java deleted file mode 100644 index e1245e1f..00000000 --- a/src/java/nginx/unit/Context.java +++ /dev/null @@ -1,3638 +0,0 @@ -package nginx.unit; - -import io.github.classgraph.ClassGraph; -import io.github.classgraph.ClassInfo; -import io.github.classgraph.ClassInfoList; -import io.github.classgraph.ScanResult; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; - -import java.lang.ClassLoader; -import java.lang.ClassNotFoundException; -import java.lang.IllegalArgumentException; -import java.lang.IllegalStateException; -import java.lang.reflect.Constructor; - -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; - -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Enumeration; -import java.util.EventListener; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.UUID; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.jar.JarInputStream; -import java.util.zip.ZipEntry; - -import javax.servlet.DispatcherType; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.FilterRegistration.Dynamic; -import javax.servlet.FilterRegistration; -import javax.servlet.MultipartConfigElement; -import javax.servlet.Registration; -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContainerInitializer; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextAttributeEvent; -import javax.servlet.ServletContextAttributeListener; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.ServletRegistration; -import javax.servlet.ServletResponse; -import javax.servlet.ServletRequest; -import javax.servlet.ServletRequestAttributeEvent; -import javax.servlet.ServletRequestAttributeListener; -import javax.servlet.ServletRequestEvent; -import javax.servlet.ServletRequestListener; -import javax.servlet.ServletSecurityElement; -import javax.servlet.SessionCookieConfig; -import javax.servlet.SessionTrackingMode; -import javax.servlet.annotation.HandlesTypes; -import javax.servlet.annotation.MultipartConfig; -import javax.servlet.annotation.WebInitParam; -import javax.servlet.annotation.WebServlet; -import javax.servlet.annotation.WebFilter; -import javax.servlet.annotation.WebListener; -import javax.servlet.descriptor.JspConfigDescriptor; -import javax.servlet.descriptor.JspPropertyGroupDescriptor; -import javax.servlet.descriptor.TaglibDescriptor; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSessionAttributeListener; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionIdListener; -import javax.servlet.http.HttpSessionListener; - -import javax.websocket.server.ServerEndpoint; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import nginx.unit.websocket.WsSession; - -import org.eclipse.jetty.http.MimeTypes; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import org.apache.jasper.servlet.JspServlet; -import org.apache.jasper.servlet.JasperInitializer; - - -public class Context implements ServletContext, InitParams -{ - public final static int SERVLET_MAJOR_VERSION = 3; - public final static int SERVLET_MINOR_VERSION = 1; - - private String context_path_ = ""; - private String server_info_ = "unit"; - private String app_version_ = ""; - private MimeTypes mime_types_; - private boolean metadata_complete_ = false; - private boolean welcome_files_list_found_ = false; - private boolean ctx_initialized_ = false; - - private ClassLoader loader_; - private File webapp_; - private File extracted_dir_; - private File temp_dir_; - - private final Map init_params_ = new HashMap<>(); - private final Map attributes_ = new HashMap<>(); - - private final Map parsed_patterns_ = new HashMap<>(); - - private final List filters_ = new ArrayList<>(); - private final Map name2filter_ = new HashMap<>(); - private final List filter_maps_ = new ArrayList<>(); - - private final List servlets_ = new ArrayList<>(); - private final Map name2servlet_ = new HashMap<>(); - private final Map pattern2servlet_ = new HashMap<>(); - private final Map exact2servlet_ = new HashMap<>(); - private final List prefix_patterns_ = new ArrayList<>(); - private final Map suffix2servlet_ = new HashMap<>(); - private ServletReg default_servlet_; - private ServletReg system_default_servlet_; - - private final List welcome_files_ = new ArrayList<>(); - - private final Map exception2location_ = new HashMap<>(); - private final Map error2location_ = new HashMap<>(); - - public static final Class[] LISTENER_TYPES = new Class[] { - ServletContextListener.class, - ServletContextAttributeListener.class, - ServletRequestListener.class, - ServletRequestAttributeListener.class, - HttpSessionAttributeListener.class, - HttpSessionIdListener.class, - HttpSessionListener.class - }; - - private final List pending_listener_classnames_ = new ArrayList<>(); - private final Set listener_classnames_ = new HashSet<>(); - - private final List ctx_listeners_ = new ArrayList<>(); - private final List destroy_listeners_ = new ArrayList<>(); - private final List ctx_attr_listeners_ = new ArrayList<>(); - private final List req_init_listeners_ = new ArrayList<>(); - private final List req_destroy_listeners_ = new ArrayList<>(); - private final List req_attr_listeners_ = new ArrayList<>(); - - private ServletRequestAttributeListener req_attr_proxy_ = null; - - private final List sess_attr_listeners_ = new ArrayList<>(); - private final List sess_id_listeners_ = new ArrayList<>(); - private final List sess_listeners_ = new ArrayList<>(); - - private HttpSessionAttributeListener sess_attr_proxy_ = null; - - private final SessionCookieConfig session_cookie_config_ = new UnitSessionCookieConfig(); - private final Set default_session_tracking_modes_ = new HashSet<>(); - private Set session_tracking_modes_ = default_session_tracking_modes_; - private int session_timeout_ = 60; - - private final Map sessions_ = new HashMap<>(); - - private static final String WEB_INF = "WEB-INF/"; - private static final String WEB_INF_CLASSES = WEB_INF + "classes/"; - private static final String WEB_INF_LIB = WEB_INF + "lib/"; - - private class PrefixPattern implements Comparable - { - public final String pattern; - public final ServletReg servlet; - - public PrefixPattern(String p, ServletReg s) - { - pattern = p; - servlet = s; - } - - public boolean match(String url) - { - return url.startsWith(pattern) && ( - url.length() == pattern.length() - || url.charAt(pattern.length()) == '/'); - } - - @Override - public int compareTo(PrefixPattern p) - { - return p.pattern.length() - pattern.length(); - } - } - - private class StaticServlet extends HttpServlet - { - @Override - public void doPost(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - doGet(request, response); - } - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - String path = null; - - if (request.getDispatcherType() == DispatcherType.INCLUDE) { - path = (String) request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH); - } - - if (path == null) { - path = request.getServletPath(); - } - - /* - 10.6 Web Application Archive File - ... - This directory [META-INF] must not be directly served as - content by the container in response to a Web client's request, - though its contents are visible to servlet code via the - getResource and getResourceAsStream calls on the - ServletContext. Also, any requests to access the resources in - META-INF directory must be returned with a SC_NOT_FOUND(404) - response. - */ - if (request.getDispatcherType() == DispatcherType.REQUEST - && (path.equals("/WEB-INF") || path.startsWith("/WEB-INF/") - || path.equals("/META-INF") || path.startsWith("/META-INF/"))) - { - response.sendError(response.SC_NOT_FOUND); - return; - } - - if (path.startsWith("/")) { - path = path.substring(1); - } - - File f = new File(webapp_, path); - if (!f.exists()) { - if (request.getDispatcherType() == DispatcherType.INCLUDE) { - /* - 9.3 The Include Method - ... - If the default servlet is the target of a - RequestDispatch.include() and the requested resource - does not exist, then the default servlet MUST throw - FileNotFoundException. - */ - - throw new FileNotFoundException(); - } - - response.sendError(response.SC_NOT_FOUND); - return; - } - - long ims = request.getDateHeader("If-Modified-Since"); - long lm = f.lastModified(); - - if (lm < ims) { - response.sendError(response.SC_NOT_MODIFIED); - return; - } - - response.setDateHeader("Last-Modified", f.lastModified()); - - if (f.isDirectory()) { - String url = request.getRequestURL().toString(); - if (!url.endsWith("/")) { - response.setHeader("Location", url + "/"); - response.sendError(response.SC_FOUND); - return; - } - - String[] ls = f.list(); - - PrintWriter writer = response.getWriter(); - - for (String n : ls) { - writer.println("" + n + "
"); - } - - writer.close(); - - } else { - response.setContentLengthLong(f.length()); - response.setContentType(getMimeType(f.getName())); - - InputStream is = new FileInputStream(f); - byte[] buffer = new byte[response.getBufferSize()]; - ServletOutputStream os = response.getOutputStream(); - while (true) { - int read = is.read(buffer); - if (read == -1) { - break; - } - os.write(buffer, 0, read); - } - - os.close(); - } - } - } - - public static Context start(String webapp, URL[] classpaths) - throws Exception - { - Context ctx = new Context(); - - ctx.loadApp(webapp, classpaths); - ctx.initialized(); - - return ctx; - } - - public Context() - { - default_session_tracking_modes_.add(SessionTrackingMode.COOKIE); - - context_path_ = System.getProperty("nginx.unit.context.path", "").trim(); - - if (context_path_.endsWith("/")) { - context_path_ = context_path_.substring(0, context_path_.length() - 1); - } - - if (!context_path_.isEmpty() && !context_path_.startsWith("/")) { - context_path_ = "/" + context_path_; - } - - if (context_path_.isEmpty()) { - session_cookie_config_.setPath("/"); - } else { - session_cookie_config_.setPath(context_path_); - } - } - - public void loadApp(String webapp, URL[] classpaths) - throws Exception - { - File root = new File(webapp); - if (!root.exists()) { - throw new FileNotFoundException( - "Unable to determine code source archive from " + root); - } - - ArrayList url_list = new ArrayList<>(); - - for (URL u : classpaths) { - url_list.add(u); - } - - if (!root.isDirectory()) { - root = extractWar(root); - extracted_dir_ = root; - } - - webapp_ = root; - - Path tmpDir = Files.createTempDirectory("webapp"); - temp_dir_ = tmpDir.toFile(); - setAttribute(ServletContext.TEMPDIR, temp_dir_); - - File web_inf_classes = new File(root, WEB_INF_CLASSES); - if (web_inf_classes.exists() && web_inf_classes.isDirectory()) { - url_list.add(new URL("file:" + root.getAbsolutePath() + "/" + WEB_INF_CLASSES)); - } - - File lib = new File(root, WEB_INF_LIB); - File[] libs = lib.listFiles(); - - if (libs != null) { - for (File l : libs) { - url_list.add(new URL("file:" + l.getAbsolutePath())); - } - } - - URL[] urls = new URL[url_list.size()]; - - for (int i = 0; i < url_list.size(); i++) { - urls[i] = url_list.get(i); - trace("archives: " + urls[i]); - } - - String custom_listener = System.getProperty("nginx.unit.context.listener", "").trim(); - if (!custom_listener.isEmpty()) { - pending_listener_classnames_.add(custom_listener); - } - - processWebXml(root); - - loader_ = new UnitClassLoader(urls, - Context.class.getClassLoader().getParent()); - - Class wsSession_class = WsSession.class; - trace("wsSession.test: " + WsSession.wsSession_test()); - - ClassLoader old = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(loader_); - - try { - for (String listener_classname : pending_listener_classnames_) { - addListener(listener_classname); - } - - ClassGraph classgraph = new ClassGraph() - //.verbose() - .overrideClassLoaders(loader_) - .ignoreParentClassLoaders() - .enableClassInfo() - .enableAnnotationInfo() - //.enableSystemPackages() - .acceptModules("javax.*") - //.enableAllInfo() - ; - - String verbose = System.getProperty("nginx.unit.context.classgraph.verbose", "").trim(); - - if (verbose.equals("true")) { - classgraph.verbose(); - } - - ScanResult scan_res = classgraph.scan(); - - javax.websocket.server.ServerEndpointConfig.Configurator.setDefault(new nginx.unit.websocket.server.DefaultServerEndpointConfigurator()); - - loadInitializer(new nginx.unit.websocket.server.WsSci(), scan_res); - - if (!metadata_complete_) { - loadInitializers(scan_res); - } - - if (!metadata_complete_) { - scanClasses(scan_res); - } - - /* - 8.1.6 Other annotations / conventions - ... - By default all applications will have index.htm(l) and index.jsp - in the list of welcome-file-list. The descriptor may to be used - to override these default settings. - */ - if (!welcome_files_list_found_) { - welcome_files_.add("index.htm"); - welcome_files_.add("index.html"); - welcome_files_.add("index.jsp"); - } - - ServletReg jsp_servlet = name2servlet_.get("jsp"); - if (jsp_servlet == null) { - jsp_servlet = new ServletReg("jsp", JspServlet.class); - jsp_servlet.system_jsp_servlet_ = true; - servlets_.add(jsp_servlet); - name2servlet_.put("jsp", jsp_servlet); - } - - if (jsp_servlet.getClassName() == null) { - jsp_servlet.setClass(JspServlet.class); - jsp_servlet.system_jsp_servlet_ = true; - } - - if (jsp_servlet.patterns_.isEmpty()) { - parseURLPattern("*.jsp", jsp_servlet); - parseURLPattern("*.jspx", jsp_servlet); - } - - ServletReg def_servlet = name2servlet_.get("default"); - if (def_servlet == null) { - def_servlet = new ServletReg("default", new StaticServlet()); - def_servlet.servlet_ = new StaticServlet(); - servlets_.add(def_servlet); - name2servlet_.put("default", def_servlet); - } - - if (def_servlet.getClassName() == null) { - def_servlet.setClass(StaticServlet.class); - def_servlet.servlet_ = new StaticServlet(); - } - - system_default_servlet_ = def_servlet; - - for (PrefixPattern p : prefix_patterns_) { - /* - Optimization: add prefix patterns to exact2servlet_ map. - This should not affect matching result because full path - is the longest matched prefix. - */ - if (!exact2servlet_.containsKey(p.pattern)) { - trace("adding prefix pattern " + p.pattern + " to exact patterns map"); - exact2servlet_.put(p.pattern, p.servlet); - } - } - - Collections.sort(prefix_patterns_); - } finally { - Thread.currentThread().setContextClassLoader(old); - } - } - - private static class UnitClassLoader extends URLClassLoader - { - static { - ClassLoader.registerAsParallelCapable(); - } - - private final static String[] system_prefix = - { - "java/", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2) - "javax/", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2) - "org/w3c/", // needed by javax.xml - "org/xml/", // needed by javax.xml - }; - - private ClassLoader system_loader; - - public UnitClassLoader(URL[] urls, ClassLoader parent) - { - super(urls, parent); - - ClassLoader j = String.class.getClassLoader(); - if (j == null) { - j = getSystemClassLoader(); - while (j.getParent() != null) { - j = j.getParent(); - } - } - system_loader = j; - } - - private boolean isSystemPath(String path) - { - int i = Arrays.binarySearch(system_prefix, path); - - if (i >= 0) { - return true; - } - - i = -i - 1; - - if (i > 0) { - return path.startsWith(system_prefix[i - 1]); - } - - return false; - } - - @Override - public URL getResource(String name) - { - URL res; - - String s = "getResource: " + name; - trace(0, s, s.length()); - - /* - This is a required for compatibility with Tomcat which - stores all resources prefixed with '/' and application code - may try to get resource with leading '/' (like Jira). Jetty - also has such workaround in WebAppClassLoader.getResource(). - */ - if (name.startsWith("/")) { - name = name.substring(1); - } - - if (isSystemPath(name)) { - return super.getResource(name); - } - - res = system_loader.getResource(name); - if (res != null) { - return res; - } - - res = findResource(name); - if (res != null) { - return res; - } - - return super.getResource(name); - } - - @Override - protected Class loadClass(String name, boolean resolve) - throws ClassNotFoundException - { - synchronized (this) { - Class res = findLoadedClass(name); - if (res != null) { - return res; - } - - try { - res = system_loader.loadClass(name); - - if (resolve) { - resolveClass(res); - } - - return res; - } catch (ClassNotFoundException e) { - } - - String path = name.replace('.', '/').concat(".class"); - - if (isSystemPath(path)) { - return super.loadClass(name, resolve); - } - - URL url = findResource(path); - - if (url != null) { - res = super.findClass(name); - - if (resolve) { - resolveClass(res); - } - - return res; - } - - return super.loadClass(name, resolve); - } - - } - } - - private File extractWar(File war) throws IOException - { - Path tmpDir = Files.createTempDirectory("webapp"); - - JarFile jf = new JarFile(war); - - for (Enumeration en = jf.entries(); en.hasMoreElements();) { - JarEntry e = en.nextElement(); - long mod_time = e.getTime(); - Path ep = tmpDir.resolve(e.getName()); - Path p; - if (e.isDirectory()) { - p = ep; - } else { - p = ep.getParent(); - } - - if (!p.toFile().isDirectory()) { - Files.createDirectories(p); - } - - if (!e.isDirectory()) { - Files.copy(jf.getInputStream(e), ep, - StandardCopyOption.REPLACE_EXISTING); - } - - if (mod_time > 0) { - ep.toFile().setLastModified(mod_time); - } - } - - return tmpDir.toFile(); - } - - private class CtxFilterChain implements FilterChain - { - private int filter_index_ = 0; - private final ServletReg servlet_; - private final List filters_; - - CtxFilterChain(ServletReg servlet, String path, DispatcherType dtype) - { - servlet_ = servlet; - - List filters = new ArrayList<>(); - - for (FilterMap m : filter_maps_) { - if (filters.indexOf(m.filter_) != -1) { - continue; - } - - if (!m.dtypes_.contains(dtype)) { - continue; - } - - if (m.pattern_.match(path)) { - filters.add(m.filter_); - - trace("add filter (matched): " + m.filter_.getName()); - } - } - - for (FilterMap m : servlet.filters_) { - if (filters.indexOf(m.filter_) != -1) { - continue; - } - - if (!m.dtypes_.contains(dtype)) { - continue; - } - - filters.add(m.filter_); - - trace("add filter (servlet): " + m.filter_.getName()); - } - - filters_ = filters; - } - - @Override - public void doFilter (ServletRequest request, ServletResponse response) - throws IOException, ServletException - { - if (filter_index_ < filters_.size()) { - filters_.get(filter_index_++).filter_.doFilter(request, response, this); - - return; - } - - servlet_.service(request, response); - } - } - - private ServletReg findServlet(String path, DynamicPathRequest req) - { - /* - 12.1 Use of URL Paths - ... - 1. The container will try to find an exact match of the path of the - request to the path of the servlet. A successful match selects - the servlet. - */ - ServletReg servlet = exact2servlet_.get(path); - if (servlet != null) { - trace("findServlet: '" + path + "' exact matched pattern"); - req.setServletPath(path, null); - return servlet; - } - - /* - 2. The container will recursively try to match the longest - path-prefix. This is done by stepping down the path tree a - directory at a time, using the '/' character as a path separator. - The longest match determines the servlet selected. - */ - for (PrefixPattern p : prefix_patterns_) { - if (p.match(path)) { - trace("findServlet: '" + path + "' matched prefix pattern '" + p.pattern + "'"); - if (p.pattern.length() == path.length()) { - log("findServlet: WARNING: it is expected '" + path + "' exactly matches " + p.pattern); - req.setServletPath(path, p.pattern, null); - } else { - req.setServletPath(path, p.pattern, path.substring(p.pattern.length())); - } - return p.servlet; - } - } - - /* - 3. If the last segment in the URL path contains an extension - (e.g. .jsp), the servlet container will try to match a servlet - that handles requests for the extension. An extension is defined - as the part of the last segment after the last '.' character. - */ - int suffix_start = path.lastIndexOf('.'); - if (suffix_start != -1) { - String suffix = path.substring(suffix_start); - servlet = suffix2servlet_.get(suffix); - if (servlet != null) { - trace("findServlet: '" + path + "' matched suffix pattern"); - req.setServletPath(path, null); - return servlet; - } - } - - /* - 4. If neither of the previous three rules result in a servlet match, - the container will attempt to serve content appropriate for the - resource requested. If a "default" servlet is defined for the - application, it will be used. ... - */ - if (default_servlet_ != null) { - trace("findServlet: '" + path + "' matched default servlet"); - req.setServletPath(path, null); - return default_servlet_; - } - - trace("findServlet: '" + path + "' no servlet found"); - - /* - 10.10 Welcome Files - ... - If a Web container receives a valid partial request, the Web - container must examine the welcome file list defined in the - deployment descriptor. - ... - */ - if (path.endsWith("/")) { - - /* - The Web server must append each welcome file in the order - specified in the deployment descriptor to the partial request - and check whether a static resource in the WAR is mapped to - that request URI. - */ - for (String wf : welcome_files_) { - String wpath = path + wf; - - File f = new File(webapp_, wpath.substring(1)); - if (!f.exists()) { - continue; - } - - trace("findServlet: '" + path + "' found static welcome " - + "file '" + wf + "'"); - - /* - Even if static file found, we should try to find matching - servlet for JSP serving etc. - */ - servlet = findWelcomeServlet(wpath, true, req); - if (servlet != null) { - return servlet; - } - - req.setServletPath(wpath, null); - - return system_default_servlet_; - } - - /* - If no match is found, the Web server MUST again append each - welcome file in the order specified in the deployment - descriptor to the partial request and check if a servlet is - mapped to that request URI. The Web container must send the - request to the first resource in the WAR that matches. - */ - for (String wf : welcome_files_) { - String wpath = path + wf; - - servlet = findWelcomeServlet(wpath, false, req); - if (servlet != null) { - return servlet; - } - } - } - - trace("findServlet: '" + path + "' fallback to system default servlet"); - req.setServletPath(path, null); - - return system_default_servlet_; - } - - private ServletReg findWelcomeServlet(String path, boolean exists, - DynamicPathRequest req) - { - ServletReg servlet = exact2servlet_.get(path); - if (servlet != null) { - trace("findWelcomeServlet: '" + path + "' exact matched pattern"); - req.setServletPath(path, null); - - return servlet; - } - - int suffix_start = path.lastIndexOf('.'); - if (suffix_start == -1) { - return null; - } - - String suffix = path.substring(suffix_start); - servlet = suffix2servlet_.get(suffix); - if (servlet == null) { - return null; - } - - trace("findWelcomeServlet: '" + path + "' matched suffix pattern"); - - /* - If we want to show the directory content when - index.jsp is absent, then we have to check file - presence here. Otherwise user will get 404. - */ - - if (servlet.system_jsp_servlet_ && !exists) { - trace("findWelcomeServlet: '" + path + "' not exists"); - return null; - } - - req.setServletPath(path, null); - - return servlet; - } - - public void service(Request req, Response resp) - throws ServletException, IOException - { - ClassLoader old = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(loader_); - - ServletRequestEvent sre = null; - - try { - if (!req_init_listeners_.isEmpty()) { - sre = new ServletRequestEvent(this, req); - - for (ServletRequestListener l : req_init_listeners_) { - l.requestInitialized(sre); - } - } - - URI uri = new URI(req.getRequestURI()); - String path = uri.getPath(); - - if (!path.startsWith(context_path_) - || (path.length() > context_path_.length() - && path.charAt(context_path_.length()) != '/')) - { - trace("service: '" + path + "' not started with '" + context_path_ + "'"); - - resp.sendError(resp.SC_NOT_FOUND); - return; - } - - if (path.equals(context_path_)) { - String url = req.getRequestURL().toString(); - if (!url.endsWith("/")) { - resp.setHeader("Location", url + "/"); - resp.sendError(resp.SC_FOUND); - return; - } - } - - path = path.substring(context_path_.length()); - - ServletReg servlet = findServlet(path, req); - - req.setMultipartConfig(servlet.multipart_config_); - - FilterChain fc = new CtxFilterChain(servlet, req.getFilterPath(), DispatcherType.REQUEST); - - fc.doFilter(req, resp); - - Object code = req.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); - if (code != null && code instanceof Integer) { - handleStatusCode((Integer) code, req, resp); - } - } catch (Throwable e) { - trace("service: caught " + e); - - try { - if (!resp.isCommitted() && !exception2location_.isEmpty()) { - handleException(e, req, resp); - } - - if (!resp.isCommitted()) { - resp.reset(); - resp.setStatus(resp.SC_INTERNAL_SERVER_ERROR); - resp.setContentType("text/plain"); - - PrintWriter w = resp.getWriter(); - w.println("Unhandled exception: " + e); - e.printStackTrace(w); - - w.close(); - } - } finally { - throw new ServletException(e); - } - } finally { - resp.flushBuffer(); - - try { - if (!req_destroy_listeners_.isEmpty()) { - for (ServletRequestListener l : req_destroy_listeners_) { - l.requestDestroyed(sre); - } - } - } finally { - Thread.currentThread().setContextClassLoader(old); - } - } - } - - private void handleException(Throwable e, Request req, Response resp) - throws ServletException, IOException - { - String location; - - Class cls = e.getClass(); - while (cls != null && !cls.equals(Throwable.class)) { - location = exception2location_.get(cls.getName()); - - if (location != null) { - trace("Exception " + e + " matched. Error page location: " + location); - - req.setAttribute_(RequestDispatcher.ERROR_EXCEPTION, e); - req.setAttribute_(RequestDispatcher.ERROR_EXCEPTION_TYPE, e.getClass()); - req.setAttribute_(RequestDispatcher.ERROR_REQUEST_URI, req.getRequestURI()); - req.setAttribute_(RequestDispatcher.ERROR_STATUS_CODE, resp.SC_INTERNAL_SERVER_ERROR); - - handleError(location, req, resp); - - return; - } - - cls = cls.getSuperclass(); - } - - if (ServletException.class.isAssignableFrom(e.getClass())) { - ServletException se = (ServletException) e; - - handleException(se.getRootCause(), req, resp); - } - } - - private void handleStatusCode(int code, Request req, Response resp) - throws ServletException, IOException - { - String location; - - location = error2location_.get(code); - - if (location != null) { - trace("Status " + code + " matched. Error page location: " + location); - - req.setAttribute_(RequestDispatcher.ERROR_REQUEST_URI, req.getRequestURI()); - - handleError(location, req, resp); - } - } - - public void handleError(String location, Request req, Response resp) - throws ServletException, IOException - { - try { - log("handleError: " + location); - - String filter_path = req.getFilterPath(); - String servlet_path = req.getServletPath(); - String path_info = req.getPathInfo(); - String req_uri = req.getRequestURI(); - DispatcherType dtype = req.getDispatcherType(); - - URI uri; - - if (location.startsWith("/")) { - uri = new URI(context_path_ + location); - } else { - uri = new URI(req_uri).resolve(location); - } - - req.setRequestURI(uri.getRawPath()); - req.setDispatcherType(DispatcherType.ERROR); - - String path = uri.getPath().substring(context_path_.length()); - - ServletReg servlet = findServlet(path, req); - - req.setMultipartConfig(servlet.multipart_config_); - - FilterChain fc = new CtxFilterChain(servlet, req.getFilterPath(), DispatcherType.ERROR); - - fc.doFilter(req, resp); - - req.setServletPath(filter_path, servlet_path, path_info); - req.setRequestURI(req_uri); - req.setDispatcherType(dtype); - } catch (URISyntaxException e) { - throw new ServletException(e); - } - } - - private void processWebXml(File root) throws Exception - { - if (root.isDirectory()) { - File web_xml = new File(root, "WEB-INF/web.xml"); - if (web_xml.exists()) { - trace("start: web.xml file found"); - - InputStream is = new FileInputStream(web_xml); - - processWebXml(is); - - is.close(); - } - } else { - JarFile jf = new JarFile(root); - ZipEntry ze = jf.getEntry("WEB-INF/web.xml"); - - if (ze == null) { - trace("start: web.xml entry NOT found"); - } else { - trace("start: web.xml entry found"); - - processWebXml(jf.getInputStream(ze)); - } - - jf.close(); - } - } - - private void processWebXml(InputStream is) - throws ParserConfigurationException, SAXException, IOException - { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - - Document doc = builder.parse(is); - - Element doc_elem = doc.getDocumentElement(); - String doc_elem_name = doc_elem.getNodeName(); - if (!doc_elem_name.equals("web-app")) { - throw new RuntimeException("Invalid web.xml: 'web-app' element expected, not '" + doc_elem_name + "'"); - } - - metadata_complete_ = doc_elem.getAttribute("metadata-complete").equals("true"); - app_version_ = doc_elem.getAttribute("version"); - - NodeList welcome_file_lists = doc_elem.getElementsByTagName("welcome-file-list"); - - if (welcome_file_lists.getLength() > 0) { - welcome_files_list_found_ = true; - } - - for (int i = 0; i < welcome_file_lists.getLength(); i++) { - Element list_el = (Element) welcome_file_lists.item(i); - NodeList files = list_el.getElementsByTagName("welcome-file"); - for (int j = 0; j < files.getLength(); j++) { - Node node = files.item(j); - String wf = node.getTextContent().trim(); - - /* - 10.10 Welcome Files - ... - The welcome file list is an ordered list of partial URLs - with no trailing or leading /. - */ - - if (wf.startsWith("/") || wf.endsWith("/")) { - log("invalid welcome file: " + wf); - continue; - } - - welcome_files_.add(wf); - } - } - - NodeList context_params = doc_elem.getElementsByTagName("context-param"); - for (int i = 0; i < context_params.getLength(); i++) { - processXmlInitParam(this, (Element) context_params.item(i)); - } - - NodeList filters = doc_elem.getElementsByTagName("filter"); - - for (int i = 0; i < filters.getLength(); i++) { - Element filter_el = (Element) filters.item(i); - NodeList names = filter_el.getElementsByTagName("filter-name"); - if (names == null || names.getLength() != 1) { - throw new RuntimeException("Invalid web.xml: 'filter-name' tag not found"); - } - - String filter_name = names.item(0).getTextContent().trim(); - trace("filter-name=" + filter_name); - - FilterReg reg = new FilterReg(filter_name); - - NodeList child_nodes = filter_el.getChildNodes(); - for(int j = 0; j < child_nodes.getLength(); j++) { - Node child_node = child_nodes.item(j); - String tag_name = child_node.getNodeName(); - - if (tag_name.equals("filter-class")) { - reg.setClassName(child_node.getTextContent().trim()); - continue; - } - - if (tag_name.equals("async-supported")) { - reg.setAsyncSupported(child_node.getTextContent().trim() - .equals("true")); - continue; - } - - if (tag_name.equals("init-param")) { - processXmlInitParam(reg, (Element) child_node); - continue; - } - - if (tag_name.equals("filter-name") - || tag_name.equals("#text") - || tag_name.equals("#comment")) - { - continue; - } - - log("processWebXml: tag '" + tag_name + "' for filter '" - + filter_name + "' is ignored"); - } - - filters_.add(reg); - name2filter_.put(filter_name, reg); - } - - NodeList filter_mappings = doc_elem.getElementsByTagName("filter-mapping"); - - for(int i = 0; i < filter_mappings.getLength(); i++) { - Element mapping_el = (Element) filter_mappings.item(i); - NodeList names = mapping_el.getElementsByTagName("filter-name"); - if (names == null || names.getLength() != 1) { - throw new RuntimeException("Invalid web.xml: 'filter-name' tag not found"); - } - - String filter_name = names.item(0).getTextContent().trim(); - trace("filter-name=" + filter_name); - - FilterReg reg = name2filter_.get(filter_name); - if (reg == null) { - throw new RuntimeException("Invalid web.xml: filter '" + filter_name + "' not found"); - } - - EnumSet dtypes = EnumSet.noneOf(DispatcherType.class); - NodeList dispatchers = mapping_el.getElementsByTagName("dispatcher"); - for (int j = 0; j < dispatchers.getLength(); j++) { - Node child_node = dispatchers.item(j); - dtypes.add(DispatcherType.valueOf(child_node.getTextContent().trim())); - } - - if (dtypes.isEmpty()) { - dtypes.add(DispatcherType.REQUEST); - } - - boolean match_after = false; - - NodeList child_nodes = mapping_el.getChildNodes(); - for (int j = 0; j < child_nodes.getLength(); j++) { - Node child_node = child_nodes.item(j); - String tag_name = child_node.getNodeName(); - - if (tag_name.equals("url-pattern")) { - reg.addMappingForUrlPatterns(dtypes, match_after, child_node.getTextContent().trim()); - continue; - } - - if (tag_name.equals("servlet-name")) { - reg.addMappingForServletNames(dtypes, match_after, child_node.getTextContent().trim()); - continue; - } - } - } - - NodeList servlets = doc_elem.getElementsByTagName("servlet"); - - for (int i = 0; i < servlets.getLength(); i++) { - Element servlet_el = (Element) servlets.item(i); - NodeList names = servlet_el.getElementsByTagName("servlet-name"); - if (names == null || names.getLength() != 1) { - throw new RuntimeException("Invalid web.xml: 'servlet-name' tag not found"); - } - - String servlet_name = names.item(0).getTextContent().trim(); - trace("servlet-name=" + servlet_name); - - ServletReg reg = new ServletReg(servlet_name); - - NodeList child_nodes = servlet_el.getChildNodes(); - for(int j = 0; j < child_nodes.getLength(); j++) { - Node child_node = child_nodes.item(j); - String tag_name = child_node.getNodeName(); - - if (tag_name.equals("servlet-class")) { - reg.setClassName(child_node.getTextContent().trim()); - continue; - } - - if (tag_name.equals("async-supported")) { - reg.setAsyncSupported(child_node.getTextContent().trim() - .equals("true")); - continue; - } - - if (tag_name.equals("init-param")) { - processXmlInitParam(reg, (Element) child_node); - continue; - } - - if (tag_name.equals("load-on-startup")) { - reg.setLoadOnStartup(Integer.parseInt(child_node.getTextContent().trim())); - continue; - } - - if (tag_name.equals("jsp-file")) { - reg.setJspFile(child_node.getTextContent().trim()); - continue; - } - - if (tag_name.equals("servlet-name") - || tag_name.equals("display-name") - || tag_name.equals("#text") - || tag_name.equals("#comment")) - { - continue; - } - - log("processWebXml: tag '" + tag_name + "' for servlet '" - + servlet_name + "' is ignored"); - } - - servlets_.add(reg); - name2servlet_.put(servlet_name, reg); - } - - NodeList servlet_mappings = doc_elem.getElementsByTagName("servlet-mapping"); - - for(int i = 0; i < servlet_mappings.getLength(); i++) { - Element mapping_el = (Element) servlet_mappings.item(i); - NodeList names = mapping_el.getElementsByTagName("servlet-name"); - if (names == null || names.getLength() != 1) { - throw new RuntimeException("Invalid web.xml: 'servlet-name' tag not found"); - } - - String servlet_name = names.item(0).getTextContent().trim(); - trace("servlet-name=" + servlet_name); - - ServletReg reg = name2servlet_.get(servlet_name); - if (reg == null) { - throw new RuntimeException("Invalid web.xml: servlet '" + servlet_name + "' not found"); - } - - NodeList child_nodes = mapping_el.getElementsByTagName("url-pattern"); - String patterns[] = new String[child_nodes.getLength()]; - for(int j = 0; j < child_nodes.getLength(); j++) { - Node child_node = child_nodes.item(j); - patterns[j] = child_node.getTextContent().trim(); - } - - reg.addMapping(patterns); - } - - NodeList listeners = doc_elem.getElementsByTagName("listener"); - - for (int i = 0; i < listeners.getLength(); i++) { - Element listener_el = (Element) listeners.item(i); - NodeList classes = listener_el.getElementsByTagName("listener-class"); - if (classes == null || classes.getLength() != 1) { - throw new RuntimeException("Invalid web.xml: 'listener-class' tag not found"); - } - - String class_name = classes.item(0).getTextContent().trim(); - trace("listener-class=" + class_name); - - pending_listener_classnames_.add(class_name); - } - - NodeList error_pages = doc_elem.getElementsByTagName("error-page"); - - for (int i = 0; i < error_pages.getLength(); i++) { - Element error_page_el = (Element) error_pages.item(i); - NodeList locations = error_page_el.getElementsByTagName("location"); - if (locations == null || locations.getLength() != 1) { - throw new RuntimeException("Invalid web.xml: 'location' tag not found"); - } - - String location = locations.item(0).getTextContent().trim(); - - NodeList child_nodes = error_page_el.getChildNodes(); - for(int j = 0; j < child_nodes.getLength(); j++) { - Node child_node = child_nodes.item(j); - String tag_name = child_node.getNodeName(); - - if (tag_name.equals("exception-type")) { - String ex = child_node.getTextContent().trim(); - - exception2location_.put(ex, location); - trace("error-page: exception " + ex + " -> " + location); - continue; - } - - if (tag_name.equals("error-code")) { - Integer code = Integer.parseInt(child_node.getTextContent().trim()); - - error2location_.put(code, location); - trace("error-page: code " + code + " -> " + location); - continue; - } - } - } - - NodeList session_config = doc_elem.getElementsByTagName("session-config"); - - for (int i = 0; i < session_config.getLength(); i++) { - Element session_config_el = (Element) session_config.item(i); - NodeList session_timeout = session_config_el.getElementsByTagName("session-timeout"); - if (session_timeout != null) { - String timeout = session_timeout.item(0).getTextContent().trim(); - - trace("session_timeout: " + timeout); - session_timeout_ = Integer.parseInt(timeout); - break; - } - } - - NodeList jsp_configs = doc_elem.getElementsByTagName("jsp-config"); - - for (int i = 0; i < jsp_configs.getLength(); i++) { - Element jsp_config_el = (Element) jsp_configs.item(i); - - NodeList jsp_nodes = jsp_config_el.getChildNodes(); - - for(int j = 0; j < jsp_nodes.getLength(); j++) { - Node jsp_node = jsp_nodes.item(j); - String tag_name = jsp_node.getNodeName(); - - if (tag_name.equals("taglib")) { - NodeList tl_nodes = ((Element) jsp_node).getChildNodes(); - Taglib tl = new Taglib(tl_nodes); - - trace("add taglib"); - - taglibs_.add(tl); - continue; - } - - if (tag_name.equals("jsp-property-group")) { - NodeList jpg_nodes = ((Element) jsp_node).getChildNodes(); - JspPropertyGroup conf = new JspPropertyGroup(jpg_nodes); - - trace("add prop group"); - - prop_groups_.add(conf); - continue; - } - } - } - } - - private static int compareVersion(String ver1, String ver2) - { - String[] varr1 = ver1.split("\\."); - String[] varr2 = ver2.split("\\."); - - int max_len = varr1.length > varr2.length ? varr1.length : varr2.length; - for (int i = 0; i < max_len; i++) { - int l = i < varr1.length ? Integer.parseInt(varr1[i]) : 0; - int r = i < varr2.length ? Integer.parseInt(varr2[i]) : 0; - - int res = l - r; - - if (res != 0) { - return res; - } - } - - return 0; - } - - private void processXmlInitParam(InitParams params, Element elem) - throws RuntimeException - { - NodeList n = elem.getElementsByTagName("param-name"); - if (n == null || n.getLength() != 1) { - throw new RuntimeException("Invalid web.xml: 'param-name' tag not found"); - } - - NodeList v = elem.getElementsByTagName("param-value"); - if (v == null || v.getLength() != 1) { - throw new RuntimeException("Invalid web.xml: 'param-value' tag not found"); - } - params.setInitParameter(n.item(0).getTextContent().trim(), - v.item(0).getTextContent().trim()); - } - - private void loadInitializers(ScanResult scan_res) - { - trace("load initializer(s)"); - - ServiceLoader initializers = - ServiceLoader.load(ServletContainerInitializer.class, loader_); - - for (ServletContainerInitializer sci : initializers) { - loadInitializer(sci, scan_res); - } - } - - private void loadInitializer(ServletContainerInitializer sci, ScanResult scan_res) - { - trace("loadInitializer: initializer: " + sci.getClass().getName()); - - /* - Unit WebSocket container is a copy of Tomcat WsSci with own - transport implementation. Tomcat implementation will not work in - Unit and should be ignored here. - */ - if (sci.getClass().getName() - .equals("org.apache.tomcat.websocket.server.WsSci")) - { - trace("loadInitializer: ignore"); - return; - } - - HandlesTypes ann = sci.getClass().getAnnotation(HandlesTypes.class); - if (ann == null) { - trace("loadInitializer: no HandlesTypes annotation"); - return; - } - - Class[] classes = ann.value(); - if (classes == null) { - trace("loadInitializer: no handles classes"); - return; - } - - Set> handles_classes = new HashSet<>(); - - for (Class c : classes) { - trace("loadInitializer: find handles: " + c.getName()); - - ClassInfoList handles = - c.isAnnotation() - ? scan_res.getClassesWithAnnotation(c.getName()) - : c.isInterface() - ? scan_res.getClassesImplementing(c.getName()) - : scan_res.getSubclasses(c.getName()); - - for (ClassInfo ci : handles) { - if (ci.isInterface() - || ci.isAnnotation() - || ci.isAbstract()) - { - continue; - } - - trace("loadInitializer: handles class: " + ci.getName()); - handles_classes.add(ci.loadClass()); - } - } - - if (handles_classes.isEmpty()) { - trace("loadInitializer: no handles implementations"); - return; - } - - try { - sci.onStartup(handles_classes, this); - } catch(Exception e) { - System.err.println("loadInitializer: exception caught: " + e.toString()); - } - } - - private void scanClasses(ScanResult scan_res) - throws ReflectiveOperationException - { - ClassInfoList filters = scan_res.getClassesWithAnnotation(WebFilter.class.getName()); - - for (ClassInfo ci : filters) { - if (ci.isInterface() - || ci.isAnnotation() - || ci.isAbstract() - || !ci.implementsInterface(Filter.class.getName())) - { - trace("scanClasses: ignoring Filter impl: " + ci.getName()); - continue; - } - - trace("scanClasses: found Filter class: " + ci.getName()); - - Class cls = ci.loadClass(); - if (!Filter.class.isAssignableFrom(cls)) { - trace("scanClasses: " + ci.getName() + " cannot be assigned to Filter"); - continue; - } - - WebFilter ann = cls.getAnnotation(WebFilter.class); - - if (ann == null) { - trace("scanClasses: no WebFilter annotation for " + ci.getName()); - continue; - } - - String filter_name = ann.filterName(); - - if (filter_name.isEmpty()) { - filter_name = ci.getName(); - } - - FilterReg reg = name2filter_.get(filter_name); - - if (reg == null) { - reg = new FilterReg(filter_name, cls); - filters_.add(reg); - name2filter_.put(filter_name, reg); - } else { - reg.setClass(cls); - } - - EnumSet dtypes = EnumSet.noneOf(DispatcherType.class); - DispatcherType[] dispatchers = ann.dispatcherTypes(); - for (DispatcherType d : dispatchers) { - dtypes.add(d); - } - - if (dtypes.isEmpty()) { - dtypes.add(DispatcherType.REQUEST); - } - - boolean match_after = false; - - reg.addMappingForUrlPatterns(dtypes, match_after, ann.value()); - reg.addMappingForUrlPatterns(dtypes, match_after, ann.urlPatterns()); - reg.addMappingForServletNames(dtypes, match_after, ann.servletNames()); - - for (WebInitParam p : ann.initParams()) { - reg.setInitParameter(p.name(), p.value()); - } - - reg.setAsyncSupported(ann.asyncSupported()); - } - - ClassInfoList servlets = scan_res.getClassesWithAnnotation(WebServlet.class.getName()); - - for (ClassInfo ci : servlets) { - if (ci.isInterface() - || ci.isAnnotation() - || ci.isAbstract() - || !ci.extendsSuperclass(HttpServlet.class.getName())) - { - trace("scanClasses: ignoring HttpServlet subclass: " + ci.getName()); - continue; - } - - trace("scanClasses: found HttpServlet class: " + ci.getName()); - - Class cls = ci.loadClass(); - if (!HttpServlet.class.isAssignableFrom(cls)) { - trace("scanClasses: " + ci.getName() + " cannot be assigned to HttpFilter"); - continue; - } - - WebServlet ann = cls.getAnnotation(WebServlet.class); - - if (ann == null) { - trace("scanClasses: no WebServlet annotation"); - continue; - } - - String servlet_name = ann.name(); - - if (servlet_name.isEmpty()) { - servlet_name = ci.getName(); - } - - ServletReg reg = name2servlet_.get(servlet_name); - - if (reg == null) { - reg = new ServletReg(servlet_name, cls); - servlets_.add(reg); - name2servlet_.put(servlet_name, reg); - } else { - reg.setClass(cls); - } - - reg.addMapping(ann.value()); - reg.addMapping(ann.urlPatterns()); - - for (WebInitParam p : ann.initParams()) { - reg.setInitParameter(p.name(), p.value()); - } - - reg.setAsyncSupported(ann.asyncSupported()); - } - - - ClassInfoList lstnrs = scan_res.getClassesWithAnnotation(WebListener.class.getName()); - - for (ClassInfo ci : lstnrs) { - if (ci.isInterface() - || ci.isAnnotation() - || ci.isAbstract()) - { - trace("scanClasses: listener impl: " + ci.getName()); - continue; - } - - trace("scanClasses: listener class: " + ci.getName()); - - if (listener_classnames_.contains(ci.getName())) { - trace("scanClasses: " + ci.getName() + " already added as listener"); - continue; - } - - Class cls = ci.loadClass(); - Class lclass = null; - for (Class c : LISTENER_TYPES) { - if (c.isAssignableFrom(cls)) { - lclass = c; - break; - } - } - - if (lclass == null) { - log("scanClasses: " + ci.getName() + " implements none of known listener interfaces"); - continue; - } - - WebListener ann = cls.getAnnotation(WebListener.class); - - if (ann == null) { - log("scanClasses: no WebListener annotation"); - continue; - } - - Constructor ctor = cls.getConstructor(); - EventListener listener = (EventListener) ctor.newInstance(); - - addListener(listener); - - listener_classnames_.add(ci.getName()); - } - - - ClassInfoList endpoints = scan_res.getClassesWithAnnotation(ServerEndpoint.class.getName()); - - for (ClassInfo ci : endpoints) { - if (ci.isInterface() - || ci.isAnnotation() - || ci.isAbstract()) - { - trace("scanClasses: skip server end point: " + ci.getName()); - continue; - } - - trace("scanClasses: server end point: " + ci.getName()); - } - } - - public void stop() throws IOException - { - ClassLoader old = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(loader_); - - try { - for (ServletReg s : servlets_) { - s.destroy(); - } - - for (FilterReg f : filters_) { - f.destroy(); - } - - if (!destroy_listeners_.isEmpty()) { - ServletContextEvent event = new ServletContextEvent(this); - for (ServletContextListener listener : destroy_listeners_) { - listener.contextDestroyed(event); - } - } - - if (extracted_dir_ != null) { - removeDir(extracted_dir_); - } - - if (temp_dir_ != null) { - removeDir(temp_dir_); - } - } finally { - Thread.currentThread().setContextClassLoader(old); - } - } - - private void removeDir(File dir) throws IOException - { - Files.walkFileTree(dir.toPath(), - new SimpleFileVisitor() { - @Override - public FileVisitResult postVisitDirectory( - Path dir, IOException exc) throws IOException { - Files.delete(dir); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile( - Path file, BasicFileAttributes attrs) - throws IOException { - Files.delete(file); - return FileVisitResult.CONTINUE; - } - }); - } - - private class CtxInitParams implements InitParams - { - private final Map init_params_ = - new HashMap(); - - public boolean setInitParameter(String name, String value) - { - trace("CtxInitParams.setInitParameter " + name + " = " + value); - - return init_params_.putIfAbsent(name, value) == null; - } - - public String getInitParameter(String name) - { - trace("CtxInitParams.getInitParameter for " + name); - - return init_params_.get(name); - } - - public Set setInitParameters(Map initParameters) - { - // illegalStateIfContextStarted(); - Set clash = null; - for (Map.Entry entry : initParameters.entrySet()) - { - if (entry.getKey() == null) { - throw new IllegalArgumentException("init parameter name required"); - } - - if (entry.getValue() == null) { - throw new IllegalArgumentException("non-null value required for init parameter " + entry.getKey()); - } - - if (init_params_.get(entry.getKey()) != null) - { - if (clash == null) - clash = new HashSet(); - clash.add(entry.getKey()); - } - - trace("CtxInitParams.setInitParameters " + entry.getKey() + " = " + entry.getValue()); - } - - if (clash != null) { - return clash; - } - - init_params_.putAll(initParameters); - return Collections.emptySet(); - } - - public Map getInitParameters() - { - trace("CtxInitParams.getInitParameters"); - return init_params_; - } - - public Enumeration getInitParameterNames() - { - return Collections.enumeration(init_params_.keySet()); - } - } - - private class NamedReg extends CtxInitParams - implements Registration - { - private final String name_; - private String class_name_; - - public NamedReg(String name) - { - name_ = name; - } - - public NamedReg(String name, String class_name) - { - name_ = name; - class_name_ = class_name; - } - - @Override - public String getName() - { - return name_; - } - - @Override - public String getClassName() - { - return class_name_; - } - - public void setClassName(String class_name) - { - class_name_ = class_name; - } - } - - private class ServletReg extends NamedReg - implements ServletRegistration.Dynamic, ServletConfig - { - private Class servlet_class_; - private Servlet servlet_; - private String role_; - private boolean async_supported_ = false; - private final List patterns_ = new ArrayList<>(); - private int load_on_startup_ = -1; - private boolean initialized_ = false; - private final List filters_ = new ArrayList<>(); - private boolean system_jsp_servlet_ = false; - private String jsp_file_; - private MultipartConfigElement multipart_config_; - - public ServletReg(String name, Class servlet_class) - { - super(name, servlet_class.getName()); - servlet_class_ = servlet_class; - getAnnotationMultipartConfig(); - } - - public ServletReg(String name, Servlet servlet) - { - super(name, servlet.getClass().getName()); - servlet_ = servlet; - } - - public ServletReg(String name, String servlet_class_name) - { - super(name, servlet_class_name); - } - - public ServletReg(String name) - { - super(name); - } - - private void init() throws ServletException - { - if (initialized_) { - return; - } - - trace("ServletReg.init(): " + getName()); - - if (jsp_file_ != null) { - setInitParameter("jspFile", jsp_file_); - jsp_file_ = null; - - ServletReg jsp_servlet = name2servlet_.get("jsp"); - - if (jsp_servlet.servlet_class_ != null) { - servlet_class_ = jsp_servlet.servlet_class_; - } else { - setClassName(jsp_servlet.getClassName()); - } - - system_jsp_servlet_ = jsp_servlet.system_jsp_servlet_; - } - - if (system_jsp_servlet_) { - JasperInitializer ji = new JasperInitializer(); - - ji.onStartup(Collections.emptySet(), Context.this); - } - - if (servlet_ == null) { - try { - if (servlet_class_ == null) { - servlet_class_ = loader_.loadClass(getClassName()); - getAnnotationMultipartConfig(); - } - - Constructor ctor = servlet_class_.getConstructor(); - servlet_ = (Servlet) ctor.newInstance(); - } catch(Exception e) { - log("ServletReg.init() failed " + e); - throw new ServletException(e); - } - } - - servlet_.init((ServletConfig) this); - - initialized_ = true; - } - - public void startup() throws ServletException - { - if (load_on_startup_ < 0) { - return; - } - - init(); - } - - public void destroy() - { - if (initialized_) { - servlet_.destroy(); - } - } - - public void setClassName(String class_name) throws IllegalStateException - { - if (servlet_ != null - || servlet_class_ != null - || getClassName() != null) - { - throw new IllegalStateException("Class already initialized"); - } - - if (jsp_file_ != null) { - throw new IllegalStateException("jsp-file already initialized"); - } - - super.setClassName(class_name); - } - - public void setClass(Class servlet_class) - throws IllegalStateException - { - if (servlet_ != null - || servlet_class_ != null - || getClassName() != null) - { - throw new IllegalStateException("Class already initialized"); - } - - if (jsp_file_ != null) { - throw new IllegalStateException("jsp-file already initialized"); - } - - super.setClassName(servlet_class.getName()); - servlet_class_ = servlet_class; - getAnnotationMultipartConfig(); - } - - public void setJspFile(String jsp_file) throws IllegalStateException - { - if (servlet_ != null - || servlet_class_ != null - || getClassName() != null) - { - throw new IllegalStateException("Class already initialized"); - } - - if (jsp_file_ != null) { - throw new IllegalStateException("jsp-file already initialized"); - } - - jsp_file_ = jsp_file; - } - - private void getAnnotationMultipartConfig() { - if (servlet_class_ == null) { - return; - } - - MultipartConfig mpc = servlet_class_.getAnnotation(MultipartConfig.class); - if (mpc == null) { - return; - } - - multipart_config_ = new MultipartConfigElement(mpc); - } - - public void service(ServletRequest request, ServletResponse response) - throws ServletException, IOException - { - init(); - - servlet_.service(request, response); - } - - public void addFilter(FilterMap fmap) - { - filters_.add(fmap); - } - - @Override - public Set addMapping(String... urlPatterns) - { - checkContextState(); - - Set clash = null; - for (String pattern : urlPatterns) { - trace("ServletReg.addMapping: " + pattern); - - if (pattern2servlet_.containsKey(pattern)) { - if (clash == null) { - clash = new HashSet(); - } - clash.add(pattern); - } - } - - /* if there were any clashes amongst the urls, return them */ - if (clash != null) { - return clash; - } - - for (String pattern : urlPatterns) { - patterns_.add(pattern); - pattern2servlet_.put(pattern, this); - parseURLPattern(pattern, this); - } - - return Collections.emptySet(); - } - - @Override - public Collection getMappings() - { - trace("ServletReg.getMappings"); - return patterns_; - } - - @Override - public String getRunAsRole() - { - return role_; - } - - @Override - public void setLoadOnStartup(int loadOnStartup) - { - checkContextState(); - - trace("ServletReg.setLoadOnStartup: " + loadOnStartup); - load_on_startup_ = loadOnStartup; - } - - @Override - public Set setServletSecurity(ServletSecurityElement constraint) - { - log("ServletReg.setServletSecurity"); - return Collections.emptySet(); - } - - @Override - public void setMultipartConfig( - MultipartConfigElement multipartConfig) - { - trace("ServletReg.setMultipartConfig"); - multipart_config_ = multipartConfig; - } - - @Override - public void setRunAsRole(String roleName) - { - log("ServletReg.setRunAsRole: " + roleName); - role_ = roleName; - } - - @Override - public void setAsyncSupported(boolean isAsyncSupported) - { - log("ServletReg.setAsyncSupported: " + isAsyncSupported); - async_supported_ = isAsyncSupported; - } - - @Override - public String getServletName() - { - return getName(); - } - - @Override - public ServletContext getServletContext() - { - return (ServletContext) Context.this; - } - } - - public void checkContextState() throws IllegalStateException - { - if (ctx_initialized_) { - throw new IllegalStateException("Context already initialized"); - } - } - - public void parseURLPattern(String p, ServletReg servlet) - throws IllegalArgumentException - { - URLPattern pattern = parseURLPattern(p); - - switch (pattern.type_) { - case PREFIX: - prefix_patterns_.add(new PrefixPattern(pattern.pattern_, servlet)); - return; - - case SUFFIX: - suffix2servlet_.put(pattern.pattern_, servlet); - return; - - case EXACT: - exact2servlet_.put(pattern.pattern_, servlet); - return; - - case DEFAULT: - default_servlet_ = servlet; - return; - } - - /* TODO process other cases, throw IllegalArgumentException */ - } - - public URLPattern parseURLPattern(String p) - throws IllegalArgumentException - { - URLPattern pattern = parsed_patterns_.get(p); - if (pattern == null) { - pattern = new URLPattern(p); - parsed_patterns_.put(p, pattern); - } - - return pattern; - } - - private static enum URLPatternType { - PREFIX, - SUFFIX, - DEFAULT, - EXACT, - }; - - private class URLPattern - { - private final String pattern_; - private final URLPatternType type_; - - public URLPattern(String p) - throws IllegalArgumentException - { - /* - 12.2 Specification of Mappings - ... - A string beginning with a '/' character and ending with a '/*' - suffix is used for path mapping. - */ - if (p.startsWith("/") && p.endsWith("/*")) { - trace("URLPattern: '" + p + "' is a prefix pattern"); - pattern_ = p.substring(0, p.length() - 2); - type_ = URLPatternType.PREFIX; - return; - } - - /* - A string beginning with a '*.' prefix is used as an extension - mapping. - */ - if (p.startsWith("*.")) { - trace("URLPattern: '" + p + "' is a suffix pattern"); - pattern_ = p.substring(1, p.length()); - type_ = URLPatternType.SUFFIX; - return; - } - - /* - The empty string ("") is a special URL pattern that exactly maps to - the application's context root, i.e., requests of the form - http://host:port//. In this case the path info is '/' - and the servlet path and context path is empty string (""). - */ - if (p.isEmpty()) { - trace("URLPattern: '" + p + "' is a root"); - pattern_ = "/"; - type_ = URLPatternType.EXACT; - return; - } - - /* - A string containing only the '/' character indicates the "default" - servlet of the application. In this case the servlet path is the - request URI minus the context path and the path info is null. - */ - if (p.equals("/")) { - trace("URLPattern: '" + p + "' is a default"); - pattern_ = p; - type_ = URLPatternType.DEFAULT; - return; - } - - /* - All other strings are used for exact matches only. - */ - trace("URLPattern: '" + p + "' is an exact pattern"); - pattern_ = p; - type_ = URLPatternType.EXACT; - - /* TODO process other cases, throw IllegalArgumentException */ - } - - public boolean match(String url) - { - switch (type_) { - case PREFIX: - return url.startsWith(pattern_) && ( - url.length() == pattern_.length() - || url.charAt(pattern_.length()) == '/'); - - case SUFFIX: - return url.endsWith(pattern_); - - case EXACT: - return url.equals(pattern_); - - case DEFAULT: - return true; - } - - return false; - } - } - - private class FilterReg extends NamedReg - implements FilterRegistration.Dynamic, FilterConfig - { - private Class filter_class_; - private Filter filter_; - private boolean async_supported_ = false; - private boolean initialized_ = false; - - public FilterReg(String name, Class filter_class) - { - super(name, filter_class.getName()); - filter_class_ = filter_class; - } - - public FilterReg(String name, Filter filter) - { - super(name, filter.getClass().getName()); - filter_ = filter; - } - - public FilterReg(String name, String filter_class_name) - { - super(name, filter_class_name); - } - - public FilterReg(String name) - { - super(name); - } - - public void setClassName(String class_name) throws IllegalStateException - { - if (filter_ != null - || filter_class_ != null - || getClassName() != null) - { - throw new IllegalStateException("Class already initialized"); - } - - super.setClassName(class_name); - } - - public void setClass(Class filter_class) throws IllegalStateException - { - if (filter_ != null - || filter_class_ != null - || getClassName() != null) - { - throw new IllegalStateException("Class already initialized"); - } - - super.setClassName(filter_class.getName()); - filter_class_ = filter_class; - } - - public void init() throws ServletException - { - if (filter_ == null) { - try { - if (filter_class_ == null) { - filter_class_ = loader_.loadClass(getClassName()); - } - - Constructor ctor = filter_class_.getConstructor(); - filter_ = (Filter) ctor.newInstance(); - } catch(Exception e) { - log("FilterReg.init() failed " + e); - throw new ServletException(e); - } - } - - filter_.init((FilterConfig) this); - - initialized_ = true; - } - - public void destroy() - { - if (initialized_) { - filter_.destroy(); - } - } - - @Override - public void addMappingForServletNames( - EnumSet dispatcherTypes, boolean isMatchAfter, - String... servletNames) - { - checkContextState(); - - for (String n : servletNames) { - trace("FilterReg.addMappingForServletNames: ... " + n); - - ServletReg sreg = name2servlet_.get(n); - if (sreg == null) { - sreg = new ServletReg(n); - servlets_.add(sreg); - name2servlet_.put(n, sreg); - } - - FilterMap map = new FilterMap(this, sreg, dispatcherTypes, - isMatchAfter); - - sreg.addFilter(map); - } - } - - @Override - public Collection getServletNameMappings() - { - checkContextState(); - - log("FilterReg.getServletNameMappings"); - return Collections.emptySet(); - } - - @Override - public void addMappingForUrlPatterns( - EnumSet dispatcherTypes, boolean isMatchAfter, - String... urlPatterns) - { - checkContextState(); - - for (String u : urlPatterns) { - trace("FilterReg.addMappingForUrlPatterns: ... " + u); - - URLPattern p = parseURLPattern(u); - FilterMap map = new FilterMap(this, p, dispatcherTypes, - isMatchAfter); - - filter_maps_.add(map); - } - } - - @Override - public Collection getUrlPatternMappings() - { - log("FilterReg.getUrlPatternMappings"); - return Collections.emptySet(); - } - - @Override - public void setAsyncSupported(boolean isAsyncSupported) - { - log("FilterReg.setAsyncSupported: " + isAsyncSupported); - async_supported_ = isAsyncSupported; - } - - @Override - public String getFilterName() - { - return getName(); - } - - @Override - public ServletContext getServletContext() - { - return (ServletContext) Context.this; - } - } - - private class FilterMap - { - private final FilterReg filter_; - private final ServletReg servlet_; - private final URLPattern pattern_; - private final EnumSet dtypes_; - private final boolean match_after_; - - public FilterMap(FilterReg filter, ServletReg servlet, - EnumSet dtypes, boolean match_after) - { - filter_ = filter; - servlet_ = servlet; - pattern_ = null; - dtypes_ = dtypes; - match_after_ = match_after; - } - - public FilterMap(FilterReg filter, URLPattern pattern, - EnumSet dtypes, boolean match_after) - { - filter_ = filter; - servlet_ = null; - pattern_ = pattern; - dtypes_ = dtypes; - match_after_ = match_after; - } - } - - private void initialized() - { - if (!sess_attr_listeners_.isEmpty()) { - sess_attr_proxy_ = new SessionAttrProxy(sess_attr_listeners_); - } - - if (!req_attr_listeners_.isEmpty()) { - req_attr_proxy_ = new RequestAttrProxy(req_attr_listeners_); - } - - ClassLoader old = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(loader_); - - try { - // Call context listeners - destroy_listeners_.clear(); - if (!ctx_listeners_.isEmpty()) { - ServletContextEvent event = new ServletContextEvent(this); - for (ServletContextListener listener : ctx_listeners_) - { - try { - listener.contextInitialized(event); - } catch(AbstractMethodError e) { - log("initialized: AbstractMethodError exception caught: " + e); - } - destroy_listeners_.add(0, listener); - } - } - - for (ServletReg sr : servlets_) { - try { - sr.startup(); - } catch(ServletException e) { - log("initialized: exception caught: " + e); - } - } - - for (FilterReg fr : filters_) { - try { - fr.init(); - } catch(ServletException e) { - log("initialized: exception caught: " + e); - } - } - - ctx_initialized_ = true; - } finally { - Thread.currentThread().setContextClassLoader(old); - } - } - - @Override - public ServletContext getContext(String uripath) - { - trace("getContext for " + uripath); - return this; - } - - @Override - public int getMajorVersion() - { - trace("getMajorVersion"); - return SERVLET_MAJOR_VERSION; - } - - @Override - public String getMimeType(String file) - { - log("getMimeType for " + file); - if (mime_types_ == null) { - mime_types_ = new MimeTypes(); - } - return mime_types_.getMimeByExtension(file); - } - - @Override - public int getMinorVersion() - { - trace("getMinorVersion"); - return SERVLET_MINOR_VERSION; - } - - private class URIRequestDispatcher implements RequestDispatcher - { - private final URI uri_; - - public URIRequestDispatcher(URI uri) - { - uri_ = uri; - } - - public URIRequestDispatcher(String uri) - throws URISyntaxException - { - uri_ = new URI(uri); - } - - @Override - public void forward(ServletRequest request, ServletResponse response) - throws ServletException, IOException - { - /* - 9.4 The Forward Method - ... - If the response has been committed, an IllegalStateException - must be thrown. - */ - if (response.isCommitted()) { - throw new IllegalStateException("Response already committed"); - } - - ForwardRequestWrapper req = new ForwardRequestWrapper(request); - - try { - trace("URIRequestDispatcher.forward"); - - String path = uri_.getPath().substring(context_path_.length()); - - ServletReg servlet = findServlet(path, req); - - req.setMultipartConfig(servlet.multipart_config_); - - req.setRequestURI(uri_.getRawPath()); - req.setQueryString(uri_.getRawQuery()); - req.setDispatcherType(DispatcherType.FORWARD); - - /* - 9.4 The Forward Method - ... - If output data exists in the response buffer that has not - been committed, the content must be cleared before the - target servlet's service method is called. - */ - response.resetBuffer(); - - FilterChain fc = new CtxFilterChain(servlet, req.getFilterPath(), DispatcherType.FORWARD); - - fc.doFilter(request, response); - - /* - 9.4 The Forward Method - ... - Before the forward method of the RequestDispatcher interface - returns without exception, the response content must be sent - and committed, and closed by the servlet container, unless - the request was put into the asynchronous mode. If an error - occurs in the target of the RequestDispatcher.forward() the - exception may be propagated back through all the calling - filters and servlets and eventually back to the container - */ - if (!request.isAsyncStarted()) { - response.flushBuffer(); - } - - /* - 9.5 Error Handling - - If the servlet that is the target of a request dispatcher - throws a runtime exception or a checked exception of type - ServletException or IOException, it should be propagated - to the calling servlet. All other exceptions should be - wrapped as ServletExceptions and the root cause of the - exception set to the original exception, as it should - not be propagated. - */ - } catch (ServletException e) { - throw e; - } catch (IOException e) { - throw e; - } catch (Exception e) { - throw new ServletException(e); - } finally { - req.close(); - - trace("URIRequestDispatcher.forward done"); - } - } - - @Override - public void include(ServletRequest request, ServletResponse response) - throws ServletException, IOException - { - IncludeRequestWrapper req = new IncludeRequestWrapper(request); - - try { - trace("URIRequestDispatcher.include"); - - String path = uri_.getPath().substring(context_path_.length()); - - ServletReg servlet = findServlet(path, req); - - req.setMultipartConfig(servlet.multipart_config_); - - req.setRequestURI(uri_.getRawPath()); - req.setQueryString(uri_.getRawQuery()); - req.setDispatcherType(DispatcherType.INCLUDE); - - FilterChain fc = new CtxFilterChain(servlet, req.getFilterPath(), DispatcherType.INCLUDE); - - fc.doFilter(request, new IncludeResponseWrapper(response)); - - } catch (ServletException e) { - throw e; - } catch (IOException e) { - throw e; - } catch (Exception e) { - throw new ServletException(e); - } finally { - req.close(); - - trace("URIRequestDispatcher.include done"); - } - } - } - - private class ServletDispatcher implements RequestDispatcher - { - private final ServletReg servlet_; - - public ServletDispatcher(ServletReg servlet) - { - servlet_ = servlet; - } - - @Override - public void forward(ServletRequest request, ServletResponse response) - throws ServletException, IOException - { - /* - 9.4 The Forward Method - ... - If the response has been committed, an IllegalStateException - must be thrown. - */ - if (response.isCommitted()) { - throw new IllegalStateException("Response already committed"); - } - - trace("ServletDispatcher.forward"); - - DispatcherType dtype = request.getDispatcherType(); - - Request req; - if (request instanceof Request) { - req = (Request) request; - } else { - req = (Request) request.getAttribute(Request.BARE); - } - - try { - req.setDispatcherType(DispatcherType.FORWARD); - - /* - 9.4 The Forward Method - ... - If output data exists in the response buffer that has not - been committed, the content must be cleared before the - target servlet's service method is called. - */ - response.resetBuffer(); - - servlet_.service(request, response); - - /* - 9.4 The Forward Method - ... - Before the forward method of the RequestDispatcher interface - returns without exception, the response content must be sent - and committed, and closed by the servlet container, unless - the request was put into the asynchronous mode. If an error - occurs in the target of the RequestDispatcher.forward() the - exception may be propagated back through all the calling - filters and servlets and eventually back to the container - */ - if (!request.isAsyncStarted()) { - response.flushBuffer(); - } - - /* - 9.5 Error Handling - - If the servlet that is the target of a request dispatcher - throws a runtime exception or a checked exception of type - ServletException or IOException, it should be propagated - to the calling servlet. All other exceptions should be - wrapped as ServletExceptions and the root cause of the - exception set to the original exception, as it should - not be propagated. - */ - } catch (ServletException e) { - throw e; - } catch (IOException e) { - throw e; - } catch (Exception e) { - throw new ServletException(e); - } finally { - req.setDispatcherType(dtype); - - trace("ServletDispatcher.forward done"); - } - } - - @Override - public void include(ServletRequest request, ServletResponse response) - throws ServletException, IOException - { - trace("ServletDispatcher.include"); - - DispatcherType dtype = request.getDispatcherType(); - - Request req; - if (request instanceof Request) { - req = (Request) request; - } else { - req = (Request) request.getAttribute(Request.BARE); - } - - try { - req.setDispatcherType(DispatcherType.INCLUDE); - - servlet_.service(request, new IncludeResponseWrapper(response)); - - } catch (ServletException e) { - throw e; - } catch (IOException e) { - throw e; - } catch (Exception e) { - throw new ServletException(e); - } finally { - req.setDispatcherType(dtype); - - trace("ServletDispatcher.include done"); - } - } - } - - @Override - public RequestDispatcher getNamedDispatcher(String name) - { - trace("getNamedDispatcher for " + name); - - ServletReg servlet = name2servlet_.get(name); - if (servlet != null) { - return new ServletDispatcher(servlet); - } - - return null; - } - - @Override - public RequestDispatcher getRequestDispatcher(String uriInContext) - { - trace("getRequestDispatcher for " + uriInContext); - try { - return new URIRequestDispatcher(context_path_ + uriInContext); - } catch (URISyntaxException e) { - log("getRequestDispatcher: failed to create dispatcher: " + e); - } - - return null; - } - - public RequestDispatcher getRequestDispatcher(URI uri) - { - trace("getRequestDispatcher for " + uri.getRawPath()); - return new URIRequestDispatcher(uri); - } - - @Override - public String getRealPath(String path) - { - trace("getRealPath for " + path); - - File f = new File(webapp_, path.isEmpty() ? "" : path.substring(1)); - - return f.getAbsolutePath(); - } - - @Override - public URL getResource(String path) throws MalformedURLException - { - trace("getResource for " + path); - - File f = new File(webapp_, path.substring(1)); - - if (f.exists()) { - return new URL("file:" + f.getAbsolutePath()); - } - - return null; - } - - @Override - public InputStream getResourceAsStream(String path) - { - trace("getResourceAsStream for " + path); - - try { - File f = new File(webapp_, path.substring(1)); - - return new FileInputStream(f); - } catch (FileNotFoundException e) { - log("getResourceAsStream: failed " + e); - - return null; - } - } - - @Override - public Set getResourcePaths(String path) - { - trace("getResourcePaths for " + path); - - File dir = new File(webapp_, path.substring(1)); - File[] list = dir.listFiles(); - - if (list == null) { - return null; - } - - Set res = new HashSet<>(); - Path root = webapp_.toPath(); - - for (File f : list) { - String r = "/" + root.relativize(f.toPath()); - if (f.isDirectory()) { - r += "/"; - } - - trace("getResourcePaths: " + r); - - res.add(r); - } - - return res; - } - - @Override - public String getServerInfo() - { - trace("getServerInfo: " + server_info_); - return server_info_; - } - - @Override - @Deprecated - public Servlet getServlet(String name) throws ServletException - { - log("getServlet for " + name); - return null; - } - - @SuppressWarnings("unchecked") - @Override - @Deprecated - public Enumeration getServletNames() - { - log("getServletNames"); - return Collections.enumeration(Collections.EMPTY_LIST); - } - - @SuppressWarnings("unchecked") - @Override - @Deprecated - public Enumeration getServlets() - { - log("getServlets"); - return Collections.enumeration(Collections.EMPTY_LIST); - } - - @Override - @Deprecated - public void log(Exception exception, String msg) - { - log(msg, exception); - } - - @Override - public void log(String msg) - { - msg = "Context." + msg; - log(0, msg, msg.length()); - } - - @Override - public void log(String message, Throwable throwable) - { - log(message); - } - - private static native void log(long ctx_ptr, String msg, int msg_len); - - - public static void trace(String msg) - { - msg = "Context." + msg; - trace(0, msg, msg.length()); - } - - private static native void trace(long ctx_ptr, String msg, int msg_len); - - @Override - public String getInitParameter(String name) - { - trace("getInitParameter for " + name); - return init_params_.get(name); - } - - @SuppressWarnings("unchecked") - @Override - public Enumeration getInitParameterNames() - { - trace("getInitParameterNames"); - return Collections.enumeration(Collections.EMPTY_LIST); - } - - @Override - public String getServletContextName() - { - log("getServletContextName"); - return "No Context"; - } - - @Override - public String getContextPath() - { - trace("getContextPath"); - return context_path_; - } - - @Override - public boolean setInitParameter(String name, String value) - { - trace("setInitParameter " + name + " = " + value); - return init_params_.putIfAbsent(name, value) == null; - } - - @Override - public Object getAttribute(String name) - { - trace("getAttribute " + name); - - return attributes_.get(name); - } - - @Override - public Enumeration getAttributeNames() - { - trace("getAttributeNames"); - - Set names = attributes_.keySet(); - return Collections.enumeration(names); - } - - @Override - public void setAttribute(String name, Object object) - { - trace("setAttribute " + name); - - Object prev = attributes_.put(name, object); - - if (ctx_attr_listeners_.isEmpty()) { - return; - } - - ServletContextAttributeEvent scae = new ServletContextAttributeEvent( - this, name, prev == null ? object : prev); - - for (ServletContextAttributeListener l : ctx_attr_listeners_) { - if (prev == null) { - l.attributeAdded(scae); - } else { - l.attributeReplaced(scae); - } - } - } - - @Override - public void removeAttribute(String name) - { - trace("removeAttribute " + name); - - Object value = attributes_.remove(name); - - if (ctx_attr_listeners_.isEmpty()) { - return; - } - - ServletContextAttributeEvent scae = new ServletContextAttributeEvent( - this, name, value); - - for (ServletContextAttributeListener l : ctx_attr_listeners_) { - l.attributeRemoved(scae); - } - } - - @Override - public FilterRegistration.Dynamic addFilter(String name, - Class filterClass) - { - log("addFilter " + name + ", " + filterClass.getName()); - - checkContextState(); - - FilterReg reg = new FilterReg(name, filterClass); - filters_.add(reg); - name2filter_.put(name, reg); - return reg; - } - - @Override - public FilterRegistration.Dynamic addFilter(String name, Filter filter) - { - log("addFilter " + name); - - checkContextState(); - - FilterReg reg = new FilterReg(name, filter); - filters_.add(reg); - name2filter_.put(name, reg); - return reg; - } - - @Override - public FilterRegistration.Dynamic addFilter(String name, String className) - { - log("addFilter " + name + ", " + className); - - checkContextState(); - - FilterReg reg = new FilterReg(name, className); - filters_.add(reg); - name2filter_.put(name, reg); - return reg; - } - - @Override - public ServletRegistration.Dynamic addServlet(String name, - Class servletClass) - { - log("addServlet " + name + ", " + servletClass.getName()); - - checkContextState(); - - ServletReg reg = null; - try { - reg = new ServletReg(name, servletClass); - servlets_.add(reg); - name2servlet_.put(name, reg); - } catch(Exception e) { - System.err.println("addServlet: exception caught: " + e.toString()); - } - - return reg; - } - - @Override - public ServletRegistration.Dynamic addServlet(String name, Servlet servlet) - { - log("addServlet " + name); - - checkContextState(); - - ServletReg reg = null; - try { - reg = new ServletReg(name, servlet); - servlets_.add(reg); - name2servlet_.put(name, reg); - } catch(Exception e) { - System.err.println("addServlet: exception caught: " + e.toString()); - } - - return reg; - } - - @Override - public ServletRegistration.Dynamic addServlet(String name, String className) - { - log("addServlet " + name + ", " + className); - - checkContextState(); - - ServletReg reg = null; - try { - reg = new ServletReg(name, className); - servlets_.add(reg); - name2servlet_.put(name, reg); - } catch(Exception e) { - System.err.println("addServlet: exception caught: " + e.toString()); - } - - return reg; - } - - @Override - public ServletRegistration.Dynamic addJspFile(String jspName, String jspFile) - { - log("addJspFile: " + jspName + " " + jspFile); - - return null; - } - - @Override - public T createFilter(Class c) throws ServletException - { - log("createFilter " + c.getName()); - - checkContextState(); - - try { - Constructor ctor = c.getConstructor(); - T filter = ctor.newInstance(); - return filter; - } catch (Exception e) { - log("createFilter() failed " + e); - - throw new ServletException(e); - } - } - - @Override - public T createServlet(Class c) throws ServletException - { - log("createServlet " + c.getName()); - - checkContextState(); - - try { - Constructor ctor = c.getConstructor(); - T servlet = ctor.newInstance(); - return servlet; - } catch (Exception e) { - log("createServlet() failed " + e); - - throw new ServletException(e); - } - } - - @Override - public Set getDefaultSessionTrackingModes() - { - log("getDefaultSessionTrackingModes"); - - return default_session_tracking_modes_; - } - - @Override - public Set getEffectiveSessionTrackingModes() - { - log("getEffectiveSessionTrackingModes"); - - return session_tracking_modes_; - } - - public boolean isSessionIdValid(String id) - { - synchronized (sessions_) { - return sessions_.containsKey(id); - } - } - - public Session getSession(String id) - { - synchronized (sessions_) { - Session s = sessions_.get(id); - - if (s != null) { - s.accessed(); - - if (s.checkTimeOut()) { - s.invalidate(); - return null; - } - } - - return s; - } - } - - public Session createSession() - { - Session session = new Session(this, generateSessionId(), - sess_attr_proxy_, session_timeout_ * 60); - - if (!sess_listeners_.isEmpty()) - { - HttpSessionEvent event = new HttpSessionEvent(session); - - for (HttpSessionListener l : sess_listeners_) - { - l.sessionCreated(event); - } - } - - synchronized (sessions_) { - sessions_.put(session.getId(), session); - - return session; - } - } - - public void invalidateSession(Session session) - { - synchronized (sessions_) { - sessions_.remove(session.getId()); - } - - if (!sess_listeners_.isEmpty()) - { - HttpSessionEvent event = new HttpSessionEvent(session); - - for (int i = sess_listeners_.size() - 1; i >= 0; i--) - { - sess_listeners_.get(i).sessionDestroyed(event); - } - } - } - - public void changeSessionId(Session session) - { - String old_id; - - synchronized (sessions_) { - old_id = session.getId(); - sessions_.remove(old_id); - - session.setId(generateSessionId()); - - sessions_.put(session.getId(), session); - } - - if (!sess_id_listeners_.isEmpty()) - { - HttpSessionEvent event = new HttpSessionEvent(session); - for (HttpSessionIdListener l : sess_id_listeners_) - { - l.sessionIdChanged(event, old_id); - } - } - } - - private String generateSessionId() - { - return UUID.randomUUID().toString(); - } - - @Override - public FilterRegistration getFilterRegistration(String filterName) - { - log("getFilterRegistration " + filterName); - return name2filter_.get(filterName); - } - - @Override - public Map getFilterRegistrations() - { - log("getFilterRegistrations"); - return name2filter_; - } - - @Override - public ServletRegistration getServletRegistration(String servletName) - { - log("getServletRegistration " + servletName); - return name2servlet_.get(servletName); - } - - @Override - public Map getServletRegistrations() - { - log("getServletRegistrations"); - return name2servlet_; - } - - @Override - public SessionCookieConfig getSessionCookieConfig() - { - log("getSessionCookieConfig"); - - return session_cookie_config_; - } - - @Override - public void setSessionTrackingModes(Set modes) - { - log("setSessionTrackingModes"); - - session_tracking_modes_ = modes; - } - - @Override - public void addListener(String className) - { - trace("addListener " + className); - - checkContextState(); - - if (listener_classnames_.contains(className)) { - log("addListener " + className + " already added as listener"); - return; - } - - try { - Class cls = loader_.loadClass(className); - - Constructor ctor = cls.getConstructor(); - EventListener listener = (EventListener) ctor.newInstance(); - - addListener(listener); - - listener_classnames_.add(className); - } catch (Exception e) { - log("addListener: exception caught: " + e.toString()); - } - } - - @Override - public void addListener(T t) - { - trace("addListener " + t.getClass().getName()); - - checkContextState(); - - for (int i = 0; i < LISTENER_TYPES.length; i++) { - Class c = LISTENER_TYPES[i]; - if (c.isAssignableFrom(t.getClass())) { - trace("addListener: assignable to " + c.getName()); - } - } - - if (t instanceof ServletContextListener) { - ctx_listeners_.add((ServletContextListener) t); - } - - if (t instanceof ServletContextAttributeListener) { - ctx_attr_listeners_.add((ServletContextAttributeListener) t); - } - - if (t instanceof ServletRequestListener) { - req_init_listeners_.add((ServletRequestListener) t); - req_destroy_listeners_.add(0, (ServletRequestListener) t); - } - - if (t instanceof ServletRequestAttributeListener) { - req_attr_listeners_.add((ServletRequestAttributeListener) t); - } - - if (t instanceof HttpSessionAttributeListener) { - sess_attr_listeners_.add((HttpSessionAttributeListener) t); - } - - if (t instanceof HttpSessionIdListener) { - sess_id_listeners_.add((HttpSessionIdListener) t); - } - - if (t instanceof HttpSessionListener) { - sess_listeners_.add((HttpSessionListener) t); - } - } - - @Override - public void addListener(Class listenerClass) - { - String className = listenerClass.getName(); - trace("addListener " + className); - - checkContextState(); - - if (listener_classnames_.contains(className)) { - log("addListener " + className + " already added as listener"); - return; - } - - try { - Constructor ctor = listenerClass.getConstructor(); - EventListener listener = (EventListener) ctor.newInstance(); - - addListener(listener); - - listener_classnames_.add(className); - } catch (Exception e) { - log("addListener: exception caught: " + e.toString()); - } - } - - @Override - public T createListener(Class clazz) - throws ServletException - { - trace("createListener " + clazz.getName()); - - checkContextState(); - - try - { - return clazz.getDeclaredConstructor().newInstance(); - } - catch (Exception e) - { - throw new ServletException(e); - } - } - - @Override - public ClassLoader getClassLoader() - { - trace("getClassLoader"); - return loader_; - } - - @Override - public int getEffectiveMajorVersion() - { - log("getEffectiveMajorVersion"); - return SERVLET_MAJOR_VERSION; - } - - @Override - public int getEffectiveMinorVersion() - { - log("getEffectiveMinorVersion"); - return SERVLET_MINOR_VERSION; - } - - private final List taglibs_ = new ArrayList<>(); - private final List prop_groups_ = new ArrayList<>(); - - private class JspConfig implements JspConfigDescriptor - { - @Override - public Collection getTaglibs() - { - trace("getTaglibs"); - return taglibs_; - } - - @Override - public Collection getJspPropertyGroups() - { - trace("getJspPropertyGroups"); - return prop_groups_; - } - } - - private final JspConfig jsp_config_ = new JspConfig(); - - @Override - public JspConfigDescriptor getJspConfigDescriptor() - { - trace("getJspConfigDescriptor"); - - return jsp_config_; - } - - @Override - public void declareRoles(String... roleNames) - { - log("declareRoles"); - //LOG.warn(__unimplmented); - } - - @Override - public String getVirtualServerName() - { - log("getVirtualServerName"); - return null; - } - - @Override - public int getSessionTimeout() - { - trace("getSessionTimeout"); - - return session_timeout_; - } - - @Override - public void setSessionTimeout(int sessionTimeout) - { - trace("setSessionTimeout: " + sessionTimeout); - - session_timeout_ = sessionTimeout; - } - - @Override - public String getRequestCharacterEncoding() - { - log("getRequestCharacterEncoding"); - - return null; - } - - @Override - public void setRequestCharacterEncoding(String encoding) - { - log("setRequestCharacterEncoding: " + encoding); - } - - @Override - public String getResponseCharacterEncoding() - { - log("getResponseCharacterEncoding"); - - return null; - } - - @Override - public void setResponseCharacterEncoding(String encoding) - { - log("setResponseCharacterEncoding: " + encoding); - } - - public ServletRequestAttributeListener getRequestAttributeListener() - { - return req_attr_proxy_; - } -} diff --git a/src/java/nginx/unit/DynamicDispatcherRequest.java b/src/java/nginx/unit/DynamicDispatcherRequest.java deleted file mode 100644 index af0747eb..00000000 --- a/src/java/nginx/unit/DynamicDispatcherRequest.java +++ /dev/null @@ -1,8 +0,0 @@ -package nginx.unit; - -import javax.servlet.DispatcherType; - -public interface DynamicDispatcherRequest -{ - public void setDispatcherType(DispatcherType type); -} diff --git a/src/java/nginx/unit/DynamicPathRequest.java b/src/java/nginx/unit/DynamicPathRequest.java deleted file mode 100644 index efc1bcd1..00000000 --- a/src/java/nginx/unit/DynamicPathRequest.java +++ /dev/null @@ -1,15 +0,0 @@ -package nginx.unit; - -public interface DynamicPathRequest - extends DynamicDispatcherRequest -{ - public void setServletPath(String servlet_path, String path_info); - - public void setServletPath(String filter_path, String servlet_path, String path_info); - - public void setRequestURI(String uri); - - public void setQueryString(String query); - - public String getFilterPath(); -} diff --git a/src/java/nginx/unit/ForwardRequestWrapper.java b/src/java/nginx/unit/ForwardRequestWrapper.java deleted file mode 100644 index fe8adf8a..00000000 --- a/src/java/nginx/unit/ForwardRequestWrapper.java +++ /dev/null @@ -1,162 +0,0 @@ -package nginx.unit; - -import java.util.List; -import java.util.Map; - -import javax.servlet.DispatcherType; -import javax.servlet.MultipartConfigElement; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletRequest; -import javax.servlet.http.HttpServletRequest; - -import org.eclipse.jetty.util.MultiMap; -import org.eclipse.jetty.util.UrlEncoded; - -public class ForwardRequestWrapper implements DynamicPathRequest -{ - private final Request request_; - - private final boolean keep_attrs; - - private final String orig_filter_path; - private final String orig_servlet_path; - private final String orig_path_info; - private final String orig_uri; - private final String orig_context_path; - private final String orig_query; - - private final MultipartConfigElement orig_multipart_config; - - private final DispatcherType orig_dtype; - - private MultiMap orig_parameters; - - public ForwardRequestWrapper(ServletRequest request) - { - if (request instanceof Request) { - request_ = (Request) request; - } else { - request_ = (Request) request.getAttribute(Request.BARE); - } - - keep_attrs = request_.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI) != null; - - orig_dtype = request_.getDispatcherType(); - - orig_filter_path = request_.getFilterPath(); - orig_servlet_path = request_.getServletPath(); - orig_path_info = request_.getPathInfo(); - orig_uri = request_.getRequestURI(); - orig_context_path = request_.getContextPath(); - orig_query = request_.getQueryString(); - - orig_multipart_config = request_.getMultipartConfig(); - } - - @Override - public void setDispatcherType(DispatcherType type) - { - request_.setDispatcherType(type); - - /* - 9.4.2 Forwarded Request Parameters - ... - Note that these attributes must always reflect the information in - the original request even under the situation that multiple - forwards and subsequent includes are called. - */ - - if (keep_attrs) { - return; - } - - /* - 9.4.2 Forwarded Request Parameters - ... - The values of these attributes must be equal to the return values - of the HttpServletRequest methods getRequestURI, getContextPath, - getServletPath, getPathInfo, getQueryString respectively, invoked - on the request object passed to the first servlet object in the - call chain that received the request from the client. - */ - - request_.setAttribute_(RequestDispatcher.FORWARD_SERVLET_PATH, orig_servlet_path); - request_.setAttribute_(RequestDispatcher.FORWARD_PATH_INFO, orig_path_info); - request_.setAttribute_(RequestDispatcher.FORWARD_REQUEST_URI, orig_uri); - request_.setAttribute_(RequestDispatcher.FORWARD_CONTEXT_PATH, orig_context_path); - request_.setAttribute_(RequestDispatcher.FORWARD_QUERY_STRING, orig_query); - } - - @Override - public void setServletPath(String servlet_path, String path_info) - { - request_.setServletPath(servlet_path, path_info); - } - - @Override - public void setServletPath(String filter_path, String servlet_path, String path_info) - { - request_.setServletPath(filter_path, servlet_path, path_info); - } - - @Override - public void setRequestURI(String uri) - { - request_.setRequestURI(uri); - } - - @Override - public void setQueryString(String query) - { - if (query != null) { - orig_parameters = request_.getParameters(); - - MultiMap parameters = new MultiMap<>(); - UrlEncoded.decodeUtf8To(query, parameters); - - for (Map.Entry> e: orig_parameters.entrySet()) { - parameters.addValues(e.getKey(), e.getValue()); - } - - request_.setParameters(parameters); - - request_.setQueryString(query); - } - } - - @Override - public String getFilterPath() - { - return request_.getFilterPath(); - } - - public void setMultipartConfig(MultipartConfigElement mce) - { - request_.setMultipartConfig(mce); - } - - public void close() - { - request_.setDispatcherType(orig_dtype); - - request_.setRequestURI(orig_uri); - request_.setServletPath(orig_filter_path, orig_servlet_path, orig_path_info); - request_.setQueryString(orig_query); - - if (orig_parameters != null) { - request_.setParameters(orig_parameters); - } - - request_.setMultipartConfig(orig_multipart_config); - - if (keep_attrs) { - return; - } - - request_.setAttribute_(RequestDispatcher.FORWARD_SERVLET_PATH, null); - request_.setAttribute_(RequestDispatcher.FORWARD_PATH_INFO, null); - request_.setAttribute_(RequestDispatcher.FORWARD_REQUEST_URI, null); - request_.setAttribute_(RequestDispatcher.FORWARD_CONTEXT_PATH, null); - request_.setAttribute_(RequestDispatcher.FORWARD_QUERY_STRING, null); - } -} diff --git a/src/java/nginx/unit/HeaderNamesEnumeration.java b/src/java/nginx/unit/HeaderNamesEnumeration.java deleted file mode 100644 index d81b8778..00000000 --- a/src/java/nginx/unit/HeaderNamesEnumeration.java +++ /dev/null @@ -1,42 +0,0 @@ -package nginx.unit; - -import java.lang.String; -import java.util.Enumeration; -import java.util.NoSuchElementException; - -public class HeaderNamesEnumeration implements Enumeration { - - private long headers_ptr; - private long size; - private long pos = 0; - - public HeaderNamesEnumeration(long _headers_ptr, long _size) { - headers_ptr = _headers_ptr; - size = _size; - } - - @Override - public boolean hasMoreElements() - { - if (pos >= size) { - return false; - } - - pos = nextElementPos(headers_ptr, size, pos); - return pos < size; - } - - static private native long nextElementPos(long headers_ptr, long size, long pos); - - @Override - public String nextElement() - { - if (pos >= size) { - throw new NoSuchElementException(); - } - - return nextElement(headers_ptr, size, pos++); - } - - static private native String nextElement(long headers_ptr, long size, long pos); -} diff --git a/src/java/nginx/unit/HeadersEnumeration.java b/src/java/nginx/unit/HeadersEnumeration.java deleted file mode 100644 index 31b5ae24..00000000 --- a/src/java/nginx/unit/HeadersEnumeration.java +++ /dev/null @@ -1,40 +0,0 @@ -package nginx.unit; - -import java.lang.String; -import java.util.Enumeration; - -public class HeadersEnumeration implements Enumeration { - - private long headers_ptr; - private long size; - private long initial_pos; - private long pos; - - public HeadersEnumeration(long _headers_ptr, long _size, long _initial_pos) { - headers_ptr = _headers_ptr; - size = _size; - initial_pos = _initial_pos; - pos = _initial_pos; - } - - @Override - public boolean hasMoreElements() - { - if (pos >= size) { - return false; - } - - pos = nextElementPos(headers_ptr, size, initial_pos, pos); - return pos < size; - } - - static private native long nextElementPos(long headers_ptr, long size, long initial_pos, long pos); - - @Override - public String nextElement() - { - return nextElement(headers_ptr, size, initial_pos, pos++); - } - - static private native String nextElement(long headers_ptr, long size, long initial_pos, long pos); -} diff --git a/src/java/nginx/unit/IncludeRequestWrapper.java b/src/java/nginx/unit/IncludeRequestWrapper.java deleted file mode 100644 index 761a0d52..00000000 --- a/src/java/nginx/unit/IncludeRequestWrapper.java +++ /dev/null @@ -1,100 +0,0 @@ -package nginx.unit; - -import javax.servlet.DispatcherType; -import javax.servlet.MultipartConfigElement; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletRequest; - -public class IncludeRequestWrapper implements DynamicPathRequest -{ - private final Request request_; - - private final Object orig_servlet_path_attr; - private final Object orig_path_info_attr; - private final Object orig_uri_attr; - private final Object orig_context_path_attr; - private final Object orig_query_string_attr; - - private final MultipartConfigElement orig_multipart_config; - - private final DispatcherType orig_dtype; - - private String filter_path_; - - public IncludeRequestWrapper(ServletRequest request) - { - if (request instanceof Request) { - request_ = (Request) request; - } else { - request_ = (Request) request.getAttribute(Request.BARE); - } - - orig_servlet_path_attr = request_.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH); - orig_path_info_attr = request_.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO); - orig_uri_attr = request_.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI); - orig_context_path_attr = request_.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH); - orig_query_string_attr = request_.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING); - - orig_multipart_config = request_.getMultipartConfig(); - - orig_dtype = request_.getDispatcherType(); - - request_.setAttribute_(RequestDispatcher.INCLUDE_CONTEXT_PATH, request_.getContextPath()); - } - - @Override - public void setDispatcherType(DispatcherType type) - { - request_.setDispatcherType(type); - } - - @Override - public void setServletPath(String servlet_path, String path_info) - { - setServletPath(servlet_path, servlet_path, path_info); - } - - @Override - public void setServletPath(String filter_path, String servlet_path, String path_info) - { - request_.setAttribute_(RequestDispatcher.INCLUDE_SERVLET_PATH, servlet_path); - request_.setAttribute_(RequestDispatcher.INCLUDE_PATH_INFO, path_info); - filter_path_ = filter_path; - } - - @Override - public void setRequestURI(String uri) - { - request_.setAttribute_(RequestDispatcher.INCLUDE_REQUEST_URI, uri); - } - - @Override - public void setQueryString(String query) - { - request_.setAttribute_(RequestDispatcher.INCLUDE_QUERY_STRING, query); - } - - @Override - public String getFilterPath() - { - return filter_path_; - } - - public void setMultipartConfig(MultipartConfigElement mce) - { - request_.setMultipartConfig(mce); - } - - public void close() - { - request_.setDispatcherType(orig_dtype); - - request_.setAttribute_(RequestDispatcher.INCLUDE_SERVLET_PATH, orig_servlet_path_attr); - request_.setAttribute_(RequestDispatcher.INCLUDE_PATH_INFO, orig_path_info_attr); - request_.setAttribute_(RequestDispatcher.INCLUDE_REQUEST_URI, orig_uri_attr); - request_.setAttribute_(RequestDispatcher.INCLUDE_CONTEXT_PATH, orig_context_path_attr); - request_.setAttribute_(RequestDispatcher.INCLUDE_QUERY_STRING, orig_query_string_attr); - - request_.setMultipartConfig(orig_multipart_config); - } -} diff --git a/src/java/nginx/unit/IncludeResponseWrapper.java b/src/java/nginx/unit/IncludeResponseWrapper.java deleted file mode 100644 index 4537114a..00000000 --- a/src/java/nginx/unit/IncludeResponseWrapper.java +++ /dev/null @@ -1,117 +0,0 @@ -package nginx.unit; - -import java.io.IOException; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -import javax.servlet.ServletResponse; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -public class IncludeResponseWrapper extends HttpServletResponseWrapper { - private static final Charset UTF_8 = StandardCharsets.UTF_8; - - public IncludeResponseWrapper(ServletResponse response) - { - super((HttpServletResponse) response); - } - - @Override - public void addCookie(Cookie cookie) - { - trace("addCookie: " + cookie.getName() + "=" + cookie.getValue()); - } - - @Override - public void addDateHeader(String name, long date) - { - trace("addDateHeader: " + name + ": " + date); - } - - @Override - public void addHeader(String name, String value) - { - trace("addHeader: " + name + ": " + value); - } - - @Override - public void addIntHeader(String name, int value) - { - trace("addIntHeader: " + name + ": " + value); - } - - @Override - public void sendRedirect(String location) throws IOException - { - trace("sendRedirect: " + location); - } - - @Override - public void setDateHeader(String name, long date) - { - trace("setDateHeader: " + name + ": " + date); - } - - @Override - public void setHeader(String name, String value) - { - trace("setHeader: " + name + ": " + value); - } - - @Override - public void setIntHeader(String name, int value) - { - trace("setIntHeader: " + name + ": " + value); - } - - @Override - public void setStatus(int sc) - { - trace("setStatus: " + sc); - } - - @Override - @Deprecated - public void setStatus(int sc, String sm) - { - trace("setStatus: " + sc + "; " + sm); - } - - @Override - public void reset() - { - trace("reset"); - } - - @Override - public void setCharacterEncoding(String charset) - { - trace("setCharacterEncoding " + charset); - } - - @Override - public void setContentLength(int len) - { - trace("setContentLength: " + len); - } - - @Override - public void setContentLengthLong(long len) - { - trace("setContentLengthLong: " + len); - } - - @Override - public void setContentType(String type) - { - trace("setContentType: " + type); - } - - private void trace(String msg) - { - msg = "IncludeResponse." + msg; - Response.trace(0, msg.getBytes(UTF_8)); - } -} diff --git a/src/java/nginx/unit/InitParams.java b/src/java/nginx/unit/InitParams.java deleted file mode 100644 index 2f5dcbf9..00000000 --- a/src/java/nginx/unit/InitParams.java +++ /dev/null @@ -1,7 +0,0 @@ -package nginx.unit; - -public interface InitParams { - public boolean setInitParameter(String name, String value); - - public String getInitParameter(String name); -} diff --git a/src/java/nginx/unit/InputStream.java b/src/java/nginx/unit/InputStream.java deleted file mode 100644 index 6fe72ace..00000000 --- a/src/java/nginx/unit/InputStream.java +++ /dev/null @@ -1,90 +0,0 @@ -package nginx.unit; - -import java.io.IOException; - -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; - -public class InputStream extends ServletInputStream { - - private long req_info_ptr; - - public InputStream(long ptr) - { - req_info_ptr = ptr; - } - - @Override - public int readLine(byte[] b, int off, int len) throws IOException { - - if (len <= 0) { - return 0; - } - return readLine(req_info_ptr, b, off, len); - } - - private static native int readLine(long req_info_ptr, byte[] b, int off, int len); - - - @Override - public boolean isFinished() - { - return isFinished(req_info_ptr); - } - - private static native boolean isFinished(long req_info_ptr); - - - @Override - public boolean isReady() - { - return true; - } - - - @Override - public void setReadListener(ReadListener listener) - { - } - - - @Override - public int read() throws IOException - { - return read(req_info_ptr); - } - - private static native int read(long req_info_ptr); - - - @Override - public int read(byte b[], int off, int len) throws IOException { - if (b == null) { - throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return 0; - } - - return read(req_info_ptr, b, off, len); - } - - private static native int read(long req_info_ptr, byte b[], int off, int len); - - - @Override - public long skip(long n) throws IOException { - return skip(req_info_ptr, n); - } - - private static native long skip(long req_info_ptr, long n); - - - @Override - public int available() throws IOException { - return available(req_info_ptr); - } - - private static native int available(long req_info_ptr); -} diff --git a/src/java/nginx/unit/JspPropertyGroup.java b/src/java/nginx/unit/JspPropertyGroup.java deleted file mode 100644 index 2df27718..00000000 --- a/src/java/nginx/unit/JspPropertyGroup.java +++ /dev/null @@ -1,169 +0,0 @@ -package nginx.unit; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import javax.servlet.descriptor.JspPropertyGroupDescriptor; - -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -public class JspPropertyGroup implements JspPropertyGroupDescriptor -{ - private final List url_patterns_ = new ArrayList<>(); - private String el_ignored_ = null; - private String page_encoding_ = null; - private String scripting_invalid_ = null; - private String is_xml_ = null; - private final List include_preludes_ = new ArrayList<>(); - private final List include_codas_ = new ArrayList<>(); - - private String deffered_syntax_allowed_as_literal_ = null; - private String trim_directive_whitespaces_ = null; - private String default_content_type_ = null; - private String buffer_ = null; - private String error_on_undeclared_namespace_ = null; - - public JspPropertyGroup(NodeList nodes) - { - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - String tag_name = node.getNodeName(); - - if (tag_name.equals("url-pattern")) { - url_patterns_.add(node.getTextContent().trim()); - continue; - } - - if (tag_name.equals("el-ignored")) { - el_ignored_ = node.getTextContent().trim(); - continue; - } - - if (tag_name.equals("page-encoding")) { - page_encoding_ = node.getTextContent().trim(); - continue; - } - - if (tag_name.equals("scripting-invalid")) { - scripting_invalid_ = node.getTextContent().trim(); - continue; - } - - if (tag_name.equals("is-xml")) { - is_xml_ = node.getTextContent().trim(); - continue; - } - - if (tag_name.equals("include-prelude")) { - include_preludes_.add(node.getTextContent().trim()); - continue; - } - - if (tag_name.equals("include-coda")) { - include_codas_.add(node.getTextContent().trim()); - continue; - } - - if (tag_name.equals("deferred-syntax-allowed-as-literal")) { - deffered_syntax_allowed_as_literal_ = node.getTextContent().trim(); - continue; - } - - if (tag_name.equals("trim-directive-whitespaces")) { - trim_directive_whitespaces_ = node.getTextContent().trim(); - continue; - } - - if (tag_name.equals("default-content-type")) { - default_content_type_ = node.getTextContent().trim(); - continue; - } - - if (tag_name.equals("buffer")) { - buffer_ = node.getTextContent().trim(); - continue; - } - - if (tag_name.equals("error-on-undeclared-namespace")) { - error_on_undeclared_namespace_ = node.getTextContent().trim(); - continue; - } - } - - } - - @Override - public Collection getUrlPatterns() - { - return new ArrayList<>(url_patterns_); - } - - @Override - public String getElIgnored() - { - return el_ignored_; - } - - @Override - public String getPageEncoding() - { - return page_encoding_; - } - - @Override - public String getScriptingInvalid() - { - return scripting_invalid_; - } - - @Override - public String getIsXml() - { - return is_xml_; - } - - @Override - public Collection getIncludePreludes() - { - return new ArrayList<>(include_preludes_); - } - - @Override - public Collection getIncludeCodas() - { - return new ArrayList<>(include_codas_); - } - - @Override - public String getDeferredSyntaxAllowedAsLiteral() - { - return deffered_syntax_allowed_as_literal_; - } - - @Override - public String getTrimDirectiveWhitespaces() - { - return trim_directive_whitespaces_; - } - - @Override - public String getDefaultContentType() - { - return default_content_type_; - } - - @Override - public String getBuffer() - { - return buffer_; - } - - @Override - public String getErrorOnUndeclaredNamespace() - { - return error_on_undeclared_namespace_; - } -} - diff --git a/src/java/nginx/unit/OutputStream.java b/src/java/nginx/unit/OutputStream.java deleted file mode 100644 index 68af3423..00000000 --- a/src/java/nginx/unit/OutputStream.java +++ /dev/null @@ -1,68 +0,0 @@ -package nginx.unit; - -import java.io.IOException; - -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; - -public class OutputStream extends ServletOutputStream { - - private long req_info_ptr; - - public OutputStream(long ptr) { - req_info_ptr = ptr; - } - - @Override - public void write(int b) throws IOException - { - write(req_info_ptr, b); - } - - private static native void write(long req_info_ptr, int b); - - - @Override - public void write(byte b[], int off, int len) throws IOException - { - if (b == null) { - throw new NullPointerException(); - } else if ((off < 0) || (off > b.length) || (len < 0) || - ((off + len) > b.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return; - } - - write(req_info_ptr, b, off, len); - } - - private static native void write(long req_info_ptr, byte b[], int off, int len); - - @Override - public void flush() - { - flush(req_info_ptr); - } - - private static native void flush(long req_info_ptr); - - @Override - public void close() - { - close(req_info_ptr); - } - - private static native void close(long req_info_ptr); - - @Override - public boolean isReady() - { - return true; - } - - @Override - public void setWriteListener(WriteListener listener) - { - } -} diff --git a/src/java/nginx/unit/Request.java b/src/java/nginx/unit/Request.java deleted file mode 100644 index 335d7980..00000000 --- a/src/java/nginx/unit/Request.java +++ /dev/null @@ -1,1338 +0,0 @@ -package nginx.unit; - -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.InputStreamReader; -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -import java.lang.IllegalArgumentException; -import java.lang.IllegalStateException; -import java.lang.Object; -import java.lang.String; -import java.lang.StringBuffer; - -import java.net.URI; -import java.net.URISyntaxException; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -import java.text.ParseException; -import java.text.SimpleDateFormat; - -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import java.security.Principal; - -import javax.servlet.AsyncContext; -import javax.servlet.DispatcherType; -import javax.servlet.MultipartConfigElement; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletRequestAttributeEvent; -import javax.servlet.ServletRequestAttributeListener; -import javax.servlet.ServletResponse; -import javax.servlet.SessionTrackingMode; -import javax.servlet.SessionCookieConfig; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpUpgradeHandler; -import javax.servlet.http.Part; - -import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.MultiMap; -import org.eclipse.jetty.util.UrlEncoded; -import org.eclipse.jetty.util.StringUtil; - -import org.eclipse.jetty.server.CookieCutter; -import org.eclipse.jetty.http.MultiPartFormInputStream; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.MimeTypes; - -import nginx.unit.websocket.WsSession; -import nginx.unit.websocket.WsIOException; - -public class Request implements HttpServletRequest, DynamicPathRequest -{ - private final Context context; - private final long req_info_ptr; - private final long req_ptr; - - protected String authType = null; - - protected boolean cookiesParsed = false; - - protected CookieCutter cookies = null; - - private final Map attributes = new HashMap<>(); - - private MultiMap parameters = null; - - private final String context_path; - private String filter_path = null; - private String servlet_path = null; - private String path_info = null; - private String request_uri = null; - private String query_string = null; - private boolean query_string_valid = false; - - private DispatcherType dispatcher_type = DispatcherType.REQUEST; - - private String characterEncoding = null; - - /** - * The only date format permitted when generating HTTP headers. - */ - public static final String RFC1123_DATE = - "EEE, dd MMM yyyy HH:mm:ss zzz"; - - private static final SimpleDateFormat formats[] = { - new SimpleDateFormat(RFC1123_DATE, Locale.US), - new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) - }; - - private InputStream inputStream = null; - private BufferedReader reader = null; - - private boolean request_session_id_parsed = false; - private String request_session_id = null; - private boolean request_session_id_from_cookie = false; - private boolean request_session_id_from_url = false; - private Session session = null; - - private WsSession wsSession = null; - private boolean skip_close_ws = false; - - private final ServletRequestAttributeListener attr_listener; - - public static final String BARE = "nginx.unit.request.bare"; - - private MultiPartFormInputStream multi_parts; - private MultipartConfigElement multipart_config; - - public Request(Context ctx, long req_info, long req) { - context = ctx; - req_info_ptr = req_info; - req_ptr = req; - - attr_listener = context.getRequestAttributeListener(); - context_path = context.getContextPath(); - } - - @Override - public boolean authenticate(HttpServletResponse response) - throws IOException, ServletException - { - log("authenticate"); - - if (response.isCommitted()) { - throw new IllegalStateException(); - } - - return false; - } - - @Override - public String getAuthType() - { - log("getAuthType"); - - return authType; - } - - @Override - public String getContextPath() - { - trace("getContextPath: " + context_path); - - return context_path; - } - - @Override - public Cookie[] getCookies() - { - trace("getCookies"); - - if (!cookiesParsed) { - parseCookies(); - } - - //Javadoc for Request.getCookies() stipulates null for no cookies - if (cookies == null || cookies.getCookies().length == 0) { - return null; - } - - return cookies.getCookies(); - } - - protected void parseCookies() - { - cookiesParsed = true; - - cookies = new CookieCutter(); - - Enumeration cookie_headers = getHeaders("Cookie"); - - while (cookie_headers.hasMoreElements()) { - cookies.addCookieField(cookie_headers.nextElement()); - } - } - - @Override - public long getDateHeader(String name) - { - trace("getDateHeader: " + name); - - String value = getHeader(name); - if (value == null) { - return -1L; - } - - long res = parseDate(value); - if (res == -1L) { - throw new IllegalArgumentException(value); - } - - return res; - } - - protected long parseDate(String value) - { - Date date = null; - for (int i = 0; (date == null) && (i < formats.length); i++) { - try { - date = formats[i].parse(value); - } catch (ParseException e) { - // Ignore - } - } - if (date == null) { - return -1L; - } - return date.getTime(); - } - - @Override - public String getHeader(String name) - { - String res = getHeader(req_ptr, name, name.length()); - - trace("getHeader: " + name + " = '" + res + "'"); - - return res; - } - - private static native String getHeader(long req_ptr, String name, int name_len); - - - @Override - public Enumeration getHeaderNames() - { - trace("getHeaderNames"); - - return getHeaderNames(req_ptr); - } - - private static native Enumeration getHeaderNames(long req_ptr); - - - @Override - public Enumeration getHeaders(String name) - { - trace("getHeaders: " + name); - - return getHeaders(req_ptr, name, name.length()); - } - - private static native Enumeration getHeaders(long req_ptr, String name, int name_len); - - - @Override - public int getIntHeader(String name) - { - trace("getIntHeader: " + name); - - return getIntHeader(req_ptr, name, name.length()); - } - - private static native int getIntHeader(long req_ptr, String name, int name_len); - - - @Override - public String getMethod() - { - trace("getMethod"); - - return getMethod(req_ptr); - } - - private static native String getMethod(long req_ptr); - - - @Override - public Part getPart(String name) throws IOException, ServletException - { - trace("getPart: " + name); - - if (multi_parts == null) { - parseMultiParts(); - } - - return multi_parts.getPart(name); - } - - @Override - public Collection getParts() throws IOException, ServletException - { - trace("getParts"); - - if (multi_parts == null) { - parseMultiParts(); - } - - return multi_parts.getParts(); - } - - private boolean checkMultiPart(String content_type) - { - return content_type != null - && MimeTypes.Type.MULTIPART_FORM_DATA.is(HttpFields.valueParameters(content_type, null)); - } - - private void parseMultiParts() throws IOException, ServletException, IllegalStateException - { - String content_type = getContentType(); - - if (!checkMultiPart(content_type)) { - throw new ServletException("Content-Type != multipart/form-data"); - } - - if (multipart_config == null) { - throw new IllegalStateException("No multipart config for servlet"); - } - - parseMultiParts(content_type); - } - - private void parseMultiParts(String content_type) throws IOException - { - File tmpDir = (File) context.getAttribute(ServletContext.TEMPDIR); - - multi_parts = new MultiPartFormInputStream(getInputStream(), - content_type, multipart_config, tmpDir); - } - - public void setMultipartConfig(MultipartConfigElement mce) - { - multipart_config = mce; - } - - public MultipartConfigElement getMultipartConfig() - { - return multipart_config; - } - - @Override - public String getPathInfo() - { - trace("getPathInfo: " + path_info); - - return path_info; - } - - @Override - public String getPathTranslated() - { - trace("getPathTranslated"); - - if (path_info == null) { - return null; - } - - return context.getRealPath(path_info); - } - - @Override - public String getQueryString() - { - if (!query_string_valid) { - query_string = getQueryString(req_ptr); - query_string_valid = true; - } - - trace("getQueryString: " + query_string); - - return query_string; - } - - private static native String getQueryString(long req_ptr); - - @Override - public void setQueryString(String query) - { - trace("setQueryString: " + query); - - query_string = query; - query_string_valid = true; - } - - @Override - public String getRemoteUser() - { - log("getRemoteUser"); - - /* TODO */ - return null; - } - - @Override - public String getRequestedSessionId() - { - trace("getRequestedSessionId"); - - if (!request_session_id_parsed) { - parseRequestSessionId(); - } - - return request_session_id; - } - - private void parseRequestSessionId() - { - request_session_id_parsed = true; - - Cookie[] cookies = getCookies(); - if (cookies == null) { - return; - } - - if (context.getEffectiveSessionTrackingModes().contains( - SessionTrackingMode.COOKIE)) - { - final String name = context.getSessionCookieConfig().getName(); - - for (Cookie c : cookies) { - if (c.getName().equals(name)) { - request_session_id = c.getValue(); - request_session_id_from_cookie = true; - - return; - } - } - } - } - - @Override - public String getRequestURI() - { - if (request_uri == null) { - request_uri = getRequestURI(req_ptr); - } - - trace("getRequestURI: " + request_uri); - - return request_uri; - } - - private static native String getRequestURI(long req_ptr); - - - @Override - public void setRequestURI(String uri) - { - trace("setRequestURI: " + uri); - - request_uri = uri; - } - - - @Override - public StringBuffer getRequestURL() - { - String host = getHeader("Host"); - String uri = getRequestURI(); - StringBuffer res = new StringBuffer("http://" + host + uri); - - trace("getRequestURL: " + res); - - return res; - } - - @Override - public String getServletPath() - { - trace("getServletPath: " + servlet_path); - - return servlet_path; - } - - @Override - public void setServletPath(String servlet_path, String path_info) - { - trace("setServletPath: " + servlet_path); - - this.filter_path = servlet_path; - this.servlet_path = servlet_path; - this.path_info = path_info; - } - - @Override - public void setServletPath(String filter_path, String servlet_path, String path_info) - { - trace("setServletPath: " + filter_path + ", " + servlet_path); - - this.filter_path = filter_path; - this.servlet_path = servlet_path; - this.path_info = path_info; - } - - @Override - public String getFilterPath() - { - return filter_path; - } - - @Override - public HttpSession getSession() - { - return getSession(true); - } - - @Override - public HttpSession getSession(boolean create) - { - if (session != null) { - if (context.isSessionIdValid(session.getId())) { - trace("getSession(" + create + "): " + session.getId()); - - return session; - } - - session = null; - } - - if (!request_session_id_parsed) { - parseRequestSessionId(); - - session = context.getSession(request_session_id); - } - - if (session != null || !create) { - trace("getSession(" + create + "): " + (session != null ? session.getId() : "null")); - - return session; - } - - session = context.createSession(); - - if (context.getEffectiveSessionTrackingModes().contains( - SessionTrackingMode.COOKIE)) - { - setSessionIdCookie(); - } - - trace("getSession(" + create + "): " + session.getId()); - - return session; - } - - private void setSessionIdCookie() - { - SessionCookieConfig config = context.getSessionCookieConfig(); - - Cookie c = new Cookie(config.getName(), session.getId()); - - c.setComment(config.getComment()); - if (!StringUtil.isBlank(config.getDomain())) { - c.setDomain(config.getDomain()); - } - - c.setHttpOnly(config.isHttpOnly()); - if (!StringUtil.isBlank(config.getPath())) { - c.setPath(config.getPath()); - } - - c.setMaxAge(config.getMaxAge()); - - getResponse(req_info_ptr).addSessionIdCookie(c); - } - - @Override - public Principal getUserPrincipal() - { - log("getUserPrincipal"); - - return null; - } - - @Override - public boolean isRequestedSessionIdFromCookie() - { - trace("isRequestedSessionIdFromCookie"); - - if (!request_session_id_parsed) { - parseRequestSessionId(); - } - - return request_session_id_from_cookie; - } - - @Override - @Deprecated - public boolean isRequestedSessionIdFromUrl() - { - trace("isRequestedSessionIdFromUrl"); - - if (!request_session_id_parsed) { - parseRequestSessionId(); - } - - return request_session_id_from_url; - } - - @Override - public boolean isRequestedSessionIdFromURL() - { - trace("isRequestedSessionIdFromURL"); - - if (!request_session_id_parsed) { - parseRequestSessionId(); - } - - return request_session_id_from_url; - } - - @Override - public boolean isRequestedSessionIdValid() - { - trace("isRequestedSessionIdValid"); - - if (!request_session_id_parsed) { - parseRequestSessionId(); - } - - return context.isSessionIdValid(request_session_id); - } - - @Override - public boolean isUserInRole(String role) - { - log("isUserInRole: " + role); - - return false; - } - - @Override - public void login(String username, String password) throws ServletException - { - log("login: " + username + "," + password); - } - - @Override - public void logout() throws ServletException - { - log("logout"); - } - - - @Override - public AsyncContext getAsyncContext() - { - log("getAsyncContext"); - - return null; - } - - @Override - public Object getAttribute(String name) - { - if (BARE.equals(name)) { - return this; - } - - Object o = attributes.get(name); - - trace("getAttribute: " + name + " = " + o); - - return o; - } - - @Override - public Enumeration getAttributeNames() - { - trace("getAttributeNames"); - - Set names = attributes.keySet(); - return Collections.enumeration(names); - } - - @Override - public String getCharacterEncoding() - { - trace("getCharacterEncoding"); - - if (characterEncoding != null) { - return characterEncoding; - } - - getContentType(); - - return characterEncoding; - } - - @Override - public int getContentLength() - { - trace("getContentLength"); - - return (int) getContentLength(req_ptr); - } - - private static native long getContentLength(long req_ptr); - - @Override - public long getContentLengthLong() - { - trace("getContentLengthLong"); - - return getContentLength(req_ptr); - } - - @Override - public String getContentType() - { - trace("getContentType"); - - String content_type = getContentType(req_ptr); - - if (characterEncoding == null && content_type != null) { - MimeTypes.Type mime = MimeTypes.CACHE.get(content_type); - String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(content_type) : mime.getCharset().toString(); - if (charset != null) { - characterEncoding = charset; - } - } - - return content_type; - } - - private static native String getContentType(long req_ptr); - - - @Override - public DispatcherType getDispatcherType() - { - trace("getDispatcherType: " + dispatcher_type); - - return dispatcher_type; - } - - @Override - public void setDispatcherType(DispatcherType type) - { - trace("setDispatcherType: " + type); - - dispatcher_type = type; - } - - @Override - public ServletInputStream getInputStream() throws IOException - { - trace("getInputStream"); - - if (reader != null) { - throw new IllegalStateException("getInputStream: getReader() already used"); - } - - if (inputStream == null) { - inputStream = new InputStream(req_info_ptr); - } - - return inputStream; - } - - @Override - public String getLocalAddr() - { - trace("getLocalAddr"); - - return getLocalAddr(req_ptr); - } - - private static native String getLocalAddr(long req_ptr); - - - @Override - public Locale getLocale() - { - log("getLocale"); - - return Locale.getDefault(); - } - - @Override - public Enumeration getLocales() - { - log("getLocales"); - - return Collections.emptyEnumeration(); - } - - @Override - public String getLocalName() - { - trace("getLocalName"); - - return getLocalName(req_ptr); - } - - private static native String getLocalName(long req_ptr); - - - @Override - public int getLocalPort() - { - trace("getLocalPort"); - - return getLocalPort(req_ptr); - } - - private static native int getLocalPort(long req_ptr); - - - public MultiMap getParameters() - { - if (parameters != null) { - return parameters; - } - - parameters = new MultiMap<>(); - - String query = getQueryString(); - - if (query != null) { - UrlEncoded.decodeUtf8To(query, parameters); - } - - int content_length = getContentLength(); - - if (content_length == 0 || !getMethod().equals("POST")) { - return parameters; - } - - String content_type = getContentType(); - - try { - if (content_type.startsWith("application/x-www-form-urlencoded")) { - UrlEncoded.decodeUtf8To(new InputStream(req_info_ptr), - parameters, content_length, -1); - } else if (checkMultiPart(content_type) && multipart_config != null) { - if (multi_parts == null) { - parseMultiParts(content_type); - } - - if (multi_parts != null) { - Collection parts = multi_parts.getParts(); - - String _charset_ = null; - Part charset_part = multi_parts.getPart("_charset_"); - if (charset_part != null) { - try (java.io.InputStream is = charset_part.getInputStream()) - { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - IO.copy(is, os); - _charset_ = new String(os.toByteArray(),StandardCharsets.UTF_8); - } - } - - /* - Select Charset to use for this part. (NOTE: charset behavior is for the part value only and not the part header/field names) - 1. Use the part specific charset as provided in that part's Content-Type header; else - 2. Use the overall default charset. Determined by: - a. if part name _charset_ exists, use that part's value. - b. if the request.getCharacterEncoding() returns a value, use that. - (note, this can be either from the charset field on the request Content-Type - header, or from a manual call to request.setCharacterEncoding()) - c. use utf-8. - */ - Charset def_charset; - if (_charset_ != null) { - def_charset = Charset.forName(_charset_); - } else if (getCharacterEncoding() != null) { - def_charset = Charset.forName(getCharacterEncoding()); - } else { - def_charset = StandardCharsets.UTF_8; - } - - ByteArrayOutputStream os = null; - for (Part p : parts) { - if (p.getSubmittedFileName() != null) { - continue; - } - - // Servlet Spec 3.0 pg 23, parts without filename must be put into params. - String charset = null; - if (p.getContentType() != null) { - charset = MimeTypes.getCharsetFromContentType(p.getContentType()); - } - - try (java.io.InputStream is = p.getInputStream()) - { - if (os == null) { - os = new ByteArrayOutputStream(); - } - IO.copy(is, os); - - String content = new String(os.toByteArray(), charset == null ? def_charset : Charset.forName(charset)); - parameters.add(p.getName(), content); - } - os.reset(); - } - } - } - } catch (IOException e) { - log("Unhandled IOException: " + e); - } - - return parameters; - } - - public void setParameters(MultiMap p) - { - parameters = p; - } - - @Override - public String getParameter(String name) - { - trace("getParameter: " + name); - - return getParameters().getValue(name, 0); - } - - @Override - public Map getParameterMap() - { - trace("getParameterMap"); - - return Collections.unmodifiableMap(getParameters().toStringArrayMap()); - } - - @Override - public Enumeration getParameterNames() - { - trace("getParameterNames"); - - return Collections.enumeration(getParameters().keySet()); - } - - @Override - public String[] getParameterValues(String name) - { - trace("getParameterValues: " + name); - - List vals = getParameters().getValues(name); - if (vals == null) - return null; - return vals.toArray(new String[vals.size()]); - } - - @Override - public String getProtocol() - { - trace("getProtocol"); - - return getProtocol(req_ptr); - } - - private static native String getProtocol(long req_ptr); - - @Override - public BufferedReader getReader() throws IOException - { - trace("getReader"); - - if (inputStream != null) { - throw new IllegalStateException("getReader: getInputStream() already used"); - } - - if (reader == null) { - reader = new BufferedReader(new InputStreamReader(new InputStream(req_info_ptr))); - } - - return reader; - } - - @Override - @Deprecated - public String getRealPath(String path) - { - trace("getRealPath: " + path); - - return context.getRealPath(path); - } - - @Override - public String getRemoteAddr() - { - String res = getRemoteAddr(req_ptr); - - trace("getRemoteAddr: " + res); - - return res; - } - - private static native String getRemoteAddr(long req_ptr); - - - @Override - public String getRemoteHost() - { - String res = getRemoteHost(req_ptr); - - trace("getRemoteHost: " + res); - - return res; - } - - private static native String getRemoteHost(long req_ptr); - - - @Override - public int getRemotePort() - { - int res = getRemotePort(req_ptr); - - trace("getRemotePort: " + res); - - return res; - } - - private static native int getRemotePort(long req_ptr); - - - @Override - public RequestDispatcher getRequestDispatcher(String path) - { - trace("getRequestDispatcher: " + path); - - if (path.startsWith("/")) { - return context.getRequestDispatcher(path); - } - - try { - URI uri = new URI(getRequestURI()); - uri = uri.resolve(path); - - return context.getRequestDispatcher(uri); - } catch (URISyntaxException e) { - log("getRequestDispatcher: failed to create dispatcher: " + e); - } - - return null; - } - - - @Override - public String getScheme() - { - trace("getScheme"); - - return getScheme(req_ptr); - } - - private static native String getScheme(long req_ptr); - - - @Override - public String getServerName() - { - String res = getServerName(req_ptr); - - trace("getServerName: " + res); - - return res; - } - - private static native String getServerName(long req_ptr); - - - @Override - public int getServerPort() - { - int res = getServerPort(req_ptr); - - trace("getServerPort: " + res); - - return res; - } - - private static native int getServerPort(long req_ptr); - - @Override - public ServletContext getServletContext() - { - trace("getServletContext"); - - return context; - } - - @Override - public boolean isAsyncStarted() - { - log("isAsyncStarted"); - - return false; - } - - @Override - public boolean isAsyncSupported() - { - log("isAsyncSupported"); - - return false; - } - - @Override - public boolean isSecure() - { - trace("isSecure"); - - return isSecure(req_ptr); - } - - private static native boolean isSecure(long req_ptr); - - @Override - public void removeAttribute(String name) - { - trace("removeAttribute: " + name); - - Object prev = attributes.remove(name); - - if (attr_listener == null || prev == null) { - return; - } - - attr_listener.attributeRemoved( - new ServletRequestAttributeEvent(context, this, name, prev)); - } - - @Override - public void setAttribute(String name, Object o) - { - trace("setAttribute: " + name + ", " + o); - - Object prev; - - if (o != null) { - prev = attributes.put(name, o); - } else { - prev = attributes.remove(name); - } - - if (attr_listener == null) { - return; - } - - if (prev == null) { - if (o == null) { - return; - } - - attr_listener.attributeAdded(new ServletRequestAttributeEvent( - context, this, name, o)); - } else { - if (o != null) { - attr_listener.attributeReplaced( - new ServletRequestAttributeEvent(context, this, name, prev)); - } else { - attr_listener.attributeRemoved( - new ServletRequestAttributeEvent(context, this, name, prev)); - } - } - } - - public void setAttribute_(String name, Object o) - { - trace("setAttribute_: " + name + ", " + o); - - if (o != null) { - attributes.put(name, o); - } else { - attributes.remove(name); - } - } - - @Override - public void setCharacterEncoding(String env) throws UnsupportedEncodingException - { - trace("setCharacterEncoding: " + env); - - characterEncoding = env; - } - - @Override - public AsyncContext startAsync() throws IllegalStateException - { - log("startAsync"); - - return null; - } - - @Override - public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException - { - log("startAsync(Req, resp)"); - - return null; - } - - @Override - public T upgrade( - Class httpUpgradeHandlerClass) throws java.io.IOException, ServletException - { - trace("upgrade: " + httpUpgradeHandlerClass.getName()); - - T handler; - - try { - handler = httpUpgradeHandlerClass.getConstructor().newInstance(); - } catch (Exception e) { - throw new ServletException(e); - } - - upgrade(req_info_ptr); - - return handler; - } - - private static native void upgrade(long req_info_ptr); - - public boolean isUpgrade() - { - return isUpgrade(req_info_ptr); - } - - private static native boolean isUpgrade(long req_info_ptr); - - @Override - public String changeSessionId() - { - trace("changeSessionId"); - - getSession(false); - - if (session == null) { - return null; - } - - context.changeSessionId(session); - - if (context.getEffectiveSessionTrackingModes().contains( - SessionTrackingMode.COOKIE)) - { - setSessionIdCookie(); - } - - return session.getId(); - } - - private void log(String msg) - { - msg = "Request." + msg; - log(req_info_ptr, msg, msg.length()); - } - - public static native void log(long req_info_ptr, String msg, int msg_len); - - - private void trace(String msg) - { - msg = "Request." + msg; - trace(req_info_ptr, msg, msg.length()); - } - - public static native void trace(long req_info_ptr, String msg, int msg_len); - - private static native Response getResponse(long req_info_ptr); - - - public void setWsSession(WsSession s) - { - wsSession = s; - } - - private void processWsFrame(ByteBuffer buf, byte opCode, boolean last) - throws IOException - { - trace("processWsFrame: " + opCode + ", [" + buf.position() + ", " + buf.limit() + "]"); - try { - wsSession.processFrame(buf, opCode, last); - } catch (WsIOException e) { - wsSession.onClose(e.getCloseReason()); - } - } - - private void closeWsSession() - { - trace("closeWsSession"); - skip_close_ws = true; - - wsSession.onClose(); - } - - public void sendWsFrame(ByteBuffer payload, byte opCode, boolean last, - long timeoutExpiry) throws IOException - { - trace("sendWsFrame: " + opCode + ", [" + payload.position() + - ", " + payload.limit() + "]"); - - if (payload.isDirect()) { - sendWsFrame(req_info_ptr, payload, payload.position(), - payload.limit() - payload.position(), opCode, last); - } else { - sendWsFrame(req_info_ptr, payload.array(), payload.position(), - payload.limit() - payload.position(), opCode, last); - } - } - - private static native void sendWsFrame(long req_info_ptr, - ByteBuffer buf, int pos, int len, byte opCode, boolean last); - - private static native void sendWsFrame(long req_info_ptr, - byte[] arr, int pos, int len, byte opCode, boolean last); - - - public void closeWs() - { - if (skip_close_ws) { - return; - } - - trace("closeWs"); - - closeWs(req_info_ptr); - } - - private static native void closeWs(long req_info_ptr); -} - diff --git a/src/java/nginx/unit/RequestAttrProxy.java b/src/java/nginx/unit/RequestAttrProxy.java deleted file mode 100644 index daedd01a..00000000 --- a/src/java/nginx/unit/RequestAttrProxy.java +++ /dev/null @@ -1,40 +0,0 @@ -package nginx.unit; - -import java.util.List; - -import javax.servlet.ServletRequestAttributeEvent; -import javax.servlet.ServletRequestAttributeListener; - -public class RequestAttrProxy implements ServletRequestAttributeListener -{ - private final List listeners_; - - public RequestAttrProxy(List listeners) - { - listeners_ = listeners; - } - - @Override - public void attributeAdded(ServletRequestAttributeEvent srae) - { - for (ServletRequestAttributeListener l : listeners_) { - l.attributeAdded(srae); - } - } - - @Override - public void attributeReplaced(ServletRequestAttributeEvent srae) - { - for (ServletRequestAttributeListener l : listeners_) { - l.attributeReplaced(srae); - } - } - - @Override - public void attributeRemoved(ServletRequestAttributeEvent srae) - { - for (ServletRequestAttributeListener l : listeners_) { - l.attributeRemoved(srae); - } - } -} diff --git a/src/java/nginx/unit/Response.java b/src/java/nginx/unit/Response.java deleted file mode 100644 index 268b359d..00000000 --- a/src/java/nginx/unit/Response.java +++ /dev/null @@ -1,832 +0,0 @@ -package nginx.unit; - -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; - -import java.lang.IllegalArgumentException; -import java.lang.String; - -import java.net.URI; -import java.net.URISyntaxException; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -import java.text.SimpleDateFormat; - -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.Locale; -import java.util.TimeZone; -import java.util.Vector; - -import javax.servlet.DispatcherType; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.MimeTypes; -import org.eclipse.jetty.util.StringUtil; - -public class Response implements HttpServletResponse { - - private long req_info_ptr; - - private static final String defaultCharacterEncoding = "iso-8859-1"; - private String characterEncoding = defaultCharacterEncoding; - private String contentType = null; - private String contentTypeHeader = null; - private Locale locale = null; - - private static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1; - private static final Charset UTF_8 = StandardCharsets.UTF_8; - - private static final String CONTENT_TYPE = "Content-Type"; - private static final byte[] CONTENT_LANGUAGE_BYTES = "Content-Language".getBytes(ISO_8859_1); - private static final byte[] SET_COOKIE_BYTES = "Set-Cookie".getBytes(ISO_8859_1); - private static final byte[] EXPIRES_BYTES = "Expires".getBytes(ISO_8859_1); - - /** - * The only date format permitted when generating HTTP headers. - */ - public static final String RFC1123_DATE = - "EEE, dd MMM yyyy HH:mm:ss zzz"; - - private static final SimpleDateFormat format = - new SimpleDateFormat(RFC1123_DATE, Locale.US); - - private static final String ZERO_DATE_STRING = dateToString(0); - private static final byte[] ZERO_DATE_BYTES = ZERO_DATE_STRING.getBytes(ISO_8859_1); - - /** - * If this string is found within the comment of a cookie added with {@link #addCookie(Cookie)}, then the cookie - * will be set as HTTP ONLY. - */ - public final static String HTTP_ONLY_COMMENT = "__HTTP_ONLY__"; - - private OutputStream outputStream = null; - - private PrintWriter writer = null; - - - public Response(long ptr) { - req_info_ptr = ptr; - } - - /** - * Format a set cookie value by RFC6265 - * - * @param name the name - * @param value the value - * @param domain the domain - * @param path the path - * @param maxAge the maximum age - * @param isSecure true if secure cookie - * @param isHttpOnly true if for http only - */ - public void addSetRFC6265Cookie( - final String name, - final String value, - final String domain, - final String path, - final long maxAge, - final boolean isSecure, - final boolean isHttpOnly) - { - // Check arguments - if (name == null || name.length() == 0) { - throw new IllegalArgumentException("Bad cookie name"); - } - - // Name is checked for legality by servlet spec, but can also be passed directly so check again for quoting - // Per RFC6265, Cookie.name follows RFC2616 Section 2.2 token rules - //Syntax.requireValidRFC2616Token(name, "RFC6265 Cookie name"); - // Ensure that Per RFC6265, Cookie.value follows syntax rules - //Syntax.requireValidRFC6265CookieValue(value); - - // Format value and params - StringBuilder buf = new StringBuilder(); - buf.append(name).append('=').append(value == null ? "" : value); - - // Append path - if (path != null && path.length() > 0) { - buf.append(";Path=").append(path); - } - - // Append domain - if (domain != null && domain.length() > 0) { - buf.append(";Domain=").append(domain); - } - - // Handle max-age and/or expires - if (maxAge >= 0) { - // Always use expires - // This is required as some browser (M$ this means you!) don't handle max-age even with v1 cookies - buf.append(";Expires="); - if (maxAge == 0) - buf.append(ZERO_DATE_STRING); - else - buf.append(dateToString(System.currentTimeMillis() + 1000L * maxAge)); - - buf.append(";Max-Age="); - buf.append(maxAge); - } - - // add the other fields - if (isSecure) - buf.append(";Secure"); - if (isHttpOnly) - buf.append(";HttpOnly"); - - // add the set cookie - addHeader(req_info_ptr, SET_COOKIE_BYTES, - buf.toString().getBytes(ISO_8859_1)); - - // Expire responses with set-cookie headers so they do not get cached. - setHeader(req_info_ptr, EXPIRES_BYTES, ZERO_DATE_BYTES); - } - - @Override - public void addCookie(Cookie cookie) - { - trace("addCookie: " + cookie.getName() + "=" + cookie.getValue()); - - if (StringUtil.isBlank(cookie.getName())) { - throw new IllegalArgumentException("Cookie.name cannot be blank/null"); - } - - if (isCommitted()) { - return; - } - - addCookie_(cookie); - } - - private void addCookie_(Cookie cookie) - { - String comment = cookie.getComment(); - boolean httpOnly = false; - - if (comment != null && comment.contains(HTTP_ONLY_COMMENT)) { - httpOnly = true; - } - - addSetRFC6265Cookie(cookie.getName(), - cookie.getValue(), - cookie.getDomain(), - cookie.getPath(), - cookie.getMaxAge(), - cookie.getSecure(), - httpOnly || cookie.isHttpOnly()); - } - - public void addSessionIdCookie(Cookie cookie) - { - trace("addSessionIdCookie: " + cookie.getName() + "=" + cookie.getValue()); - - if (isCommitted()) { - /* - 9.3 The Include Method - - ... any call to HttpServletRequest.getSession() or - HttpServletRequest.getSession(boolean) that would require - adding a Cookie response header must throw an - IllegalStateException if the response has been committed. - */ - throw new IllegalStateException("Response already sent"); - } - - addCookie_(cookie); - } - - @Override - public void addDateHeader(String name, long date) - { - trace("addDateHeader: " + name + ": " + date); - - if (isCommitted()) { - return; - } - - String value = dateToString(date); - - addHeader(req_info_ptr, name.getBytes(ISO_8859_1), - value.getBytes(ISO_8859_1)); - } - - private static String dateToString(long date) - { - Date dateValue = new Date(date); - format.setTimeZone(TimeZone.getTimeZone("GMT")); - return format.format(dateValue); - } - - - @Override - public void addHeader(String name, String value) - { - trace("addHeader: " + name + ": " + value); - - if (value == null) { - return; - } - - if (isCommitted()) { - return; - } - - if (CONTENT_TYPE.equalsIgnoreCase(name)) { - setContentType(value); - return; - } - - addHeader(req_info_ptr, name.getBytes(ISO_8859_1), - value.getBytes(ISO_8859_1)); - } - - private static native void addHeader(long req_info_ptr, byte[] name, byte[] value); - - - @Override - public void addIntHeader(String name, int value) - { - trace("addIntHeader: " + name + ": " + value); - - if (isCommitted()) { - return; - } - - addIntHeader(req_info_ptr, name.getBytes(ISO_8859_1), value); - } - - private static native void addIntHeader(long req_info_ptr, byte[] name, int value); - - - @Override - public boolean containsHeader(String name) - { - trace("containsHeader: " + name); - - return containsHeader(req_info_ptr, name.getBytes(ISO_8859_1)); - } - - private static native boolean containsHeader(long req_info_ptr, byte[] name); - - - @Override - @Deprecated - public String encodeRedirectUrl(String url) - { - return encodeRedirectURL(url); - } - - @Override - public String encodeRedirectURL(String url) - { - log("encodeRedirectURL: " + url); - - return url; - } - - @Override - @Deprecated - public String encodeUrl(String url) - { - return encodeURL(url); - } - - @Override - public String encodeURL(String url) - { - log("encodeURL: " + url); - - return url; - } - - @Override - public String getHeader(String name) - { - trace("getHeader: " + name); - - return getHeader(req_info_ptr, name.getBytes(ISO_8859_1)); - } - - private static native String getHeader(long req_info_ptr, byte[] name); - - - @Override - public Collection getHeaderNames() - { - trace("getHeaderNames"); - - Enumeration e = getHeaderNames(req_info_ptr); - if (e == null) { - return Collections.emptyList(); - } - - return Collections.list(e); - } - - private static native Enumeration getHeaderNames(long req_info_ptr); - - - @Override - public Collection getHeaders(String name) - { - trace("getHeaders: " + name); - - Enumeration e = getHeaders(req_info_ptr, name.getBytes(ISO_8859_1)); - if (e == null) { - return Collections.emptyList(); - } - - return Collections.list(e); - } - - private static native Enumeration getHeaders(long req_info_ptr, byte[] name); - - - @Override - public int getStatus() - { - trace("getStatus"); - - return getStatus(req_info_ptr); - } - - private static native int getStatus(long req_info_ptr); - - - @Override - public void sendError(int sc) throws IOException - { - sendError(sc, null); - } - - @Override - public void sendError(int sc, String msg) throws IOException - { - trace("sendError: " + sc + ", " + msg); - - if (isCommitted()) { - throw new IllegalStateException("Response already sent"); - } - - setStatus(sc); - - Request request = getRequest(req_info_ptr); - - // If we are allowed to have a body, then produce the error page. - if (sc != SC_NO_CONTENT && sc != SC_NOT_MODIFIED && - sc != SC_PARTIAL_CONTENT && sc >= SC_OK) - { - request.setAttribute_(RequestDispatcher.ERROR_STATUS_CODE, sc); - request.setAttribute_(RequestDispatcher.ERROR_MESSAGE, msg); - request.setAttribute_(RequestDispatcher.ERROR_REQUEST_URI, - request.getRequestURI()); -/* - request.setAttribute_(RequestDispatcher.ERROR_SERVLET_NAME, - request.getServletName()); -*/ - } - -/* - Avoid commit and give chance for error handlers. - - if (!request.isAsyncStarted()) { - commit(); - } -*/ - } - - private static native Request getRequest(long req_info_ptr); - - private void commit() - { - if (writer != null) { - writer.close(); - - } else if (outputStream != null) { - outputStream.close(); - - } else { - commit(req_info_ptr); - } - } - - private static native void commit(long req_info_ptr); - - - @Override - public void sendRedirect(String location) throws IOException - { - trace("sendRedirect: " + location); - - if (isCommitted()) { - return; - } - - try { - URI uri = new URI(location); - - if (!uri.isAbsolute()) { - URI req_uri = new URI(getRequest(req_info_ptr).getRequestURL().toString()); - uri = req_uri.resolve(uri); - - location = uri.toString(); - } - } catch (URISyntaxException e) { - log("sendRedirect: failed to send redirect: " + e); - return; - } - - sendRedirect(req_info_ptr, location.getBytes(ISO_8859_1)); - } - - private static native void sendRedirect(long req_info_ptr, byte[] location); - - - @Override - public void setDateHeader(String name, long date) - { - trace("setDateHeader: " + name + ": " + date); - - if (isCommitted()) { - return; - } - - String value = dateToString(date); - - setHeader(req_info_ptr, name.getBytes(ISO_8859_1), - value.getBytes(ISO_8859_1)); - } - - - @Override - public void setHeader(String name, String value) - { - trace("setHeader: " + name + ": " + value); - - if (isCommitted()) { - return; - } - - if (CONTENT_TYPE.equalsIgnoreCase(name)) { - setContentType(value); - return; - } - - /* - * When value is null container behaviour is undefined. - * - Tomcat ignores setHeader call; - * - Jetty & Resin acts as removeHeader; - */ - if (value == null) { - removeHeader(req_info_ptr, name.getBytes(ISO_8859_1)); - return; - } - - setHeader(req_info_ptr, name.getBytes(ISO_8859_1), - value.getBytes(ISO_8859_1)); - } - - private static native void setHeader(long req_info_ptr, byte[] name, byte[] value); - - private static native void removeHeader(long req_info_ptr, byte[] name); - - @Override - public void setIntHeader(String name, int value) - { - trace("setIntHeader: " + name + ": " + value); - - if (isCommitted()) { - return; - } - - setIntHeader(req_info_ptr, name.getBytes(ISO_8859_1), value); - } - - private static native void setIntHeader(long req_info_ptr, byte[] name, int value); - - - @Override - public void setStatus(int sc) - { - trace("setStatus: " + sc); - - if (isCommitted()) { - return; - } - - setStatus(req_info_ptr, sc); - } - - private static native void setStatus(long req_info_ptr, int sc); - - - @Override - @Deprecated - public void setStatus(int sc, String sm) - { - trace("setStatus: " + sc + "; " + sm); - - if (isCommitted()) { - return; - } - - setStatus(req_info_ptr, sc); - } - - - @Override - public void flushBuffer() throws IOException - { - trace("flushBuffer"); - - if (writer != null) { - writer.flush(); - } - - if (outputStream != null) { - outputStream.flush(); - } - } - - @Override - public int getBufferSize() - { - trace("getBufferSize"); - - return getBufferSize(req_info_ptr); - } - - public static native int getBufferSize(long req_info_ptr); - - - @Override - public String getCharacterEncoding() - { - trace("getCharacterEncoding"); - - return characterEncoding; - } - - @Override - public String getContentType() - { - /* In JIRA decorator get content type called after commit. */ - - String res = contentTypeHeader; - - trace("getContentType: " + res); - - return res; - } - - private static native String getContentType(long req_info_ptr); - - @Override - public Locale getLocale() - { - trace("getLocale"); - - if (locale == null) { - return Locale.getDefault(); - } - - return locale; - } - - @Override - public ServletOutputStream getOutputStream() throws IOException - { - trace("getOutputStream"); - - if (writer != null) { - throw new IllegalStateException("Writer already created"); - } - - if (outputStream == null) { - outputStream = new OutputStream(req_info_ptr); - } - - return outputStream; - } - - @Override - public PrintWriter getWriter() throws IOException - { - trace("getWriter ( characterEncoding = '" + characterEncoding + "' )"); - - if (outputStream != null) { - throw new IllegalStateException("OutputStream already created"); - } - - if (writer == null) { - ServletOutputStream stream = new OutputStream(req_info_ptr); - - writer = new PrintWriter( - new OutputStreamWriter(stream, Charset.forName(characterEncoding)), - false); - } - - return writer; - } - - @Override - public boolean isCommitted() - { - trace("isCommitted"); - - return isCommitted(req_info_ptr); - } - - public static native boolean isCommitted(long req_info_ptr); - - @Override - public void reset() - { - trace("reset"); - - if (isCommitted()) { - return; - } - - reset(req_info_ptr); - - writer = null; - outputStream = null; - } - - public static native void reset(long req_info_ptr); - - @Override - public void resetBuffer() - { - trace("resetBuffer"); - - resetBuffer(req_info_ptr); - - writer = null; - outputStream = null; - } - - public static native void resetBuffer(long req_info_ptr); - - @Override - public void setBufferSize(int size) - { - trace("setBufferSize: " + size); - - setBufferSize(req_info_ptr, size); - } - - public static native void setBufferSize(long req_info_ptr, int size); - - @Override - public void setCharacterEncoding(String charset) - { - trace("setCharacterEncoding " + charset); - - if (isCommitted()) { - return; - } - - if (charset == null) { - if (writer != null - && !characterEncoding.equalsIgnoreCase(defaultCharacterEncoding)) - { - /* TODO throw */ - return; - } - - characterEncoding = defaultCharacterEncoding; - } else { - if (writer != null - && !characterEncoding.equalsIgnoreCase(charset)) - { - /* TODO throw */ - return; - } - - characterEncoding = charset; - } - - if (contentType != null) { - String type = contentType + ";charset=" + characterEncoding; - - contentTypeHeader = type; - - setContentType(req_info_ptr, type.getBytes(ISO_8859_1)); - } - } - - - @Override - public void setContentLength(int len) - { - trace("setContentLength: " + len); - - if (isCommitted()) { - return; - } - - setContentLength(req_info_ptr, len); - } - - @Override - public void setContentLengthLong(long len) - { - trace("setContentLengthLong: " + len); - - if (isCommitted()) { - return; - } - - setContentLength(req_info_ptr, len); - } - - private static native void setContentLength(long req_info_ptr, long len); - - - @Override - public void setContentType(String type) - { - trace("setContentType: " + type); - - if (isCommitted()) { - return; - } - - if (type == null) { - removeContentType(req_info_ptr); - contentType = null; - contentTypeHeader = null; - return; - } - - String charset = MimeTypes.getCharsetFromContentType(type); - String ctype = MimeTypes.getContentTypeWithoutCharset(type); - - if (writer != null - && charset != null - && !characterEncoding.equalsIgnoreCase(charset)) - { - /* To late to change character encoding */ - charset = characterEncoding; - type = ctype + ";charset=" + characterEncoding; - } - - if (charset == null) { - type = type + ";charset=" + characterEncoding; - } else { - characterEncoding = charset; - } - - contentType = ctype; - contentTypeHeader = type; - - setContentType(req_info_ptr, type.getBytes(ISO_8859_1)); - } - - private static native void setContentType(long req_info_ptr, byte[] type); - - private static native void removeContentType(long req_info_ptr); - - - @Override - public void setLocale(Locale loc) - { - trace("setLocale: " + loc); - - if (loc == null || isCommitted()) { - return; - } - - locale = loc; - String lang = locale.toString().replace('_', '-'); - - setHeader(req_info_ptr, CONTENT_LANGUAGE_BYTES, lang.getBytes(ISO_8859_1)); - } - - private void log(String msg) - { - msg = "Response." + msg; - log(req_info_ptr, msg.getBytes(UTF_8)); - } - - public static native void log(long req_info_ptr, byte[] msg); - - - private void trace(String msg) - { - msg = "Response." + msg; - trace(req_info_ptr, msg.getBytes(UTF_8)); - } - - public static native void trace(long req_info_ptr, byte[] msg); -} diff --git a/src/java/nginx/unit/Session.java b/src/java/nginx/unit/Session.java deleted file mode 100644 index 6be74709..00000000 --- a/src/java/nginx/unit/Session.java +++ /dev/null @@ -1,251 +0,0 @@ -package nginx.unit; - -import java.io.Serializable; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionAttributeListener; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; - -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; - -/** - * @author Andrey Kazankov - */ -public class Session implements HttpSession, Serializable -{ - private final Map attributes = new HashMap<>(); - private final long creation_time = new Date().getTime(); - private long last_access_time = creation_time; - private long access_time = creation_time; - private int max_inactive_interval; - private String id; - private final Context context; - private boolean is_new = true; - private final HttpSessionAttributeListener attr_listener; - - public Session(Context context, String id, - HttpSessionAttributeListener al, int max_inactive_interval) - { - this.id = id; - this.context = context; - attr_listener = al; - this.max_inactive_interval = max_inactive_interval; - } - - public void setId(String id) - { - this.id = id; - } - - @Override - public long getCreationTime() - { - return creation_time; - } - - @Override - public String getId() - { - return id; - } - - @Override - public long getLastAccessedTime() - { - return last_access_time; - } - - @Override - public ServletContext getServletContext() - { - return context; - } - - @Override - public void setMaxInactiveInterval(int i) - { - max_inactive_interval = i; - } - - @Override - public int getMaxInactiveInterval() - { - return max_inactive_interval; - } - - @Deprecated - @Override - public javax.servlet.http.HttpSessionContext getSessionContext() - { - return null; - } - - @Override - public Object getAttribute(String s) - { - synchronized (attributes) { - return attributes.get(s); - } - } - - @Deprecated - @Override - public Object getValue(String s) - { - return getAttribute(s); - } - - @Override - public Enumeration getAttributeNames() - { - synchronized (attributes) { - return Collections.enumeration(attributes.keySet()); - } - } - - @Deprecated - @Override - public String[] getValueNames() - { - synchronized (attributes) { - return attributes.keySet().toArray(new String[attributes.keySet().size()]); - } - } - - @Override - public void setAttribute(String s, Object o) - { - Object old; - - if (o != null && o instanceof HttpSessionBindingListener) { - HttpSessionBindingListener l = (HttpSessionBindingListener) o; - HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s); - - l.valueBound(e); - } - - synchronized (attributes) { - if (o != null) { - old = attributes.put(s, o); - } else { - old = attributes.remove(s); - } - } - - if (old != null && old instanceof HttpSessionBindingListener) { - HttpSessionBindingListener l = (HttpSessionBindingListener) old; - HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s); - - l.valueUnbound(e); - } - - if (attr_listener == null) { - return; - } - - if (o == null) { - if (old != null) { - HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s, old); - attr_listener.attributeRemoved(e); - } - - return; - } - - if (old != null) { - HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s, old); - attr_listener.attributeReplaced(e); - } else { - HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s, o); - attr_listener.attributeAdded(e); - } - } - - @Deprecated - @Override - public void putValue(String s, Object o) - { - setAttribute(s,o); - } - - @Override - public void removeAttribute(String s) - { - Object o; - - synchronized (attributes) { - o = attributes.remove(s); - } - - if (o != null && o instanceof HttpSessionBindingListener) { - HttpSessionBindingListener l = (HttpSessionBindingListener) o; - HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s); - - l.valueUnbound(e); - } - - if (attr_listener == null || o == null) { - return; - } - - HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s, o); - attr_listener.attributeRemoved(e); - } - - @Deprecated - @Override - public void removeValue(String s) - { - removeAttribute(s); - } - - @Override - public void invalidate() - { - context.invalidateSession(this); - - unboundAttributes(); - } - - private void unboundAttributes() - { - for (Map.Entry a : attributes.entrySet()) { - Object o = a.getValue(); - if (o != null && o instanceof HttpSessionBindingListener) { - HttpSessionBindingListener l = (HttpSessionBindingListener) o; - HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, a.getKey()); - - l.valueUnbound(e); - } - } - - attributes.clear(); - } - - @Override - public boolean isNew() - { - return is_new; - } - - public void accessed() { - synchronized (this) { - is_new = false; - - last_access_time = access_time; - access_time = new Date().getTime(); - } - } - - public boolean checkTimeOut() - { - return (max_inactive_interval > 0) && - (access_time - last_access_time > max_inactive_interval * 1000); - } -} \ No newline at end of file diff --git a/src/java/nginx/unit/SessionAttrProxy.java b/src/java/nginx/unit/SessionAttrProxy.java deleted file mode 100644 index bddeede9..00000000 --- a/src/java/nginx/unit/SessionAttrProxy.java +++ /dev/null @@ -1,40 +0,0 @@ -package nginx.unit; - -import java.util.List; - -import javax.servlet.http.HttpSessionAttributeListener; -import javax.servlet.http.HttpSessionBindingEvent; - -public class SessionAttrProxy implements HttpSessionAttributeListener -{ - private final List listeners_; - - public SessionAttrProxy(List listeners) - { - listeners_ = listeners; - } - - @Override - public void attributeAdded(HttpSessionBindingEvent event) - { - for (HttpSessionAttributeListener l : listeners_) { - l.attributeAdded(event); - } - } - - @Override - public void attributeRemoved(HttpSessionBindingEvent event) - { - for (HttpSessionAttributeListener l : listeners_) { - l.attributeRemoved(event); - } - } - - @Override - public void attributeReplaced(HttpSessionBindingEvent event) - { - for (HttpSessionAttributeListener l : listeners_) { - l.attributeReplaced(event); - } - } -} diff --git a/src/java/nginx/unit/Taglib.java b/src/java/nginx/unit/Taglib.java deleted file mode 100644 index f72033ba..00000000 --- a/src/java/nginx/unit/Taglib.java +++ /dev/null @@ -1,44 +0,0 @@ -package nginx.unit; - -import javax.servlet.descriptor.TaglibDescriptor; - -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -public class Taglib implements TaglibDescriptor -{ - private String uri_ = null; - private String location_ = null; - - public Taglib(NodeList nodes) - { - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - String tag_name = node.getNodeName(); - - if (tag_name.equals("taglib-uri")) { - uri_ = node.getTextContent().trim(); - continue; - } - - if (tag_name.equals("taglib-location")) { - location_ = node.getTextContent().trim(); - continue; - } - } - - } - - @Override - public String getTaglibURI() - { - return uri_; - } - - @Override - public String getTaglibLocation() - { - return location_; - } -} - diff --git a/src/java/nginx/unit/UnitSessionCookieConfig.java b/src/java/nginx/unit/UnitSessionCookieConfig.java deleted file mode 100644 index e1b2ae04..00000000 --- a/src/java/nginx/unit/UnitSessionCookieConfig.java +++ /dev/null @@ -1,110 +0,0 @@ -package nginx.unit; - -import javax.servlet.SessionCookieConfig; - -/* - - - 60 - - - - - - */ -public class UnitSessionCookieConfig implements SessionCookieConfig { - - private static final String default_name = "JSESSIONID"; - - private String name = default_name; - private String domain; - private String path; - private String comment; - private boolean httpOnly = true; - private boolean secure = false; - private int maxAge = -1; - - @Override - public void setName(String name) - { - this.name = name; - } - - @Override - public String getName() - { - return name; - } - - @Override - public void setDomain(String domain) - { - this.domain = domain; - } - - @Override - public String getDomain() - { - return domain; - } - - @Override - public void setPath(String path) - { - this.path = path; - } - - @Override - public String getPath() - { - return path; - } - - @Override - public void setComment(String comment) - { - this.comment = comment; - } - - @Override - public String getComment() - { - return comment; - } - - @Override - public void setHttpOnly(boolean httpOnly) - { - this.httpOnly = httpOnly; - } - - @Override - public boolean isHttpOnly() - { - return httpOnly; - } - - @Override - public void setSecure(boolean secure) - { - this.secure = secure; - } - - @Override - public boolean isSecure() - { - return secure; - } - - @Override - public void setMaxAge(int maxAge) - { - this.maxAge = maxAge; - } - - @Override - public int getMaxAge() - { - return maxAge; - } -} diff --git a/src/java/nginx/unit/websocket/AsyncChannelGroupUtil.java b/src/java/nginx/unit/websocket/AsyncChannelGroupUtil.java deleted file mode 100644 index 147112c1..00000000 --- a/src/java/nginx/unit/websocket/AsyncChannelGroupUtil.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; -import java.nio.channels.AsynchronousChannelGroup; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.tomcat.util.res.StringManager; -import org.apache.tomcat.util.threads.ThreadPoolExecutor; - -/** - * This is a utility class that enables multiple {@link WsWebSocketContainer} - * instances to share a single {@link AsynchronousChannelGroup} while ensuring - * that the group is destroyed when no longer required. - */ -public class AsyncChannelGroupUtil { - - private static final StringManager sm = - StringManager.getManager(AsyncChannelGroupUtil.class); - - private static AsynchronousChannelGroup group = null; - private static int usageCount = 0; - private static final Object lock = new Object(); - - - private AsyncChannelGroupUtil() { - // Hide the default constructor - } - - - public static AsynchronousChannelGroup register() { - synchronized (lock) { - if (usageCount == 0) { - group = createAsynchronousChannelGroup(); - } - usageCount++; - return group; - } - } - - - public static void unregister() { - synchronized (lock) { - usageCount--; - if (usageCount == 0) { - group.shutdown(); - group = null; - } - } - } - - - private static AsynchronousChannelGroup createAsynchronousChannelGroup() { - // Need to do this with the right thread context class loader else the - // first web app to call this will trigger a leak - ClassLoader original = Thread.currentThread().getContextClassLoader(); - - try { - Thread.currentThread().setContextClassLoader( - AsyncIOThreadFactory.class.getClassLoader()); - - // These are the same settings as the default - // AsynchronousChannelGroup - int initialSize = Runtime.getRuntime().availableProcessors(); - ExecutorService executorService = new ThreadPoolExecutor( - 0, - Integer.MAX_VALUE, - Long.MAX_VALUE, TimeUnit.MILLISECONDS, - new SynchronousQueue(), - new AsyncIOThreadFactory()); - - try { - return AsynchronousChannelGroup.withCachedThreadPool( - executorService, initialSize); - } catch (IOException e) { - // No good reason for this to happen. - throw new IllegalStateException(sm.getString("asyncChannelGroup.createFail")); - } - } finally { - Thread.currentThread().setContextClassLoader(original); - } - } - - - private static class AsyncIOThreadFactory implements ThreadFactory { - - static { - // Load NewThreadPrivilegedAction since newThread() will not be able - // to if called from an InnocuousThread. - // See https://bz.apache.org/bugzilla/show_bug.cgi?id=57490 - NewThreadPrivilegedAction.load(); - } - - - @Override - public Thread newThread(final Runnable r) { - // Create the new Thread within a doPrivileged block to ensure that - // the thread inherits the current ProtectionDomain which is - // essential to be able to use this with a Java Applet. See - // https://bz.apache.org/bugzilla/show_bug.cgi?id=57091 - return AccessController.doPrivileged(new NewThreadPrivilegedAction(r)); - } - - // Non-anonymous class so that AsyncIOThreadFactory can load it - // explicitly - private static class NewThreadPrivilegedAction implements PrivilegedAction { - - private static AtomicInteger count = new AtomicInteger(0); - - private final Runnable r; - - public NewThreadPrivilegedAction(Runnable r) { - this.r = r; - } - - @Override - public Thread run() { - Thread t = new Thread(r); - t.setName("WebSocketClient-AsyncIO-" + count.incrementAndGet()); - t.setContextClassLoader(this.getClass().getClassLoader()); - t.setDaemon(true); - return t; - } - - private static void load() { - // NO-OP. Just provides a hook to enable the class to be loaded - } - } - } -} diff --git a/src/java/nginx/unit/websocket/AsyncChannelWrapper.java b/src/java/nginx/unit/websocket/AsyncChannelWrapper.java deleted file mode 100644 index 060ae9cb..00000000 --- a/src/java/nginx/unit/websocket/AsyncChannelWrapper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import javax.net.ssl.SSLException; - -/** - * This is a wrapper for a {@link java.nio.channels.AsynchronousSocketChannel} - * that limits the methods available thereby simplifying the process of - * implementing SSL/TLS support since there are fewer methods to intercept. - */ -public interface AsyncChannelWrapper { - - Future read(ByteBuffer dst); - - void read(ByteBuffer dst, A attachment, - CompletionHandler handler); - - Future write(ByteBuffer src); - - void write(ByteBuffer[] srcs, int offset, int length, - long timeout, TimeUnit unit, A attachment, - CompletionHandler handler); - - void close(); - - Future handshake() throws SSLException; -} diff --git a/src/java/nginx/unit/websocket/AsyncChannelWrapperNonSecure.java b/src/java/nginx/unit/websocket/AsyncChannelWrapperNonSecure.java deleted file mode 100644 index 5b88bfe1..00000000 --- a/src/java/nginx/unit/websocket/AsyncChannelWrapperNonSecure.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.AsynchronousSocketChannel; -import java.nio.channels.CompletionHandler; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** - * Generally, just passes calls straight to the wrapped - * {@link AsynchronousSocketChannel}. In some cases exceptions may be swallowed - * to save them being swallowed by the calling code. - */ -public class AsyncChannelWrapperNonSecure implements AsyncChannelWrapper { - - private static final Future NOOP_FUTURE = new NoOpFuture(); - - private final AsynchronousSocketChannel socketChannel; - - public AsyncChannelWrapperNonSecure( - AsynchronousSocketChannel socketChannel) { - this.socketChannel = socketChannel; - } - - @Override - public Future read(ByteBuffer dst) { - return socketChannel.read(dst); - } - - @Override - public void read(ByteBuffer dst, A attachment, - CompletionHandler handler) { - socketChannel.read(dst, attachment, handler); - } - - @Override - public Future write(ByteBuffer src) { - return socketChannel.write(src); - } - - @Override - public void write(ByteBuffer[] srcs, int offset, int length, - long timeout, TimeUnit unit, A attachment, - CompletionHandler handler) { - socketChannel.write( - srcs, offset, length, timeout, unit, attachment, handler); - } - - @Override - public void close() { - try { - socketChannel.close(); - } catch (IOException e) { - // Ignore - } - } - - @Override - public Future handshake() { - return NOOP_FUTURE; - } - - - private static final class NoOpFuture implements Future { - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return false; - } - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public boolean isDone() { - return true; - } - - @Override - public Void get() throws InterruptedException, ExecutionException { - return null; - } - - @Override - public Void get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, - TimeoutException { - return null; - } - } -} diff --git a/src/java/nginx/unit/websocket/AsyncChannelWrapperSecure.java b/src/java/nginx/unit/websocket/AsyncChannelWrapperSecure.java deleted file mode 100644 index 21654487..00000000 --- a/src/java/nginx/unit/websocket/AsyncChannelWrapperSecure.java +++ /dev/null @@ -1,578 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.EOFException; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.AsynchronousSocketChannel; -import java.nio.channels.CompletionHandler; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import javax.net.ssl.SSLEngineResult.Status; -import javax.net.ssl.SSLException; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.util.res.StringManager; - -/** - * Wraps the {@link AsynchronousSocketChannel} with SSL/TLS. This needs a lot - * more testing before it can be considered robust. - */ -public class AsyncChannelWrapperSecure implements AsyncChannelWrapper { - - private final Log log = - LogFactory.getLog(AsyncChannelWrapperSecure.class); - private static final StringManager sm = - StringManager.getManager(AsyncChannelWrapperSecure.class); - - private static final ByteBuffer DUMMY = ByteBuffer.allocate(16921); - private final AsynchronousSocketChannel socketChannel; - private final SSLEngine sslEngine; - private final ByteBuffer socketReadBuffer; - private final ByteBuffer socketWriteBuffer; - // One thread for read, one for write - private final ExecutorService executor = - Executors.newFixedThreadPool(2, new SecureIOThreadFactory()); - private AtomicBoolean writing = new AtomicBoolean(false); - private AtomicBoolean reading = new AtomicBoolean(false); - - public AsyncChannelWrapperSecure(AsynchronousSocketChannel socketChannel, - SSLEngine sslEngine) { - this.socketChannel = socketChannel; - this.sslEngine = sslEngine; - - int socketBufferSize = sslEngine.getSession().getPacketBufferSize(); - socketReadBuffer = ByteBuffer.allocateDirect(socketBufferSize); - socketWriteBuffer = ByteBuffer.allocateDirect(socketBufferSize); - } - - @Override - public Future read(ByteBuffer dst) { - WrapperFuture future = new WrapperFuture<>(); - - if (!reading.compareAndSet(false, true)) { - throw new IllegalStateException(sm.getString( - "asyncChannelWrapperSecure.concurrentRead")); - } - - ReadTask readTask = new ReadTask(dst, future); - - executor.execute(readTask); - - return future; - } - - @Override - public void read(ByteBuffer dst, A attachment, - CompletionHandler handler) { - - WrapperFuture future = - new WrapperFuture<>(handler, attachment); - - if (!reading.compareAndSet(false, true)) { - throw new IllegalStateException(sm.getString( - "asyncChannelWrapperSecure.concurrentRead")); - } - - ReadTask readTask = new ReadTask(dst, future); - - executor.execute(readTask); - } - - @Override - public Future write(ByteBuffer src) { - - WrapperFuture inner = new WrapperFuture<>(); - - if (!writing.compareAndSet(false, true)) { - throw new IllegalStateException(sm.getString( - "asyncChannelWrapperSecure.concurrentWrite")); - } - - WriteTask writeTask = - new WriteTask(new ByteBuffer[] {src}, 0, 1, inner); - - executor.execute(writeTask); - - Future future = new LongToIntegerFuture(inner); - return future; - } - - @Override - public void write(ByteBuffer[] srcs, int offset, int length, - long timeout, TimeUnit unit, A attachment, - CompletionHandler handler) { - - WrapperFuture future = - new WrapperFuture<>(handler, attachment); - - if (!writing.compareAndSet(false, true)) { - throw new IllegalStateException(sm.getString( - "asyncChannelWrapperSecure.concurrentWrite")); - } - - WriteTask writeTask = new WriteTask(srcs, offset, length, future); - - executor.execute(writeTask); - } - - @Override - public void close() { - try { - socketChannel.close(); - } catch (IOException e) { - log.info(sm.getString("asyncChannelWrapperSecure.closeFail")); - } - executor.shutdownNow(); - } - - @Override - public Future handshake() throws SSLException { - - WrapperFuture wFuture = new WrapperFuture<>(); - - Thread t = new WebSocketSslHandshakeThread(wFuture); - t.start(); - - return wFuture; - } - - - private class WriteTask implements Runnable { - - private final ByteBuffer[] srcs; - private final int offset; - private final int length; - private final WrapperFuture future; - - public WriteTask(ByteBuffer[] srcs, int offset, int length, - WrapperFuture future) { - this.srcs = srcs; - this.future = future; - this.offset = offset; - this.length = length; - } - - @Override - public void run() { - long written = 0; - - try { - for (int i = offset; i < offset + length; i++) { - ByteBuffer src = srcs[i]; - while (src.hasRemaining()) { - socketWriteBuffer.clear(); - - // Encrypt the data - SSLEngineResult r = sslEngine.wrap(src, socketWriteBuffer); - written += r.bytesConsumed(); - Status s = r.getStatus(); - - if (s == Status.OK || s == Status.BUFFER_OVERFLOW) { - // Need to write out the bytes and may need to read from - // the source again to empty it - } else { - // Status.BUFFER_UNDERFLOW - only happens on unwrap - // Status.CLOSED - unexpected - throw new IllegalStateException(sm.getString( - "asyncChannelWrapperSecure.statusWrap")); - } - - // Check for tasks - if (r.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable = sslEngine.getDelegatedTask(); - while (runnable != null) { - runnable.run(); - runnable = sslEngine.getDelegatedTask(); - } - } - - socketWriteBuffer.flip(); - - // Do the write - int toWrite = r.bytesProduced(); - while (toWrite > 0) { - Future f = - socketChannel.write(socketWriteBuffer); - Integer socketWrite = f.get(); - toWrite -= socketWrite.intValue(); - } - } - } - - - if (writing.compareAndSet(true, false)) { - future.complete(Long.valueOf(written)); - } else { - future.fail(new IllegalStateException(sm.getString( - "asyncChannelWrapperSecure.wrongStateWrite"))); - } - } catch (Exception e) { - writing.set(false); - future.fail(e); - } - } - } - - - private class ReadTask implements Runnable { - - private final ByteBuffer dest; - private final WrapperFuture future; - - public ReadTask(ByteBuffer dest, WrapperFuture future) { - this.dest = dest; - this.future = future; - } - - @Override - public void run() { - int read = 0; - - boolean forceRead = false; - - try { - while (read == 0) { - socketReadBuffer.compact(); - - if (forceRead) { - forceRead = false; - Future f = socketChannel.read(socketReadBuffer); - Integer socketRead = f.get(); - if (socketRead.intValue() == -1) { - throw new EOFException(sm.getString("asyncChannelWrapperSecure.eof")); - } - } - - socketReadBuffer.flip(); - - if (socketReadBuffer.hasRemaining()) { - // Decrypt the data in the buffer - SSLEngineResult r = sslEngine.unwrap(socketReadBuffer, dest); - read += r.bytesProduced(); - Status s = r.getStatus(); - - if (s == Status.OK) { - // Bytes available for reading and there may be - // sufficient data in the socketReadBuffer to - // support further reads without reading from the - // socket - } else if (s == Status.BUFFER_UNDERFLOW) { - // There is partial data in the socketReadBuffer - if (read == 0) { - // Need more data before the partial data can be - // processed and some output generated - forceRead = true; - } - // else return the data we have and deal with the - // partial data on the next read - } else if (s == Status.BUFFER_OVERFLOW) { - // Not enough space in the destination buffer to - // store all of the data. We could use a bytes read - // value of -bufferSizeRequired to signal the new - // buffer size required but an explicit exception is - // clearer. - if (reading.compareAndSet(true, false)) { - throw new ReadBufferOverflowException(sslEngine. - getSession().getApplicationBufferSize()); - } else { - future.fail(new IllegalStateException(sm.getString( - "asyncChannelWrapperSecure.wrongStateRead"))); - } - } else { - // Status.CLOSED - unexpected - throw new IllegalStateException(sm.getString( - "asyncChannelWrapperSecure.statusUnwrap")); - } - - // Check for tasks - if (r.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - Runnable runnable = sslEngine.getDelegatedTask(); - while (runnable != null) { - runnable.run(); - runnable = sslEngine.getDelegatedTask(); - } - } - } else { - forceRead = true; - } - } - - - if (reading.compareAndSet(true, false)) { - future.complete(Integer.valueOf(read)); - } else { - future.fail(new IllegalStateException(sm.getString( - "asyncChannelWrapperSecure.wrongStateRead"))); - } - } catch (RuntimeException | ReadBufferOverflowException | SSLException | EOFException | - ExecutionException | InterruptedException e) { - reading.set(false); - future.fail(e); - } - } - } - - - private class WebSocketSslHandshakeThread extends Thread { - - private final WrapperFuture hFuture; - - private HandshakeStatus handshakeStatus; - private Status resultStatus; - - public WebSocketSslHandshakeThread(WrapperFuture hFuture) { - this.hFuture = hFuture; - } - - @Override - public void run() { - try { - sslEngine.beginHandshake(); - // So the first compact does the right thing - socketReadBuffer.position(socketReadBuffer.limit()); - - handshakeStatus = sslEngine.getHandshakeStatus(); - resultStatus = Status.OK; - - boolean handshaking = true; - - while(handshaking) { - switch (handshakeStatus) { - case NEED_WRAP: { - socketWriteBuffer.clear(); - SSLEngineResult r = - sslEngine.wrap(DUMMY, socketWriteBuffer); - checkResult(r, true); - socketWriteBuffer.flip(); - Future fWrite = - socketChannel.write(socketWriteBuffer); - fWrite.get(); - break; - } - case NEED_UNWRAP: { - socketReadBuffer.compact(); - if (socketReadBuffer.position() == 0 || - resultStatus == Status.BUFFER_UNDERFLOW) { - Future fRead = - socketChannel.read(socketReadBuffer); - fRead.get(); - } - socketReadBuffer.flip(); - SSLEngineResult r = - sslEngine.unwrap(socketReadBuffer, DUMMY); - checkResult(r, false); - break; - } - case NEED_TASK: { - Runnable r = null; - while ((r = sslEngine.getDelegatedTask()) != null) { - r.run(); - } - handshakeStatus = sslEngine.getHandshakeStatus(); - break; - } - case FINISHED: { - handshaking = false; - break; - } - case NOT_HANDSHAKING: { - throw new SSLException( - sm.getString("asyncChannelWrapperSecure.notHandshaking")); - } - } - } - } catch (Exception e) { - hFuture.fail(e); - return; - } - - hFuture.complete(null); - } - - private void checkResult(SSLEngineResult result, boolean wrap) - throws SSLException { - - handshakeStatus = result.getHandshakeStatus(); - resultStatus = result.getStatus(); - - if (resultStatus != Status.OK && - (wrap || resultStatus != Status.BUFFER_UNDERFLOW)) { - throw new SSLException( - sm.getString("asyncChannelWrapperSecure.check.notOk", resultStatus)); - } - if (wrap && result.bytesConsumed() != 0) { - throw new SSLException(sm.getString("asyncChannelWrapperSecure.check.wrap")); - } - if (!wrap && result.bytesProduced() != 0) { - throw new SSLException(sm.getString("asyncChannelWrapperSecure.check.unwrap")); - } - } - } - - - private static class WrapperFuture implements Future { - - private final CompletionHandler handler; - private final A attachment; - - private volatile T result = null; - private volatile Throwable throwable = null; - private CountDownLatch completionLatch = new CountDownLatch(1); - - public WrapperFuture() { - this(null, null); - } - - public WrapperFuture(CompletionHandler handler, A attachment) { - this.handler = handler; - this.attachment = attachment; - } - - public void complete(T result) { - this.result = result; - completionLatch.countDown(); - if (handler != null) { - handler.completed(result, attachment); - } - } - - public void fail(Throwable t) { - throwable = t; - completionLatch.countDown(); - if (handler != null) { - handler.failed(throwable, attachment); - } - } - - @Override - public final boolean cancel(boolean mayInterruptIfRunning) { - // Could support cancellation by closing the connection - return false; - } - - @Override - public final boolean isCancelled() { - // Could support cancellation by closing the connection - return false; - } - - @Override - public final boolean isDone() { - return completionLatch.getCount() > 0; - } - - @Override - public T get() throws InterruptedException, ExecutionException { - completionLatch.await(); - if (throwable != null) { - throw new ExecutionException(throwable); - } - return result; - } - - @Override - public T get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, - TimeoutException { - boolean latchResult = completionLatch.await(timeout, unit); - if (latchResult == false) { - throw new TimeoutException(); - } - if (throwable != null) { - throw new ExecutionException(throwable); - } - return result; - } - } - - private static final class LongToIntegerFuture implements Future { - - private final Future wrapped; - - public LongToIntegerFuture(Future wrapped) { - this.wrapped = wrapped; - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return wrapped.cancel(mayInterruptIfRunning); - } - - @Override - public boolean isCancelled() { - return wrapped.isCancelled(); - } - - @Override - public boolean isDone() { - return wrapped.isDone(); - } - - @Override - public Integer get() throws InterruptedException, ExecutionException { - Long result = wrapped.get(); - if (result.longValue() > Integer.MAX_VALUE) { - throw new ExecutionException(sm.getString( - "asyncChannelWrapperSecure.tooBig", result), null); - } - return Integer.valueOf(result.intValue()); - } - - @Override - public Integer get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, - TimeoutException { - Long result = wrapped.get(timeout, unit); - if (result.longValue() > Integer.MAX_VALUE) { - throw new ExecutionException(sm.getString( - "asyncChannelWrapperSecure.tooBig", result), null); - } - return Integer.valueOf(result.intValue()); - } - } - - - private static class SecureIOThreadFactory implements ThreadFactory { - - private AtomicInteger count = new AtomicInteger(0); - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setName("WebSocketClient-SecureIO-" + count.incrementAndGet()); - // No need to set the context class loader. The threads will be - // cleaned up when the connection is closed. - t.setDaemon(true); - return t; - } - } -} diff --git a/src/java/nginx/unit/websocket/AuthenticationException.java b/src/java/nginx/unit/websocket/AuthenticationException.java deleted file mode 100644 index 001f1829..00000000 --- a/src/java/nginx/unit/websocket/AuthenticationException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -/** - * Exception thrown on authentication error connecting to a remote - * websocket endpoint. - */ -public class AuthenticationException extends Exception { - - private static final long serialVersionUID = 5709887412240096441L; - - /** - * Create authentication exception. - * @param message the error message - */ - public AuthenticationException(String message) { - super(message); - } - -} diff --git a/src/java/nginx/unit/websocket/Authenticator.java b/src/java/nginx/unit/websocket/Authenticator.java deleted file mode 100644 index 87b3ce6d..00000000 --- a/src/java/nginx/unit/websocket/Authenticator.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Base class for the authentication methods used by the websocket client. - */ -public abstract class Authenticator { - private static final Pattern pattern = Pattern - .compile("(\\w+)\\s*=\\s*(\"([^\"]+)\"|([^,=\"]+))\\s*,?"); - - /** - * Generate the authentication header that will be sent to the server. - * @param requestUri The request URI - * @param WWWAuthenticate The server auth challenge - * @param UserProperties The user information - * @return The auth header - * @throws AuthenticationException When an error occurs - */ - public abstract String getAuthorization(String requestUri, String WWWAuthenticate, - Map UserProperties) throws AuthenticationException; - - /** - * Get the authentication method. - * @return the auth scheme - */ - public abstract String getSchemeName(); - - /** - * Utility method to parse the authentication header. - * @param WWWAuthenticate The server auth challenge - * @return the parsed header - */ - public Map parseWWWAuthenticateHeader(String WWWAuthenticate) { - - Matcher m = pattern.matcher(WWWAuthenticate); - Map challenge = new HashMap<>(); - - while (m.find()) { - String key = m.group(1); - String qtedValue = m.group(3); - String value = m.group(4); - - challenge.put(key, qtedValue != null ? qtedValue : value); - - } - - return challenge; - - } - -} diff --git a/src/java/nginx/unit/websocket/AuthenticatorFactory.java b/src/java/nginx/unit/websocket/AuthenticatorFactory.java deleted file mode 100644 index 7d46d7f9..00000000 --- a/src/java/nginx/unit/websocket/AuthenticatorFactory.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.util.Iterator; -import java.util.ServiceLoader; - -/** - * Utility method to return the appropriate authenticator according to - * the scheme that the server uses. - */ -public class AuthenticatorFactory { - - /** - * Return a new authenticator instance. - * @param authScheme The scheme used - * @return the authenticator - */ - public static Authenticator getAuthenticator(String authScheme) { - - Authenticator auth = null; - switch (authScheme.toLowerCase()) { - - case BasicAuthenticator.schemeName: - auth = new BasicAuthenticator(); - break; - - case DigestAuthenticator.schemeName: - auth = new DigestAuthenticator(); - break; - - default: - auth = loadAuthenticators(authScheme); - break; - } - - return auth; - - } - - private static Authenticator loadAuthenticators(String authScheme) { - ServiceLoader serviceLoader = ServiceLoader.load(Authenticator.class); - Iterator auths = serviceLoader.iterator(); - - while (auths.hasNext()) { - Authenticator auth = auths.next(); - if (auth.getSchemeName().equalsIgnoreCase(authScheme)) - return auth; - } - - return null; - } - -} diff --git a/src/java/nginx/unit/websocket/BackgroundProcess.java b/src/java/nginx/unit/websocket/BackgroundProcess.java deleted file mode 100644 index 0d2e1288..00000000 --- a/src/java/nginx/unit/websocket/BackgroundProcess.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -public interface BackgroundProcess { - - void backgroundProcess(); - - void setProcessPeriod(int period); - - int getProcessPeriod(); -} diff --git a/src/java/nginx/unit/websocket/BackgroundProcessManager.java b/src/java/nginx/unit/websocket/BackgroundProcessManager.java deleted file mode 100644 index d8b1b950..00000000 --- a/src/java/nginx/unit/websocket/BackgroundProcessManager.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.util.HashSet; -import java.util.Set; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.util.ExceptionUtils; -import org.apache.tomcat.util.res.StringManager; - -/** - * Provides a background processing mechanism that triggers roughly once a - * second. The class maintains a thread that only runs when there is at least - * one instance of {@link BackgroundProcess} registered. - */ -public class BackgroundProcessManager { - - private final Log log = - LogFactory.getLog(BackgroundProcessManager.class); - private static final StringManager sm = - StringManager.getManager(BackgroundProcessManager.class); - private static final BackgroundProcessManager instance; - - - static { - instance = new BackgroundProcessManager(); - } - - - public static BackgroundProcessManager getInstance() { - return instance; - } - - private final Set processes = new HashSet<>(); - private final Object processesLock = new Object(); - private WsBackgroundThread wsBackgroundThread = null; - - private BackgroundProcessManager() { - // Hide default constructor - } - - - public void register(BackgroundProcess process) { - synchronized (processesLock) { - if (processes.size() == 0) { - wsBackgroundThread = new WsBackgroundThread(this); - wsBackgroundThread.setContextClassLoader( - this.getClass().getClassLoader()); - wsBackgroundThread.setDaemon(true); - wsBackgroundThread.start(); - } - processes.add(process); - } - } - - - public void unregister(BackgroundProcess process) { - synchronized (processesLock) { - processes.remove(process); - if (wsBackgroundThread != null && processes.size() == 0) { - wsBackgroundThread.halt(); - wsBackgroundThread = null; - } - } - } - - - private void process() { - Set currentProcesses = new HashSet<>(); - synchronized (processesLock) { - currentProcesses.addAll(processes); - } - for (BackgroundProcess process : currentProcesses) { - try { - process.backgroundProcess(); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - log.error(sm.getString( - "backgroundProcessManager.processFailed"), t); - } - } - } - - - /* - * For unit testing. - */ - int getProcessCount() { - synchronized (processesLock) { - return processes.size(); - } - } - - - void shutdown() { - synchronized (processesLock) { - processes.clear(); - if (wsBackgroundThread != null) { - wsBackgroundThread.halt(); - wsBackgroundThread = null; - } - } - } - - - private static class WsBackgroundThread extends Thread { - - private final BackgroundProcessManager manager; - private volatile boolean running = true; - - public WsBackgroundThread(BackgroundProcessManager manager) { - setName("WebSocket background processing"); - this.manager = manager; - } - - @Override - public void run() { - while (running) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // Ignore - } - manager.process(); - } - } - - public void halt() { - setName("WebSocket background processing - stopping"); - running = false; - } - } -} diff --git a/src/java/nginx/unit/websocket/BasicAuthenticator.java b/src/java/nginx/unit/websocket/BasicAuthenticator.java deleted file mode 100644 index 1b1a6b83..00000000 --- a/src/java/nginx/unit/websocket/BasicAuthenticator.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.Map; - -/** - * Authenticator supporting the BASIC auth method. - */ -public class BasicAuthenticator extends Authenticator { - - public static final String schemeName = "basic"; - public static final String charsetparam = "charset"; - - @Override - public String getAuthorization(String requestUri, String WWWAuthenticate, - Map userProperties) throws AuthenticationException { - - String userName = (String) userProperties.get(Constants.WS_AUTHENTICATION_USER_NAME); - String password = (String) userProperties.get(Constants.WS_AUTHENTICATION_PASSWORD); - - if (userName == null || password == null) { - throw new AuthenticationException( - "Failed to perform Basic authentication due to missing user/password"); - } - - Map wwwAuthenticate = parseWWWAuthenticateHeader(WWWAuthenticate); - - String userPass = userName + ":" + password; - Charset charset; - - if (wwwAuthenticate.get(charsetparam) != null - && wwwAuthenticate.get(charsetparam).equalsIgnoreCase("UTF-8")) { - charset = StandardCharsets.UTF_8; - } else { - charset = StandardCharsets.ISO_8859_1; - } - - String base64 = Base64.getEncoder().encodeToString(userPass.getBytes(charset)); - - return " Basic " + base64; - } - - @Override - public String getSchemeName() { - return schemeName; - } - -} diff --git a/src/java/nginx/unit/websocket/Constants.java b/src/java/nginx/unit/websocket/Constants.java deleted file mode 100644 index 38b22fe0..00000000 --- a/src/java/nginx/unit/websocket/Constants.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.websocket.Extension; - -/** - * Internal implementation constants. - */ -public class Constants { - - // OP Codes - public static final byte OPCODE_CONTINUATION = 0x00; - public static final byte OPCODE_TEXT = 0x01; - public static final byte OPCODE_BINARY = 0x02; - public static final byte OPCODE_CLOSE = 0x08; - public static final byte OPCODE_PING = 0x09; - public static final byte OPCODE_PONG = 0x0A; - - // Internal OP Codes - // RFC 6455 limits OP Codes to 4 bits so these should never clash - // Always set bit 4 so these will be treated as control codes - static final byte INTERNAL_OPCODE_FLUSH = 0x18; - - // Buffers - static final int DEFAULT_BUFFER_SIZE = Integer.getInteger( - "nginx.unit.websocket.DEFAULT_BUFFER_SIZE", 8 * 1024) - .intValue(); - - // Client connection - /** - * Property name to set to configure the value that is passed to - * {@link javax.net.ssl.SSLEngine#setEnabledProtocols(String[])}. The value - * should be a comma separated string. - */ - public static final String SSL_PROTOCOLS_PROPERTY = - "nginx.unit.websocket.SSL_PROTOCOLS"; - public static final String SSL_TRUSTSTORE_PROPERTY = - "nginx.unit.websocket.SSL_TRUSTSTORE"; - public static final String SSL_TRUSTSTORE_PWD_PROPERTY = - "nginx.unit.websocket.SSL_TRUSTSTORE_PWD"; - public static final String SSL_TRUSTSTORE_PWD_DEFAULT = "changeit"; - /** - * Property name to set to configure used SSLContext. The value should be an - * instance of SSLContext. If this property is present, the SSL_TRUSTSTORE* - * properties are ignored. - */ - public static final String SSL_CONTEXT_PROPERTY = - "nginx.unit.websocket.SSL_CONTEXT"; - /** - * Property name to set to configure the timeout (in milliseconds) when - * establishing a WebSocket connection to server. The default is - * {@link #IO_TIMEOUT_MS_DEFAULT}. - */ - public static final String IO_TIMEOUT_MS_PROPERTY = - "nginx.unit.websocket.IO_TIMEOUT_MS"; - public static final long IO_TIMEOUT_MS_DEFAULT = 5000; - - // RFC 2068 recommended a limit of 5 - // Most browsers have a default limit of 20 - public static final String MAX_REDIRECTIONS_PROPERTY = - "nginx.unit.websocket.MAX_REDIRECTIONS"; - public static final int MAX_REDIRECTIONS_DEFAULT = 20; - - // HTTP upgrade header names and values - public static final String HOST_HEADER_NAME = "Host"; - public static final String UPGRADE_HEADER_NAME = "Upgrade"; - public static final String UPGRADE_HEADER_VALUE = "websocket"; - public static final String ORIGIN_HEADER_NAME = "Origin"; - public static final String CONNECTION_HEADER_NAME = "Connection"; - public static final String CONNECTION_HEADER_VALUE = "upgrade"; - public static final String LOCATION_HEADER_NAME = "Location"; - public static final String AUTHORIZATION_HEADER_NAME = "Authorization"; - public static final String WWW_AUTHENTICATE_HEADER_NAME = "WWW-Authenticate"; - public static final String WS_VERSION_HEADER_NAME = "Sec-WebSocket-Version"; - public static final String WS_VERSION_HEADER_VALUE = "13"; - public static final String WS_KEY_HEADER_NAME = "Sec-WebSocket-Key"; - public static final String WS_PROTOCOL_HEADER_NAME = "Sec-WebSocket-Protocol"; - public static final String WS_EXTENSIONS_HEADER_NAME = "Sec-WebSocket-Extensions"; - - /// HTTP redirection status codes - public static final int MULTIPLE_CHOICES = 300; - public static final int MOVED_PERMANENTLY = 301; - public static final int FOUND = 302; - public static final int SEE_OTHER = 303; - public static final int USE_PROXY = 305; - public static final int TEMPORARY_REDIRECT = 307; - - // Configuration for Origin header in client - static final String DEFAULT_ORIGIN_HEADER_VALUE = - System.getProperty("nginx.unit.websocket.DEFAULT_ORIGIN_HEADER_VALUE"); - - // Configuration for blocking sends - public static final String BLOCKING_SEND_TIMEOUT_PROPERTY = - "nginx.unit.websocket.BLOCKING_SEND_TIMEOUT"; - // Milliseconds so this is 20 seconds - public static final long DEFAULT_BLOCKING_SEND_TIMEOUT = 20 * 1000; - - // Configuration for background processing checks intervals - static final int DEFAULT_PROCESS_PERIOD = Integer.getInteger( - "nginx.unit.websocket.DEFAULT_PROCESS_PERIOD", 10) - .intValue(); - - public static final String WS_AUTHENTICATION_USER_NAME = "nginx.unit.websocket.WS_AUTHENTICATION_USER_NAME"; - public static final String WS_AUTHENTICATION_PASSWORD = "nginx.unit.websocket.WS_AUTHENTICATION_PASSWORD"; - - /* Configuration for extensions - * Note: These options are primarily present to enable this implementation - * to pass compliance tests. They are expected to be removed once - * the WebSocket API includes a mechanism for adding custom extensions - * and disabling built-in extensions. - */ - static final boolean DISABLE_BUILTIN_EXTENSIONS = - Boolean.getBoolean("nginx.unit.websocket.DISABLE_BUILTIN_EXTENSIONS"); - static final boolean ALLOW_UNSUPPORTED_EXTENSIONS = - Boolean.getBoolean("nginx.unit.websocket.ALLOW_UNSUPPORTED_EXTENSIONS"); - - // Configuration for stream behavior - static final boolean STREAMS_DROP_EMPTY_MESSAGES = - Boolean.getBoolean("nginx.unit.websocket.STREAMS_DROP_EMPTY_MESSAGES"); - - public static final boolean STRICT_SPEC_COMPLIANCE = - Boolean.getBoolean("nginx.unit.websocket.STRICT_SPEC_COMPLIANCE"); - - public static final List INSTALLED_EXTENSIONS; - - static { - if (DISABLE_BUILTIN_EXTENSIONS) { - INSTALLED_EXTENSIONS = Collections.unmodifiableList(new ArrayList()); - } else { - List installed = new ArrayList<>(1); - installed.add(new WsExtension("permessage-deflate")); - INSTALLED_EXTENSIONS = Collections.unmodifiableList(installed); - } - } - - private Constants() { - // Hide default constructor - } -} diff --git a/src/java/nginx/unit/websocket/DecoderEntry.java b/src/java/nginx/unit/websocket/DecoderEntry.java deleted file mode 100644 index 36112ef4..00000000 --- a/src/java/nginx/unit/websocket/DecoderEntry.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import javax.websocket.Decoder; - -public class DecoderEntry { - - private final Class clazz; - private final Class decoderClazz; - - public DecoderEntry(Class clazz, - Class decoderClazz) { - this.clazz = clazz; - this.decoderClazz = decoderClazz; - } - - public Class getClazz() { - return clazz; - } - - public Class getDecoderClazz() { - return decoderClazz; - } -} diff --git a/src/java/nginx/unit/websocket/DigestAuthenticator.java b/src/java/nginx/unit/websocket/DigestAuthenticator.java deleted file mode 100644 index eb91a9b4..00000000 --- a/src/java/nginx/unit/websocket/DigestAuthenticator.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Map; - -import org.apache.tomcat.util.buf.HexUtils; - -/** - * Authenticator supporting the DIGEST auth method. - */ -public class DigestAuthenticator extends Authenticator { - - public static final String schemeName = "digest"; - private SecureRandom cnonceGenerator; - private int nonceCount = 0; - private long cNonce; - - @Override - public String getAuthorization(String requestUri, String WWWAuthenticate, - Map userProperties) throws AuthenticationException { - - String userName = (String) userProperties.get(Constants.WS_AUTHENTICATION_USER_NAME); - String password = (String) userProperties.get(Constants.WS_AUTHENTICATION_PASSWORD); - - if (userName == null || password == null) { - throw new AuthenticationException( - "Failed to perform Digest authentication due to missing user/password"); - } - - Map wwwAuthenticate = parseWWWAuthenticateHeader(WWWAuthenticate); - - String realm = wwwAuthenticate.get("realm"); - String nonce = wwwAuthenticate.get("nonce"); - String messageQop = wwwAuthenticate.get("qop"); - String algorithm = wwwAuthenticate.get("algorithm") == null ? "MD5" - : wwwAuthenticate.get("algorithm"); - String opaque = wwwAuthenticate.get("opaque"); - - StringBuilder challenge = new StringBuilder(); - - if (!messageQop.isEmpty()) { - if (cnonceGenerator == null) { - cnonceGenerator = new SecureRandom(); - } - - cNonce = cnonceGenerator.nextLong(); - nonceCount++; - } - - challenge.append("Digest "); - challenge.append("username =\"" + userName + "\","); - challenge.append("realm=\"" + realm + "\","); - challenge.append("nonce=\"" + nonce + "\","); - challenge.append("uri=\"" + requestUri + "\","); - - try { - challenge.append("response=\"" + calculateRequestDigest(requestUri, userName, password, - realm, nonce, messageQop, algorithm) + "\","); - } - - catch (NoSuchAlgorithmException e) { - throw new AuthenticationException( - "Unable to generate request digest " + e.getMessage()); - } - - challenge.append("algorithm=" + algorithm + ","); - challenge.append("opaque=\"" + opaque + "\","); - - if (!messageQop.isEmpty()) { - challenge.append("qop=\"" + messageQop + "\""); - challenge.append(",cnonce=\"" + cNonce + "\","); - challenge.append("nc=" + String.format("%08X", Integer.valueOf(nonceCount))); - } - - return challenge.toString(); - - } - - private String calculateRequestDigest(String requestUri, String userName, String password, - String realm, String nonce, String qop, String algorithm) - throws NoSuchAlgorithmException { - - StringBuilder preDigest = new StringBuilder(); - String A1; - - if (algorithm.equalsIgnoreCase("MD5")) - A1 = userName + ":" + realm + ":" + password; - - else - A1 = encodeMD5(userName + ":" + realm + ":" + password) + ":" + nonce + ":" + cNonce; - - /* - * If the "qop" value is "auth-int", then A2 is: A2 = Method ":" - * digest-uri-value ":" H(entity-body) since we do not have an entity-body, A2 = - * Method ":" digest-uri-value for auth and auth_int - */ - String A2 = "GET:" + requestUri; - - preDigest.append(encodeMD5(A1)); - preDigest.append(":"); - preDigest.append(nonce); - - if (qop.toLowerCase().contains("auth")) { - preDigest.append(":"); - preDigest.append(String.format("%08X", Integer.valueOf(nonceCount))); - preDigest.append(":"); - preDigest.append(String.valueOf(cNonce)); - preDigest.append(":"); - preDigest.append(qop); - } - - preDigest.append(":"); - preDigest.append(encodeMD5(A2)); - - return encodeMD5(preDigest.toString()); - - } - - private String encodeMD5(String value) throws NoSuchAlgorithmException { - byte[] bytesOfMessage = value.getBytes(StandardCharsets.ISO_8859_1); - MessageDigest md = MessageDigest.getInstance("MD5"); - byte[] thedigest = md.digest(bytesOfMessage); - - return HexUtils.toHexString(thedigest); - } - - @Override - public String getSchemeName() { - return schemeName; - } -} diff --git a/src/java/nginx/unit/websocket/FutureToSendHandler.java b/src/java/nginx/unit/websocket/FutureToSendHandler.java deleted file mode 100644 index 4a0809cb..00000000 --- a/src/java/nginx/unit/websocket/FutureToSendHandler.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicReference; - -import javax.websocket.SendHandler; -import javax.websocket.SendResult; - -import org.apache.tomcat.util.res.StringManager; - - -/** - * Converts a Future to a SendHandler. - */ -class FutureToSendHandler implements Future, SendHandler { - - private static final StringManager sm = StringManager.getManager(FutureToSendHandler.class); - - private final CountDownLatch latch = new CountDownLatch(1); - private final WsSession wsSession; - private volatile AtomicReference result = new AtomicReference<>(null); - - public FutureToSendHandler(WsSession wsSession) { - this.wsSession = wsSession; - } - - - // --------------------------------------------------------- SendHandler - - @Override - public void onResult(SendResult result) { - this.result.compareAndSet(null, result); - latch.countDown(); - } - - - // -------------------------------------------------------------- Future - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - // Cancelling the task is not supported - return false; - } - - @Override - public boolean isCancelled() { - // Cancelling the task is not supported - return false; - } - - @Override - public boolean isDone() { - return latch.getCount() == 0; - } - - @Override - public Void get() throws InterruptedException, - ExecutionException { - try { - wsSession.registerFuture(this); - latch.await(); - } finally { - wsSession.unregisterFuture(this); - } - if (result.get().getException() != null) { - throw new ExecutionException(result.get().getException()); - } - return null; - } - - @Override - public Void get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, - TimeoutException { - boolean retval = false; - try { - wsSession.registerFuture(this); - retval = latch.await(timeout, unit); - } finally { - wsSession.unregisterFuture(this); - - } - if (retval == false) { - throw new TimeoutException(sm.getString("futureToSendHandler.timeout", - Long.valueOf(timeout), unit.toString().toLowerCase())); - } - if (result.get().getException() != null) { - throw new ExecutionException(result.get().getException()); - } - return null; - } -} diff --git a/src/java/nginx/unit/websocket/LocalStrings.properties b/src/java/nginx/unit/websocket/LocalStrings.properties deleted file mode 100644 index aeafe082..00000000 --- a/src/java/nginx/unit/websocket/LocalStrings.properties +++ /dev/null @@ -1,147 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -asyncChannelGroup.createFail=Unable to create dedicated AsynchronousChannelGroup for WebSocket clients which is required to prevent memory leaks in complex class loader environments like JavaEE containers - -asyncChannelWrapperSecure.closeFail=Failed to close channel cleanly -asyncChannelWrapperSecure.check.notOk=TLS handshake returned an unexpected status [{0}] -asyncChannelWrapperSecure.check.unwrap=Bytes were written to the output during a read -asyncChannelWrapperSecure.check.wrap=Bytes were consumed from the input during a write -asyncChannelWrapperSecure.concurrentRead=Concurrent read operations are not permitted -asyncChannelWrapperSecure.concurrentWrite=Concurrent write operations are not permitted -asyncChannelWrapperSecure.eof=Unexpected end of stream -asyncChannelWrapperSecure.notHandshaking=Unexpected state [NOT_HANDSHAKING] during TLS handshake -asyncChannelWrapperSecure.readOverflow=Buffer overflow. [{0}] bytes to write into a [{1}] byte buffer that already contained [{2}] bytes. -asyncChannelWrapperSecure.statusUnwrap=Unexpected Status of SSLEngineResult after an unwrap() operation -asyncChannelWrapperSecure.statusWrap=Unexpected Status of SSLEngineResult after a wrap() operation -asyncChannelWrapperSecure.tooBig=The result [{0}] is too big to be expressed as an Integer -asyncChannelWrapperSecure.wrongStateRead=Flag that indicates a read is in progress was found to be false (it should have been true) when trying to complete a read operation -asyncChannelWrapperSecure.wrongStateWrite=Flag that indicates a write is in progress was found to be false (it should have been true) when trying to complete a write operation - -backgroundProcessManager.processFailed=A background process failed - -caseInsensitiveKeyMap.nullKey=Null keys are not permitted - -futureToSendHandler.timeout=Operation timed out after waiting [{0}] [{1}] to complete - -perMessageDeflate.deflateFailed=Failed to decompress a compressed WebSocket frame -perMessageDeflate.duplicateParameter=Duplicate definition of the [{0}] extension parameter -perMessageDeflate.invalidWindowSize=An invalid windows of [{1}] size was specified for [{0}]. Valid values are whole numbers from 8 to 15 inclusive. -perMessageDeflate.unknownParameter=An unknown extension parameter [{0}] was defined - -transformerFactory.unsupportedExtension=The extension [{0}] is not supported - -util.notToken=An illegal extension parameter was specified with name [{0}] and value [{1}] -util.invalidMessageHandler=The message handler provided does not have an onMessage(Object) method -util.invalidType=Unable to coerce value [{0}] to type [{1}]. That type is not supported. -util.unknownDecoderType=The Decoder type [{0}] is not recognized - -# Note the wsFrame.* messages are used as close reasons in WebSocket control -# frames and therefore must be 123 bytes (not characters) or less in length. -# Messages are encoded using UTF-8 where a single character may be encoded in -# as many as 4 bytes. -wsFrame.alreadyResumed=Message receiving has already been resumed. -wsFrame.alreadySuspended=Message receiving has already been suspended. -wsFrame.bufferTooSmall=No async message support and buffer too small. Buffer size: [{0}], Message size: [{1}] -wsFrame.byteToLongFail=Too many bytes ([{0}]) were provided to be converted into a long -wsFrame.closed=New frame received after a close control frame -wsFrame.controlFragmented=A fragmented control frame was received but control frames may not be fragmented -wsFrame.controlPayloadTooBig=A control frame was sent with a payload of size [{0}] which is larger than the maximum permitted of 125 bytes -wsFrame.controlNoFin=A control frame was sent that did not have the fin bit set. Control frames are not permitted to use continuation frames. -wsFrame.illegalReadState=Unexpected read state [{0}] -wsFrame.invalidOpCode= A WebSocket frame was sent with an unrecognised opCode of [{0}] -wsFrame.invalidUtf8=A WebSocket text frame was received that could not be decoded to UTF-8 because it contained invalid byte sequences -wsFrame.invalidUtf8Close=A WebSocket close frame was received with a close reason that contained invalid UTF-8 byte sequences -wsFrame.ioeTriggeredClose=An unrecoverable IOException occurred so the connection was closed -wsFrame.messageTooBig=The message was [{0}] bytes long but the MessageHandler has a limit of [{1}] bytes -wsFrame.noContinuation=A new message was started when a continuation frame was expected -wsFrame.notMasked=The client frame was not masked but all client frames must be masked -wsFrame.oneByteCloseCode=The client sent a close frame with a single byte payload which is not valid -wsFrame.partialHeaderComplete=WebSocket frame received. fin [{0}], rsv [{1}], OpCode [{2}], payload length [{3}] -wsFrame.sessionClosed=The client data cannot be processed because the session has already been closed -wsFrame.suspendRequested=Suspend of the message receiving has already been requested. -wsFrame.textMessageTooBig=The decoded text message was too big for the output buffer and the endpoint does not support partial messages -wsFrame.wrongRsv=The client frame set the reserved bits to [{0}] for a message with opCode [{1}] which was not supported by this endpoint - -wsFrameClient.ioe=Failure while reading data sent by server - -wsHandshakeRequest.invalidUri=The string [{0}] cannot be used to construct a valid URI -wsHandshakeRequest.unknownScheme=The scheme [{0}] in the request is not recognised - -wsRemoteEndpoint.acquireTimeout=The current message was not fully sent within the specified timeout -wsRemoteEndpoint.closed=Message will not be sent because the WebSocket session has been closed -wsRemoteEndpoint.closedDuringMessage=The remainder of the message will not be sent because the WebSocket session has been closed -wsRemoteEndpoint.closedOutputStream=This method may not be called as the OutputStream has been closed -wsRemoteEndpoint.closedWriter=This method may not be called as the Writer has been closed -wsRemoteEndpoint.changeType=When sending a fragmented message, all fragments must be of the same type -wsRemoteEndpoint.concurrentMessageSend=Messages may not be sent concurrently even when using the asynchronous send messages. The client must wait for the previous message to complete before sending the next. -wsRemoteEndpoint.flushOnCloseFailed=Batched messages still enabled after session has been closed. Unable to flush remaining batched message. -wsRemoteEndpoint.invalidEncoder=The specified encoder of type [{0}] could not be instantiated -wsRemoteEndpoint.noEncoder=No encoder specified for object of class [{0}] -wsRemoteEndpoint.nullData=Invalid null data argument -wsRemoteEndpoint.nullHandler=Invalid null handler argument -wsRemoteEndpoint.sendInterrupt=The current thread was interrupted while waiting for a blocking send to complete -wsRemoteEndpoint.tooMuchData=Ping or pong may not send more than 125 bytes -wsRemoteEndpoint.wrongState=The remote endpoint was in state [{0}] which is an invalid state for called method - -# Note the following message is used as a close reason in a WebSocket control -# frame and therefore must be 123 bytes (not characters) or less in length. -# Messages are encoded using UTF-8 where a single character may be encoded in -# as many as 4 bytes. -wsSession.timeout=The WebSocket session [{0}] timeout expired - -wsSession.closed=The WebSocket session [{0}] has been closed and no method (apart from close()) may be called on a closed session -wsSession.created=Created WebSocket session [{0}] -wsSession.doClose=Closing WebSocket session [{1}] -wsSession.duplicateHandlerBinary=A binary message handler has already been configured -wsSession.duplicateHandlerPong=A pong message handler has already been configured -wsSession.duplicateHandlerText=A text message handler has already been configured -wsSession.invalidHandlerTypePong=A pong message handler must implement MessageHandler.Whole -wsSession.flushFailOnClose=Failed to flush batched messages on session close -wsSession.messageFailed=Unable to write the complete message as the WebSocket connection has been closed -wsSession.sendCloseFail=Failed to send close message for session [{0}] to remote endpoint -wsSession.removeHandlerFailed=Unable to remove the handler [{0}] as it was not registered with this session -wsSession.unknownHandler=Unable to add the message handler [{0}] as it was for the unrecognised type [{1}] -wsSession.unknownHandlerType=Unable to add the message handler [{0}] as it was wrapped as the unrecognised type [{1}] -wsSession.instanceNew=Endpoint instance registration failed -wsSession.instanceDestroy=Endpoint instance unregistration failed - -# Note the following message is used as a close reason in a WebSocket control -# frame and therefore must be 123 bytes (not characters) or less in length. -# Messages are encoded using UTF-8 where a single character may be encoded in -# as many as 4 bytes. -wsWebSocketContainer.shutdown=The web application is stopping - -wsWebSocketContainer.defaultConfiguratorFail=Failed to create the default configurator -wsWebSocketContainer.endpointCreateFail=Failed to create a local endpoint of type [{0}] -wsWebSocketContainer.maxBuffer=This implementation limits the maximum size of a buffer to Integer.MAX_VALUE -wsWebSocketContainer.missingAnnotation=Cannot use POJO class [{0}] as it is not annotated with @ClientEndpoint -wsWebSocketContainer.sessionCloseFail=Session with ID [{0}] did not close cleanly - -wsWebSocketContainer.asynchronousSocketChannelFail=Unable to open a connection to the server -wsWebSocketContainer.httpRequestFailed=The HTTP request to initiate the WebSocket connection failed -wsWebSocketContainer.invalidExtensionParameters=The server responded with extension parameters the client is unable to support -wsWebSocketContainer.invalidHeader=Unable to parse HTTP header as no colon is present to delimit header name and header value in [{0}]. The header has been skipped. -wsWebSocketContainer.invalidStatus=The HTTP response from the server [{0}] did not permit the HTTP upgrade to WebSocket -wsWebSocketContainer.invalidSubProtocol=The WebSocket server returned multiple values for the Sec-WebSocket-Protocol header -wsWebSocketContainer.pathNoHost=No host was specified in URI -wsWebSocketContainer.pathWrongScheme=The scheme [{0}] is not supported. The supported schemes are ws and wss -wsWebSocketContainer.proxyConnectFail=Failed to connect to the configured Proxy [{0}]. The HTTP response code was [{1}] -wsWebSocketContainer.sslEngineFail=Unable to create SSLEngine to support SSL/TLS connections -wsWebSocketContainer.missingLocationHeader=Failed to handle HTTP response code [{0}]. Missing Location header in response -wsWebSocketContainer.redirectThreshold=Cyclic Location header [{0}] detected / reached max number of redirects [{1}] of max [{2}] -wsWebSocketContainer.unsupportedAuthScheme=Failed to handle HTTP response code [{0}]. Unsupported Authentication scheme [{1}] returned in response -wsWebSocketContainer.failedAuthentication=Failed to handle HTTP response code [{0}]. Authentication header was not accepted by server. -wsWebSocketContainer.missingWWWAuthenticateHeader=Failed to handle HTTP response code [{0}]. Missing WWW-Authenticate header in response diff --git a/src/java/nginx/unit/websocket/MessageHandlerResult.java b/src/java/nginx/unit/websocket/MessageHandlerResult.java deleted file mode 100644 index 8d532d1e..00000000 --- a/src/java/nginx/unit/websocket/MessageHandlerResult.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import javax.websocket.MessageHandler; - -public class MessageHandlerResult { - - private final MessageHandler handler; - private final MessageHandlerResultType type; - - - public MessageHandlerResult(MessageHandler handler, - MessageHandlerResultType type) { - this.handler = handler; - this.type = type; - } - - - public MessageHandler getHandler() { - return handler; - } - - - public MessageHandlerResultType getType() { - return type; - } -} diff --git a/src/java/nginx/unit/websocket/MessageHandlerResultType.java b/src/java/nginx/unit/websocket/MessageHandlerResultType.java deleted file mode 100644 index 1961bb4f..00000000 --- a/src/java/nginx/unit/websocket/MessageHandlerResultType.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -public enum MessageHandlerResultType { - BINARY, - TEXT, - PONG -} diff --git a/src/java/nginx/unit/websocket/MessagePart.java b/src/java/nginx/unit/websocket/MessagePart.java deleted file mode 100644 index b52c26f1..00000000 --- a/src/java/nginx/unit/websocket/MessagePart.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.nio.ByteBuffer; - -import javax.websocket.SendHandler; - -class MessagePart { - private final boolean fin; - private final int rsv; - private final byte opCode; - private final ByteBuffer payload; - private final SendHandler intermediateHandler; - private volatile SendHandler endHandler; - private final long blockingWriteTimeoutExpiry; - - public MessagePart( boolean fin, int rsv, byte opCode, ByteBuffer payload, - SendHandler intermediateHandler, SendHandler endHandler, - long blockingWriteTimeoutExpiry) { - this.fin = fin; - this.rsv = rsv; - this.opCode = opCode; - this.payload = payload; - this.intermediateHandler = intermediateHandler; - this.endHandler = endHandler; - this.blockingWriteTimeoutExpiry = blockingWriteTimeoutExpiry; - } - - - public boolean isFin() { - return fin; - } - - - public int getRsv() { - return rsv; - } - - - public byte getOpCode() { - return opCode; - } - - - public ByteBuffer getPayload() { - return payload; - } - - - public SendHandler getIntermediateHandler() { - return intermediateHandler; - } - - - public SendHandler getEndHandler() { - return endHandler; - } - - public void setEndHandler(SendHandler endHandler) { - this.endHandler = endHandler; - } - - public long getBlockingWriteTimeoutExpiry() { - return blockingWriteTimeoutExpiry; - } -} - - diff --git a/src/java/nginx/unit/websocket/PerMessageDeflate.java b/src/java/nginx/unit/websocket/PerMessageDeflate.java deleted file mode 100644 index 88e0a0bc..00000000 --- a/src/java/nginx/unit/websocket/PerMessageDeflate.java +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.zip.DataFormatException; -import java.util.zip.Deflater; -import java.util.zip.Inflater; - -import javax.websocket.Extension; -import javax.websocket.Extension.Parameter; -import javax.websocket.SendHandler; - -import org.apache.tomcat.util.res.StringManager; - -public class PerMessageDeflate implements Transformation { - - private static final StringManager sm = StringManager.getManager(PerMessageDeflate.class); - - private static final String SERVER_NO_CONTEXT_TAKEOVER = "server_no_context_takeover"; - private static final String CLIENT_NO_CONTEXT_TAKEOVER = "client_no_context_takeover"; - private static final String SERVER_MAX_WINDOW_BITS = "server_max_window_bits"; - private static final String CLIENT_MAX_WINDOW_BITS = "client_max_window_bits"; - - private static final int RSV_BITMASK = 0b100; - private static final byte[] EOM_BYTES = new byte[] {0, 0, -1, -1}; - - public static final String NAME = "permessage-deflate"; - - private final boolean serverContextTakeover; - private final int serverMaxWindowBits; - private final boolean clientContextTakeover; - private final int clientMaxWindowBits; - private final boolean isServer; - private final Inflater inflater = new Inflater(true); - private final ByteBuffer readBuffer = ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE); - private final Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true); - private final byte[] EOM_BUFFER = new byte[EOM_BYTES.length + 1]; - - private volatile Transformation next; - private volatile boolean skipDecompression = false; - private volatile ByteBuffer writeBuffer = ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE); - private volatile boolean firstCompressedFrameWritten = false; - // Flag to track if a message is completely empty - private volatile boolean emptyMessage = true; - - static PerMessageDeflate negotiate(List> preferences, boolean isServer) { - // Accept the first preference that the endpoint is able to support - for (List preference : preferences) { - boolean ok = true; - boolean serverContextTakeover = true; - int serverMaxWindowBits = -1; - boolean clientContextTakeover = true; - int clientMaxWindowBits = -1; - - for (Parameter param : preference) { - if (SERVER_NO_CONTEXT_TAKEOVER.equals(param.getName())) { - if (serverContextTakeover) { - serverContextTakeover = false; - } else { - // Duplicate definition - throw new IllegalArgumentException(sm.getString( - "perMessageDeflate.duplicateParameter", - SERVER_NO_CONTEXT_TAKEOVER )); - } - } else if (CLIENT_NO_CONTEXT_TAKEOVER.equals(param.getName())) { - if (clientContextTakeover) { - clientContextTakeover = false; - } else { - // Duplicate definition - throw new IllegalArgumentException(sm.getString( - "perMessageDeflate.duplicateParameter", - CLIENT_NO_CONTEXT_TAKEOVER )); - } - } else if (SERVER_MAX_WINDOW_BITS.equals(param.getName())) { - if (serverMaxWindowBits == -1) { - serverMaxWindowBits = Integer.parseInt(param.getValue()); - if (serverMaxWindowBits < 8 || serverMaxWindowBits > 15) { - throw new IllegalArgumentException(sm.getString( - "perMessageDeflate.invalidWindowSize", - SERVER_MAX_WINDOW_BITS, - Integer.valueOf(serverMaxWindowBits))); - } - // Java SE API (as of Java 8) does not expose the API to - // control the Window size. It is effectively hard-coded - // to 15 - if (isServer && serverMaxWindowBits != 15) { - ok = false; - break; - // Note server window size is not an issue for the - // client since the client will assume 15 and if the - // server uses a smaller window everything will - // still work - } - } else { - // Duplicate definition - throw new IllegalArgumentException(sm.getString( - "perMessageDeflate.duplicateParameter", - SERVER_MAX_WINDOW_BITS )); - } - } else if (CLIENT_MAX_WINDOW_BITS.equals(param.getName())) { - if (clientMaxWindowBits == -1) { - if (param.getValue() == null) { - // Hint to server that the client supports this - // option. Java SE API (as of Java 8) does not - // expose the API to control the Window size. It is - // effectively hard-coded to 15 - clientMaxWindowBits = 15; - } else { - clientMaxWindowBits = Integer.parseInt(param.getValue()); - if (clientMaxWindowBits < 8 || clientMaxWindowBits > 15) { - throw new IllegalArgumentException(sm.getString( - "perMessageDeflate.invalidWindowSize", - CLIENT_MAX_WINDOW_BITS, - Integer.valueOf(clientMaxWindowBits))); - } - } - // Java SE API (as of Java 8) does not expose the API to - // control the Window size. It is effectively hard-coded - // to 15 - if (!isServer && clientMaxWindowBits != 15) { - ok = false; - break; - // Note client window size is not an issue for the - // server since the server will assume 15 and if the - // client uses a smaller window everything will - // still work - } - } else { - // Duplicate definition - throw new IllegalArgumentException(sm.getString( - "perMessageDeflate.duplicateParameter", - CLIENT_MAX_WINDOW_BITS )); - } - } else { - // Unknown parameter - throw new IllegalArgumentException(sm.getString( - "perMessageDeflate.unknownParameter", param.getName())); - } - } - if (ok) { - return new PerMessageDeflate(serverContextTakeover, serverMaxWindowBits, - clientContextTakeover, clientMaxWindowBits, isServer); - } - } - // Failed to negotiate agreeable terms - return null; - } - - - private PerMessageDeflate(boolean serverContextTakeover, int serverMaxWindowBits, - boolean clientContextTakeover, int clientMaxWindowBits, boolean isServer) { - this.serverContextTakeover = serverContextTakeover; - this.serverMaxWindowBits = serverMaxWindowBits; - this.clientContextTakeover = clientContextTakeover; - this.clientMaxWindowBits = clientMaxWindowBits; - this.isServer = isServer; - } - - - @Override - public TransformationResult getMoreData(byte opCode, boolean fin, int rsv, ByteBuffer dest) - throws IOException { - // Control frames are never compressed and may appear in the middle of - // a WebSocket method. Pass them straight through. - if (Util.isControl(opCode)) { - return next.getMoreData(opCode, fin, rsv, dest); - } - - if (!Util.isContinuation(opCode)) { - // First frame in new message - skipDecompression = (rsv & RSV_BITMASK) == 0; - } - - // Pass uncompressed frames straight through. - if (skipDecompression) { - return next.getMoreData(opCode, fin, rsv, dest); - } - - int written; - boolean usedEomBytes = false; - - while (dest.remaining() > 0) { - // Space available in destination. Try and fill it. - try { - written = inflater.inflate( - dest.array(), dest.arrayOffset() + dest.position(), dest.remaining()); - } catch (DataFormatException e) { - throw new IOException(sm.getString("perMessageDeflate.deflateFailed"), e); - } - dest.position(dest.position() + written); - - if (inflater.needsInput() && !usedEomBytes ) { - if (dest.hasRemaining()) { - readBuffer.clear(); - TransformationResult nextResult = - next.getMoreData(opCode, fin, (rsv ^ RSV_BITMASK), readBuffer); - inflater.setInput( - readBuffer.array(), readBuffer.arrayOffset(), readBuffer.position()); - if (TransformationResult.UNDERFLOW.equals(nextResult)) { - return nextResult; - } else if (TransformationResult.END_OF_FRAME.equals(nextResult) && - readBuffer.position() == 0) { - if (fin) { - inflater.setInput(EOM_BYTES); - usedEomBytes = true; - } else { - return TransformationResult.END_OF_FRAME; - } - } - } - } else if (written == 0) { - if (fin && (isServer && !clientContextTakeover || - !isServer && !serverContextTakeover)) { - inflater.reset(); - } - return TransformationResult.END_OF_FRAME; - } - } - - return TransformationResult.OVERFLOW; - } - - - @Override - public boolean validateRsv(int rsv, byte opCode) { - if (Util.isControl(opCode)) { - if ((rsv & RSV_BITMASK) != 0) { - return false; - } else { - if (next == null) { - return true; - } else { - return next.validateRsv(rsv, opCode); - } - } - } else { - int rsvNext = rsv; - if ((rsv & RSV_BITMASK) != 0) { - rsvNext = rsv ^ RSV_BITMASK; - } - if (next == null) { - return true; - } else { - return next.validateRsv(rsvNext, opCode); - } - } - } - - - @Override - public Extension getExtensionResponse() { - Extension result = new WsExtension(NAME); - - List params = result.getParameters(); - - if (!serverContextTakeover) { - params.add(new WsExtensionParameter(SERVER_NO_CONTEXT_TAKEOVER, null)); - } - if (serverMaxWindowBits != -1) { - params.add(new WsExtensionParameter(SERVER_MAX_WINDOW_BITS, - Integer.toString(serverMaxWindowBits))); - } - if (!clientContextTakeover) { - params.add(new WsExtensionParameter(CLIENT_NO_CONTEXT_TAKEOVER, null)); - } - if (clientMaxWindowBits != -1) { - params.add(new WsExtensionParameter(CLIENT_MAX_WINDOW_BITS, - Integer.toString(clientMaxWindowBits))); - } - - return result; - } - - - @Override - public void setNext(Transformation t) { - if (next == null) { - this.next = t; - } else { - next.setNext(t); - } - } - - - @Override - public boolean validateRsvBits(int i) { - if ((i & RSV_BITMASK) != 0) { - return false; - } - if (next == null) { - return true; - } else { - return next.validateRsvBits(i | RSV_BITMASK); - } - } - - - @Override - public List sendMessagePart(List uncompressedParts) { - List allCompressedParts = new ArrayList<>(); - - for (MessagePart uncompressedPart : uncompressedParts) { - byte opCode = uncompressedPart.getOpCode(); - boolean emptyPart = uncompressedPart.getPayload().limit() == 0; - emptyMessage = emptyMessage && emptyPart; - if (Util.isControl(opCode)) { - // Control messages can appear in the middle of other messages - // and must not be compressed. Pass it straight through - allCompressedParts.add(uncompressedPart); - } else if (emptyMessage && uncompressedPart.isFin()) { - // Zero length messages can't be compressed so pass the - // final (empty) part straight through. - allCompressedParts.add(uncompressedPart); - } else { - List compressedParts = new ArrayList<>(); - ByteBuffer uncompressedPayload = uncompressedPart.getPayload(); - SendHandler uncompressedIntermediateHandler = - uncompressedPart.getIntermediateHandler(); - - deflater.setInput(uncompressedPayload.array(), - uncompressedPayload.arrayOffset() + uncompressedPayload.position(), - uncompressedPayload.remaining()); - - int flush = (uncompressedPart.isFin() ? Deflater.SYNC_FLUSH : Deflater.NO_FLUSH); - boolean deflateRequired = true; - - while (deflateRequired) { - ByteBuffer compressedPayload = writeBuffer; - - int written = deflater.deflate(compressedPayload.array(), - compressedPayload.arrayOffset() + compressedPayload.position(), - compressedPayload.remaining(), flush); - compressedPayload.position(compressedPayload.position() + written); - - if (!uncompressedPart.isFin() && compressedPayload.hasRemaining() && deflater.needsInput()) { - // This message part has been fully processed by the - // deflater. Fire the send handler for this message part - // and move on to the next message part. - break; - } - - // If this point is reached, a new compressed message part - // will be created... - MessagePart compressedPart; - - // .. and a new writeBuffer will be required. - writeBuffer = ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE); - - // Flip the compressed payload ready for writing - compressedPayload.flip(); - - boolean fin = uncompressedPart.isFin(); - boolean full = compressedPayload.limit() == compressedPayload.capacity(); - boolean needsInput = deflater.needsInput(); - long blockingWriteTimeoutExpiry = uncompressedPart.getBlockingWriteTimeoutExpiry(); - - if (fin && !full && needsInput) { - // End of compressed message. Drop EOM bytes and output. - compressedPayload.limit(compressedPayload.limit() - EOM_BYTES.length); - compressedPart = new MessagePart(true, getRsv(uncompressedPart), - opCode, compressedPayload, uncompressedIntermediateHandler, - uncompressedIntermediateHandler, blockingWriteTimeoutExpiry); - deflateRequired = false; - startNewMessage(); - } else if (full && !needsInput) { - // Write buffer full and input message not fully read. - // Output and start new compressed part. - compressedPart = new MessagePart(false, getRsv(uncompressedPart), - opCode, compressedPayload, uncompressedIntermediateHandler, - uncompressedIntermediateHandler, blockingWriteTimeoutExpiry); - } else if (!fin && full && needsInput) { - // Write buffer full and input message not fully read. - // Output and get more data. - compressedPart = new MessagePart(false, getRsv(uncompressedPart), - opCode, compressedPayload, uncompressedIntermediateHandler, - uncompressedIntermediateHandler, blockingWriteTimeoutExpiry); - deflateRequired = false; - } else if (fin && full && needsInput) { - // Write buffer full. Input fully read. Deflater may be - // in one of four states: - // - output complete (just happened to align with end of - // buffer - // - in middle of EOM bytes - // - about to write EOM bytes - // - more data to write - int eomBufferWritten = deflater.deflate(EOM_BUFFER, 0, EOM_BUFFER.length, Deflater.SYNC_FLUSH); - if (eomBufferWritten < EOM_BUFFER.length) { - // EOM has just been completed - compressedPayload.limit(compressedPayload.limit() - EOM_BYTES.length + eomBufferWritten); - compressedPart = new MessagePart(true, - getRsv(uncompressedPart), opCode, compressedPayload, - uncompressedIntermediateHandler, uncompressedIntermediateHandler, - blockingWriteTimeoutExpiry); - deflateRequired = false; - startNewMessage(); - } else { - // More data to write - // Copy bytes to new write buffer - writeBuffer.put(EOM_BUFFER, 0, eomBufferWritten); - compressedPart = new MessagePart(false, - getRsv(uncompressedPart), opCode, compressedPayload, - uncompressedIntermediateHandler, uncompressedIntermediateHandler, - blockingWriteTimeoutExpiry); - } - } else { - throw new IllegalStateException("Should never happen"); - } - - // Add the newly created compressed part to the set of parts - // to pass on to the next transformation. - compressedParts.add(compressedPart); - } - - SendHandler uncompressedEndHandler = uncompressedPart.getEndHandler(); - int size = compressedParts.size(); - if (size > 0) { - compressedParts.get(size - 1).setEndHandler(uncompressedEndHandler); - } - - allCompressedParts.addAll(compressedParts); - } - } - - if (next == null) { - return allCompressedParts; - } else { - return next.sendMessagePart(allCompressedParts); - } - } - - - private void startNewMessage() { - firstCompressedFrameWritten = false; - emptyMessage = true; - if (isServer && !serverContextTakeover || !isServer && !clientContextTakeover) { - deflater.reset(); - } - } - - - private int getRsv(MessagePart uncompressedMessagePart) { - int result = uncompressedMessagePart.getRsv(); - if (!firstCompressedFrameWritten) { - result += RSV_BITMASK; - firstCompressedFrameWritten = true; - } - return result; - } - - - @Override - public void close() { - // There will always be a next transformation - next.close(); - inflater.end(); - deflater.end(); - } -} diff --git a/src/java/nginx/unit/websocket/ReadBufferOverflowException.java b/src/java/nginx/unit/websocket/ReadBufferOverflowException.java deleted file mode 100644 index 9ce7ac27..00000000 --- a/src/java/nginx/unit/websocket/ReadBufferOverflowException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; - -public class ReadBufferOverflowException extends IOException { - - private static final long serialVersionUID = 1L; - - private final int minBufferSize; - - public ReadBufferOverflowException(int minBufferSize) { - this.minBufferSize = minBufferSize; - } - - public int getMinBufferSize() { - return minBufferSize; - } -} diff --git a/src/java/nginx/unit/websocket/Transformation.java b/src/java/nginx/unit/websocket/Transformation.java deleted file mode 100644 index 45474c7d..00000000 --- a/src/java/nginx/unit/websocket/Transformation.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.List; - -import javax.websocket.Extension; - -/** - * The internal representation of the transformation that a WebSocket extension - * performs on a message. - */ -public interface Transformation { - - /** - * Sets the next transformation in the pipeline. - * @param t The next transformation - */ - void setNext(Transformation t); - - /** - * Validate that the RSV bit(s) required by this transformation are not - * being used by another extension. The implementation is expected to set - * any bits it requires before passing the set of in-use bits to the next - * transformation. - * - * @param i The RSV bits marked as in use so far as an int in the - * range zero to seven with RSV1 as the MSB and RSV3 as the - * LSB - * - * @return true if the combination of RSV bits used by the - * transformations in the pipeline do not conflict otherwise - * false - */ - boolean validateRsvBits(int i); - - /** - * Obtain the extension that describes the information to be returned to the - * client. - * - * @return The extension information that describes the parameters that have - * been agreed for this transformation - */ - Extension getExtensionResponse(); - - /** - * Obtain more input data. - * - * @param opCode The opcode for the frame currently being processed - * @param fin Is this the final frame in this WebSocket message? - * @param rsv The reserved bits for the frame currently being - * processed - * @param dest The buffer in which the data is to be written - * - * @return The result of trying to read more data from the transform - * - * @throws IOException If an I/O error occurs while reading data from the - * transform - */ - TransformationResult getMoreData(byte opCode, boolean fin, int rsv, ByteBuffer dest) throws IOException; - - /** - * Validates the RSV and opcode combination (assumed to have been extracted - * from a WebSocket Frame) for this extension. The implementation is - * expected to unset any RSV bits it has validated before passing the - * remaining RSV bits to the next transformation in the pipeline. - * - * @param rsv The RSV bits received as an int in the range zero to - * seven with RSV1 as the MSB and RSV3 as the LSB - * @param opCode The opCode received - * - * @return true if the RSV is valid otherwise - * false - */ - boolean validateRsv(int rsv, byte opCode); - - /** - * Takes the provided list of messages, transforms them, passes the - * transformed list on to the next transformation (if any) and then returns - * the resulting list of message parts after all of the transformations have - * been applied. - * - * @param messageParts The list of messages to be transformed - * - * @return The list of messages after this any any subsequent - * transformations have been applied. The size of the returned list - * may be bigger or smaller than the size of the input list - */ - List sendMessagePart(List messageParts); - - /** - * Clean-up any resources that were used by the transformation. - */ - void close(); -} diff --git a/src/java/nginx/unit/websocket/TransformationFactory.java b/src/java/nginx/unit/websocket/TransformationFactory.java deleted file mode 100644 index fac04555..00000000 --- a/src/java/nginx/unit/websocket/TransformationFactory.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.util.List; - -import javax.websocket.Extension; - -import org.apache.tomcat.util.res.StringManager; - -public class TransformationFactory { - - private static final StringManager sm = StringManager.getManager(TransformationFactory.class); - - private static final TransformationFactory factory = new TransformationFactory(); - - private TransformationFactory() { - // Hide default constructor - } - - public static TransformationFactory getInstance() { - return factory; - } - - public Transformation create(String name, List> preferences, - boolean isServer) { - if (PerMessageDeflate.NAME.equals(name)) { - return PerMessageDeflate.negotiate(preferences, isServer); - } - if (Constants.ALLOW_UNSUPPORTED_EXTENSIONS) { - return null; - } else { - throw new IllegalArgumentException( - sm.getString("transformerFactory.unsupportedExtension", name)); - } - } -} diff --git a/src/java/nginx/unit/websocket/TransformationResult.java b/src/java/nginx/unit/websocket/TransformationResult.java deleted file mode 100644 index 0de35e55..00000000 --- a/src/java/nginx/unit/websocket/TransformationResult.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -public enum TransformationResult { - /** - * The end of the available data was reached before the WebSocket frame was - * completely read. - */ - UNDERFLOW, - - /** - * The provided destination buffer was filled before all of the available - * data from the WebSocket frame could be processed. - */ - OVERFLOW, - - /** - * The end of the WebSocket frame was reached and all the data from that - * frame processed into the provided destination buffer. - */ - END_OF_FRAME -} diff --git a/src/java/nginx/unit/websocket/Util.java b/src/java/nginx/unit/websocket/Util.java deleted file mode 100644 index 5388431f..00000000 --- a/src/java/nginx/unit/websocket/Util.java +++ /dev/null @@ -1,666 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.InputStream; -import java.io.Reader; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.nio.ByteBuffer; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; - -import javax.websocket.CloseReason.CloseCode; -import javax.websocket.CloseReason.CloseCodes; -import javax.websocket.Decoder; -import javax.websocket.Decoder.Binary; -import javax.websocket.Decoder.BinaryStream; -import javax.websocket.Decoder.Text; -import javax.websocket.Decoder.TextStream; -import javax.websocket.DeploymentException; -import javax.websocket.Encoder; -import javax.websocket.EndpointConfig; -import javax.websocket.Extension; -import javax.websocket.MessageHandler; -import javax.websocket.PongMessage; -import javax.websocket.Session; - -import org.apache.tomcat.util.res.StringManager; -import nginx.unit.websocket.pojo.PojoMessageHandlerPartialBinary; -import nginx.unit.websocket.pojo.PojoMessageHandlerWholeBinary; -import nginx.unit.websocket.pojo.PojoMessageHandlerWholeText; - -/** - * Utility class for internal use only within the - * {@link nginx.unit.websocket} package. - */ -public class Util { - - private static final StringManager sm = StringManager.getManager(Util.class); - private static final Queue randoms = - new ConcurrentLinkedQueue<>(); - - private Util() { - // Hide default constructor - } - - - static boolean isControl(byte opCode) { - return (opCode & 0x08) != 0; - } - - - static boolean isText(byte opCode) { - return opCode == Constants.OPCODE_TEXT; - } - - - static boolean isContinuation(byte opCode) { - return opCode == Constants.OPCODE_CONTINUATION; - } - - - static CloseCode getCloseCode(int code) { - if (code > 2999 && code < 5000) { - return CloseCodes.getCloseCode(code); - } - switch (code) { - case 1000: - return CloseCodes.NORMAL_CLOSURE; - case 1001: - return CloseCodes.GOING_AWAY; - case 1002: - return CloseCodes.PROTOCOL_ERROR; - case 1003: - return CloseCodes.CANNOT_ACCEPT; - case 1004: - // Should not be used in a close frame - // return CloseCodes.RESERVED; - return CloseCodes.PROTOCOL_ERROR; - case 1005: - // Should not be used in a close frame - // return CloseCodes.NO_STATUS_CODE; - return CloseCodes.PROTOCOL_ERROR; - case 1006: - // Should not be used in a close frame - // return CloseCodes.CLOSED_ABNORMALLY; - return CloseCodes.PROTOCOL_ERROR; - case 1007: - return CloseCodes.NOT_CONSISTENT; - case 1008: - return CloseCodes.VIOLATED_POLICY; - case 1009: - return CloseCodes.TOO_BIG; - case 1010: - return CloseCodes.NO_EXTENSION; - case 1011: - return CloseCodes.UNEXPECTED_CONDITION; - case 1012: - // Not in RFC6455 - // return CloseCodes.SERVICE_RESTART; - return CloseCodes.PROTOCOL_ERROR; - case 1013: - // Not in RFC6455 - // return CloseCodes.TRY_AGAIN_LATER; - return CloseCodes.PROTOCOL_ERROR; - case 1015: - // Should not be used in a close frame - // return CloseCodes.TLS_HANDSHAKE_FAILURE; - return CloseCodes.PROTOCOL_ERROR; - default: - return CloseCodes.PROTOCOL_ERROR; - } - } - - - static byte[] generateMask() { - // SecureRandom is not thread-safe so need to make sure only one thread - // uses it at a time. In theory, the pool could grow to the same size - // as the number of request processing threads. In reality it will be - // a lot smaller. - - // Get a SecureRandom from the pool - SecureRandom sr = randoms.poll(); - - // If one isn't available, generate a new one - if (sr == null) { - try { - sr = SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - // Fall back to platform default - sr = new SecureRandom(); - } - } - - // Generate the mask - byte[] result = new byte[4]; - sr.nextBytes(result); - - // Put the SecureRandom back in the poll - randoms.add(sr); - - return result; - } - - - static Class getMessageType(MessageHandler listener) { - return Util.getGenericType(MessageHandler.class, - listener.getClass()).getClazz(); - } - - - private static Class getDecoderType(Class decoder) { - return Util.getGenericType(Decoder.class, decoder).getClazz(); - } - - - static Class getEncoderType(Class encoder) { - return Util.getGenericType(Encoder.class, encoder).getClazz(); - } - - - private static TypeResult getGenericType(Class type, - Class clazz) { - - // Look to see if this class implements the interface of interest - - // Get all the interfaces - Type[] interfaces = clazz.getGenericInterfaces(); - for (Type iface : interfaces) { - // Only need to check interfaces that use generics - if (iface instanceof ParameterizedType) { - ParameterizedType pi = (ParameterizedType) iface; - // Look for the interface of interest - if (pi.getRawType() instanceof Class) { - if (type.isAssignableFrom((Class) pi.getRawType())) { - return getTypeParameter( - clazz, pi.getActualTypeArguments()[0]); - } - } - } - } - - // Interface not found on this class. Look at the superclass. - @SuppressWarnings("unchecked") - Class superClazz = - (Class) clazz.getSuperclass(); - if (superClazz == null) { - // Finished looking up the class hierarchy without finding anything - return null; - } - - TypeResult superClassTypeResult = getGenericType(type, superClazz); - int dimension = superClassTypeResult.getDimension(); - if (superClassTypeResult.getIndex() == -1 && dimension == 0) { - // Superclass implements interface and defines explicit type for - // the interface of interest - return superClassTypeResult; - } - - if (superClassTypeResult.getIndex() > -1) { - // Superclass implements interface and defines unknown type for - // the interface of interest - // Map that unknown type to the generic types defined in this class - ParameterizedType superClassType = - (ParameterizedType) clazz.getGenericSuperclass(); - TypeResult result = getTypeParameter(clazz, - superClassType.getActualTypeArguments()[ - superClassTypeResult.getIndex()]); - result.incrementDimension(superClassTypeResult.getDimension()); - if (result.getClazz() != null && result.getDimension() > 0) { - superClassTypeResult = result; - } else { - return result; - } - } - - if (superClassTypeResult.getDimension() > 0) { - StringBuilder className = new StringBuilder(); - for (int i = 0; i < dimension; i++) { - className.append('['); - } - className.append('L'); - className.append(superClassTypeResult.getClazz().getCanonicalName()); - className.append(';'); - - Class arrayClazz; - try { - arrayClazz = Class.forName(className.toString()); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException(e); - } - - return new TypeResult(arrayClazz, -1, 0); - } - - // Error will be logged further up the call stack - return null; - } - - - /* - * For a generic parameter, return either the Class used or if the type - * is unknown, the index for the type in definition of the class - */ - private static TypeResult getTypeParameter(Class clazz, Type argType) { - if (argType instanceof Class) { - return new TypeResult((Class) argType, -1, 0); - } else if (argType instanceof ParameterizedType) { - return new TypeResult((Class)((ParameterizedType) argType).getRawType(), -1, 0); - } else if (argType instanceof GenericArrayType) { - Type arrayElementType = ((GenericArrayType) argType).getGenericComponentType(); - TypeResult result = getTypeParameter(clazz, arrayElementType); - result.incrementDimension(1); - return result; - } else { - TypeVariable[] tvs = clazz.getTypeParameters(); - for (int i = 0; i < tvs.length; i++) { - if (tvs[i].equals(argType)) { - return new TypeResult(null, i, 0); - } - } - return null; - } - } - - - public static boolean isPrimitive(Class clazz) { - if (clazz.isPrimitive()) { - return true; - } else if(clazz.equals(Boolean.class) || - clazz.equals(Byte.class) || - clazz.equals(Character.class) || - clazz.equals(Double.class) || - clazz.equals(Float.class) || - clazz.equals(Integer.class) || - clazz.equals(Long.class) || - clazz.equals(Short.class)) { - return true; - } - return false; - } - - - public static Object coerceToType(Class type, String value) { - if (type.equals(String.class)) { - return value; - } else if (type.equals(boolean.class) || type.equals(Boolean.class)) { - return Boolean.valueOf(value); - } else if (type.equals(byte.class) || type.equals(Byte.class)) { - return Byte.valueOf(value); - } else if (type.equals(char.class) || type.equals(Character.class)) { - return Character.valueOf(value.charAt(0)); - } else if (type.equals(double.class) || type.equals(Double.class)) { - return Double.valueOf(value); - } else if (type.equals(float.class) || type.equals(Float.class)) { - return Float.valueOf(value); - } else if (type.equals(int.class) || type.equals(Integer.class)) { - return Integer.valueOf(value); - } else if (type.equals(long.class) || type.equals(Long.class)) { - return Long.valueOf(value); - } else if (type.equals(short.class) || type.equals(Short.class)) { - return Short.valueOf(value); - } else { - throw new IllegalArgumentException(sm.getString( - "util.invalidType", value, type.getName())); - } - } - - - public static List getDecoders( - List> decoderClazzes) - throws DeploymentException { - - List result = new ArrayList<>(); - if (decoderClazzes != null) { - for (Class decoderClazz : decoderClazzes) { - // Need to instantiate decoder to ensure it is valid and that - // deployment can be failed if it is not - @SuppressWarnings("unused") - Decoder instance; - try { - instance = decoderClazz.getConstructor().newInstance(); - } catch (ReflectiveOperationException e) { - throw new DeploymentException( - sm.getString("pojoMethodMapping.invalidDecoder", - decoderClazz.getName()), e); - } - DecoderEntry entry = new DecoderEntry( - Util.getDecoderType(decoderClazz), decoderClazz); - result.add(entry); - } - } - - return result; - } - - - static Set getMessageHandlers(Class target, - MessageHandler listener, EndpointConfig endpointConfig, - Session session) { - - // Will never be more than 2 types - Set results = new HashSet<>(2); - - // Simple cases - handlers already accepts one of the types expected by - // the frame handling code - if (String.class.isAssignableFrom(target)) { - MessageHandlerResult result = - new MessageHandlerResult(listener, - MessageHandlerResultType.TEXT); - results.add(result); - } else if (ByteBuffer.class.isAssignableFrom(target)) { - MessageHandlerResult result = - new MessageHandlerResult(listener, - MessageHandlerResultType.BINARY); - results.add(result); - } else if (PongMessage.class.isAssignableFrom(target)) { - MessageHandlerResult result = - new MessageHandlerResult(listener, - MessageHandlerResultType.PONG); - results.add(result); - // Handler needs wrapping and optional decoder to convert it to one of - // the types expected by the frame handling code - } else if (byte[].class.isAssignableFrom(target)) { - boolean whole = MessageHandler.Whole.class.isAssignableFrom(listener.getClass()); - MessageHandlerResult result = new MessageHandlerResult( - whole ? new PojoMessageHandlerWholeBinary(listener, - getOnMessageMethod(listener), session, - endpointConfig, matchDecoders(target, endpointConfig, true), - new Object[1], 0, true, -1, false, -1) : - new PojoMessageHandlerPartialBinary(listener, - getOnMessagePartialMethod(listener), session, - new Object[2], 0, true, 1, -1, -1), - MessageHandlerResultType.BINARY); - results.add(result); - } else if (InputStream.class.isAssignableFrom(target)) { - MessageHandlerResult result = new MessageHandlerResult( - new PojoMessageHandlerWholeBinary(listener, - getOnMessageMethod(listener), session, - endpointConfig, matchDecoders(target, endpointConfig, true), - new Object[1], 0, true, -1, true, -1), - MessageHandlerResultType.BINARY); - results.add(result); - } else if (Reader.class.isAssignableFrom(target)) { - MessageHandlerResult result = new MessageHandlerResult( - new PojoMessageHandlerWholeText(listener, - getOnMessageMethod(listener), session, - endpointConfig, matchDecoders(target, endpointConfig, false), - new Object[1], 0, true, -1, -1), - MessageHandlerResultType.TEXT); - results.add(result); - } else { - // Handler needs wrapping and requires decoder to convert it to one - // of the types expected by the frame handling code - DecoderMatch decoderMatch = matchDecoders(target, endpointConfig); - Method m = getOnMessageMethod(listener); - if (decoderMatch.getBinaryDecoders().size() > 0) { - MessageHandlerResult result = new MessageHandlerResult( - new PojoMessageHandlerWholeBinary(listener, m, session, - endpointConfig, - decoderMatch.getBinaryDecoders(), new Object[1], - 0, false, -1, false, -1), - MessageHandlerResultType.BINARY); - results.add(result); - } - if (decoderMatch.getTextDecoders().size() > 0) { - MessageHandlerResult result = new MessageHandlerResult( - new PojoMessageHandlerWholeText(listener, m, session, - endpointConfig, - decoderMatch.getTextDecoders(), new Object[1], - 0, false, -1, -1), - MessageHandlerResultType.TEXT); - results.add(result); - } - } - - if (results.size() == 0) { - throw new IllegalArgumentException( - sm.getString("wsSession.unknownHandler", listener, target)); - } - - return results; - } - - private static List> matchDecoders(Class target, - EndpointConfig endpointConfig, boolean binary) { - DecoderMatch decoderMatch = matchDecoders(target, endpointConfig); - if (binary) { - if (decoderMatch.getBinaryDecoders().size() > 0) { - return decoderMatch.getBinaryDecoders(); - } - } else if (decoderMatch.getTextDecoders().size() > 0) { - return decoderMatch.getTextDecoders(); - } - return null; - } - - private static DecoderMatch matchDecoders(Class target, - EndpointConfig endpointConfig) { - DecoderMatch decoderMatch; - try { - List> decoders = - endpointConfig.getDecoders(); - List decoderEntries = getDecoders(decoders); - decoderMatch = new DecoderMatch(target, decoderEntries); - } catch (DeploymentException e) { - throw new IllegalArgumentException(e); - } - return decoderMatch; - } - - public static void parseExtensionHeader(List extensions, - String header) { - // The relevant ABNF for the Sec-WebSocket-Extensions is as follows: - // extension-list = 1#extension - // extension = extension-token *( ";" extension-param ) - // extension-token = registered-token - // registered-token = token - // extension-param = token [ "=" (token | quoted-string) ] - // ; When using the quoted-string syntax variant, the value - // ; after quoted-string unescaping MUST conform to the - // ; 'token' ABNF. - // - // The limiting of parameter values to tokens or "quoted tokens" makes - // the parsing of the header significantly simpler and allows a number - // of short-cuts to be taken. - - // Step one, split the header into individual extensions using ',' as a - // separator - String unparsedExtensions[] = header.split(","); - for (String unparsedExtension : unparsedExtensions) { - // Step two, split the extension into the registered name and - // parameter/value pairs using ';' as a separator - String unparsedParameters[] = unparsedExtension.split(";"); - WsExtension extension = new WsExtension(unparsedParameters[0].trim()); - - for (int i = 1; i < unparsedParameters.length; i++) { - int equalsPos = unparsedParameters[i].indexOf('='); - String name; - String value; - if (equalsPos == -1) { - name = unparsedParameters[i].trim(); - value = null; - } else { - name = unparsedParameters[i].substring(0, equalsPos).trim(); - value = unparsedParameters[i].substring(equalsPos + 1).trim(); - int len = value.length(); - if (len > 1) { - if (value.charAt(0) == '\"' && value.charAt(len - 1) == '\"') { - value = value.substring(1, value.length() - 1); - } - } - } - // Make sure value doesn't contain any of the delimiters since - // that would indicate something went wrong - if (containsDelims(name) || containsDelims(value)) { - throw new IllegalArgumentException(sm.getString( - "util.notToken", name, value)); - } - if (value != null && - (value.indexOf(',') > -1 || value.indexOf(';') > -1 || - value.indexOf('\"') > -1 || value.indexOf('=') > -1)) { - throw new IllegalArgumentException(sm.getString("", value)); - } - extension.addParameter(new WsExtensionParameter(name, value)); - } - extensions.add(extension); - } - } - - - private static boolean containsDelims(String input) { - if (input == null || input.length() == 0) { - return false; - } - for (char c : input.toCharArray()) { - switch (c) { - case ',': - case ';': - case '\"': - case '=': - return true; - default: - // NO_OP - } - - } - return false; - } - - private static Method getOnMessageMethod(MessageHandler listener) { - try { - return listener.getClass().getMethod("onMessage", Object.class); - } catch (NoSuchMethodException | SecurityException e) { - throw new IllegalArgumentException( - sm.getString("util.invalidMessageHandler"), e); - } - } - - private static Method getOnMessagePartialMethod(MessageHandler listener) { - try { - return listener.getClass().getMethod("onMessage", Object.class, Boolean.TYPE); - } catch (NoSuchMethodException | SecurityException e) { - throw new IllegalArgumentException( - sm.getString("util.invalidMessageHandler"), e); - } - } - - - public static class DecoderMatch { - - private final List> textDecoders = - new ArrayList<>(); - private final List> binaryDecoders = - new ArrayList<>(); - private final Class target; - - public DecoderMatch(Class target, List decoderEntries) { - this.target = target; - for (DecoderEntry decoderEntry : decoderEntries) { - if (decoderEntry.getClazz().isAssignableFrom(target)) { - if (Binary.class.isAssignableFrom( - decoderEntry.getDecoderClazz())) { - binaryDecoders.add(decoderEntry.getDecoderClazz()); - // willDecode() method means this decoder may or may not - // decode a message so need to carry on checking for - // other matches - } else if (BinaryStream.class.isAssignableFrom( - decoderEntry.getDecoderClazz())) { - binaryDecoders.add(decoderEntry.getDecoderClazz()); - // Stream decoders have to process the message so no - // more decoders can be matched - break; - } else if (Text.class.isAssignableFrom( - decoderEntry.getDecoderClazz())) { - textDecoders.add(decoderEntry.getDecoderClazz()); - // willDecode() method means this decoder may or may not - // decode a message so need to carry on checking for - // other matches - } else if (TextStream.class.isAssignableFrom( - decoderEntry.getDecoderClazz())) { - textDecoders.add(decoderEntry.getDecoderClazz()); - // Stream decoders have to process the message so no - // more decoders can be matched - break; - } else { - throw new IllegalArgumentException( - sm.getString("util.unknownDecoderType")); - } - } - } - } - - - public List> getTextDecoders() { - return textDecoders; - } - - - public List> getBinaryDecoders() { - return binaryDecoders; - } - - - public Class getTarget() { - return target; - } - - - public boolean hasMatches() { - return (textDecoders.size() > 0) || (binaryDecoders.size() > 0); - } - } - - - private static class TypeResult { - private final Class clazz; - private final int index; - private int dimension; - - public TypeResult(Class clazz, int index, int dimension) { - this.clazz= clazz; - this.index = index; - this.dimension = dimension; - } - - public Class getClazz() { - return clazz; - } - - public int getIndex() { - return index; - } - - public int getDimension() { - return dimension; - } - - public void incrementDimension(int inc) { - dimension += inc; - } - } -} diff --git a/src/java/nginx/unit/websocket/WrappedMessageHandler.java b/src/java/nginx/unit/websocket/WrappedMessageHandler.java deleted file mode 100644 index 2557a73e..00000000 --- a/src/java/nginx/unit/websocket/WrappedMessageHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import javax.websocket.MessageHandler; - -public interface WrappedMessageHandler { - long getMaxMessageSize(); - - MessageHandler getWrappedHandler(); -} diff --git a/src/java/nginx/unit/websocket/WsContainerProvider.java b/src/java/nginx/unit/websocket/WsContainerProvider.java deleted file mode 100644 index f8a404a1..00000000 --- a/src/java/nginx/unit/websocket/WsContainerProvider.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import javax.websocket.ContainerProvider; -import javax.websocket.WebSocketContainer; - -public class WsContainerProvider extends ContainerProvider { - - @Override - protected WebSocketContainer getContainer() { - return new WsWebSocketContainer(); - } -} diff --git a/src/java/nginx/unit/websocket/WsExtension.java b/src/java/nginx/unit/websocket/WsExtension.java deleted file mode 100644 index 3846feb1..00000000 --- a/src/java/nginx/unit/websocket/WsExtension.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.util.ArrayList; -import java.util.List; - -import javax.websocket.Extension; - -public class WsExtension implements Extension { - - private final String name; - private final List parameters = new ArrayList<>(); - - WsExtension(String name) { - this.name = name; - } - - void addParameter(Parameter parameter) { - parameters.add(parameter); - } - - @Override - public String getName() { - return name; - } - - @Override - public List getParameters() { - return parameters; - } -} diff --git a/src/java/nginx/unit/websocket/WsExtensionParameter.java b/src/java/nginx/unit/websocket/WsExtensionParameter.java deleted file mode 100644 index 9b82f1c7..00000000 --- a/src/java/nginx/unit/websocket/WsExtensionParameter.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import javax.websocket.Extension.Parameter; - -public class WsExtensionParameter implements Parameter { - - private final String name; - private final String value; - - WsExtensionParameter(String name, String value) { - this.name = name; - this.value = value; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getValue() { - return value; - } -} diff --git a/src/java/nginx/unit/websocket/WsFrameBase.java b/src/java/nginx/unit/websocket/WsFrameBase.java deleted file mode 100644 index 06d20bf4..00000000 --- a/src/java/nginx/unit/websocket/WsFrameBase.java +++ /dev/null @@ -1,1010 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.util.List; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; - -import javax.websocket.CloseReason; -import javax.websocket.CloseReason.CloseCodes; -import javax.websocket.Extension; -import javax.websocket.MessageHandler; -import javax.websocket.PongMessage; - -import org.apache.juli.logging.Log; -import org.apache.tomcat.util.ExceptionUtils; -import org.apache.tomcat.util.buf.Utf8Decoder; -import org.apache.tomcat.util.res.StringManager; - -/** - * Takes the ServletInputStream, processes the WebSocket frames it contains and - * extracts the messages. WebSocket Pings received will be responded to - * automatically without any action required by the application. - */ -public abstract class WsFrameBase { - - private static final StringManager sm = StringManager.getManager(WsFrameBase.class); - - // Connection level attributes - protected final WsSession wsSession; - protected final ByteBuffer inputBuffer; - private final Transformation transformation; - - // Attributes for control messages - // Control messages can appear in the middle of other messages so need - // separate attributes - private final ByteBuffer controlBufferBinary = ByteBuffer.allocate(125); - private final CharBuffer controlBufferText = CharBuffer.allocate(125); - - // Attributes of the current message - private final CharsetDecoder utf8DecoderControl = new Utf8Decoder(). - onMalformedInput(CodingErrorAction.REPORT). - onUnmappableCharacter(CodingErrorAction.REPORT); - private final CharsetDecoder utf8DecoderMessage = new Utf8Decoder(). - onMalformedInput(CodingErrorAction.REPORT). - onUnmappableCharacter(CodingErrorAction.REPORT); - private boolean continuationExpected = false; - private boolean textMessage = false; - private ByteBuffer messageBufferBinary; - private CharBuffer messageBufferText; - // Cache the message handler in force when the message starts so it is used - // consistently for the entire message - private MessageHandler binaryMsgHandler = null; - private MessageHandler textMsgHandler = null; - - // Attributes of the current frame - private boolean fin = false; - private int rsv = 0; - private byte opCode = 0; - private final byte[] mask = new byte[4]; - private int maskIndex = 0; - private long payloadLength = 0; - private volatile long payloadWritten = 0; - - // Attributes tracking state - private volatile State state = State.NEW_FRAME; - private volatile boolean open = true; - - private static final AtomicReferenceFieldUpdater READ_STATE_UPDATER = - AtomicReferenceFieldUpdater.newUpdater(WsFrameBase.class, ReadState.class, "readState"); - private volatile ReadState readState = ReadState.WAITING; - - public WsFrameBase(WsSession wsSession, Transformation transformation) { - inputBuffer = ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE); - inputBuffer.position(0).limit(0); - messageBufferBinary = ByteBuffer.allocate(wsSession.getMaxBinaryMessageBufferSize()); - messageBufferText = CharBuffer.allocate(wsSession.getMaxTextMessageBufferSize()); - this.wsSession = wsSession; - Transformation finalTransformation; - if (isMasked()) { - finalTransformation = new UnmaskTransformation(); - } else { - finalTransformation = new NoopTransformation(); - } - if (transformation == null) { - this.transformation = finalTransformation; - } else { - transformation.setNext(finalTransformation); - this.transformation = transformation; - } - } - - - protected void processInputBuffer() throws IOException { - while (!isSuspended()) { - wsSession.updateLastActive(); - if (state == State.NEW_FRAME) { - if (!processInitialHeader()) { - break; - } - // If a close frame has been received, no further data should - // have seen - if (!open) { - throw new IOException(sm.getString("wsFrame.closed")); - } - } - if (state == State.PARTIAL_HEADER) { - if (!processRemainingHeader()) { - break; - } - } - if (state == State.DATA) { - if (!processData()) { - break; - } - } - } - } - - - /** - * @return true if sufficient data was present to process all - * of the initial header - */ - private boolean processInitialHeader() throws IOException { - // Need at least two bytes of data to do this - if (inputBuffer.remaining() < 2) { - return false; - } - int b = inputBuffer.get(); - fin = (b & 0x80) != 0; - rsv = (b & 0x70) >>> 4; - opCode = (byte) (b & 0x0F); - if (!transformation.validateRsv(rsv, opCode)) { - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.wrongRsv", Integer.valueOf(rsv), Integer.valueOf(opCode)))); - } - - if (Util.isControl(opCode)) { - if (!fin) { - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.controlFragmented"))); - } - if (opCode != Constants.OPCODE_PING && - opCode != Constants.OPCODE_PONG && - opCode != Constants.OPCODE_CLOSE) { - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.invalidOpCode", Integer.valueOf(opCode)))); - } - } else { - if (continuationExpected) { - if (!Util.isContinuation(opCode)) { - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.noContinuation"))); - } - } else { - try { - if (opCode == Constants.OPCODE_BINARY) { - // New binary message - textMessage = false; - int size = wsSession.getMaxBinaryMessageBufferSize(); - if (size != messageBufferBinary.capacity()) { - messageBufferBinary = ByteBuffer.allocate(size); - } - binaryMsgHandler = wsSession.getBinaryMessageHandler(); - textMsgHandler = null; - } else if (opCode == Constants.OPCODE_TEXT) { - // New text message - textMessage = true; - int size = wsSession.getMaxTextMessageBufferSize(); - if (size != messageBufferText.capacity()) { - messageBufferText = CharBuffer.allocate(size); - } - binaryMsgHandler = null; - textMsgHandler = wsSession.getTextMessageHandler(); - } else { - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.invalidOpCode", Integer.valueOf(opCode)))); - } - } catch (IllegalStateException ise) { - // Thrown if the session is already closed - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.sessionClosed"))); - } - } - continuationExpected = !fin; - } - b = inputBuffer.get(); - // Client data must be masked - if ((b & 0x80) == 0 && isMasked()) { - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.notMasked"))); - } - payloadLength = b & 0x7F; - state = State.PARTIAL_HEADER; - if (getLog().isDebugEnabled()) { - getLog().debug(sm.getString("wsFrame.partialHeaderComplete", Boolean.toString(fin), - Integer.toString(rsv), Integer.toString(opCode), Long.toString(payloadLength))); - } - return true; - } - - - protected abstract boolean isMasked(); - protected abstract Log getLog(); - - - /** - * @return true if sufficient data was present to complete the - * processing of the header - */ - private boolean processRemainingHeader() throws IOException { - // Ignore the 2 bytes already read. 4 for the mask - int headerLength; - if (isMasked()) { - headerLength = 4; - } else { - headerLength = 0; - } - // Add additional bytes depending on length - if (payloadLength == 126) { - headerLength += 2; - } else if (payloadLength == 127) { - headerLength += 8; - } - if (inputBuffer.remaining() < headerLength) { - return false; - } - // Calculate new payload length if necessary - if (payloadLength == 126) { - payloadLength = byteArrayToLong(inputBuffer.array(), - inputBuffer.arrayOffset() + inputBuffer.position(), 2); - inputBuffer.position(inputBuffer.position() + 2); - } else if (payloadLength == 127) { - payloadLength = byteArrayToLong(inputBuffer.array(), - inputBuffer.arrayOffset() + inputBuffer.position(), 8); - inputBuffer.position(inputBuffer.position() + 8); - } - if (Util.isControl(opCode)) { - if (payloadLength > 125) { - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.controlPayloadTooBig", Long.valueOf(payloadLength)))); - } - if (!fin) { - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.controlNoFin"))); - } - } - if (isMasked()) { - inputBuffer.get(mask, 0, 4); - } - state = State.DATA; - return true; - } - - - private boolean processData() throws IOException { - boolean result; - if (Util.isControl(opCode)) { - result = processDataControl(); - } else if (textMessage) { - if (textMsgHandler == null) { - result = swallowInput(); - } else { - result = processDataText(); - } - } else { - if (binaryMsgHandler == null) { - result = swallowInput(); - } else { - result = processDataBinary(); - } - } - checkRoomPayload(); - return result; - } - - - private boolean processDataControl() throws IOException { - TransformationResult tr = transformation.getMoreData(opCode, fin, rsv, controlBufferBinary); - if (TransformationResult.UNDERFLOW.equals(tr)) { - return false; - } - // Control messages have fixed message size so - // TransformationResult.OVERFLOW is not possible here - - controlBufferBinary.flip(); - if (opCode == Constants.OPCODE_CLOSE) { - open = false; - String reason = null; - int code = CloseCodes.NORMAL_CLOSURE.getCode(); - if (controlBufferBinary.remaining() == 1) { - controlBufferBinary.clear(); - // Payload must be zero or 2+ bytes long - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.oneByteCloseCode"))); - } - if (controlBufferBinary.remaining() > 1) { - code = controlBufferBinary.getShort(); - if (controlBufferBinary.remaining() > 0) { - CoderResult cr = utf8DecoderControl.decode(controlBufferBinary, - controlBufferText, true); - if (cr.isError()) { - controlBufferBinary.clear(); - controlBufferText.clear(); - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.invalidUtf8Close"))); - } - // There will be no overflow as the output buffer is big - // enough. There will be no underflow as all the data is - // passed to the decoder in a single call. - controlBufferText.flip(); - reason = controlBufferText.toString(); - } - } - wsSession.onClose(new CloseReason(Util.getCloseCode(code), reason)); - } else if (opCode == Constants.OPCODE_PING) { - if (wsSession.isOpen()) { - wsSession.getBasicRemote().sendPong(controlBufferBinary); - } - } else if (opCode == Constants.OPCODE_PONG) { - MessageHandler.Whole mhPong = wsSession.getPongMessageHandler(); - if (mhPong != null) { - try { - mhPong.onMessage(new WsPongMessage(controlBufferBinary)); - } catch (Throwable t) { - handleThrowableOnSend(t); - } finally { - controlBufferBinary.clear(); - } - } - } else { - // Should have caught this earlier but just in case... - controlBufferBinary.clear(); - throw new WsIOException(new CloseReason( - CloseCodes.PROTOCOL_ERROR, - sm.getString("wsFrame.invalidOpCode", Integer.valueOf(opCode)))); - } - controlBufferBinary.clear(); - newFrame(); - return true; - } - - - @SuppressWarnings("unchecked") - protected void sendMessageText(boolean last) throws WsIOException { - if (textMsgHandler instanceof WrappedMessageHandler) { - long maxMessageSize = ((WrappedMessageHandler) textMsgHandler).getMaxMessageSize(); - if (maxMessageSize > -1 && messageBufferText.remaining() > maxMessageSize) { - throw new WsIOException(new CloseReason(CloseCodes.TOO_BIG, - sm.getString("wsFrame.messageTooBig", - Long.valueOf(messageBufferText.remaining()), - Long.valueOf(maxMessageSize)))); - } - } - - try { - if (textMsgHandler instanceof MessageHandler.Partial) { - ((MessageHandler.Partial) textMsgHandler) - .onMessage(messageBufferText.toString(), last); - } else { - // Caller ensures last == true if this branch is used - ((MessageHandler.Whole) textMsgHandler) - .onMessage(messageBufferText.toString()); - } - } catch (Throwable t) { - handleThrowableOnSend(t); - } finally { - messageBufferText.clear(); - } - } - - - private boolean processDataText() throws IOException { - // Copy the available data to the buffer - TransformationResult tr = transformation.getMoreData(opCode, fin, rsv, messageBufferBinary); - while (!TransformationResult.END_OF_FRAME.equals(tr)) { - // Frame not complete - we ran out of something - // Convert bytes to UTF-8 - messageBufferBinary.flip(); - while (true) { - CoderResult cr = utf8DecoderMessage.decode(messageBufferBinary, messageBufferText, - false); - if (cr.isError()) { - throw new WsIOException(new CloseReason( - CloseCodes.NOT_CONSISTENT, - sm.getString("wsFrame.invalidUtf8"))); - } else if (cr.isOverflow()) { - // Ran out of space in text buffer - flush it - if (usePartial()) { - messageBufferText.flip(); - sendMessageText(false); - messageBufferText.clear(); - } else { - throw new WsIOException(new CloseReason( - CloseCodes.TOO_BIG, - sm.getString("wsFrame.textMessageTooBig"))); - } - } else if (cr.isUnderflow()) { - // Compact what we have to create as much space as possible - messageBufferBinary.compact(); - - // Need more input - // What did we run out of? - if (TransformationResult.OVERFLOW.equals(tr)) { - // Ran out of message buffer - exit inner loop and - // refill - break; - } else { - // TransformationResult.UNDERFLOW - // Ran out of input data - get some more - return false; - } - } - } - // Read more input data - tr = transformation.getMoreData(opCode, fin, rsv, messageBufferBinary); - } - - messageBufferBinary.flip(); - boolean last = false; - // Frame is fully received - // Convert bytes to UTF-8 - while (true) { - CoderResult cr = utf8DecoderMessage.decode(messageBufferBinary, messageBufferText, - last); - if (cr.isError()) { - throw new WsIOException(new CloseReason( - CloseCodes.NOT_CONSISTENT, - sm.getString("wsFrame.invalidUtf8"))); - } else if (cr.isOverflow()) { - // Ran out of space in text buffer - flush it - if (usePartial()) { - messageBufferText.flip(); - sendMessageText(false); - messageBufferText.clear(); - } else { - throw new WsIOException(new CloseReason( - CloseCodes.TOO_BIG, - sm.getString("wsFrame.textMessageTooBig"))); - } - } else if (cr.isUnderflow() && !last) { - // End of frame and possible message as well. - - if (continuationExpected) { - // If partial messages are supported, send what we have - // managed to decode - if (usePartial()) { - messageBufferText.flip(); - sendMessageText(false); - messageBufferText.clear(); - } - messageBufferBinary.compact(); - newFrame(); - // Process next frame - return true; - } else { - // Make sure coder has flushed all output - last = true; - } - } else { - // End of message - messageBufferText.flip(); - sendMessageText(true); - - newMessage(); - return true; - } - } - } - - - private boolean processDataBinary() throws IOException { - // Copy the available data to the buffer - TransformationResult tr = transformation.getMoreData(opCode, fin, rsv, messageBufferBinary); - while (!TransformationResult.END_OF_FRAME.equals(tr)) { - // Frame not complete - what did we run out of? - if (TransformationResult.UNDERFLOW.equals(tr)) { - // Ran out of input data - get some more - return false; - } - - // Ran out of message buffer - flush it - if (!usePartial()) { - CloseReason cr = new CloseReason(CloseCodes.TOO_BIG, - sm.getString("wsFrame.bufferTooSmall", - Integer.valueOf(messageBufferBinary.capacity()), - Long.valueOf(payloadLength))); - throw new WsIOException(cr); - } - messageBufferBinary.flip(); - ByteBuffer copy = ByteBuffer.allocate(messageBufferBinary.limit()); - copy.put(messageBufferBinary); - copy.flip(); - sendMessageBinary(copy, false); - messageBufferBinary.clear(); - // Read more data - tr = transformation.getMoreData(opCode, fin, rsv, messageBufferBinary); - } - - // Frame is fully received - // Send the message if either: - // - partial messages are supported - // - the message is complete - if (usePartial() || !continuationExpected) { - messageBufferBinary.flip(); - ByteBuffer copy = ByteBuffer.allocate(messageBufferBinary.limit()); - copy.put(messageBufferBinary); - copy.flip(); - sendMessageBinary(copy, !continuationExpected); - messageBufferBinary.clear(); - } - - if (continuationExpected) { - // More data for this message expected, start a new frame - newFrame(); - } else { - // Message is complete, start a new message - newMessage(); - } - - return true; - } - - - private void handleThrowableOnSend(Throwable t) throws WsIOException { - ExceptionUtils.handleThrowable(t); - wsSession.getLocal().onError(wsSession, t); - CloseReason cr = new CloseReason(CloseCodes.CLOSED_ABNORMALLY, - sm.getString("wsFrame.ioeTriggeredClose")); - throw new WsIOException(cr); - } - - - @SuppressWarnings("unchecked") - protected void sendMessageBinary(ByteBuffer msg, boolean last) throws WsIOException { - if (binaryMsgHandler instanceof WrappedMessageHandler) { - long maxMessageSize = ((WrappedMessageHandler) binaryMsgHandler).getMaxMessageSize(); - if (maxMessageSize > -1 && msg.remaining() > maxMessageSize) { - throw new WsIOException(new CloseReason(CloseCodes.TOO_BIG, - sm.getString("wsFrame.messageTooBig", - Long.valueOf(msg.remaining()), - Long.valueOf(maxMessageSize)))); - } - } - try { - if (binaryMsgHandler instanceof MessageHandler.Partial) { - ((MessageHandler.Partial) binaryMsgHandler).onMessage(msg, last); - } else { - // Caller ensures last == true if this branch is used - ((MessageHandler.Whole) binaryMsgHandler).onMessage(msg); - } - } catch (Throwable t) { - handleThrowableOnSend(t); - } - } - - - private void newMessage() { - messageBufferBinary.clear(); - messageBufferText.clear(); - utf8DecoderMessage.reset(); - continuationExpected = false; - newFrame(); - } - - - private void newFrame() { - if (inputBuffer.remaining() == 0) { - inputBuffer.position(0).limit(0); - } - - maskIndex = 0; - payloadWritten = 0; - state = State.NEW_FRAME; - - // These get reset in processInitialHeader() - // fin, rsv, opCode, payloadLength, mask - - checkRoomHeaders(); - } - - - private void checkRoomHeaders() { - // Is the start of the current frame too near the end of the input - // buffer? - if (inputBuffer.capacity() - inputBuffer.position() < 131) { - // Limit based on a control frame with a full payload - makeRoom(); - } - } - - - private void checkRoomPayload() { - if (inputBuffer.capacity() - inputBuffer.position() - payloadLength + payloadWritten < 0) { - makeRoom(); - } - } - - - private void makeRoom() { - inputBuffer.compact(); - inputBuffer.flip(); - } - - - private boolean usePartial() { - if (Util.isControl(opCode)) { - return false; - } else if (textMessage) { - return textMsgHandler instanceof MessageHandler.Partial; - } else { - // Must be binary - return binaryMsgHandler instanceof MessageHandler.Partial; - } - } - - - private boolean swallowInput() { - long toSkip = Math.min(payloadLength - payloadWritten, inputBuffer.remaining()); - inputBuffer.position(inputBuffer.position() + (int) toSkip); - payloadWritten += toSkip; - if (payloadWritten == payloadLength) { - if (continuationExpected) { - newFrame(); - } else { - newMessage(); - } - return true; - } else { - return false; - } - } - - - protected static long byteArrayToLong(byte[] b, int start, int len) throws IOException { - if (len > 8) { - throw new IOException(sm.getString("wsFrame.byteToLongFail", Long.valueOf(len))); - } - int shift = 0; - long result = 0; - for (int i = start + len - 1; i >= start; i--) { - result = result + ((b[i] & 0xFF) << shift); - shift += 8; - } - return result; - } - - - protected boolean isOpen() { - return open; - } - - - protected Transformation getTransformation() { - return transformation; - } - - - private enum State { - NEW_FRAME, PARTIAL_HEADER, DATA - } - - - /** - * WAITING - not suspended - * Server case: waiting for a notification that data - * is ready to be read from the socket, the socket is - * registered to the poller - * Client case: data has been read from the socket and - * is waiting for data to be processed - * PROCESSING - not suspended - * Server case: reading from the socket and processing - * the data - * Client case: processing the data if such has - * already been read and more data will be read from - * the socket - * SUSPENDING_WAIT - suspended, a call to suspend() was made while in - * WAITING state. A call to resume() will do nothing - * and will transition to WAITING state - * SUSPENDING_PROCESS - suspended, a call to suspend() was made while in - * PROCESSING state. A call to resume() will do - * nothing and will transition to PROCESSING state - * SUSPENDED - suspended - * Server case: processing data finished - * (SUSPENDING_PROCESS) / a notification was received - * that data is ready to be read from the socket - * (SUSPENDING_WAIT), socket is not registered to the - * poller - * Client case: processing data finished - * (SUSPENDING_PROCESS) / data has been read from the - * socket and is available for processing - * (SUSPENDING_WAIT) - * A call to resume() will: - * Server case: register the socket to the poller - * Client case: resume data processing - * CLOSING - not suspended, a close will be send - * - *
-     *     resume           data to be        resume
-     *     no action        processed         no action
-     *  |---------------| |---------------| |----------|
-     *  |               v |               v v          |
-     *  |  |----------WAITING --------PROCESSING----|  |
-     *  |  |             ^   processing             |  |
-     *  |  |             |   finished               |  |
-     *  |  |             |                          |  |
-     *  | suspend        |                     suspend |
-     *  |  |             |                          |  |
-     *  |  |          resume                        |  |
-     *  |  |    register socket to poller (server)  |  |
-     *  |  |    resume data processing (client)     |  |
-     *  |  |             |                          |  |
-     *  |  v             |                          v  |
-     * SUSPENDING_WAIT   |                  SUSPENDING_PROCESS
-     *  |                |                             |
-     *  | data available |        processing finished  |
-     *  |------------- SUSPENDED ----------------------|
-     * 
- */ - protected enum ReadState { - WAITING (false), - PROCESSING (false), - SUSPENDING_WAIT (true), - SUSPENDING_PROCESS(true), - SUSPENDED (true), - CLOSING (false); - - private final boolean isSuspended; - - ReadState(boolean isSuspended) { - this.isSuspended = isSuspended; - } - - public boolean isSuspended() { - return isSuspended; - } - } - - public void suspend() { - while (true) { - switch (readState) { - case WAITING: - if (!READ_STATE_UPDATER.compareAndSet(this, ReadState.WAITING, - ReadState.SUSPENDING_WAIT)) { - continue; - } - return; - case PROCESSING: - if (!READ_STATE_UPDATER.compareAndSet(this, ReadState.PROCESSING, - ReadState.SUSPENDING_PROCESS)) { - continue; - } - return; - case SUSPENDING_WAIT: - if (readState != ReadState.SUSPENDING_WAIT) { - continue; - } else { - if (getLog().isWarnEnabled()) { - getLog().warn(sm.getString("wsFrame.suspendRequested")); - } - } - return; - case SUSPENDING_PROCESS: - if (readState != ReadState.SUSPENDING_PROCESS) { - continue; - } else { - if (getLog().isWarnEnabled()) { - getLog().warn(sm.getString("wsFrame.suspendRequested")); - } - } - return; - case SUSPENDED: - if (readState != ReadState.SUSPENDED) { - continue; - } else { - if (getLog().isWarnEnabled()) { - getLog().warn(sm.getString("wsFrame.alreadySuspended")); - } - } - return; - case CLOSING: - return; - default: - throw new IllegalStateException(sm.getString("wsFrame.illegalReadState", state)); - } - } - } - - public void resume() { - while (true) { - switch (readState) { - case WAITING: - if (readState != ReadState.WAITING) { - continue; - } else { - if (getLog().isWarnEnabled()) { - getLog().warn(sm.getString("wsFrame.alreadyResumed")); - } - } - return; - case PROCESSING: - if (readState != ReadState.PROCESSING) { - continue; - } else { - if (getLog().isWarnEnabled()) { - getLog().warn(sm.getString("wsFrame.alreadyResumed")); - } - } - return; - case SUSPENDING_WAIT: - if (!READ_STATE_UPDATER.compareAndSet(this, ReadState.SUSPENDING_WAIT, - ReadState.WAITING)) { - continue; - } - return; - case SUSPENDING_PROCESS: - if (!READ_STATE_UPDATER.compareAndSet(this, ReadState.SUSPENDING_PROCESS, - ReadState.PROCESSING)) { - continue; - } - return; - case SUSPENDED: - if (!READ_STATE_UPDATER.compareAndSet(this, ReadState.SUSPENDED, - ReadState.WAITING)) { - continue; - } - resumeProcessing(); - return; - case CLOSING: - return; - default: - throw new IllegalStateException(sm.getString("wsFrame.illegalReadState", state)); - } - } - } - - protected boolean isSuspended() { - return readState.isSuspended(); - } - - protected ReadState getReadState() { - return readState; - } - - protected void changeReadState(ReadState newState) { - READ_STATE_UPDATER.set(this, newState); - } - - protected boolean changeReadState(ReadState oldState, ReadState newState) { - return READ_STATE_UPDATER.compareAndSet(this, oldState, newState); - } - - /** - * This method will be invoked when the read operation is resumed. - * As the suspend of the read operation can be invoked at any time, when - * implementing this method one should consider that there might still be - * data remaining into the internal buffers that needs to be processed - * before reading again from the socket. - */ - protected abstract void resumeProcessing(); - - - private abstract class TerminalTransformation implements Transformation { - - @Override - public boolean validateRsvBits(int i) { - // Terminal transformations don't use RSV bits and there is no next - // transformation so always return true. - return true; - } - - @Override - public Extension getExtensionResponse() { - // Return null since terminal transformations are not extensions - return null; - } - - @Override - public void setNext(Transformation t) { - // NO-OP since this is the terminal transformation - } - - /** - * {@inheritDoc} - *

- * Anything other than a value of zero for rsv is invalid. - */ - @Override - public boolean validateRsv(int rsv, byte opCode) { - return rsv == 0; - } - - @Override - public void close() { - // NO-OP for the terminal transformations - } - } - - - /** - * For use by the client implementation that needs to obtain payload data - * without the need for unmasking. - */ - private final class NoopTransformation extends TerminalTransformation { - - @Override - public TransformationResult getMoreData(byte opCode, boolean fin, int rsv, - ByteBuffer dest) { - // opCode is ignored as the transformation is the same for all - // opCodes - // rsv is ignored as it known to be zero at this point - long toWrite = Math.min(payloadLength - payloadWritten, inputBuffer.remaining()); - toWrite = Math.min(toWrite, dest.remaining()); - - int orgLimit = inputBuffer.limit(); - inputBuffer.limit(inputBuffer.position() + (int) toWrite); - dest.put(inputBuffer); - inputBuffer.limit(orgLimit); - payloadWritten += toWrite; - - if (payloadWritten == payloadLength) { - return TransformationResult.END_OF_FRAME; - } else if (inputBuffer.remaining() == 0) { - return TransformationResult.UNDERFLOW; - } else { - // !dest.hasRemaining() - return TransformationResult.OVERFLOW; - } - } - - - @Override - public List sendMessagePart(List messageParts) { - // TODO Masking should move to this method - // NO-OP send so simply return the message unchanged. - return messageParts; - } - } - - - /** - * For use by the server implementation that needs to obtain payload data - * and unmask it before any further processing. - */ - private final class UnmaskTransformation extends TerminalTransformation { - - @Override - public TransformationResult getMoreData(byte opCode, boolean fin, int rsv, - ByteBuffer dest) { - // opCode is ignored as the transformation is the same for all - // opCodes - // rsv is ignored as it known to be zero at this point - while (payloadWritten < payloadLength && inputBuffer.remaining() > 0 && - dest.hasRemaining()) { - byte b = (byte) ((inputBuffer.get() ^ mask[maskIndex]) & 0xFF); - maskIndex++; - if (maskIndex == 4) { - maskIndex = 0; - } - payloadWritten++; - dest.put(b); - } - if (payloadWritten == payloadLength) { - return TransformationResult.END_OF_FRAME; - } else if (inputBuffer.remaining() == 0) { - return TransformationResult.UNDERFLOW; - } else { - // !dest.hasRemaining() - return TransformationResult.OVERFLOW; - } - } - - @Override - public List sendMessagePart(List messageParts) { - // NO-OP send so simply return the message unchanged. - return messageParts; - } - } -} diff --git a/src/java/nginx/unit/websocket/WsFrameClient.java b/src/java/nginx/unit/websocket/WsFrameClient.java deleted file mode 100644 index 3174c766..00000000 --- a/src/java/nginx/unit/websocket/WsFrameClient.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.EOFException; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; - -import javax.websocket.CloseReason; -import javax.websocket.CloseReason.CloseCodes; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.util.res.StringManager; - -public class WsFrameClient extends WsFrameBase { - - private final Log log = LogFactory.getLog(WsFrameClient.class); // must not be static - private static final StringManager sm = StringManager.getManager(WsFrameClient.class); - - private final AsyncChannelWrapper channel; - private final CompletionHandler handler; - // Not final as it may need to be re-sized - private volatile ByteBuffer response; - - public WsFrameClient(ByteBuffer response, AsyncChannelWrapper channel, WsSession wsSession, - Transformation transformation) { - super(wsSession, transformation); - this.response = response; - this.channel = channel; - this.handler = new WsFrameClientCompletionHandler(); - } - - - void startInputProcessing() { - try { - processSocketRead(); - } catch (IOException e) { - close(e); - } - } - - - private void processSocketRead() throws IOException { - while (true) { - switch (getReadState()) { - case WAITING: - if (!changeReadState(ReadState.WAITING, ReadState.PROCESSING)) { - continue; - } - while (response.hasRemaining()) { - if (isSuspended()) { - if (!changeReadState(ReadState.SUSPENDING_PROCESS, ReadState.SUSPENDED)) { - continue; - } - // There is still data available in the response buffer - // Return here so that the response buffer will not be - // cleared and there will be no data read from the - // socket. Thus when the read operation is resumed first - // the data left in the response buffer will be consumed - // and then a new socket read will be performed - return; - } - inputBuffer.mark(); - inputBuffer.position(inputBuffer.limit()).limit(inputBuffer.capacity()); - - int toCopy = Math.min(response.remaining(), inputBuffer.remaining()); - - // Copy remaining bytes read in HTTP phase to input buffer used by - // frame processing - - int orgLimit = response.limit(); - response.limit(response.position() + toCopy); - inputBuffer.put(response); - response.limit(orgLimit); - - inputBuffer.limit(inputBuffer.position()).reset(); - - // Process the data we have - processInputBuffer(); - } - response.clear(); - - // Get some more data - if (isOpen()) { - channel.read(response, null, handler); - } else { - changeReadState(ReadState.CLOSING); - } - return; - case SUSPENDING_WAIT: - if (!changeReadState(ReadState.SUSPENDING_WAIT, ReadState.SUSPENDED)) { - continue; - } - return; - default: - throw new IllegalStateException( - sm.getString("wsFrameServer.illegalReadState", getReadState())); - } - } - } - - - private final void close(Throwable t) { - changeReadState(ReadState.CLOSING); - CloseReason cr; - if (t instanceof WsIOException) { - cr = ((WsIOException) t).getCloseReason(); - } else { - cr = new CloseReason(CloseCodes.CLOSED_ABNORMALLY, t.getMessage()); - } - - try { - wsSession.close(cr); - } catch (IOException ignore) { - // Ignore - } - } - - - @Override - protected boolean isMasked() { - // Data is from the server so it is not masked - return false; - } - - - @Override - protected Log getLog() { - return log; - } - - private class WsFrameClientCompletionHandler implements CompletionHandler { - - @Override - public void completed(Integer result, Void attachment) { - if (result.intValue() == -1) { - // BZ 57762. A dropped connection will get reported as EOF - // rather than as an error so handle it here. - if (isOpen()) { - // No close frame was received - close(new EOFException()); - } - // No data to process - return; - } - response.flip(); - doResumeProcessing(true); - } - - @Override - public void failed(Throwable exc, Void attachment) { - if (exc instanceof ReadBufferOverflowException) { - // response will be empty if this exception is thrown - response = ByteBuffer - .allocate(((ReadBufferOverflowException) exc).getMinBufferSize()); - response.flip(); - doResumeProcessing(false); - } else { - close(exc); - } - } - - private void doResumeProcessing(boolean checkOpenOnError) { - while (true) { - switch (getReadState()) { - case PROCESSING: - if (!changeReadState(ReadState.PROCESSING, ReadState.WAITING)) { - continue; - } - resumeProcessing(checkOpenOnError); - return; - case SUSPENDING_PROCESS: - if (!changeReadState(ReadState.SUSPENDING_PROCESS, ReadState.SUSPENDED)) { - continue; - } - return; - default: - throw new IllegalStateException( - sm.getString("wsFrame.illegalReadState", getReadState())); - } - } - } - } - - - @Override - protected void resumeProcessing() { - resumeProcessing(true); - } - - private void resumeProcessing(boolean checkOpenOnError) { - try { - processSocketRead(); - } catch (IOException e) { - if (checkOpenOnError) { - // Only send a close message on an IOException if the client - // has not yet received a close control message from the server - // as the IOException may be in response to the client - // continuing to send a message after the server sent a close - // control message. - if (isOpen()) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("wsFrameClient.ioe"), e); - } - close(e); - } - } else { - close(e); - } - } - } -} diff --git a/src/java/nginx/unit/websocket/WsHandshakeResponse.java b/src/java/nginx/unit/websocket/WsHandshakeResponse.java deleted file mode 100644 index 6e57ffd5..00000000 --- a/src/java/nginx/unit/websocket/WsHandshakeResponse.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import javax.websocket.HandshakeResponse; - -import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap; - -/** - * Represents the response to a WebSocket handshake. - */ -public class WsHandshakeResponse implements HandshakeResponse { - - private final Map> headers = new CaseInsensitiveKeyMap<>(); - - - public WsHandshakeResponse() { - } - - - public WsHandshakeResponse(Map> headers) { - for (Entry> entry : headers.entrySet()) { - if (this.headers.containsKey(entry.getKey())) { - this.headers.get(entry.getKey()).addAll(entry.getValue()); - } else { - List values = new ArrayList<>(entry.getValue()); - this.headers.put(entry.getKey(), values); - } - } - } - - - @Override - public Map> getHeaders() { - return headers; - } -} diff --git a/src/java/nginx/unit/websocket/WsIOException.java b/src/java/nginx/unit/websocket/WsIOException.java deleted file mode 100644 index 0362dc1d..00000000 --- a/src/java/nginx/unit/websocket/WsIOException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; - -import javax.websocket.CloseReason; - -/** - * Allows the WebSocket implementation to throw an {@link IOException} that - * includes a {@link CloseReason} specific to the error that can be passed back - * to the client. - */ -public class WsIOException extends IOException { - - private static final long serialVersionUID = 1L; - - private final CloseReason closeReason; - - public WsIOException(CloseReason closeReason) { - this.closeReason = closeReason; - } - - public CloseReason getCloseReason() { - return closeReason; - } -} diff --git a/src/java/nginx/unit/websocket/WsPongMessage.java b/src/java/nginx/unit/websocket/WsPongMessage.java deleted file mode 100644 index 531bcda9..00000000 --- a/src/java/nginx/unit/websocket/WsPongMessage.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.nio.ByteBuffer; - -import javax.websocket.PongMessage; - -public class WsPongMessage implements PongMessage { - - private final ByteBuffer applicationData; - - - public WsPongMessage(ByteBuffer applicationData) { - byte[] dst = new byte[applicationData.limit()]; - applicationData.get(dst); - this.applicationData = ByteBuffer.wrap(dst); - } - - - @Override - public ByteBuffer getApplicationData() { - return applicationData; - } -} diff --git a/src/java/nginx/unit/websocket/WsRemoteEndpointAsync.java b/src/java/nginx/unit/websocket/WsRemoteEndpointAsync.java deleted file mode 100644 index 0ea20795..00000000 --- a/src/java/nginx/unit/websocket/WsRemoteEndpointAsync.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.nio.ByteBuffer; -import java.util.concurrent.Future; - -import javax.websocket.RemoteEndpoint; -import javax.websocket.SendHandler; - -public class WsRemoteEndpointAsync extends WsRemoteEndpointBase - implements RemoteEndpoint.Async { - - WsRemoteEndpointAsync(WsRemoteEndpointImplBase base) { - super(base); - } - - - @Override - public long getSendTimeout() { - return base.getSendTimeout(); - } - - - @Override - public void setSendTimeout(long timeout) { - base.setSendTimeout(timeout); - } - - - @Override - public void sendText(String text, SendHandler completion) { - base.sendStringByCompletion(text, completion); - } - - - @Override - public Future sendText(String text) { - return base.sendStringByFuture(text); - } - - - @Override - public Future sendBinary(ByteBuffer data) { - return base.sendBytesByFuture(data); - } - - - @Override - public void sendBinary(ByteBuffer data, SendHandler completion) { - base.sendBytesByCompletion(data, completion); - } - - - @Override - public Future sendObject(Object obj) { - return base.sendObjectByFuture(obj); - } - - - @Override - public void sendObject(Object obj, SendHandler completion) { - base.sendObjectByCompletion(obj, completion); - } -} diff --git a/src/java/nginx/unit/websocket/WsRemoteEndpointBase.java b/src/java/nginx/unit/websocket/WsRemoteEndpointBase.java deleted file mode 100644 index 21cb2040..00000000 --- a/src/java/nginx/unit/websocket/WsRemoteEndpointBase.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; -import java.nio.ByteBuffer; - -import javax.websocket.RemoteEndpoint; - -public abstract class WsRemoteEndpointBase implements RemoteEndpoint { - - protected final WsRemoteEndpointImplBase base; - - - WsRemoteEndpointBase(WsRemoteEndpointImplBase base) { - this.base = base; - } - - - @Override - public final void setBatchingAllowed(boolean batchingAllowed) throws IOException { - base.setBatchingAllowed(batchingAllowed); - } - - - @Override - public final boolean getBatchingAllowed() { - return base.getBatchingAllowed(); - } - - - @Override - public final void flushBatch() throws IOException { - base.flushBatch(); - } - - - @Override - public final void sendPing(ByteBuffer applicationData) throws IOException, - IllegalArgumentException { - base.sendPing(applicationData); - } - - - @Override - public final void sendPong(ByteBuffer applicationData) throws IOException, - IllegalArgumentException { - base.sendPong(applicationData); - } -} diff --git a/src/java/nginx/unit/websocket/WsRemoteEndpointBasic.java b/src/java/nginx/unit/websocket/WsRemoteEndpointBasic.java deleted file mode 100644 index 2a93cc7b..00000000 --- a/src/java/nginx/unit/websocket/WsRemoteEndpointBasic.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.nio.ByteBuffer; - -import javax.websocket.EncodeException; -import javax.websocket.RemoteEndpoint; - -public class WsRemoteEndpointBasic extends WsRemoteEndpointBase - implements RemoteEndpoint.Basic { - - WsRemoteEndpointBasic(WsRemoteEndpointImplBase base) { - super(base); - } - - - @Override - public void sendText(String text) throws IOException { - base.sendString(text); - } - - - @Override - public void sendBinary(ByteBuffer data) throws IOException { - base.sendBytes(data); - } - - - @Override - public void sendText(String fragment, boolean isLast) throws IOException { - base.sendPartialString(fragment, isLast); - } - - - @Override - public void sendBinary(ByteBuffer partialByte, boolean isLast) - throws IOException { - base.sendPartialBytes(partialByte, isLast); - } - - - @Override - public OutputStream getSendStream() throws IOException { - return base.getSendStream(); - } - - - @Override - public Writer getSendWriter() throws IOException { - return base.getSendWriter(); - } - - - @Override - public void sendObject(Object o) throws IOException, EncodeException { - base.sendObject(o); - } -} diff --git a/src/java/nginx/unit/websocket/WsRemoteEndpointImplBase.java b/src/java/nginx/unit/websocket/WsRemoteEndpointImplBase.java deleted file mode 100644 index d451db7d..00000000 --- a/src/java/nginx/unit/websocket/WsRemoteEndpointImplBase.java +++ /dev/null @@ -1,1234 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.net.SocketTimeoutException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.websocket.CloseReason; -import javax.websocket.CloseReason.CloseCodes; -import javax.websocket.DeploymentException; -import javax.websocket.EncodeException; -import javax.websocket.Encoder; -import javax.websocket.EndpointConfig; -import javax.websocket.RemoteEndpoint; -import javax.websocket.SendHandler; -import javax.websocket.SendResult; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.util.buf.Utf8Encoder; -import org.apache.tomcat.util.res.StringManager; - -import nginx.unit.Request; - -public abstract class WsRemoteEndpointImplBase implements RemoteEndpoint { - - private static final StringManager sm = - StringManager.getManager(WsRemoteEndpointImplBase.class); - - protected static final SendResult SENDRESULT_OK = new SendResult(); - - private final Log log = LogFactory.getLog(WsRemoteEndpointImplBase.class); // must not be static - - private final StateMachine stateMachine = new StateMachine(); - - private final IntermediateMessageHandler intermediateMessageHandler = - new IntermediateMessageHandler(this); - - private Transformation transformation = null; - private final Semaphore messagePartInProgress = new Semaphore(1); - private final Queue messagePartQueue = new ArrayDeque<>(); - private final Object messagePartLock = new Object(); - - // State - private volatile boolean closed = false; - private boolean fragmented = false; - private boolean nextFragmented = false; - private boolean text = false; - private boolean nextText = false; - - // Max size of WebSocket header is 14 bytes - private final ByteBuffer headerBuffer = ByteBuffer.allocate(14); - private final ByteBuffer outputBuffer = ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE); - private final CharsetEncoder encoder = new Utf8Encoder(); - private final ByteBuffer encoderBuffer = ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE); - private final AtomicBoolean batchingAllowed = new AtomicBoolean(false); - private volatile long sendTimeout = -1; - private WsSession wsSession; - private List encoderEntries = new ArrayList<>(); - - private Request request; - - - protected void setTransformation(Transformation transformation) { - this.transformation = transformation; - } - - - public long getSendTimeout() { - return sendTimeout; - } - - - public void setSendTimeout(long timeout) { - this.sendTimeout = timeout; - } - - - @Override - public void setBatchingAllowed(boolean batchingAllowed) throws IOException { - boolean oldValue = this.batchingAllowed.getAndSet(batchingAllowed); - - if (oldValue && !batchingAllowed) { - flushBatch(); - } - } - - - @Override - public boolean getBatchingAllowed() { - return batchingAllowed.get(); - } - - - @Override - public void flushBatch() throws IOException { - sendMessageBlock(Constants.INTERNAL_OPCODE_FLUSH, null, true); - } - - - public void sendBytes(ByteBuffer data) throws IOException { - if (data == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullData")); - } - stateMachine.binaryStart(); - sendMessageBlock(Constants.OPCODE_BINARY, data, true); - stateMachine.complete(true); - } - - - public Future sendBytesByFuture(ByteBuffer data) { - FutureToSendHandler f2sh = new FutureToSendHandler(wsSession); - sendBytesByCompletion(data, f2sh); - return f2sh; - } - - - public void sendBytesByCompletion(ByteBuffer data, SendHandler handler) { - if (data == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullData")); - } - if (handler == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullHandler")); - } - StateUpdateSendHandler sush = new StateUpdateSendHandler(handler, stateMachine); - stateMachine.binaryStart(); - startMessage(Constants.OPCODE_BINARY, data, true, sush); - } - - - public void sendPartialBytes(ByteBuffer partialByte, boolean last) - throws IOException { - if (partialByte == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullData")); - } - stateMachine.binaryPartialStart(); - sendMessageBlock(Constants.OPCODE_BINARY, partialByte, last); - stateMachine.complete(last); - } - - - @Override - public void sendPing(ByteBuffer applicationData) throws IOException, - IllegalArgumentException { - if (applicationData.remaining() > 125) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.tooMuchData")); - } - sendMessageBlock(Constants.OPCODE_PING, applicationData, true); - } - - - @Override - public void sendPong(ByteBuffer applicationData) throws IOException, - IllegalArgumentException { - if (applicationData.remaining() > 125) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.tooMuchData")); - } - sendMessageBlock(Constants.OPCODE_PONG, applicationData, true); - } - - - public void sendString(String text) throws IOException { - if (text == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullData")); - } - stateMachine.textStart(); - sendMessageBlock(CharBuffer.wrap(text), true); - } - - - public Future sendStringByFuture(String text) { - FutureToSendHandler f2sh = new FutureToSendHandler(wsSession); - sendStringByCompletion(text, f2sh); - return f2sh; - } - - - public void sendStringByCompletion(String text, SendHandler handler) { - if (text == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullData")); - } - if (handler == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullHandler")); - } - stateMachine.textStart(); - TextMessageSendHandler tmsh = new TextMessageSendHandler(handler, - CharBuffer.wrap(text), true, encoder, encoderBuffer, this); - tmsh.write(); - // TextMessageSendHandler will update stateMachine when it completes - } - - - public void sendPartialString(String fragment, boolean isLast) - throws IOException { - if (fragment == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullData")); - } - stateMachine.textPartialStart(); - sendMessageBlock(CharBuffer.wrap(fragment), isLast); - } - - - public OutputStream getSendStream() { - stateMachine.streamStart(); - return new WsOutputStream(this); - } - - - public Writer getSendWriter() { - stateMachine.writeStart(); - return new WsWriter(this); - } - - - void sendMessageBlock(CharBuffer part, boolean last) throws IOException { - long timeoutExpiry = getTimeoutExpiry(); - boolean isDone = false; - while (!isDone) { - encoderBuffer.clear(); - CoderResult cr = encoder.encode(part, encoderBuffer, true); - if (cr.isError()) { - throw new IllegalArgumentException(cr.toString()); - } - isDone = !cr.isOverflow(); - encoderBuffer.flip(); - sendMessageBlock(Constants.OPCODE_TEXT, encoderBuffer, last && isDone, timeoutExpiry); - } - stateMachine.complete(last); - } - - - void sendMessageBlock(byte opCode, ByteBuffer payload, boolean last) - throws IOException { - sendMessageBlock(opCode, payload, last, getTimeoutExpiry()); - } - - - private long getTimeoutExpiry() { - // Get the timeout before we send the message. The message may - // trigger a session close and depending on timing the client - // session may close before we can read the timeout. - long timeout = getBlockingSendTimeout(); - if (timeout < 0) { - return Long.MAX_VALUE; - } else { - return System.currentTimeMillis() + timeout; - } - } - - private byte currentOpCode = Constants.OPCODE_CONTINUATION; - - private void sendMessageBlock(byte opCode, ByteBuffer payload, boolean last, - long timeoutExpiry) throws IOException { - wsSession.updateLastActive(); - - if (opCode == currentOpCode) { - opCode = Constants.OPCODE_CONTINUATION; - } - - request.sendWsFrame(payload, opCode, last, timeoutExpiry); - - if (!last && opCode != Constants.OPCODE_CONTINUATION) { - currentOpCode = opCode; - } - - if (last && opCode == Constants.OPCODE_CONTINUATION) { - currentOpCode = Constants.OPCODE_CONTINUATION; - } - } - - - void startMessage(byte opCode, ByteBuffer payload, boolean last, - SendHandler handler) { - - wsSession.updateLastActive(); - - List messageParts = new ArrayList<>(); - messageParts.add(new MessagePart(last, 0, opCode, payload, - intermediateMessageHandler, - new EndMessageHandler(this, handler), -1)); - - messageParts = transformation.sendMessagePart(messageParts); - - // Some extensions/transformations may buffer messages so it is possible - // that no message parts will be returned. If this is the case the - // trigger the supplied SendHandler - if (messageParts.size() == 0) { - handler.onResult(new SendResult()); - return; - } - - MessagePart mp = messageParts.remove(0); - - boolean doWrite = false; - synchronized (messagePartLock) { - if (Constants.OPCODE_CLOSE == mp.getOpCode() && getBatchingAllowed()) { - // Should not happen. To late to send batched messages now since - // the session has been closed. Complain loudly. - log.warn(sm.getString("wsRemoteEndpoint.flushOnCloseFailed")); - } - if (messagePartInProgress.tryAcquire()) { - doWrite = true; - } else { - // When a control message is sent while another message is being - // sent, the control message is queued. Chances are the - // subsequent data message part will end up queued while the - // control message is sent. The logic in this class (state - // machine, EndMessageHandler, TextMessageSendHandler) ensures - // that there will only ever be one data message part in the - // queue. There could be multiple control messages in the queue. - - // Add it to the queue - messagePartQueue.add(mp); - } - // Add any remaining messages to the queue - messagePartQueue.addAll(messageParts); - } - if (doWrite) { - // Actual write has to be outside sync block to avoid possible - // deadlock between messagePartLock and writeLock in - // o.a.coyote.http11.upgrade.AbstractServletOutputStream - writeMessagePart(mp); - } - } - - - void endMessage(SendHandler handler, SendResult result) { - boolean doWrite = false; - MessagePart mpNext = null; - synchronized (messagePartLock) { - - fragmented = nextFragmented; - text = nextText; - - mpNext = messagePartQueue.poll(); - if (mpNext == null) { - messagePartInProgress.release(); - } else if (!closed){ - // Session may have been closed unexpectedly in the middle of - // sending a fragmented message closing the endpoint. If this - // happens, clearly there is no point trying to send the rest of - // the message. - doWrite = true; - } - } - if (doWrite) { - // Actual write has to be outside sync block to avoid possible - // deadlock between messagePartLock and writeLock in - // o.a.coyote.http11.upgrade.AbstractServletOutputStream - writeMessagePart(mpNext); - } - - wsSession.updateLastActive(); - - // Some handlers, such as the IntermediateMessageHandler, do not have a - // nested handler so handler may be null. - if (handler != null) { - handler.onResult(result); - } - } - - - void writeMessagePart(MessagePart mp) { - if (closed) { - throw new IllegalStateException( - sm.getString("wsRemoteEndpoint.closed")); - } - - if (Constants.INTERNAL_OPCODE_FLUSH == mp.getOpCode()) { - nextFragmented = fragmented; - nextText = text; - outputBuffer.flip(); - SendHandler flushHandler = new OutputBufferFlushSendHandler( - outputBuffer, mp.getEndHandler()); - doWrite(flushHandler, mp.getBlockingWriteTimeoutExpiry(), outputBuffer); - return; - } - - // Control messages may be sent in the middle of fragmented message - // so they have no effect on the fragmented or text flags - boolean first; - if (Util.isControl(mp.getOpCode())) { - nextFragmented = fragmented; - nextText = text; - if (mp.getOpCode() == Constants.OPCODE_CLOSE) { - closed = true; - } - first = true; - } else { - boolean isText = Util.isText(mp.getOpCode()); - - if (fragmented) { - // Currently fragmented - if (text != isText) { - throw new IllegalStateException( - sm.getString("wsRemoteEndpoint.changeType")); - } - nextText = text; - nextFragmented = !mp.isFin(); - first = false; - } else { - // Wasn't fragmented. Might be now - if (mp.isFin()) { - nextFragmented = false; - } else { - nextFragmented = true; - nextText = isText; - } - first = true; - } - } - - byte[] mask; - - if (isMasked()) { - mask = Util.generateMask(); - } else { - mask = null; - } - - headerBuffer.clear(); - writeHeader(headerBuffer, mp.isFin(), mp.getRsv(), mp.getOpCode(), - isMasked(), mp.getPayload(), mask, first); - headerBuffer.flip(); - - if (getBatchingAllowed() || isMasked()) { - // Need to write via output buffer - OutputBufferSendHandler obsh = new OutputBufferSendHandler( - mp.getEndHandler(), mp.getBlockingWriteTimeoutExpiry(), - headerBuffer, mp.getPayload(), mask, - outputBuffer, !getBatchingAllowed(), this); - obsh.write(); - } else { - // Can write directly - doWrite(mp.getEndHandler(), mp.getBlockingWriteTimeoutExpiry(), - headerBuffer, mp.getPayload()); - } - } - - - private long getBlockingSendTimeout() { - Object obj = wsSession.getUserProperties().get(Constants.BLOCKING_SEND_TIMEOUT_PROPERTY); - Long userTimeout = null; - if (obj instanceof Long) { - userTimeout = (Long) obj; - } - if (userTimeout == null) { - return Constants.DEFAULT_BLOCKING_SEND_TIMEOUT; - } else { - return userTimeout.longValue(); - } - } - - - /** - * Wraps the user provided handler so that the end point is notified when - * the message is complete. - */ - private static class EndMessageHandler implements SendHandler { - - private final WsRemoteEndpointImplBase endpoint; - private final SendHandler handler; - - public EndMessageHandler(WsRemoteEndpointImplBase endpoint, - SendHandler handler) { - this.endpoint = endpoint; - this.handler = handler; - } - - - @Override - public void onResult(SendResult result) { - endpoint.endMessage(handler, result); - } - } - - - /** - * If a transformation needs to split a {@link MessagePart} into multiple - * {@link MessagePart}s, it uses this handler as the end handler for each of - * the additional {@link MessagePart}s. This handler notifies this this - * class that the {@link MessagePart} has been processed and that the next - * {@link MessagePart} in the queue should be started. The final - * {@link MessagePart} will use the {@link EndMessageHandler} provided with - * the original {@link MessagePart}. - */ - private static class IntermediateMessageHandler implements SendHandler { - - private final WsRemoteEndpointImplBase endpoint; - - public IntermediateMessageHandler(WsRemoteEndpointImplBase endpoint) { - this.endpoint = endpoint; - } - - - @Override - public void onResult(SendResult result) { - endpoint.endMessage(null, result); - } - } - - - @SuppressWarnings({"unchecked", "rawtypes"}) - public void sendObject(Object obj) throws IOException, EncodeException { - if (obj == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullData")); - } - /* - * Note that the implementation will convert primitives and their object - * equivalents by default but that users are free to specify their own - * encoders and decoders for this if they wish. - */ - Encoder encoder = findEncoder(obj); - if (encoder == null && Util.isPrimitive(obj.getClass())) { - String msg = obj.toString(); - sendString(msg); - return; - } - if (encoder == null && byte[].class.isAssignableFrom(obj.getClass())) { - ByteBuffer msg = ByteBuffer.wrap((byte[]) obj); - sendBytes(msg); - return; - } - - if (encoder instanceof Encoder.Text) { - String msg = ((Encoder.Text) encoder).encode(obj); - sendString(msg); - } else if (encoder instanceof Encoder.TextStream) { - try (Writer w = getSendWriter()) { - ((Encoder.TextStream) encoder).encode(obj, w); - } - } else if (encoder instanceof Encoder.Binary) { - ByteBuffer msg = ((Encoder.Binary) encoder).encode(obj); - sendBytes(msg); - } else if (encoder instanceof Encoder.BinaryStream) { - try (OutputStream os = getSendStream()) { - ((Encoder.BinaryStream) encoder).encode(obj, os); - } - } else { - throw new EncodeException(obj, sm.getString( - "wsRemoteEndpoint.noEncoder", obj.getClass())); - } - } - - - public Future sendObjectByFuture(Object obj) { - FutureToSendHandler f2sh = new FutureToSendHandler(wsSession); - sendObjectByCompletion(obj, f2sh); - return f2sh; - } - - - @SuppressWarnings({"unchecked", "rawtypes"}) - public void sendObjectByCompletion(Object obj, SendHandler completion) { - - if (obj == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullData")); - } - if (completion == null) { - throw new IllegalArgumentException(sm.getString("wsRemoteEndpoint.nullHandler")); - } - - /* - * Note that the implementation will convert primitives and their object - * equivalents by default but that users are free to specify their own - * encoders and decoders for this if they wish. - */ - Encoder encoder = findEncoder(obj); - if (encoder == null && Util.isPrimitive(obj.getClass())) { - String msg = obj.toString(); - sendStringByCompletion(msg, completion); - return; - } - if (encoder == null && byte[].class.isAssignableFrom(obj.getClass())) { - ByteBuffer msg = ByteBuffer.wrap((byte[]) obj); - sendBytesByCompletion(msg, completion); - return; - } - - try { - if (encoder instanceof Encoder.Text) { - String msg = ((Encoder.Text) encoder).encode(obj); - sendStringByCompletion(msg, completion); - } else if (encoder instanceof Encoder.TextStream) { - try (Writer w = getSendWriter()) { - ((Encoder.TextStream) encoder).encode(obj, w); - } - completion.onResult(new SendResult()); - } else if (encoder instanceof Encoder.Binary) { - ByteBuffer msg = ((Encoder.Binary) encoder).encode(obj); - sendBytesByCompletion(msg, completion); - } else if (encoder instanceof Encoder.BinaryStream) { - try (OutputStream os = getSendStream()) { - ((Encoder.BinaryStream) encoder).encode(obj, os); - } - completion.onResult(new SendResult()); - } else { - throw new EncodeException(obj, sm.getString( - "wsRemoteEndpoint.noEncoder", obj.getClass())); - } - } catch (Exception e) { - SendResult sr = new SendResult(e); - completion.onResult(sr); - } - } - - - protected void setSession(WsSession wsSession) { - this.wsSession = wsSession; - } - - - protected void setRequest(Request request) { - this.request = request; - } - - protected void setEncoders(EndpointConfig endpointConfig) - throws DeploymentException { - encoderEntries.clear(); - for (Class encoderClazz : - endpointConfig.getEncoders()) { - Encoder instance; - try { - instance = encoderClazz.getConstructor().newInstance(); - instance.init(endpointConfig); - } catch (ReflectiveOperationException e) { - throw new DeploymentException( - sm.getString("wsRemoteEndpoint.invalidEncoder", - encoderClazz.getName()), e); - } - EncoderEntry entry = new EncoderEntry( - Util.getEncoderType(encoderClazz), instance); - encoderEntries.add(entry); - } - } - - - private Encoder findEncoder(Object obj) { - for (EncoderEntry entry : encoderEntries) { - if (entry.getClazz().isAssignableFrom(obj.getClass())) { - return entry.getEncoder(); - } - } - return null; - } - - - public final void close() { - for (EncoderEntry entry : encoderEntries) { - entry.getEncoder().destroy(); - } - - request.closeWs(); - } - - - protected abstract void doWrite(SendHandler handler, long blockingWriteTimeoutExpiry, - ByteBuffer... data); - protected abstract boolean isMasked(); - protected abstract void doClose(); - - private static void writeHeader(ByteBuffer headerBuffer, boolean fin, - int rsv, byte opCode, boolean masked, ByteBuffer payload, - byte[] mask, boolean first) { - - byte b = 0; - - if (fin) { - // Set the fin bit - b -= 128; - } - - b += (rsv << 4); - - if (first) { - // This is the first fragment of this message - b += opCode; - } - // If not the first fragment, it is a continuation with opCode of zero - - headerBuffer.put(b); - - if (masked) { - b = (byte) 0x80; - } else { - b = 0; - } - - // Next write the mask && length length - if (payload.limit() < 126) { - headerBuffer.put((byte) (payload.limit() | b)); - } else if (payload.limit() < 65536) { - headerBuffer.put((byte) (126 | b)); - headerBuffer.put((byte) (payload.limit() >>> 8)); - headerBuffer.put((byte) (payload.limit() & 0xFF)); - } else { - // Will never be more than 2^31-1 - headerBuffer.put((byte) (127 | b)); - headerBuffer.put((byte) 0); - headerBuffer.put((byte) 0); - headerBuffer.put((byte) 0); - headerBuffer.put((byte) 0); - headerBuffer.put((byte) (payload.limit() >>> 24)); - headerBuffer.put((byte) (payload.limit() >>> 16)); - headerBuffer.put((byte) (payload.limit() >>> 8)); - headerBuffer.put((byte) (payload.limit() & 0xFF)); - } - if (masked) { - headerBuffer.put(mask[0]); - headerBuffer.put(mask[1]); - headerBuffer.put(mask[2]); - headerBuffer.put(mask[3]); - } - } - - - private class TextMessageSendHandler implements SendHandler { - - private final SendHandler handler; - private final CharBuffer message; - private final boolean isLast; - private final CharsetEncoder encoder; - private final ByteBuffer buffer; - private final WsRemoteEndpointImplBase endpoint; - private volatile boolean isDone = false; - - public TextMessageSendHandler(SendHandler handler, CharBuffer message, - boolean isLast, CharsetEncoder encoder, - ByteBuffer encoderBuffer, WsRemoteEndpointImplBase endpoint) { - this.handler = handler; - this.message = message; - this.isLast = isLast; - this.encoder = encoder.reset(); - this.buffer = encoderBuffer; - this.endpoint = endpoint; - } - - public void write() { - buffer.clear(); - CoderResult cr = encoder.encode(message, buffer, true); - if (cr.isError()) { - throw new IllegalArgumentException(cr.toString()); - } - isDone = !cr.isOverflow(); - buffer.flip(); - endpoint.startMessage(Constants.OPCODE_TEXT, buffer, - isDone && isLast, this); - } - - @Override - public void onResult(SendResult result) { - if (isDone) { - endpoint.stateMachine.complete(isLast); - handler.onResult(result); - } else if(!result.isOK()) { - handler.onResult(result); - } else if (closed){ - SendResult sr = new SendResult(new IOException( - sm.getString("wsRemoteEndpoint.closedDuringMessage"))); - handler.onResult(sr); - } else { - write(); - } - } - } - - - /** - * Used to write data to the output buffer, flushing the buffer if it fills - * up. - */ - private static class OutputBufferSendHandler implements SendHandler { - - private final SendHandler handler; - private final long blockingWriteTimeoutExpiry; - private final ByteBuffer headerBuffer; - private final ByteBuffer payload; - private final byte[] mask; - private final ByteBuffer outputBuffer; - private final boolean flushRequired; - private final WsRemoteEndpointImplBase endpoint; - private int maskIndex = 0; - - public OutputBufferSendHandler(SendHandler completion, - long blockingWriteTimeoutExpiry, - ByteBuffer headerBuffer, ByteBuffer payload, byte[] mask, - ByteBuffer outputBuffer, boolean flushRequired, - WsRemoteEndpointImplBase endpoint) { - this.blockingWriteTimeoutExpiry = blockingWriteTimeoutExpiry; - this.handler = completion; - this.headerBuffer = headerBuffer; - this.payload = payload; - this.mask = mask; - this.outputBuffer = outputBuffer; - this.flushRequired = flushRequired; - this.endpoint = endpoint; - } - - public void write() { - // Write the header - while (headerBuffer.hasRemaining() && outputBuffer.hasRemaining()) { - outputBuffer.put(headerBuffer.get()); - } - if (headerBuffer.hasRemaining()) { - // Still more headers to write, need to flush - outputBuffer.flip(); - endpoint.doWrite(this, blockingWriteTimeoutExpiry, outputBuffer); - return; - } - - // Write the payload - int payloadLeft = payload.remaining(); - int payloadLimit = payload.limit(); - int outputSpace = outputBuffer.remaining(); - int toWrite = payloadLeft; - - if (payloadLeft > outputSpace) { - toWrite = outputSpace; - // Temporarily reduce the limit - payload.limit(payload.position() + toWrite); - } - - if (mask == null) { - // Use a bulk copy - outputBuffer.put(payload); - } else { - for (int i = 0; i < toWrite; i++) { - outputBuffer.put( - (byte) (payload.get() ^ (mask[maskIndex++] & 0xFF))); - if (maskIndex > 3) { - maskIndex = 0; - } - } - } - - if (payloadLeft > outputSpace) { - // Restore the original limit - payload.limit(payloadLimit); - // Still more data to write, need to flush - outputBuffer.flip(); - endpoint.doWrite(this, blockingWriteTimeoutExpiry, outputBuffer); - return; - } - - if (flushRequired) { - outputBuffer.flip(); - if (outputBuffer.remaining() == 0) { - handler.onResult(SENDRESULT_OK); - } else { - endpoint.doWrite(this, blockingWriteTimeoutExpiry, outputBuffer); - } - } else { - handler.onResult(SENDRESULT_OK); - } - } - - // ------------------------------------------------- SendHandler methods - @Override - public void onResult(SendResult result) { - if (result.isOK()) { - if (outputBuffer.hasRemaining()) { - endpoint.doWrite(this, blockingWriteTimeoutExpiry, outputBuffer); - } else { - outputBuffer.clear(); - write(); - } - } else { - handler.onResult(result); - } - } - } - - - /** - * Ensures that the output buffer is cleared after it has been flushed. - */ - private static class OutputBufferFlushSendHandler implements SendHandler { - - private final ByteBuffer outputBuffer; - private final SendHandler handler; - - public OutputBufferFlushSendHandler(ByteBuffer outputBuffer, SendHandler handler) { - this.outputBuffer = outputBuffer; - this.handler = handler; - } - - @Override - public void onResult(SendResult result) { - if (result.isOK()) { - outputBuffer.clear(); - } - handler.onResult(result); - } - } - - - private static class WsOutputStream extends OutputStream { - - private final WsRemoteEndpointImplBase endpoint; - private final ByteBuffer buffer = ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE); - private final Object closeLock = new Object(); - private volatile boolean closed = false; - private volatile boolean used = false; - - public WsOutputStream(WsRemoteEndpointImplBase endpoint) { - this.endpoint = endpoint; - } - - @Override - public void write(int b) throws IOException { - if (closed) { - throw new IllegalStateException( - sm.getString("wsRemoteEndpoint.closedOutputStream")); - } - - used = true; - if (buffer.remaining() == 0) { - flush(); - } - buffer.put((byte) b); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - if (closed) { - throw new IllegalStateException( - sm.getString("wsRemoteEndpoint.closedOutputStream")); - } - if (len == 0) { - return; - } - if ((off < 0) || (off > b.length) || (len < 0) || - ((off + len) > b.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } - - used = true; - if (buffer.remaining() == 0) { - flush(); - } - int remaining = buffer.remaining(); - int written = 0; - - while (remaining < len - written) { - buffer.put(b, off + written, remaining); - written += remaining; - flush(); - remaining = buffer.remaining(); - } - buffer.put(b, off + written, len - written); - } - - @Override - public void flush() throws IOException { - if (closed) { - throw new IllegalStateException( - sm.getString("wsRemoteEndpoint.closedOutputStream")); - } - - // Optimisation. If there is no data to flush then do not send an - // empty message. - if (!Constants.STREAMS_DROP_EMPTY_MESSAGES || buffer.position() > 0) { - doWrite(false); - } - } - - @Override - public void close() throws IOException { - synchronized (closeLock) { - if (closed) { - return; - } - closed = true; - } - - doWrite(true); - } - - private void doWrite(boolean last) throws IOException { - if (!Constants.STREAMS_DROP_EMPTY_MESSAGES || used) { - buffer.flip(); - endpoint.sendMessageBlock(Constants.OPCODE_BINARY, buffer, last); - } - endpoint.stateMachine.complete(last); - buffer.clear(); - } - } - - - private static class WsWriter extends Writer { - - private final WsRemoteEndpointImplBase endpoint; - private final CharBuffer buffer = CharBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE); - private final Object closeLock = new Object(); - private volatile boolean closed = false; - private volatile boolean used = false; - - public WsWriter(WsRemoteEndpointImplBase endpoint) { - this.endpoint = endpoint; - } - - @Override - public void write(char[] cbuf, int off, int len) throws IOException { - if (closed) { - throw new IllegalStateException( - sm.getString("wsRemoteEndpoint.closedWriter")); - } - if (len == 0) { - return; - } - if ((off < 0) || (off > cbuf.length) || (len < 0) || - ((off + len) > cbuf.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } - - used = true; - if (buffer.remaining() == 0) { - flush(); - } - int remaining = buffer.remaining(); - int written = 0; - - while (remaining < len - written) { - buffer.put(cbuf, off + written, remaining); - written += remaining; - flush(); - remaining = buffer.remaining(); - } - buffer.put(cbuf, off + written, len - written); - } - - @Override - public void flush() throws IOException { - if (closed) { - throw new IllegalStateException( - sm.getString("wsRemoteEndpoint.closedWriter")); - } - - if (!Constants.STREAMS_DROP_EMPTY_MESSAGES || buffer.position() > 0) { - doWrite(false); - } - } - - @Override - public void close() throws IOException { - synchronized (closeLock) { - if (closed) { - return; - } - closed = true; - } - - doWrite(true); - } - - private void doWrite(boolean last) throws IOException { - if (!Constants.STREAMS_DROP_EMPTY_MESSAGES || used) { - buffer.flip(); - endpoint.sendMessageBlock(buffer, last); - buffer.clear(); - } else { - endpoint.stateMachine.complete(last); - } - } - } - - - private static class EncoderEntry { - - private final Class clazz; - private final Encoder encoder; - - public EncoderEntry(Class clazz, Encoder encoder) { - this.clazz = clazz; - this.encoder = encoder; - } - - public Class getClazz() { - return clazz; - } - - public Encoder getEncoder() { - return encoder; - } - } - - - private enum State { - OPEN, - STREAM_WRITING, - WRITER_WRITING, - BINARY_PARTIAL_WRITING, - BINARY_PARTIAL_READY, - BINARY_FULL_WRITING, - TEXT_PARTIAL_WRITING, - TEXT_PARTIAL_READY, - TEXT_FULL_WRITING - } - - - private static class StateMachine { - private State state = State.OPEN; - - public synchronized void streamStart() { - checkState(State.OPEN); - state = State.STREAM_WRITING; - } - - public synchronized void writeStart() { - checkState(State.OPEN); - state = State.WRITER_WRITING; - } - - public synchronized void binaryPartialStart() { - checkState(State.OPEN, State.BINARY_PARTIAL_READY); - state = State.BINARY_PARTIAL_WRITING; - } - - public synchronized void binaryStart() { - checkState(State.OPEN); - state = State.BINARY_FULL_WRITING; - } - - public synchronized void textPartialStart() { - checkState(State.OPEN, State.TEXT_PARTIAL_READY); - state = State.TEXT_PARTIAL_WRITING; - } - - public synchronized void textStart() { - checkState(State.OPEN); - state = State.TEXT_FULL_WRITING; - } - - public synchronized void complete(boolean last) { - if (last) { - checkState(State.TEXT_PARTIAL_WRITING, State.TEXT_FULL_WRITING, - State.BINARY_PARTIAL_WRITING, State.BINARY_FULL_WRITING, - State.STREAM_WRITING, State.WRITER_WRITING); - state = State.OPEN; - } else { - checkState(State.TEXT_PARTIAL_WRITING, State.BINARY_PARTIAL_WRITING, - State.STREAM_WRITING, State.WRITER_WRITING); - if (state == State.TEXT_PARTIAL_WRITING) { - state = State.TEXT_PARTIAL_READY; - } else if (state == State.BINARY_PARTIAL_WRITING){ - state = State.BINARY_PARTIAL_READY; - } else if (state == State.WRITER_WRITING) { - // NO-OP. Leave state as is. - } else if (state == State.STREAM_WRITING) { - // NO-OP. Leave state as is. - } else { - // Should never happen - // The if ... else ... blocks above should cover all states - // permitted by the preceding checkState() call - throw new IllegalStateException( - "BUG: This code should never be called"); - } - } - } - - private void checkState(State... required) { - for (State state : required) { - if (this.state == state) { - return; - } - } - throw new IllegalStateException( - sm.getString("wsRemoteEndpoint.wrongState", this.state)); - } - } - - - private static class StateUpdateSendHandler implements SendHandler { - - private final SendHandler handler; - private final StateMachine stateMachine; - - public StateUpdateSendHandler(SendHandler handler, StateMachine stateMachine) { - this.handler = handler; - this.stateMachine = stateMachine; - } - - @Override - public void onResult(SendResult result) { - if (result.isOK()) { - stateMachine.complete(true); - } - handler.onResult(result); - } - } - - - private static class BlockingSendHandler implements SendHandler { - - private SendResult sendResult = null; - - @Override - public void onResult(SendResult result) { - sendResult = result; - } - - public SendResult getSendResult() { - return sendResult; - } - } -} diff --git a/src/java/nginx/unit/websocket/WsRemoteEndpointImplClient.java b/src/java/nginx/unit/websocket/WsRemoteEndpointImplClient.java deleted file mode 100644 index 70b66789..00000000 --- a/src/java/nginx/unit/websocket/WsRemoteEndpointImplClient.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import javax.websocket.SendHandler; -import javax.websocket.SendResult; - -public class WsRemoteEndpointImplClient extends WsRemoteEndpointImplBase { - - private final AsyncChannelWrapper channel; - - public WsRemoteEndpointImplClient(AsyncChannelWrapper channel) { - this.channel = channel; - } - - - @Override - protected boolean isMasked() { - return true; - } - - - @Override - protected void doWrite(SendHandler handler, long blockingWriteTimeoutExpiry, - ByteBuffer... data) { - long timeout; - for (ByteBuffer byteBuffer : data) { - if (blockingWriteTimeoutExpiry == -1) { - timeout = getSendTimeout(); - if (timeout < 1) { - timeout = Long.MAX_VALUE; - } - } else { - timeout = blockingWriteTimeoutExpiry - System.currentTimeMillis(); - if (timeout < 0) { - SendResult sr = new SendResult(new IOException("Blocking write timeout")); - handler.onResult(sr); - } - } - - try { - channel.write(byteBuffer).get(timeout, TimeUnit.MILLISECONDS); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - handler.onResult(new SendResult(e)); - return; - } - } - handler.onResult(SENDRESULT_OK); - } - - @Override - protected void doClose() { - channel.close(); - } -} diff --git a/src/java/nginx/unit/websocket/WsSession.java b/src/java/nginx/unit/websocket/WsSession.java deleted file mode 100644 index b654eb37..00000000 --- a/src/java/nginx/unit/websocket/WsSession.java +++ /dev/null @@ -1,1070 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.IOException; -import java.net.URI; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.CharBuffer; -import java.nio.channels.WritePendingException; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.nio.charset.StandardCharsets; -import java.security.Principal; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; - -import javax.websocket.CloseReason; -import javax.websocket.CloseReason.CloseCode; -import javax.websocket.CloseReason.CloseCodes; -import javax.websocket.DeploymentException; -import javax.websocket.Endpoint; -import javax.websocket.EndpointConfig; -import javax.websocket.Extension; -import javax.websocket.MessageHandler; -import javax.websocket.MessageHandler.Partial; -import javax.websocket.MessageHandler.Whole; -import javax.websocket.PongMessage; -import javax.websocket.RemoteEndpoint; -import javax.websocket.SendResult; -import javax.websocket.Session; -import javax.websocket.WebSocketContainer; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.InstanceManager; -import org.apache.tomcat.InstanceManagerBindings; -import org.apache.tomcat.util.ExceptionUtils; -import org.apache.tomcat.util.buf.Utf8Decoder; -import org.apache.tomcat.util.res.StringManager; - -import nginx.unit.Request; - -public class WsSession implements Session { - - // An ellipsis is a single character that looks like three periods in a row - // and is used to indicate a continuation. - private static final byte[] ELLIPSIS_BYTES = "\u2026".getBytes(StandardCharsets.UTF_8); - // An ellipsis is three bytes in UTF-8 - private static final int ELLIPSIS_BYTES_LEN = ELLIPSIS_BYTES.length; - - private static final StringManager sm = StringManager.getManager(WsSession.class); - private static AtomicLong ids = new AtomicLong(0); - - private final Log log = LogFactory.getLog(WsSession.class); // must not be static - - private final CharsetDecoder utf8DecoderMessage = new Utf8Decoder(). - onMalformedInput(CodingErrorAction.REPORT). - onUnmappableCharacter(CodingErrorAction.REPORT); - - private final Endpoint localEndpoint; - private final WsRemoteEndpointImplBase wsRemoteEndpoint; - private final RemoteEndpoint.Async remoteEndpointAsync; - private final RemoteEndpoint.Basic remoteEndpointBasic; - private final ClassLoader applicationClassLoader; - private final WsWebSocketContainer webSocketContainer; - private final URI requestUri; - private final Map> requestParameterMap; - private final String queryString; - private final Principal userPrincipal; - private final EndpointConfig endpointConfig; - - private final List negotiatedExtensions; - private final String subProtocol; - private final Map pathParameters; - private final boolean secure; - private final String httpSessionId; - private final String id; - - // Expected to handle message types of only - private volatile MessageHandler textMessageHandler = null; - // Expected to handle message types of only - private volatile MessageHandler binaryMessageHandler = null; - private volatile MessageHandler.Whole pongMessageHandler = null; - private volatile State state = State.OPEN; - private final Object stateLock = new Object(); - private final Map userProperties = new ConcurrentHashMap<>(); - private volatile int maxBinaryMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE; - private volatile int maxTextMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE; - private volatile long maxIdleTimeout = 0; - private volatile long lastActive = System.currentTimeMillis(); - private Map futures = new ConcurrentHashMap<>(); - - private CharBuffer messageBufferText; - private ByteBuffer binaryBuffer; - private byte startOpCode = Constants.OPCODE_CONTINUATION; - - /** - * Creates a new WebSocket session for communication between the two - * provided end points. The result of {@link Thread#getContextClassLoader()} - * at the time this constructor is called will be used when calling - * {@link Endpoint#onClose(Session, CloseReason)}. - * - * @param localEndpoint The end point managed by this code - * @param wsRemoteEndpoint The other / remote endpoint - * @param wsWebSocketContainer The container that created this session - * @param requestUri The URI used to connect to this endpoint or - * null is this is a client session - * @param requestParameterMap The parameters associated with the request - * that initiated this session or - * null if this is a client session - * @param queryString The query string associated with the request - * that initiated this session or - * null if this is a client session - * @param userPrincipal The principal associated with the request - * that initiated this session or - * null if this is a client session - * @param httpSessionId The HTTP session ID associated with the - * request that initiated this session or - * null if this is a client session - * @param negotiatedExtensions The agreed extensions to use for this session - * @param subProtocol The agreed subprotocol to use for this - * session - * @param pathParameters The path parameters associated with the - * request that initiated this session or - * null if this is a client session - * @param secure Was this session initiated over a secure - * connection? - * @param endpointConfig The configuration information for the - * endpoint - * @throws DeploymentException if an invalid encode is specified - */ - public WsSession(Endpoint localEndpoint, - WsRemoteEndpointImplBase wsRemoteEndpoint, - WsWebSocketContainer wsWebSocketContainer, - URI requestUri, Map> requestParameterMap, - String queryString, Principal userPrincipal, String httpSessionId, - List negotiatedExtensions, String subProtocol, Map pathParameters, - boolean secure, EndpointConfig endpointConfig, - Request request) throws DeploymentException { - this.localEndpoint = localEndpoint; - this.wsRemoteEndpoint = wsRemoteEndpoint; - this.wsRemoteEndpoint.setSession(this); - this.wsRemoteEndpoint.setRequest(request); - - request.setWsSession(this); - - this.remoteEndpointAsync = new WsRemoteEndpointAsync(wsRemoteEndpoint); - this.remoteEndpointBasic = new WsRemoteEndpointBasic(wsRemoteEndpoint); - this.webSocketContainer = wsWebSocketContainer; - applicationClassLoader = Thread.currentThread().getContextClassLoader(); - wsRemoteEndpoint.setSendTimeout(wsWebSocketContainer.getDefaultAsyncSendTimeout()); - this.maxBinaryMessageBufferSize = webSocketContainer.getDefaultMaxBinaryMessageBufferSize(); - this.maxTextMessageBufferSize = webSocketContainer.getDefaultMaxTextMessageBufferSize(); - this.maxIdleTimeout = webSocketContainer.getDefaultMaxSessionIdleTimeout(); - this.requestUri = requestUri; - if (requestParameterMap == null) { - this.requestParameterMap = Collections.emptyMap(); - } else { - this.requestParameterMap = requestParameterMap; - } - this.queryString = queryString; - this.userPrincipal = userPrincipal; - this.httpSessionId = httpSessionId; - this.negotiatedExtensions = negotiatedExtensions; - if (subProtocol == null) { - this.subProtocol = ""; - } else { - this.subProtocol = subProtocol; - } - this.pathParameters = pathParameters; - this.secure = secure; - this.wsRemoteEndpoint.setEncoders(endpointConfig); - this.endpointConfig = endpointConfig; - - this.userProperties.putAll(endpointConfig.getUserProperties()); - this.id = Long.toHexString(ids.getAndIncrement()); - - InstanceManager instanceManager = webSocketContainer.getInstanceManager(); - if (instanceManager == null) { - instanceManager = InstanceManagerBindings.get(applicationClassLoader); - } - if (instanceManager != null) { - try { - instanceManager.newInstance(localEndpoint); - } catch (Exception e) { - throw new DeploymentException(sm.getString("wsSession.instanceNew"), e); - } - } - - if (log.isDebugEnabled()) { - log.debug(sm.getString("wsSession.created", id)); - } - - messageBufferText = CharBuffer.allocate(maxTextMessageBufferSize); - } - - public static String wsSession_test() { - return sm.getString("wsSession.instanceNew"); - } - - - @Override - public WebSocketContainer getContainer() { - checkState(); - return webSocketContainer; - } - - - @Override - public void addMessageHandler(MessageHandler listener) { - Class target = Util.getMessageType(listener); - doAddMessageHandler(target, listener); - } - - - @Override - public void addMessageHandler(Class clazz, Partial handler) - throws IllegalStateException { - doAddMessageHandler(clazz, handler); - } - - - @Override - public void addMessageHandler(Class clazz, Whole handler) - throws IllegalStateException { - doAddMessageHandler(clazz, handler); - } - - - @SuppressWarnings("unchecked") - private void doAddMessageHandler(Class target, MessageHandler listener) { - checkState(); - - // Message handlers that require decoders may map to text messages, - // binary messages, both or neither. - - // The frame processing code expects binary message handlers to - // accept ByteBuffer - - // Use the POJO message handler wrappers as they are designed to wrap - // arbitrary objects with MessageHandlers and can wrap MessageHandlers - // just as easily. - - Set mhResults = Util.getMessageHandlers(target, listener, - endpointConfig, this); - - for (MessageHandlerResult mhResult : mhResults) { - switch (mhResult.getType()) { - case TEXT: { - if (textMessageHandler != null) { - throw new IllegalStateException(sm.getString("wsSession.duplicateHandlerText")); - } - textMessageHandler = mhResult.getHandler(); - break; - } - case BINARY: { - if (binaryMessageHandler != null) { - throw new IllegalStateException( - sm.getString("wsSession.duplicateHandlerBinary")); - } - binaryMessageHandler = mhResult.getHandler(); - break; - } - case PONG: { - if (pongMessageHandler != null) { - throw new IllegalStateException(sm.getString("wsSession.duplicateHandlerPong")); - } - MessageHandler handler = mhResult.getHandler(); - if (handler instanceof MessageHandler.Whole) { - pongMessageHandler = (MessageHandler.Whole) handler; - } else { - throw new IllegalStateException( - sm.getString("wsSession.invalidHandlerTypePong")); - } - - break; - } - default: { - throw new IllegalArgumentException( - sm.getString("wsSession.unknownHandlerType", listener, mhResult.getType())); - } - } - } - } - - - @Override - public Set getMessageHandlers() { - checkState(); - Set result = new HashSet<>(); - if (binaryMessageHandler != null) { - result.add(binaryMessageHandler); - } - if (textMessageHandler != null) { - result.add(textMessageHandler); - } - if (pongMessageHandler != null) { - result.add(pongMessageHandler); - } - return result; - } - - - @Override - public void removeMessageHandler(MessageHandler listener) { - checkState(); - if (listener == null) { - return; - } - - MessageHandler wrapped = null; - - if (listener instanceof WrappedMessageHandler) { - wrapped = ((WrappedMessageHandler) listener).getWrappedHandler(); - } - - if (wrapped == null) { - wrapped = listener; - } - - boolean removed = false; - if (wrapped.equals(textMessageHandler) || listener.equals(textMessageHandler)) { - textMessageHandler = null; - removed = true; - } - - if (wrapped.equals(binaryMessageHandler) || listener.equals(binaryMessageHandler)) { - binaryMessageHandler = null; - removed = true; - } - - if (wrapped.equals(pongMessageHandler) || listener.equals(pongMessageHandler)) { - pongMessageHandler = null; - removed = true; - } - - if (!removed) { - // ISE for now. Could swallow this silently / log this if the ISE - // becomes a problem - throw new IllegalStateException( - sm.getString("wsSession.removeHandlerFailed", listener)); - } - } - - - @Override - public String getProtocolVersion() { - checkState(); - return Constants.WS_VERSION_HEADER_VALUE; - } - - - @Override - public String getNegotiatedSubprotocol() { - checkState(); - return subProtocol; - } - - - @Override - public List getNegotiatedExtensions() { - checkState(); - return negotiatedExtensions; - } - - - @Override - public boolean isSecure() { - checkState(); - return secure; - } - - - @Override - public boolean isOpen() { - return state == State.OPEN; - } - - - @Override - public long getMaxIdleTimeout() { - checkState(); - return maxIdleTimeout; - } - - - @Override - public void setMaxIdleTimeout(long timeout) { - checkState(); - this.maxIdleTimeout = timeout; - } - - - @Override - public void setMaxBinaryMessageBufferSize(int max) { - checkState(); - this.maxBinaryMessageBufferSize = max; - } - - - @Override - public int getMaxBinaryMessageBufferSize() { - checkState(); - return maxBinaryMessageBufferSize; - } - - - @Override - public void setMaxTextMessageBufferSize(int max) { - checkState(); - this.maxTextMessageBufferSize = max; - } - - - @Override - public int getMaxTextMessageBufferSize() { - checkState(); - return maxTextMessageBufferSize; - } - - - @Override - public Set getOpenSessions() { - checkState(); - return webSocketContainer.getOpenSessions(localEndpoint); - } - - - @Override - public RemoteEndpoint.Async getAsyncRemote() { - checkState(); - return remoteEndpointAsync; - } - - - @Override - public RemoteEndpoint.Basic getBasicRemote() { - checkState(); - return remoteEndpointBasic; - } - - - @Override - public void close() throws IOException { - close(new CloseReason(CloseCodes.NORMAL_CLOSURE, "")); - } - - - @Override - public void close(CloseReason closeReason) throws IOException { - doClose(closeReason, closeReason); - } - - - /** - * WebSocket 1.0. Section 2.1.5. - * Need internal close method as spec requires that the local endpoint - * receives a 1006 on timeout. - * - * @param closeReasonMessage The close reason to pass to the remote endpoint - * @param closeReasonLocal The close reason to pass to the local endpoint - */ - public void doClose(CloseReason closeReasonMessage, CloseReason closeReasonLocal) { - // Double-checked locking. OK because state is volatile - if (state != State.OPEN) { - return; - } - - synchronized (stateLock) { - if (state != State.OPEN) { - return; - } - - if (log.isDebugEnabled()) { - log.debug(sm.getString("wsSession.doClose", id)); - } - try { - wsRemoteEndpoint.setBatchingAllowed(false); - } catch (IOException e) { - log.warn(sm.getString("wsSession.flushFailOnClose"), e); - fireEndpointOnError(e); - } - - state = State.OUTPUT_CLOSED; - - sendCloseMessage(closeReasonMessage); - fireEndpointOnClose(closeReasonLocal); - } - - IOException ioe = new IOException(sm.getString("wsSession.messageFailed")); - SendResult sr = new SendResult(ioe); - for (FutureToSendHandler f2sh : futures.keySet()) { - f2sh.onResult(sr); - } - } - - - /** - * Called when a close message is received. Should only ever happen once. - * Also called after a protocol error when the ProtocolHandler needs to - * force the closing of the connection. - * - * @param closeReason The reason contained within the received close - * message. - */ - public void onClose(CloseReason closeReason) { - - synchronized (stateLock) { - if (state != State.CLOSED) { - try { - wsRemoteEndpoint.setBatchingAllowed(false); - } catch (IOException e) { - log.warn(sm.getString("wsSession.flushFailOnClose"), e); - fireEndpointOnError(e); - } - if (state == State.OPEN) { - state = State.OUTPUT_CLOSED; - sendCloseMessage(closeReason); - fireEndpointOnClose(closeReason); - } - state = State.CLOSED; - - // Close the socket - wsRemoteEndpoint.close(); - } - } - } - - - public void onClose() { - - synchronized (stateLock) { - if (state != State.CLOSED) { - try { - wsRemoteEndpoint.setBatchingAllowed(false); - } catch (IOException e) { - log.warn(sm.getString("wsSession.flushFailOnClose"), e); - fireEndpointOnError(e); - } - if (state == State.OPEN) { - state = State.OUTPUT_CLOSED; - fireEndpointOnClose(new CloseReason( - CloseReason.CloseCodes.NORMAL_CLOSURE, "")); - } - state = State.CLOSED; - - // Close the socket - wsRemoteEndpoint.close(); - } - } - } - - - private void fireEndpointOnClose(CloseReason closeReason) { - - // Fire the onClose event - Throwable throwable = null; - InstanceManager instanceManager = webSocketContainer.getInstanceManager(); - if (instanceManager == null) { - instanceManager = InstanceManagerBindings.get(applicationClassLoader); - } - Thread t = Thread.currentThread(); - ClassLoader cl = t.getContextClassLoader(); - t.setContextClassLoader(applicationClassLoader); - try { - localEndpoint.onClose(this, closeReason); - } catch (Throwable t1) { - ExceptionUtils.handleThrowable(t1); - throwable = t1; - } finally { - if (instanceManager != null) { - try { - instanceManager.destroyInstance(localEndpoint); - } catch (Throwable t2) { - ExceptionUtils.handleThrowable(t2); - if (throwable == null) { - throwable = t2; - } - } - } - t.setContextClassLoader(cl); - } - - if (throwable != null) { - fireEndpointOnError(throwable); - } - } - - - private void fireEndpointOnError(Throwable throwable) { - - // Fire the onError event - Thread t = Thread.currentThread(); - ClassLoader cl = t.getContextClassLoader(); - t.setContextClassLoader(applicationClassLoader); - try { - localEndpoint.onError(this, throwable); - } finally { - t.setContextClassLoader(cl); - } - } - - - private void sendCloseMessage(CloseReason closeReason) { - // 125 is maximum size for the payload of a control message - ByteBuffer msg = ByteBuffer.allocate(125); - CloseCode closeCode = closeReason.getCloseCode(); - // CLOSED_ABNORMALLY should not be put on the wire - if (closeCode == CloseCodes.CLOSED_ABNORMALLY) { - // PROTOCOL_ERROR is probably better than GOING_AWAY here - msg.putShort((short) CloseCodes.PROTOCOL_ERROR.getCode()); - } else { - msg.putShort((short) closeCode.getCode()); - } - - String reason = closeReason.getReasonPhrase(); - if (reason != null && reason.length() > 0) { - appendCloseReasonWithTruncation(msg, reason); - } - msg.flip(); - try { - wsRemoteEndpoint.sendMessageBlock(Constants.OPCODE_CLOSE, msg, true); - } catch (IOException | WritePendingException e) { - // Failed to send close message. Close the socket and let the caller - // deal with the Exception - if (log.isDebugEnabled()) { - log.debug(sm.getString("wsSession.sendCloseFail", id), e); - } - wsRemoteEndpoint.close(); - // Failure to send a close message is not unexpected in the case of - // an abnormal closure (usually triggered by a failure to read/write - // from/to the client. In this case do not trigger the endpoint's - // error handling - if (closeCode != CloseCodes.CLOSED_ABNORMALLY) { - localEndpoint.onError(this, e); - } - } finally { - webSocketContainer.unregisterSession(localEndpoint, this); - } - } - - - /** - * Use protected so unit tests can access this method directly. - * @param msg The message - * @param reason The reason - */ - protected static void appendCloseReasonWithTruncation(ByteBuffer msg, String reason) { - // Once the close code has been added there are a maximum of 123 bytes - // left for the reason phrase. If it is truncated then care needs to be - // taken to ensure the bytes are not truncated in the middle of a - // multi-byte UTF-8 character. - byte[] reasonBytes = reason.getBytes(StandardCharsets.UTF_8); - - if (reasonBytes.length <= 123) { - // No need to truncate - msg.put(reasonBytes); - } else { - // Need to truncate - int remaining = 123 - ELLIPSIS_BYTES_LEN; - int pos = 0; - byte[] bytesNext = reason.substring(pos, pos + 1).getBytes(StandardCharsets.UTF_8); - while (remaining >= bytesNext.length) { - msg.put(bytesNext); - remaining -= bytesNext.length; - pos++; - bytesNext = reason.substring(pos, pos + 1).getBytes(StandardCharsets.UTF_8); - } - msg.put(ELLIPSIS_BYTES); - } - } - - - /** - * Make the session aware of a {@link FutureToSendHandler} that will need to - * be forcibly closed if the session closes before the - * {@link FutureToSendHandler} completes. - * @param f2sh The handler - */ - protected void registerFuture(FutureToSendHandler f2sh) { - // Ideally, this code should sync on stateLock so that the correct - // action is taken based on the current state of the connection. - // However, a sync on stateLock can't be used here as it will create the - // possibility of a dead-lock. See BZ 61183. - // Therefore, a slightly less efficient approach is used. - - // Always register the future. - futures.put(f2sh, f2sh); - - if (state == State.OPEN) { - // The session is open. The future has been registered with the open - // session. Normal processing continues. - return; - } - - // The session is closed. The future may or may not have been registered - // in time for it to be processed during session closure. - - if (f2sh.isDone()) { - // The future has completed. It is not known if the future was - // completed normally by the I/O layer or in error by doClose(). It - // doesn't matter which. There is nothing more to do here. - return; - } - - // The session is closed. The Future had not completed when last checked. - // There is a small timing window that means the Future may have been - // completed since the last check. There is also the possibility that - // the Future was not registered in time to be cleaned up during session - // close. - // Attempt to complete the Future with an error result as this ensures - // that the Future completes and any client code waiting on it does not - // hang. It is slightly inefficient since the Future may have been - // completed in another thread or another thread may be about to - // complete the Future but knowing if this is the case requires the sync - // on stateLock (see above). - // Note: If multiple attempts are made to complete the Future, the - // second and subsequent attempts are ignored. - - IOException ioe = new IOException(sm.getString("wsSession.messageFailed")); - SendResult sr = new SendResult(ioe); - f2sh.onResult(sr); - } - - - /** - * Remove a {@link FutureToSendHandler} from the set of tracked instances. - * @param f2sh The handler - */ - protected void unregisterFuture(FutureToSendHandler f2sh) { - futures.remove(f2sh); - } - - - @Override - public URI getRequestURI() { - checkState(); - return requestUri; - } - - - @Override - public Map> getRequestParameterMap() { - checkState(); - return requestParameterMap; - } - - - @Override - public String getQueryString() { - checkState(); - return queryString; - } - - - @Override - public Principal getUserPrincipal() { - checkState(); - return userPrincipal; - } - - - @Override - public Map getPathParameters() { - checkState(); - return pathParameters; - } - - - @Override - public String getId() { - return id; - } - - - @Override - public Map getUserProperties() { - checkState(); - return userProperties; - } - - - public Endpoint getLocal() { - return localEndpoint; - } - - - public String getHttpSessionId() { - return httpSessionId; - } - - private ByteBuffer rawFragments; - - public void processFrame(ByteBuffer buf, byte opCode, boolean last) - throws IOException - { - if (state == State.CLOSED) { - return; - } - - if (opCode == Constants.OPCODE_CONTINUATION) { - opCode = startOpCode; - - if (rawFragments != null && rawFragments.position() > 0) { - rawFragments.put(buf); - rawFragments.flip(); - buf = rawFragments; - } - } else { - if (!last && (opCode == Constants.OPCODE_BINARY || - opCode == Constants.OPCODE_TEXT)) { - startOpCode = opCode; - - if (rawFragments != null) { - rawFragments.clear(); - } - } - } - - if (last) { - startOpCode = Constants.OPCODE_CONTINUATION; - } - - if (opCode == Constants.OPCODE_PONG) { - if (pongMessageHandler != null) { - final ByteBuffer b = buf; - - PongMessage pongMessage = new PongMessage() { - @Override - public ByteBuffer getApplicationData() { - return b; - } - }; - - pongMessageHandler.onMessage(pongMessage); - } - } - - if (opCode == Constants.OPCODE_CLOSE) { - CloseReason closeReason; - - if (buf.remaining() >= 2) { - short closeCode = buf.order(ByteOrder.BIG_ENDIAN).getShort(); - - closeReason = new CloseReason( - CloseReason.CloseCodes.getCloseCode(closeCode), - buf.asCharBuffer().toString()); - } else { - closeReason = new CloseReason( - CloseReason.CloseCodes.NORMAL_CLOSURE, ""); - } - - onClose(closeReason); - } - - if (opCode == Constants.OPCODE_BINARY) { - onMessage(buf, last); - } - - if (opCode == Constants.OPCODE_TEXT) { - if (messageBufferText.position() == 0 && maxTextMessageBufferSize != messageBufferText.capacity()) { - messageBufferText = CharBuffer.allocate(maxTextMessageBufferSize); - } - - CoderResult cr = utf8DecoderMessage.decode(buf, messageBufferText, last); - if (cr.isError()) { - throw new WsIOException(new CloseReason( - CloseCodes.NOT_CONSISTENT, - sm.getString("wsFrame.invalidUtf8"))); - } else if (cr.isOverflow()) { - // Ran out of space in text buffer - flush it - if (hasTextPartial()) { - do { - onMessage(messageBufferText, false); - - cr = utf8DecoderMessage.decode(buf, messageBufferText, last); - } while (cr.isOverflow()); - } else { - throw new WsIOException(new CloseReason( - CloseCodes.TOO_BIG, - sm.getString("wsFrame.textMessageTooBig"))); - } - } else if (cr.isUnderflow() && !last) { - updateRawFragments(buf, last); - - if (hasTextPartial()) { - onMessage(messageBufferText, false); - } - - return; - } - - if (last) { - utf8DecoderMessage.reset(); - } - - updateRawFragments(buf, last); - - onMessage(messageBufferText, last); - } - } - - - private boolean hasTextPartial() { - return textMessageHandler instanceof MessageHandler.Partial; - } - - - private void onMessage(CharBuffer buf, boolean last) throws IOException { - buf.flip(); - try { - onMessage(buf.toString(), last); - } catch (Throwable t) { - handleThrowableOnSend(t); - } finally { - buf.clear(); - } - } - - - private void updateRawFragments(ByteBuffer buf, boolean last) { - if (!last && buf.remaining() > 0) { - if (buf == rawFragments) { - buf.compact(); - } else { - if (rawFragments == null || (rawFragments.position() == 0 && maxTextMessageBufferSize != rawFragments.capacity())) { - rawFragments = ByteBuffer.allocateDirect(maxTextMessageBufferSize); - } - rawFragments.put(buf); - } - } else { - if (rawFragments != null) { - rawFragments.clear(); - } - } - } - - - @SuppressWarnings("unchecked") - public void onMessage(String text, boolean last) { - if (hasTextPartial()) { - ((MessageHandler.Partial) textMessageHandler).onMessage(text, last); - } else { - // Caller ensures last == true if this branch is used - ((MessageHandler.Whole) textMessageHandler).onMessage(text); - } - } - - - @SuppressWarnings("unchecked") - public void onMessage(ByteBuffer buf, boolean last) - throws IOException - { - if (binaryMessageHandler instanceof MessageHandler.Partial) { - ((MessageHandler.Partial) binaryMessageHandler).onMessage(buf, last); - } else { - if (last && (binaryBuffer == null || binaryBuffer.position() == 0)) { - ((MessageHandler.Whole) binaryMessageHandler).onMessage(buf); - return; - } - - if (binaryBuffer == null || - (binaryBuffer.position() == 0 && binaryBuffer.capacity() != maxBinaryMessageBufferSize)) - { - binaryBuffer = ByteBuffer.allocateDirect(maxBinaryMessageBufferSize); - } - - if (binaryBuffer.remaining() < buf.remaining()) { - throw new WsIOException(new CloseReason( - CloseCodes.TOO_BIG, - sm.getString("wsFrame.textMessageTooBig"))); - } - - binaryBuffer.put(buf); - - if (last) { - binaryBuffer.flip(); - try { - ((MessageHandler.Whole) binaryMessageHandler).onMessage(binaryBuffer); - } finally { - binaryBuffer.clear(); - } - } - } - } - - - private void handleThrowableOnSend(Throwable t) throws WsIOException { - ExceptionUtils.handleThrowable(t); - getLocal().onError(this, t); - CloseReason cr = new CloseReason(CloseCodes.CLOSED_ABNORMALLY, - sm.getString("wsFrame.ioeTriggeredClose")); - throw new WsIOException(cr); - } - - - protected MessageHandler getTextMessageHandler() { - return textMessageHandler; - } - - - protected MessageHandler getBinaryMessageHandler() { - return binaryMessageHandler; - } - - - protected MessageHandler.Whole getPongMessageHandler() { - return pongMessageHandler; - } - - - protected void updateLastActive() { - lastActive = System.currentTimeMillis(); - } - - - protected void checkExpiration() { - long timeout = maxIdleTimeout; - if (timeout < 1) { - return; - } - - if (System.currentTimeMillis() - lastActive > timeout) { - String msg = sm.getString("wsSession.timeout", getId()); - if (log.isDebugEnabled()) { - log.debug(msg); - } - doClose(new CloseReason(CloseCodes.GOING_AWAY, msg), - new CloseReason(CloseCodes.CLOSED_ABNORMALLY, msg)); - } - } - - - private void checkState() { - if (state == State.CLOSED) { - /* - * As per RFC 6455, a WebSocket connection is considered to be - * closed once a peer has sent and received a WebSocket close frame. - */ - throw new IllegalStateException(sm.getString("wsSession.closed", id)); - } - } - - private enum State { - OPEN, - OUTPUT_CLOSED, - CLOSED - } -} diff --git a/src/java/nginx/unit/websocket/WsWebSocketContainer.java b/src/java/nginx/unit/websocket/WsWebSocketContainer.java deleted file mode 100644 index 282665ef..00000000 --- a/src/java/nginx/unit/websocket/WsWebSocketContainer.java +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket; - -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.ProxySelector; -import java.net.SocketAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.ByteBuffer; -import java.nio.channels.AsynchronousChannelGroup; -import java.nio.channels.AsynchronousSocketChannel; -import java.nio.charset.StandardCharsets; -import java.security.KeyStore; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLParameters; -import javax.net.ssl.TrustManagerFactory; -import javax.websocket.ClientEndpoint; -import javax.websocket.ClientEndpointConfig; -import javax.websocket.CloseReason; -import javax.websocket.CloseReason.CloseCodes; -import javax.websocket.DeploymentException; -import javax.websocket.Endpoint; -import javax.websocket.Extension; -import javax.websocket.HandshakeResponse; -import javax.websocket.Session; -import javax.websocket.WebSocketContainer; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.InstanceManager; -import org.apache.tomcat.util.buf.StringUtils; -import org.apache.tomcat.util.codec.binary.Base64; -import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap; -import org.apache.tomcat.util.res.StringManager; -import nginx.unit.websocket.pojo.PojoEndpointClient; - -public class WsWebSocketContainer implements WebSocketContainer, BackgroundProcess { - - private static final StringManager sm = StringManager.getManager(WsWebSocketContainer.class); - private static final Random RANDOM = new Random(); - private static final byte[] CRLF = new byte[] { 13, 10 }; - - private static final byte[] GET_BYTES = "GET ".getBytes(StandardCharsets.ISO_8859_1); - private static final byte[] ROOT_URI_BYTES = "/".getBytes(StandardCharsets.ISO_8859_1); - private static final byte[] HTTP_VERSION_BYTES = - " HTTP/1.1\r\n".getBytes(StandardCharsets.ISO_8859_1); - - private volatile AsynchronousChannelGroup asynchronousChannelGroup = null; - private final Object asynchronousChannelGroupLock = new Object(); - - private final Log log = LogFactory.getLog(WsWebSocketContainer.class); // must not be static - private final Map> endpointSessionMap = - new HashMap<>(); - private final Map sessions = new ConcurrentHashMap<>(); - private final Object endPointSessionMapLock = new Object(); - - private long defaultAsyncTimeout = -1; - private int maxBinaryMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE; - private int maxTextMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE; - private volatile long defaultMaxSessionIdleTimeout = 0; - private int backgroundProcessCount = 0; - private int processPeriod = Constants.DEFAULT_PROCESS_PERIOD; - - private InstanceManager instanceManager; - - InstanceManager getInstanceManager() { - return instanceManager; - } - - protected void setInstanceManager(InstanceManager instanceManager) { - this.instanceManager = instanceManager; - } - - @Override - public Session connectToServer(Object pojo, URI path) - throws DeploymentException { - - ClientEndpoint annotation = - pojo.getClass().getAnnotation(ClientEndpoint.class); - if (annotation == null) { - throw new DeploymentException( - sm.getString("wsWebSocketContainer.missingAnnotation", - pojo.getClass().getName())); - } - - Endpoint ep = new PojoEndpointClient(pojo, Arrays.asList(annotation.decoders())); - - Class configuratorClazz = - annotation.configurator(); - - ClientEndpointConfig.Configurator configurator = null; - if (!ClientEndpointConfig.Configurator.class.equals( - configuratorClazz)) { - try { - configurator = configuratorClazz.getConstructor().newInstance(); - } catch (ReflectiveOperationException e) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.defaultConfiguratorFail"), e); - } - } - - ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create(); - // Avoid NPE when using RI API JAR - see BZ 56343 - if (configurator != null) { - builder.configurator(configurator); - } - ClientEndpointConfig config = builder. - decoders(Arrays.asList(annotation.decoders())). - encoders(Arrays.asList(annotation.encoders())). - preferredSubprotocols(Arrays.asList(annotation.subprotocols())). - build(); - return connectToServer(ep, config, path); - } - - - @Override - public Session connectToServer(Class annotatedEndpointClass, URI path) - throws DeploymentException { - - Object pojo; - try { - pojo = annotatedEndpointClass.getConstructor().newInstance(); - } catch (ReflectiveOperationException e) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.endpointCreateFail", - annotatedEndpointClass.getName()), e); - } - - return connectToServer(pojo, path); - } - - - @Override - public Session connectToServer(Class clazz, - ClientEndpointConfig clientEndpointConfiguration, URI path) - throws DeploymentException { - - Endpoint endpoint; - try { - endpoint = clazz.getConstructor().newInstance(); - } catch (ReflectiveOperationException e) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.endpointCreateFail", clazz.getName()), - e); - } - - return connectToServer(endpoint, clientEndpointConfiguration, path); - } - - - @Override - public Session connectToServer(Endpoint endpoint, - ClientEndpointConfig clientEndpointConfiguration, URI path) - throws DeploymentException { - return connectToServerRecursive(endpoint, clientEndpointConfiguration, path, new HashSet<>()); - } - - private Session connectToServerRecursive(Endpoint endpoint, - ClientEndpointConfig clientEndpointConfiguration, URI path, - Set redirectSet) - throws DeploymentException { - - boolean secure = false; - ByteBuffer proxyConnect = null; - URI proxyPath; - - // Validate scheme (and build proxyPath) - String scheme = path.getScheme(); - if ("ws".equalsIgnoreCase(scheme)) { - proxyPath = URI.create("http" + path.toString().substring(2)); - } else if ("wss".equalsIgnoreCase(scheme)) { - proxyPath = URI.create("https" + path.toString().substring(3)); - secure = true; - } else { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.pathWrongScheme", scheme)); - } - - // Validate host - String host = path.getHost(); - if (host == null) { - throw new DeploymentException( - sm.getString("wsWebSocketContainer.pathNoHost")); - } - int port = path.getPort(); - - SocketAddress sa = null; - - // Check to see if a proxy is configured. Javadoc indicates return value - // will never be null - List proxies = ProxySelector.getDefault().select(proxyPath); - Proxy selectedProxy = null; - for (Proxy proxy : proxies) { - if (proxy.type().equals(Proxy.Type.HTTP)) { - sa = proxy.address(); - if (sa instanceof InetSocketAddress) { - InetSocketAddress inet = (InetSocketAddress) sa; - if (inet.isUnresolved()) { - sa = new InetSocketAddress(inet.getHostName(), inet.getPort()); - } - } - selectedProxy = proxy; - break; - } - } - - // If the port is not explicitly specified, compute it based on the - // scheme - if (port == -1) { - if ("ws".equalsIgnoreCase(scheme)) { - port = 80; - } else { - // Must be wss due to scheme validation above - port = 443; - } - } - - // If sa is null, no proxy is configured so need to create sa - if (sa == null) { - sa = new InetSocketAddress(host, port); - } else { - proxyConnect = createProxyRequest(host, port); - } - - // Create the initial HTTP request to open the WebSocket connection - Map> reqHeaders = createRequestHeaders(host, port, - clientEndpointConfiguration); - clientEndpointConfiguration.getConfigurator().beforeRequest(reqHeaders); - if (Constants.DEFAULT_ORIGIN_HEADER_VALUE != null - && !reqHeaders.containsKey(Constants.ORIGIN_HEADER_NAME)) { - List originValues = new ArrayList<>(1); - originValues.add(Constants.DEFAULT_ORIGIN_HEADER_VALUE); - reqHeaders.put(Constants.ORIGIN_HEADER_NAME, originValues); - } - ByteBuffer request = createRequest(path, reqHeaders); - - AsynchronousSocketChannel socketChannel; - try { - socketChannel = AsynchronousSocketChannel.open(getAsynchronousChannelGroup()); - } catch (IOException ioe) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.asynchronousSocketChannelFail"), ioe); - } - - Map userProperties = clientEndpointConfiguration.getUserProperties(); - - // Get the connection timeout - long timeout = Constants.IO_TIMEOUT_MS_DEFAULT; - String timeoutValue = (String) userProperties.get(Constants.IO_TIMEOUT_MS_PROPERTY); - if (timeoutValue != null) { - timeout = Long.valueOf(timeoutValue).intValue(); - } - - // Set-up - // Same size as the WsFrame input buffer - ByteBuffer response = ByteBuffer.allocate(getDefaultMaxBinaryMessageBufferSize()); - String subProtocol; - boolean success = false; - List extensionsAgreed = new ArrayList<>(); - Transformation transformation = null; - - // Open the connection - Future fConnect = socketChannel.connect(sa); - AsyncChannelWrapper channel = null; - - if (proxyConnect != null) { - try { - fConnect.get(timeout, TimeUnit.MILLISECONDS); - // Proxy CONNECT is clear text - channel = new AsyncChannelWrapperNonSecure(socketChannel); - writeRequest(channel, proxyConnect, timeout); - HttpResponse httpResponse = processResponse(response, channel, timeout); - if (httpResponse.getStatus() != 200) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.proxyConnectFail", selectedProxy, - Integer.toString(httpResponse.getStatus()))); - } - } catch (TimeoutException | InterruptedException | ExecutionException | - EOFException e) { - if (channel != null) { - channel.close(); - } - throw new DeploymentException( - sm.getString("wsWebSocketContainer.httpRequestFailed"), e); - } - } - - if (secure) { - // Regardless of whether a non-secure wrapper was created for a - // proxy CONNECT, need to use TLS from this point on so wrap the - // original AsynchronousSocketChannel - SSLEngine sslEngine = createSSLEngine(userProperties, host, port); - channel = new AsyncChannelWrapperSecure(socketChannel, sslEngine); - } else if (channel == null) { - // Only need to wrap as this point if it wasn't wrapped to process a - // proxy CONNECT - channel = new AsyncChannelWrapperNonSecure(socketChannel); - } - - try { - fConnect.get(timeout, TimeUnit.MILLISECONDS); - - Future fHandshake = channel.handshake(); - fHandshake.get(timeout, TimeUnit.MILLISECONDS); - - writeRequest(channel, request, timeout); - - HttpResponse httpResponse = processResponse(response, channel, timeout); - - // Check maximum permitted redirects - int maxRedirects = Constants.MAX_REDIRECTIONS_DEFAULT; - String maxRedirectsValue = - (String) userProperties.get(Constants.MAX_REDIRECTIONS_PROPERTY); - if (maxRedirectsValue != null) { - maxRedirects = Integer.parseInt(maxRedirectsValue); - } - - if (httpResponse.status != 101) { - if(isRedirectStatus(httpResponse.status)){ - List locationHeader = - httpResponse.getHandshakeResponse().getHeaders().get( - Constants.LOCATION_HEADER_NAME); - - if (locationHeader == null || locationHeader.isEmpty() || - locationHeader.get(0) == null || locationHeader.get(0).isEmpty()) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.missingLocationHeader", - Integer.toString(httpResponse.status))); - } - - URI redirectLocation = URI.create(locationHeader.get(0)).normalize(); - - if (!redirectLocation.isAbsolute()) { - redirectLocation = path.resolve(redirectLocation); - } - - String redirectScheme = redirectLocation.getScheme().toLowerCase(); - - if (redirectScheme.startsWith("http")) { - redirectLocation = new URI(redirectScheme.replace("http", "ws"), - redirectLocation.getUserInfo(), redirectLocation.getHost(), - redirectLocation.getPort(), redirectLocation.getPath(), - redirectLocation.getQuery(), redirectLocation.getFragment()); - } - - if (!redirectSet.add(redirectLocation) || redirectSet.size() > maxRedirects) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.redirectThreshold", redirectLocation, - Integer.toString(redirectSet.size()), - Integer.toString(maxRedirects))); - } - - return connectToServerRecursive(endpoint, clientEndpointConfiguration, redirectLocation, redirectSet); - - } - - else if (httpResponse.status == 401) { - - if (userProperties.get(Constants.AUTHORIZATION_HEADER_NAME) != null) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.failedAuthentication", - Integer.valueOf(httpResponse.status))); - } - - List wwwAuthenticateHeaders = httpResponse.getHandshakeResponse() - .getHeaders().get(Constants.WWW_AUTHENTICATE_HEADER_NAME); - - if (wwwAuthenticateHeaders == null || wwwAuthenticateHeaders.isEmpty() || - wwwAuthenticateHeaders.get(0) == null || wwwAuthenticateHeaders.get(0).isEmpty()) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.missingWWWAuthenticateHeader", - Integer.toString(httpResponse.status))); - } - - String authScheme = wwwAuthenticateHeaders.get(0).split("\\s+", 2)[0]; - String requestUri = new String(request.array(), StandardCharsets.ISO_8859_1) - .split("\\s", 3)[1]; - - Authenticator auth = AuthenticatorFactory.getAuthenticator(authScheme); - - if (auth == null) { - throw new DeploymentException( - sm.getString("wsWebSocketContainer.unsupportedAuthScheme", - Integer.valueOf(httpResponse.status), authScheme)); - } - - userProperties.put(Constants.AUTHORIZATION_HEADER_NAME, auth.getAuthorization( - requestUri, wwwAuthenticateHeaders.get(0), userProperties)); - - return connectToServerRecursive(endpoint, clientEndpointConfiguration, path, redirectSet); - - } - - else { - throw new DeploymentException(sm.getString("wsWebSocketContainer.invalidStatus", - Integer.toString(httpResponse.status))); - } - } - HandshakeResponse handshakeResponse = httpResponse.getHandshakeResponse(); - clientEndpointConfiguration.getConfigurator().afterResponse(handshakeResponse); - - // Sub-protocol - List protocolHeaders = handshakeResponse.getHeaders().get( - Constants.WS_PROTOCOL_HEADER_NAME); - if (protocolHeaders == null || protocolHeaders.size() == 0) { - subProtocol = null; - } else if (protocolHeaders.size() == 1) { - subProtocol = protocolHeaders.get(0); - } else { - throw new DeploymentException( - sm.getString("wsWebSocketContainer.invalidSubProtocol")); - } - - // Extensions - // Should normally only be one header but handle the case of - // multiple headers - List extHeaders = handshakeResponse.getHeaders().get( - Constants.WS_EXTENSIONS_HEADER_NAME); - if (extHeaders != null) { - for (String extHeader : extHeaders) { - Util.parseExtensionHeader(extensionsAgreed, extHeader); - } - } - - // Build the transformations - TransformationFactory factory = TransformationFactory.getInstance(); - for (Extension extension : extensionsAgreed) { - List> wrapper = new ArrayList<>(1); - wrapper.add(extension.getParameters()); - Transformation t = factory.create(extension.getName(), wrapper, false); - if (t == null) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.invalidExtensionParameters")); - } - if (transformation == null) { - transformation = t; - } else { - transformation.setNext(t); - } - } - - success = true; - } catch (ExecutionException | InterruptedException | SSLException | - EOFException | TimeoutException | URISyntaxException | AuthenticationException e) { - throw new DeploymentException( - sm.getString("wsWebSocketContainer.httpRequestFailed"), e); - } finally { - if (!success) { - channel.close(); - } - } - - // Switch to WebSocket - WsRemoteEndpointImplClient wsRemoteEndpointClient = new WsRemoteEndpointImplClient(channel); - - WsSession wsSession = new WsSession(endpoint, wsRemoteEndpointClient, - this, null, null, null, null, null, extensionsAgreed, - subProtocol, Collections.emptyMap(), secure, - clientEndpointConfiguration, null); - - WsFrameClient wsFrameClient = new WsFrameClient(response, channel, - wsSession, transformation); - // WsFrame adds the necessary final transformations. Copy the - // completed transformation chain to the remote end point. - wsRemoteEndpointClient.setTransformation(wsFrameClient.getTransformation()); - - endpoint.onOpen(wsSession, clientEndpointConfiguration); - registerSession(endpoint, wsSession); - - /* It is possible that the server sent one or more messages as soon as - * the WebSocket connection was established. Depending on the exact - * timing of when those messages were sent they could be sat in the - * input buffer waiting to be read and will not trigger a "data - * available to read" event. Therefore, it is necessary to process the - * input buffer here. Note that this happens on the current thread which - * means that this thread will be used for any onMessage notifications. - * This is a special case. Subsequent "data available to read" events - * will be handled by threads from the AsyncChannelGroup's executor. - */ - wsFrameClient.startInputProcessing(); - - return wsSession; - } - - - private static void writeRequest(AsyncChannelWrapper channel, ByteBuffer request, - long timeout) throws TimeoutException, InterruptedException, ExecutionException { - int toWrite = request.limit(); - - Future fWrite = channel.write(request); - Integer thisWrite = fWrite.get(timeout, TimeUnit.MILLISECONDS); - toWrite -= thisWrite.intValue(); - - while (toWrite > 0) { - fWrite = channel.write(request); - thisWrite = fWrite.get(timeout, TimeUnit.MILLISECONDS); - toWrite -= thisWrite.intValue(); - } - } - - - private static boolean isRedirectStatus(int httpResponseCode) { - - boolean isRedirect = false; - - switch (httpResponseCode) { - case Constants.MULTIPLE_CHOICES: - case Constants.MOVED_PERMANENTLY: - case Constants.FOUND: - case Constants.SEE_OTHER: - case Constants.USE_PROXY: - case Constants.TEMPORARY_REDIRECT: - isRedirect = true; - break; - default: - break; - } - - return isRedirect; - } - - - private static ByteBuffer createProxyRequest(String host, int port) { - StringBuilder request = new StringBuilder(); - request.append("CONNECT "); - request.append(host); - request.append(':'); - request.append(port); - - request.append(" HTTP/1.1\r\nProxy-Connection: keep-alive\r\nConnection: keepalive\r\nHost: "); - request.append(host); - request.append(':'); - request.append(port); - - request.append("\r\n\r\n"); - - byte[] bytes = request.toString().getBytes(StandardCharsets.ISO_8859_1); - return ByteBuffer.wrap(bytes); - } - - protected void registerSession(Endpoint endpoint, WsSession wsSession) { - - if (!wsSession.isOpen()) { - // The session was closed during onOpen. No need to register it. - return; - } - synchronized (endPointSessionMapLock) { - if (endpointSessionMap.size() == 0) { - BackgroundProcessManager.getInstance().register(this); - } - Set wsSessions = endpointSessionMap.get(endpoint); - if (wsSessions == null) { - wsSessions = new HashSet<>(); - endpointSessionMap.put(endpoint, wsSessions); - } - wsSessions.add(wsSession); - } - sessions.put(wsSession, wsSession); - } - - - protected void unregisterSession(Endpoint endpoint, WsSession wsSession) { - - synchronized (endPointSessionMapLock) { - Set wsSessions = endpointSessionMap.get(endpoint); - if (wsSessions != null) { - wsSessions.remove(wsSession); - if (wsSessions.size() == 0) { - endpointSessionMap.remove(endpoint); - } - } - if (endpointSessionMap.size() == 0) { - BackgroundProcessManager.getInstance().unregister(this); - } - } - sessions.remove(wsSession); - } - - - Set getOpenSessions(Endpoint endpoint) { - HashSet result = new HashSet<>(); - synchronized (endPointSessionMapLock) { - Set sessions = endpointSessionMap.get(endpoint); - if (sessions != null) { - result.addAll(sessions); - } - } - return result; - } - - private static Map> createRequestHeaders(String host, int port, - ClientEndpointConfig clientEndpointConfiguration) { - - Map> headers = new HashMap<>(); - List extensions = clientEndpointConfiguration.getExtensions(); - List subProtocols = clientEndpointConfiguration.getPreferredSubprotocols(); - Map userProperties = clientEndpointConfiguration.getUserProperties(); - - if (userProperties.get(Constants.AUTHORIZATION_HEADER_NAME) != null) { - List authValues = new ArrayList<>(1); - authValues.add((String) userProperties.get(Constants.AUTHORIZATION_HEADER_NAME)); - headers.put(Constants.AUTHORIZATION_HEADER_NAME, authValues); - } - - // Host header - List hostValues = new ArrayList<>(1); - if (port == -1) { - hostValues.add(host); - } else { - hostValues.add(host + ':' + port); - } - - headers.put(Constants.HOST_HEADER_NAME, hostValues); - - // Upgrade header - List upgradeValues = new ArrayList<>(1); - upgradeValues.add(Constants.UPGRADE_HEADER_VALUE); - headers.put(Constants.UPGRADE_HEADER_NAME, upgradeValues); - - // Connection header - List connectionValues = new ArrayList<>(1); - connectionValues.add(Constants.CONNECTION_HEADER_VALUE); - headers.put(Constants.CONNECTION_HEADER_NAME, connectionValues); - - // WebSocket version header - List wsVersionValues = new ArrayList<>(1); - wsVersionValues.add(Constants.WS_VERSION_HEADER_VALUE); - headers.put(Constants.WS_VERSION_HEADER_NAME, wsVersionValues); - - // WebSocket key - List wsKeyValues = new ArrayList<>(1); - wsKeyValues.add(generateWsKeyValue()); - headers.put(Constants.WS_KEY_HEADER_NAME, wsKeyValues); - - // WebSocket sub-protocols - if (subProtocols != null && subProtocols.size() > 0) { - headers.put(Constants.WS_PROTOCOL_HEADER_NAME, subProtocols); - } - - // WebSocket extensions - if (extensions != null && extensions.size() > 0) { - headers.put(Constants.WS_EXTENSIONS_HEADER_NAME, - generateExtensionHeaders(extensions)); - } - - return headers; - } - - - private static List generateExtensionHeaders(List extensions) { - List result = new ArrayList<>(extensions.size()); - for (Extension extension : extensions) { - StringBuilder header = new StringBuilder(); - header.append(extension.getName()); - for (Extension.Parameter param : extension.getParameters()) { - header.append(';'); - header.append(param.getName()); - String value = param.getValue(); - if (value != null && value.length() > 0) { - header.append('='); - header.append(value); - } - } - result.add(header.toString()); - } - return result; - } - - - private static String generateWsKeyValue() { - byte[] keyBytes = new byte[16]; - RANDOM.nextBytes(keyBytes); - return Base64.encodeBase64String(keyBytes); - } - - - private static ByteBuffer createRequest(URI uri, Map> reqHeaders) { - ByteBuffer result = ByteBuffer.allocate(4 * 1024); - - // Request line - result.put(GET_BYTES); - if (null == uri.getPath() || "".equals(uri.getPath())) { - result.put(ROOT_URI_BYTES); - } else { - result.put(uri.getRawPath().getBytes(StandardCharsets.ISO_8859_1)); - } - String query = uri.getRawQuery(); - if (query != null) { - result.put((byte) '?'); - result.put(query.getBytes(StandardCharsets.ISO_8859_1)); - } - result.put(HTTP_VERSION_BYTES); - - // Headers - for (Entry> entry : reqHeaders.entrySet()) { - result = addHeader(result, entry.getKey(), entry.getValue()); - } - - // Terminating CRLF - result.put(CRLF); - - result.flip(); - - return result; - } - - - private static ByteBuffer addHeader(ByteBuffer result, String key, List values) { - if (values.isEmpty()) { - return result; - } - - result = putWithExpand(result, key.getBytes(StandardCharsets.ISO_8859_1)); - result = putWithExpand(result, ": ".getBytes(StandardCharsets.ISO_8859_1)); - result = putWithExpand(result, StringUtils.join(values).getBytes(StandardCharsets.ISO_8859_1)); - result = putWithExpand(result, CRLF); - - return result; - } - - - private static ByteBuffer putWithExpand(ByteBuffer input, byte[] bytes) { - if (bytes.length > input.remaining()) { - int newSize; - if (bytes.length > input.capacity()) { - newSize = 2 * bytes.length; - } else { - newSize = input.capacity() * 2; - } - ByteBuffer expanded = ByteBuffer.allocate(newSize); - input.flip(); - expanded.put(input); - input = expanded; - } - return input.put(bytes); - } - - - /** - * Process response, blocking until HTTP response has been fully received. - * @throws ExecutionException - * @throws InterruptedException - * @throws DeploymentException - * @throws TimeoutException - */ - private HttpResponse processResponse(ByteBuffer response, - AsyncChannelWrapper channel, long timeout) throws InterruptedException, - ExecutionException, DeploymentException, EOFException, - TimeoutException { - - Map> headers = new CaseInsensitiveKeyMap<>(); - - int status = 0; - boolean readStatus = false; - boolean readHeaders = false; - String line = null; - while (!readHeaders) { - // On entering loop buffer will be empty and at the start of a new - // loop the buffer will have been fully read. - response.clear(); - // Blocking read - Future read = channel.read(response); - Integer bytesRead = read.get(timeout, TimeUnit.MILLISECONDS); - if (bytesRead.intValue() == -1) { - throw new EOFException(); - } - response.flip(); - while (response.hasRemaining() && !readHeaders) { - if (line == null) { - line = readLine(response); - } else { - line += readLine(response); - } - if ("\r\n".equals(line)) { - readHeaders = true; - } else if (line.endsWith("\r\n")) { - if (readStatus) { - parseHeaders(line, headers); - } else { - status = parseStatus(line); - readStatus = true; - } - line = null; - } - } - } - - return new HttpResponse(status, new WsHandshakeResponse(headers)); - } - - - private int parseStatus(String line) throws DeploymentException { - // This client only understands HTTP 1. - // RFC2616 is case specific - String[] parts = line.trim().split(" "); - // CONNECT for proxy may return a 1.0 response - if (parts.length < 2 || !("HTTP/1.0".equals(parts[0]) || "HTTP/1.1".equals(parts[0]))) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.invalidStatus", line)); - } - try { - return Integer.parseInt(parts[1]); - } catch (NumberFormatException nfe) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.invalidStatus", line)); - } - } - - - private void parseHeaders(String line, Map> headers) { - // Treat headers as single values by default. - - int index = line.indexOf(':'); - if (index == -1) { - log.warn(sm.getString("wsWebSocketContainer.invalidHeader", line)); - return; - } - // Header names are case insensitive so always use lower case - String headerName = line.substring(0, index).trim().toLowerCase(Locale.ENGLISH); - // Multi-value headers are stored as a single header and the client is - // expected to handle splitting into individual values - String headerValue = line.substring(index + 1).trim(); - - List values = headers.get(headerName); - if (values == null) { - values = new ArrayList<>(1); - headers.put(headerName, values); - } - values.add(headerValue); - } - - private String readLine(ByteBuffer response) { - // All ISO-8859-1 - StringBuilder sb = new StringBuilder(); - - char c = 0; - while (response.hasRemaining()) { - c = (char) response.get(); - sb.append(c); - if (c == 10) { - break; - } - } - - return sb.toString(); - } - - - private SSLEngine createSSLEngine(Map userProperties, String host, int port) - throws DeploymentException { - - try { - // See if a custom SSLContext has been provided - SSLContext sslContext = - (SSLContext) userProperties.get(Constants.SSL_CONTEXT_PROPERTY); - - if (sslContext == null) { - // Create the SSL Context - sslContext = SSLContext.getInstance("TLS"); - - // Trust store - String sslTrustStoreValue = - (String) userProperties.get(Constants.SSL_TRUSTSTORE_PROPERTY); - if (sslTrustStoreValue != null) { - String sslTrustStorePwdValue = (String) userProperties.get( - Constants.SSL_TRUSTSTORE_PWD_PROPERTY); - if (sslTrustStorePwdValue == null) { - sslTrustStorePwdValue = Constants.SSL_TRUSTSTORE_PWD_DEFAULT; - } - - File keyStoreFile = new File(sslTrustStoreValue); - KeyStore ks = KeyStore.getInstance("JKS"); - try (InputStream is = new FileInputStream(keyStoreFile)) { - ks.load(is, sslTrustStorePwdValue.toCharArray()); - } - - TrustManagerFactory tmf = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(ks); - - sslContext.init(null, tmf.getTrustManagers(), null); - } else { - sslContext.init(null, null, null); - } - } - - SSLEngine engine = sslContext.createSSLEngine(host, port); - - String sslProtocolsValue = - (String) userProperties.get(Constants.SSL_PROTOCOLS_PROPERTY); - if (sslProtocolsValue != null) { - engine.setEnabledProtocols(sslProtocolsValue.split(",")); - } - - engine.setUseClientMode(true); - - // Enable host verification - // Start with current settings (returns a copy) - SSLParameters sslParams = engine.getSSLParameters(); - // Use HTTPS since WebSocket starts over HTTP(S) - sslParams.setEndpointIdentificationAlgorithm("HTTPS"); - // Write the parameters back - engine.setSSLParameters(sslParams); - - return engine; - } catch (Exception e) { - throw new DeploymentException(sm.getString( - "wsWebSocketContainer.sslEngineFail"), e); - } - } - - - @Override - public long getDefaultMaxSessionIdleTimeout() { - return defaultMaxSessionIdleTimeout; - } - - - @Override - public void setDefaultMaxSessionIdleTimeout(long timeout) { - this.defaultMaxSessionIdleTimeout = timeout; - } - - - @Override - public int getDefaultMaxBinaryMessageBufferSize() { - return maxBinaryMessageBufferSize; - } - - - @Override - public void setDefaultMaxBinaryMessageBufferSize(int max) { - maxBinaryMessageBufferSize = max; - } - - - @Override - public int getDefaultMaxTextMessageBufferSize() { - return maxTextMessageBufferSize; - } - - - @Override - public void setDefaultMaxTextMessageBufferSize(int max) { - maxTextMessageBufferSize = max; - } - - - /** - * {@inheritDoc} - * - * Currently, this implementation does not support any extensions. - */ - @Override - public Set getInstalledExtensions() { - return Collections.emptySet(); - } - - - /** - * {@inheritDoc} - * - * The default value for this implementation is -1. - */ - @Override - public long getDefaultAsyncSendTimeout() { - return defaultAsyncTimeout; - } - - - /** - * {@inheritDoc} - * - * The default value for this implementation is -1. - */ - @Override - public void setAsyncSendTimeout(long timeout) { - this.defaultAsyncTimeout = timeout; - } - - - /** - * Cleans up the resources still in use by WebSocket sessions created from - * this container. This includes closing sessions and cancelling - * {@link Future}s associated with blocking read/writes. - */ - public void destroy() { - CloseReason cr = new CloseReason( - CloseCodes.GOING_AWAY, sm.getString("wsWebSocketContainer.shutdown")); - - for (WsSession session : sessions.keySet()) { - try { - session.close(cr); - } catch (IOException ioe) { - log.debug(sm.getString( - "wsWebSocketContainer.sessionCloseFail", session.getId()), ioe); - } - } - - // Only unregister with AsyncChannelGroupUtil if this instance - // registered with it - if (asynchronousChannelGroup != null) { - synchronized (asynchronousChannelGroupLock) { - if (asynchronousChannelGroup != null) { - AsyncChannelGroupUtil.unregister(); - asynchronousChannelGroup = null; - } - } - } - } - - - private AsynchronousChannelGroup getAsynchronousChannelGroup() { - // Use AsyncChannelGroupUtil to share a common group amongst all - // WebSocket clients - AsynchronousChannelGroup result = asynchronousChannelGroup; - if (result == null) { - synchronized (asynchronousChannelGroupLock) { - if (asynchronousChannelGroup == null) { - asynchronousChannelGroup = AsyncChannelGroupUtil.register(); - } - result = asynchronousChannelGroup; - } - } - return result; - } - - - // ----------------------------------------------- BackgroundProcess methods - - @Override - public void backgroundProcess() { - // This method gets called once a second. - backgroundProcessCount ++; - if (backgroundProcessCount >= processPeriod) { - backgroundProcessCount = 0; - - for (WsSession wsSession : sessions.keySet()) { - wsSession.checkExpiration(); - } - } - - } - - - @Override - public void setProcessPeriod(int period) { - this.processPeriod = period; - } - - - /** - * {@inheritDoc} - * - * The default value is 10 which means session expirations are processed - * every 10 seconds. - */ - @Override - public int getProcessPeriod() { - return processPeriod; - } - - - private static class HttpResponse { - private final int status; - private final HandshakeResponse handshakeResponse; - - public HttpResponse(int status, HandshakeResponse handshakeResponse) { - this.status = status; - this.handshakeResponse = handshakeResponse; - } - - - public int getStatus() { - return status; - } - - - public HandshakeResponse getHandshakeResponse() { - return handshakeResponse; - } - } -} diff --git a/src/java/nginx/unit/websocket/pojo/Constants.java b/src/java/nginx/unit/websocket/pojo/Constants.java deleted file mode 100644 index 93cdecc7..00000000 --- a/src/java/nginx/unit/websocket/pojo/Constants.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -/** - * Internal implementation constants. - */ -public class Constants { - - public static final String POJO_PATH_PARAM_KEY = - "nginx.unit.websocket.pojo.PojoEndpoint.pathParams"; - public static final String POJO_METHOD_MAPPING_KEY = - "nginx.unit.websocket.pojo.PojoEndpoint.methodMapping"; - - private Constants() { - // Hide default constructor - } -} diff --git a/src/java/nginx/unit/websocket/pojo/LocalStrings.properties b/src/java/nginx/unit/websocket/pojo/LocalStrings.properties deleted file mode 100644 index 00ab7e6b..00000000 --- a/src/java/nginx/unit/websocket/pojo/LocalStrings.properties +++ /dev/null @@ -1,40 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -pojoEndpointBase.closeSessionFail=Failed to close WebSocket session during error handling -pojoEndpointBase.onCloseFail=Failed to call onClose method of POJO end point for POJO of type [{0}] -pojoEndpointBase.onError=No error handling configured for [{0}] and the following error occurred -pojoEndpointBase.onErrorFail=Failed to call onError method of POJO end point for POJO of type [{0}] -pojoEndpointBase.onOpenFail=Failed to call onOpen method of POJO end point for POJO of type [{0}] -pojoEndpointServer.getPojoInstanceFail=Failed to create instance of POJO of type [{0}] -pojoMethodMapping.decodePathParamFail=Failed to decode path parameter value [{0}] to expected type [{1}] -pojoMethodMapping.duplicateAnnotation=Duplicate annotations [{0}] present on class [{1}] -pojoMethodMapping.duplicateLastParam=Multiple boolean (last) parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage -pojoMethodMapping.duplicateMessageParam=Multiple message parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage -pojoMethodMapping.duplicatePongMessageParam=Multiple PongMessage parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage -pojoMethodMapping.duplicateSessionParam=Multiple session parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage -pojoMethodMapping.invalidDecoder=The specified decoder of type [{0}] could not be instantiated -pojoMethodMapping.invalidPathParamType=Parameters annotated with @PathParam may only be Strings, Java primitives or a boxed version thereof -pojoMethodMapping.methodNotPublic=The annotated method [{0}] is not public -pojoMethodMapping.noPayload=No payload parameter present on the method [{0}] of class [{1}] that was annotated with OnMessage -pojoMethodMapping.onErrorNoThrowable=No Throwable parameter was present on the method [{0}] of class [{1}] that was annotated with OnError -pojoMethodMapping.paramWithoutAnnotation=A parameter of type [{0}] was found on method[{1}] of class [{2}] that did not have a @PathParam annotation -pojoMethodMapping.partialInputStream=Invalid InputStream and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage -pojoMethodMapping.partialObject=Invalid Object and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage -pojoMethodMapping.partialPong=Invalid PongMessage and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage -pojoMethodMapping.partialReader=Invalid Reader and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage -pojoMethodMapping.pongWithPayload=Invalid PongMessage and Message parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage -pojoMessageHandlerWhole.decodeIoFail=IO error while decoding message -pojoMessageHandlerWhole.maxBufferSize=The maximum supported message size for this implementation is Integer.MAX_VALUE diff --git a/src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java b/src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java deleted file mode 100644 index be679a35..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.util.Map; -import java.util.Set; - -import javax.websocket.CloseReason; -import javax.websocket.Endpoint; -import javax.websocket.EndpointConfig; -import javax.websocket.MessageHandler; -import javax.websocket.Session; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.util.ExceptionUtils; -import org.apache.tomcat.util.res.StringManager; - -/** - * Base implementation (client and server have different concrete - * implementations) of the wrapper that converts a POJO instance into a - * WebSocket endpoint instance. - */ -public abstract class PojoEndpointBase extends Endpoint { - - private final Log log = LogFactory.getLog(PojoEndpointBase.class); // must not be static - private static final StringManager sm = StringManager.getManager(PojoEndpointBase.class); - - private Object pojo; - private Map pathParameters; - private PojoMethodMapping methodMapping; - - - protected final void doOnOpen(Session session, EndpointConfig config) { - PojoMethodMapping methodMapping = getMethodMapping(); - Object pojo = getPojo(); - Map pathParameters = getPathParameters(); - - // Add message handlers before calling onOpen since that may trigger a - // message which in turn could trigger a response and/or close the - // session - for (MessageHandler mh : methodMapping.getMessageHandlers(pojo, - pathParameters, session, config)) { - session.addMessageHandler(mh); - } - - if (methodMapping.getOnOpen() != null) { - try { - methodMapping.getOnOpen().invoke(pojo, - methodMapping.getOnOpenArgs( - pathParameters, session, config)); - - } catch (IllegalAccessException e) { - // Reflection related problems - log.error(sm.getString( - "pojoEndpointBase.onOpenFail", - pojo.getClass().getName()), e); - handleOnOpenOrCloseError(session, e); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - handleOnOpenOrCloseError(session, cause); - } catch (Throwable t) { - handleOnOpenOrCloseError(session, t); - } - } - } - - - private void handleOnOpenOrCloseError(Session session, Throwable t) { - // If really fatal - re-throw - ExceptionUtils.handleThrowable(t); - - // Trigger the error handler and close the session - onError(session, t); - try { - session.close(); - } catch (IOException ioe) { - log.warn(sm.getString("pojoEndpointBase.closeSessionFail"), ioe); - } - } - - @Override - public final void onClose(Session session, CloseReason closeReason) { - - if (methodMapping.getOnClose() != null) { - try { - methodMapping.getOnClose().invoke(pojo, - methodMapping.getOnCloseArgs(pathParameters, session, closeReason)); - } catch (Throwable t) { - log.error(sm.getString("pojoEndpointBase.onCloseFail", - pojo.getClass().getName()), t); - handleOnOpenOrCloseError(session, t); - } - } - - // Trigger the destroy method for any associated decoders - Set messageHandlers = session.getMessageHandlers(); - for (MessageHandler messageHandler : messageHandlers) { - if (messageHandler instanceof PojoMessageHandlerWholeBase) { - ((PojoMessageHandlerWholeBase) messageHandler).onClose(); - } - } - } - - - @Override - public final void onError(Session session, Throwable throwable) { - - if (methodMapping.getOnError() == null) { - log.error(sm.getString("pojoEndpointBase.onError", - pojo.getClass().getName()), throwable); - } else { - try { - methodMapping.getOnError().invoke( - pojo, - methodMapping.getOnErrorArgs(pathParameters, session, - throwable)); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - log.error(sm.getString("pojoEndpointBase.onErrorFail", - pojo.getClass().getName()), t); - } - } - } - - protected Object getPojo() { return pojo; } - protected void setPojo(Object pojo) { this.pojo = pojo; } - - - protected Map getPathParameters() { return pathParameters; } - protected void setPathParameters(Map pathParameters) { - this.pathParameters = pathParameters; - } - - - protected PojoMethodMapping getMethodMapping() { return methodMapping; } - protected void setMethodMapping(PojoMethodMapping methodMapping) { - this.methodMapping = methodMapping; - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoEndpointClient.java b/src/java/nginx/unit/websocket/pojo/PojoEndpointClient.java deleted file mode 100644 index 6e569487..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoEndpointClient.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.util.Collections; -import java.util.List; - -import javax.websocket.Decoder; -import javax.websocket.DeploymentException; -import javax.websocket.EndpointConfig; -import javax.websocket.Session; - - -/** - * Wrapper class for instances of POJOs annotated with - * {@link javax.websocket.ClientEndpoint} so they appear as standard - * {@link javax.websocket.Endpoint} instances. - */ -public class PojoEndpointClient extends PojoEndpointBase { - - public PojoEndpointClient(Object pojo, - List> decoders) throws DeploymentException { - setPojo(pojo); - setMethodMapping( - new PojoMethodMapping(pojo.getClass(), decoders, null)); - setPathParameters(Collections.emptyMap()); - } - - @Override - public void onOpen(Session session, EndpointConfig config) { - doOnOpen(session, config); - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoEndpointServer.java b/src/java/nginx/unit/websocket/pojo/PojoEndpointServer.java deleted file mode 100644 index 499f8274..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoEndpointServer.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.util.Map; - -import javax.websocket.EndpointConfig; -import javax.websocket.Session; -import javax.websocket.server.ServerEndpointConfig; - -import org.apache.tomcat.util.res.StringManager; - -/** - * Wrapper class for instances of POJOs annotated with - * {@link javax.websocket.server.ServerEndpoint} so they appear as standard - * {@link javax.websocket.Endpoint} instances. - */ -public class PojoEndpointServer extends PojoEndpointBase { - - private static final StringManager sm = - StringManager.getManager(PojoEndpointServer.class); - - @Override - public void onOpen(Session session, EndpointConfig endpointConfig) { - - ServerEndpointConfig sec = (ServerEndpointConfig) endpointConfig; - - Object pojo; - try { - pojo = sec.getConfigurator().getEndpointInstance( - sec.getEndpointClass()); - } catch (InstantiationException e) { - throw new IllegalArgumentException(sm.getString( - "pojoEndpointServer.getPojoInstanceFail", - sec.getEndpointClass().getName()), e); - } - setPojo(pojo); - - @SuppressWarnings("unchecked") - Map pathParameters = - (Map) sec.getUserProperties().get( - Constants.POJO_PATH_PARAM_KEY); - setPathParameters(pathParameters); - - PojoMethodMapping methodMapping = - (PojoMethodMapping) sec.getUserProperties().get( - Constants.POJO_METHOD_MAPPING_KEY); - setMethodMapping(methodMapping); - - doOnOpen(session, endpointConfig); - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerBase.java b/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerBase.java deleted file mode 100644 index b72d719a..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerBase.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; - -import javax.websocket.EncodeException; -import javax.websocket.MessageHandler; -import javax.websocket.RemoteEndpoint; -import javax.websocket.Session; - -import org.apache.tomcat.util.ExceptionUtils; -import nginx.unit.websocket.WrappedMessageHandler; - -/** - * Common implementation code for the POJO message handlers. - * - * @param The type of message to handle - */ -public abstract class PojoMessageHandlerBase - implements WrappedMessageHandler { - - protected final Object pojo; - protected final Method method; - protected final Session session; - protected final Object[] params; - protected final int indexPayload; - protected final boolean convert; - protected final int indexSession; - protected final long maxMessageSize; - - public PojoMessageHandlerBase(Object pojo, Method method, - Session session, Object[] params, int indexPayload, boolean convert, - int indexSession, long maxMessageSize) { - this.pojo = pojo; - this.method = method; - // TODO: The method should already be accessible here but the following - // code seems to be necessary in some as yet not fully understood cases. - try { - this.method.setAccessible(true); - } catch (Exception e) { - // It is better to make sure the method is accessible, but - // ignore exceptions and hope for the best - } - this.session = session; - this.params = params; - this.indexPayload = indexPayload; - this.convert = convert; - this.indexSession = indexSession; - this.maxMessageSize = maxMessageSize; - } - - - protected final void processResult(Object result) { - if (result == null) { - return; - } - - RemoteEndpoint.Basic remoteEndpoint = session.getBasicRemote(); - try { - if (result instanceof String) { - remoteEndpoint.sendText((String) result); - } else if (result instanceof ByteBuffer) { - remoteEndpoint.sendBinary((ByteBuffer) result); - } else if (result instanceof byte[]) { - remoteEndpoint.sendBinary(ByteBuffer.wrap((byte[]) result)); - } else { - remoteEndpoint.sendObject(result); - } - } catch (IOException | EncodeException ioe) { - throw new IllegalStateException(ioe); - } - } - - - /** - * Expose the POJO if it is a message handler so the Session is able to - * match requests to remove handlers if the original handler has been - * wrapped. - */ - @Override - public final MessageHandler getWrappedHandler() { - if (pojo instanceof MessageHandler) { - return (MessageHandler) pojo; - } else { - return null; - } - } - - - @Override - public final long getMaxMessageSize() { - return maxMessageSize; - } - - - protected final void handlePojoMethodException(Throwable t) { - t = ExceptionUtils.unwrapInvocationTargetException(t); - ExceptionUtils.handleThrowable(t); - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else { - throw new RuntimeException(t.getMessage(), t); - } - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialBase.java b/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialBase.java deleted file mode 100644 index d6f37724..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialBase.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; - -import javax.websocket.DecodeException; -import javax.websocket.MessageHandler; -import javax.websocket.Session; - -import nginx.unit.websocket.WsSession; - -/** - * Common implementation code for the POJO partial message handlers. All - * the real work is done in this class and in the superclass. - * - * @param The type of message to handle - */ -public abstract class PojoMessageHandlerPartialBase - extends PojoMessageHandlerBase implements MessageHandler.Partial { - - private final int indexBoolean; - - public PojoMessageHandlerPartialBase(Object pojo, Method method, - Session session, Object[] params, int indexPayload, - boolean convert, int indexBoolean, int indexSession, - long maxMessageSize) { - super(pojo, method, session, params, indexPayload, convert, - indexSession, maxMessageSize); - this.indexBoolean = indexBoolean; - } - - - @Override - public final void onMessage(T message, boolean last) { - if (params.length == 1 && params[0] instanceof DecodeException) { - ((WsSession) session).getLocal().onError(session, - (DecodeException) params[0]); - return; - } - Object[] parameters = params.clone(); - if (indexBoolean != -1) { - parameters[indexBoolean] = Boolean.valueOf(last); - } - if (indexSession != -1) { - parameters[indexSession] = session; - } - if (convert) { - parameters[indexPayload] = ((ByteBuffer) message).array(); - } else { - parameters[indexPayload] = message; - } - Object result = null; - try { - result = method.invoke(pojo, parameters); - } catch (IllegalAccessException | InvocationTargetException e) { - handlePojoMethodException(e); - } - processResult(result); - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialBinary.java b/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialBinary.java deleted file mode 100644 index 1d334017..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialBinary.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.lang.reflect.Method; -import java.nio.ByteBuffer; - -import javax.websocket.Session; - -/** - * ByteBuffer specific concrete implementation for handling partial messages. - */ -public class PojoMessageHandlerPartialBinary - extends PojoMessageHandlerPartialBase { - - public PojoMessageHandlerPartialBinary(Object pojo, Method method, - Session session, Object[] params, int indexPayload, boolean convert, - int indexBoolean, int indexSession, long maxMessageSize) { - super(pojo, method, session, params, indexPayload, convert, indexBoolean, - indexSession, maxMessageSize); - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialText.java b/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialText.java deleted file mode 100644 index 8f7c1a0d..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerPartialText.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.lang.reflect.Method; - -import javax.websocket.Session; - -/** - * Text specific concrete implementation for handling partial messages. - */ -public class PojoMessageHandlerPartialText - extends PojoMessageHandlerPartialBase { - - public PojoMessageHandlerPartialText(Object pojo, Method method, - Session session, Object[] params, int indexPayload, boolean convert, - int indexBoolean, int indexSession, long maxMessageSize) { - super(pojo, method, session, params, indexPayload, convert, indexBoolean, - indexSession, maxMessageSize); - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeBase.java b/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeBase.java deleted file mode 100644 index 23333eb7..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeBase.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import javax.websocket.DecodeException; -import javax.websocket.MessageHandler; -import javax.websocket.Session; - -import nginx.unit.websocket.WsSession; - -/** - * Common implementation code for the POJO whole message handlers. All the real - * work is done in this class and in the superclass. - * - * @param The type of message to handle - */ -public abstract class PojoMessageHandlerWholeBase - extends PojoMessageHandlerBase implements MessageHandler.Whole { - - public PojoMessageHandlerWholeBase(Object pojo, Method method, - Session session, Object[] params, int indexPayload, - boolean convert, int indexSession, long maxMessageSize) { - super(pojo, method, session, params, indexPayload, convert, - indexSession, maxMessageSize); - } - - - @Override - public final void onMessage(T message) { - - if (params.length == 1 && params[0] instanceof DecodeException) { - ((WsSession) session).getLocal().onError(session, - (DecodeException) params[0]); - return; - } - - // Can this message be decoded? - Object payload; - try { - payload = decode(message); - } catch (DecodeException de) { - ((WsSession) session).getLocal().onError(session, de); - return; - } - - if (payload == null) { - // Not decoded. Convert if required. - if (convert) { - payload = convert(message); - } else { - payload = message; - } - } - - Object[] parameters = params.clone(); - if (indexSession != -1) { - parameters[indexSession] = session; - } - parameters[indexPayload] = payload; - - Object result = null; - try { - result = method.invoke(pojo, parameters); - } catch (IllegalAccessException | InvocationTargetException e) { - handlePojoMethodException(e); - } - processResult(result); - } - - protected Object convert(T message) { - return message; - } - - - protected abstract Object decode(T message) throws DecodeException; - protected abstract void onClose(); -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeBinary.java b/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeBinary.java deleted file mode 100644 index 07ff0648..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeBinary.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -import javax.websocket.DecodeException; -import javax.websocket.Decoder; -import javax.websocket.Decoder.Binary; -import javax.websocket.Decoder.BinaryStream; -import javax.websocket.EndpointConfig; -import javax.websocket.Session; - -import org.apache.tomcat.util.res.StringManager; - -/** - * ByteBuffer specific concrete implementation for handling whole messages. - */ -public class PojoMessageHandlerWholeBinary - extends PojoMessageHandlerWholeBase { - - private static final StringManager sm = - StringManager.getManager(PojoMessageHandlerWholeBinary.class); - - private final List decoders = new ArrayList<>(); - - private final boolean isForInputStream; - - public PojoMessageHandlerWholeBinary(Object pojo, Method method, - Session session, EndpointConfig config, - List> decoderClazzes, Object[] params, - int indexPayload, boolean convert, int indexSession, - boolean isForInputStream, long maxMessageSize) { - super(pojo, method, session, params, indexPayload, convert, - indexSession, maxMessageSize); - - // Update binary text size handled by session - if (maxMessageSize > -1 && maxMessageSize > session.getMaxBinaryMessageBufferSize()) { - if (maxMessageSize > Integer.MAX_VALUE) { - throw new IllegalArgumentException(sm.getString( - "pojoMessageHandlerWhole.maxBufferSize")); - } - session.setMaxBinaryMessageBufferSize((int) maxMessageSize); - } - - try { - if (decoderClazzes != null) { - for (Class decoderClazz : decoderClazzes) { - if (Binary.class.isAssignableFrom(decoderClazz)) { - Binary decoder = (Binary) decoderClazz.getConstructor().newInstance(); - decoder.init(config); - decoders.add(decoder); - } else if (BinaryStream.class.isAssignableFrom( - decoderClazz)) { - BinaryStream decoder = (BinaryStream) - decoderClazz.getConstructor().newInstance(); - decoder.init(config); - decoders.add(decoder); - } else { - // Text decoder - ignore it - } - } - } - } catch (ReflectiveOperationException e) { - throw new IllegalArgumentException(e); - } - this.isForInputStream = isForInputStream; - } - - - @Override - protected Object decode(ByteBuffer message) throws DecodeException { - for (Decoder decoder : decoders) { - if (decoder instanceof Binary) { - if (((Binary) decoder).willDecode(message)) { - return ((Binary) decoder).decode(message); - } - } else { - byte[] array = new byte[message.limit() - message.position()]; - message.get(array); - ByteArrayInputStream bais = new ByteArrayInputStream(array); - try { - return ((BinaryStream) decoder).decode(bais); - } catch (IOException ioe) { - throw new DecodeException(message, sm.getString( - "pojoMessageHandlerWhole.decodeIoFail"), ioe); - } - } - } - return null; - } - - - @Override - protected Object convert(ByteBuffer message) { - byte[] array = new byte[message.remaining()]; - message.get(array); - if (isForInputStream) { - return new ByteArrayInputStream(array); - } else { - return array; - } - } - - - @Override - protected void onClose() { - for (Decoder decoder : decoders) { - decoder.destroy(); - } - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholePong.java b/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholePong.java deleted file mode 100644 index bdedd7de..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholePong.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.lang.reflect.Method; - -import javax.websocket.PongMessage; -import javax.websocket.Session; - -/** - * PongMessage specific concrete implementation for handling whole messages. - */ -public class PojoMessageHandlerWholePong - extends PojoMessageHandlerWholeBase { - - public PojoMessageHandlerWholePong(Object pojo, Method method, - Session session, Object[] params, int indexPayload, boolean convert, - int indexSession) { - super(pojo, method, session, params, indexPayload, convert, - indexSession, -1); - } - - @Override - protected Object decode(PongMessage message) { - // Never decoded - return null; - } - - - @Override - protected void onClose() { - // NO-OP - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeText.java b/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeText.java deleted file mode 100644 index 59007349..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoMessageHandlerWholeText.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.io.IOException; -import java.io.StringReader; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import javax.websocket.DecodeException; -import javax.websocket.Decoder; -import javax.websocket.Decoder.Text; -import javax.websocket.Decoder.TextStream; -import javax.websocket.EndpointConfig; -import javax.websocket.Session; - -import org.apache.tomcat.util.res.StringManager; -import nginx.unit.websocket.Util; - - -/** - * Text specific concrete implementation for handling whole messages. - */ -public class PojoMessageHandlerWholeText - extends PojoMessageHandlerWholeBase { - - private static final StringManager sm = - StringManager.getManager(PojoMessageHandlerWholeText.class); - - private final List decoders = new ArrayList<>(); - private final Class primitiveType; - - public PojoMessageHandlerWholeText(Object pojo, Method method, - Session session, EndpointConfig config, - List> decoderClazzes, Object[] params, - int indexPayload, boolean convert, int indexSession, - long maxMessageSize) { - super(pojo, method, session, params, indexPayload, convert, - indexSession, maxMessageSize); - - // Update max text size handled by session - if (maxMessageSize > -1 && maxMessageSize > session.getMaxTextMessageBufferSize()) { - if (maxMessageSize > Integer.MAX_VALUE) { - throw new IllegalArgumentException(sm.getString( - "pojoMessageHandlerWhole.maxBufferSize")); - } - session.setMaxTextMessageBufferSize((int) maxMessageSize); - } - - // Check for primitives - Class type = method.getParameterTypes()[indexPayload]; - if (Util.isPrimitive(type)) { - primitiveType = type; - return; - } else { - primitiveType = null; - } - - try { - if (decoderClazzes != null) { - for (Class decoderClazz : decoderClazzes) { - if (Text.class.isAssignableFrom(decoderClazz)) { - Text decoder = (Text) decoderClazz.getConstructor().newInstance(); - decoder.init(config); - decoders.add(decoder); - } else if (TextStream.class.isAssignableFrom( - decoderClazz)) { - TextStream decoder = - (TextStream) decoderClazz.getConstructor().newInstance(); - decoder.init(config); - decoders.add(decoder); - } else { - // Binary decoder - ignore it - } - } - } - } catch (ReflectiveOperationException e) { - throw new IllegalArgumentException(e); - } - } - - - @Override - protected Object decode(String message) throws DecodeException { - // Handle primitives - if (primitiveType != null) { - return Util.coerceToType(primitiveType, message); - } - // Handle full decoders - for (Decoder decoder : decoders) { - if (decoder instanceof Text) { - if (((Text) decoder).willDecode(message)) { - return ((Text) decoder).decode(message); - } - } else { - StringReader r = new StringReader(message); - try { - return ((TextStream) decoder).decode(r); - } catch (IOException ioe) { - throw new DecodeException(message, sm.getString( - "pojoMessageHandlerWhole.decodeIoFail"), ioe); - } - } - } - return null; - } - - - @Override - protected Object convert(String message) { - return new StringReader(message); - } - - - @Override - protected void onClose() { - for (Decoder decoder : decoders) { - decoder.destroy(); - } - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoMethodMapping.java b/src/java/nginx/unit/websocket/pojo/PojoMethodMapping.java deleted file mode 100644 index 2385b5c7..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoMethodMapping.java +++ /dev/null @@ -1,731 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -import java.io.InputStream; -import java.io.Reader; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.websocket.CloseReason; -import javax.websocket.DecodeException; -import javax.websocket.Decoder; -import javax.websocket.DeploymentException; -import javax.websocket.EndpointConfig; -import javax.websocket.MessageHandler; -import javax.websocket.OnClose; -import javax.websocket.OnError; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.PongMessage; -import javax.websocket.Session; -import javax.websocket.server.PathParam; - -import org.apache.tomcat.util.res.StringManager; -import nginx.unit.websocket.DecoderEntry; -import nginx.unit.websocket.Util; -import nginx.unit.websocket.Util.DecoderMatch; - -/** - * For a POJO class annotated with - * {@link javax.websocket.server.ServerEndpoint}, an instance of this class - * creates and caches the method handler, method information and parameter - * information for the onXXX calls. - */ -public class PojoMethodMapping { - - private static final StringManager sm = - StringManager.getManager(PojoMethodMapping.class); - - private final Method onOpen; - private final Method onClose; - private final Method onError; - private final PojoPathParam[] onOpenParams; - private final PojoPathParam[] onCloseParams; - private final PojoPathParam[] onErrorParams; - private final List onMessage = new ArrayList<>(); - private final String wsPath; - - - public PojoMethodMapping(Class clazzPojo, - List> decoderClazzes, String wsPath) - throws DeploymentException { - - this.wsPath = wsPath; - - List decoders = Util.getDecoders(decoderClazzes); - Method open = null; - Method close = null; - Method error = null; - Method[] clazzPojoMethods = null; - Class currentClazz = clazzPojo; - while (!currentClazz.equals(Object.class)) { - Method[] currentClazzMethods = currentClazz.getDeclaredMethods(); - if (currentClazz == clazzPojo) { - clazzPojoMethods = currentClazzMethods; - } - for (Method method : currentClazzMethods) { - if (method.getAnnotation(OnOpen.class) != null) { - checkPublic(method); - if (open == null) { - open = method; - } else { - if (currentClazz == clazzPojo || - !isMethodOverride(open, method)) { - // Duplicate annotation - throw new DeploymentException(sm.getString( - "pojoMethodMapping.duplicateAnnotation", - OnOpen.class, currentClazz)); - } - } - } else if (method.getAnnotation(OnClose.class) != null) { - checkPublic(method); - if (close == null) { - close = method; - } else { - if (currentClazz == clazzPojo || - !isMethodOverride(close, method)) { - // Duplicate annotation - throw new DeploymentException(sm.getString( - "pojoMethodMapping.duplicateAnnotation", - OnClose.class, currentClazz)); - } - } - } else if (method.getAnnotation(OnError.class) != null) { - checkPublic(method); - if (error == null) { - error = method; - } else { - if (currentClazz == clazzPojo || - !isMethodOverride(error, method)) { - // Duplicate annotation - throw new DeploymentException(sm.getString( - "pojoMethodMapping.duplicateAnnotation", - OnError.class, currentClazz)); - } - } - } else if (method.getAnnotation(OnMessage.class) != null) { - checkPublic(method); - MessageHandlerInfo messageHandler = new MessageHandlerInfo(method, decoders); - boolean found = false; - for (MessageHandlerInfo otherMessageHandler : onMessage) { - if (messageHandler.targetsSameWebSocketMessageType(otherMessageHandler)) { - found = true; - if (currentClazz == clazzPojo || - !isMethodOverride(messageHandler.m, otherMessageHandler.m)) { - // Duplicate annotation - throw new DeploymentException(sm.getString( - "pojoMethodMapping.duplicateAnnotation", - OnMessage.class, currentClazz)); - } - } - } - if (!found) { - onMessage.add(messageHandler); - } - } else { - // Method not annotated - } - } - currentClazz = currentClazz.getSuperclass(); - } - // If the methods are not on clazzPojo and they are overridden - // by a non annotated method in clazzPojo, they should be ignored - if (open != null && open.getDeclaringClass() != clazzPojo) { - if (isOverridenWithoutAnnotation(clazzPojoMethods, open, OnOpen.class)) { - open = null; - } - } - if (close != null && close.getDeclaringClass() != clazzPojo) { - if (isOverridenWithoutAnnotation(clazzPojoMethods, close, OnClose.class)) { - close = null; - } - } - if (error != null && error.getDeclaringClass() != clazzPojo) { - if (isOverridenWithoutAnnotation(clazzPojoMethods, error, OnError.class)) { - error = null; - } - } - List overriddenOnMessage = new ArrayList<>(); - for (MessageHandlerInfo messageHandler : onMessage) { - if (messageHandler.m.getDeclaringClass() != clazzPojo - && isOverridenWithoutAnnotation(clazzPojoMethods, messageHandler.m, OnMessage.class)) { - overriddenOnMessage.add(messageHandler); - } - } - for (MessageHandlerInfo messageHandler : overriddenOnMessage) { - onMessage.remove(messageHandler); - } - this.onOpen = open; - this.onClose = close; - this.onError = error; - onOpenParams = getPathParams(onOpen, MethodType.ON_OPEN); - onCloseParams = getPathParams(onClose, MethodType.ON_CLOSE); - onErrorParams = getPathParams(onError, MethodType.ON_ERROR); - } - - - private void checkPublic(Method m) throws DeploymentException { - if (!Modifier.isPublic(m.getModifiers())) { - throw new DeploymentException(sm.getString( - "pojoMethodMapping.methodNotPublic", m.getName())); - } - } - - - private boolean isMethodOverride(Method method1, Method method2) { - return method1.getName().equals(method2.getName()) - && method1.getReturnType().equals(method2.getReturnType()) - && Arrays.equals(method1.getParameterTypes(), method2.getParameterTypes()); - } - - - private boolean isOverridenWithoutAnnotation(Method[] methods, - Method superclazzMethod, Class annotation) { - for (Method method : methods) { - if (isMethodOverride(method, superclazzMethod) - && (method.getAnnotation(annotation) == null)) { - return true; - } - } - return false; - } - - - public String getWsPath() { - return wsPath; - } - - - public Method getOnOpen() { - return onOpen; - } - - - public Object[] getOnOpenArgs(Map pathParameters, - Session session, EndpointConfig config) throws DecodeException { - return buildArgs(onOpenParams, pathParameters, session, config, null, - null); - } - - - public Method getOnClose() { - return onClose; - } - - - public Object[] getOnCloseArgs(Map pathParameters, - Session session, CloseReason closeReason) throws DecodeException { - return buildArgs(onCloseParams, pathParameters, session, null, null, - closeReason); - } - - - public Method getOnError() { - return onError; - } - - - public Object[] getOnErrorArgs(Map pathParameters, - Session session, Throwable throwable) throws DecodeException { - return buildArgs(onErrorParams, pathParameters, session, null, - throwable, null); - } - - - public boolean hasMessageHandlers() { - return !onMessage.isEmpty(); - } - - - public Set getMessageHandlers(Object pojo, - Map pathParameters, Session session, - EndpointConfig config) { - Set result = new HashSet<>(); - for (MessageHandlerInfo messageMethod : onMessage) { - result.addAll(messageMethod.getMessageHandlers(pojo, pathParameters, - session, config)); - } - return result; - } - - - private static PojoPathParam[] getPathParams(Method m, - MethodType methodType) throws DeploymentException { - if (m == null) { - return new PojoPathParam[0]; - } - boolean foundThrowable = false; - Class[] types = m.getParameterTypes(); - Annotation[][] paramsAnnotations = m.getParameterAnnotations(); - PojoPathParam[] result = new PojoPathParam[types.length]; - for (int i = 0; i < types.length; i++) { - Class type = types[i]; - if (type.equals(Session.class)) { - result[i] = new PojoPathParam(type, null); - } else if (methodType == MethodType.ON_OPEN && - type.equals(EndpointConfig.class)) { - result[i] = new PojoPathParam(type, null); - } else if (methodType == MethodType.ON_ERROR - && type.equals(Throwable.class)) { - foundThrowable = true; - result[i] = new PojoPathParam(type, null); - } else if (methodType == MethodType.ON_CLOSE && - type.equals(CloseReason.class)) { - result[i] = new PojoPathParam(type, null); - } else { - Annotation[] paramAnnotations = paramsAnnotations[i]; - for (Annotation paramAnnotation : paramAnnotations) { - if (paramAnnotation.annotationType().equals( - PathParam.class)) { - // Check that the type is valid. "0" coerces to every - // valid type - try { - Util.coerceToType(type, "0"); - } catch (IllegalArgumentException iae) { - throw new DeploymentException(sm.getString( - "pojoMethodMapping.invalidPathParamType"), - iae); - } - result[i] = new PojoPathParam(type, - ((PathParam) paramAnnotation).value()); - break; - } - } - // Parameters without annotations are not permitted - if (result[i] == null) { - throw new DeploymentException(sm.getString( - "pojoMethodMapping.paramWithoutAnnotation", - type, m.getName(), m.getClass().getName())); - } - } - } - if (methodType == MethodType.ON_ERROR && !foundThrowable) { - throw new DeploymentException(sm.getString( - "pojoMethodMapping.onErrorNoThrowable", - m.getName(), m.getDeclaringClass().getName())); - } - return result; - } - - - private static Object[] buildArgs(PojoPathParam[] pathParams, - Map pathParameters, Session session, - EndpointConfig config, Throwable throwable, CloseReason closeReason) - throws DecodeException { - Object[] result = new Object[pathParams.length]; - for (int i = 0; i < pathParams.length; i++) { - Class type = pathParams[i].getType(); - if (type.equals(Session.class)) { - result[i] = session; - } else if (type.equals(EndpointConfig.class)) { - result[i] = config; - } else if (type.equals(Throwable.class)) { - result[i] = throwable; - } else if (type.equals(CloseReason.class)) { - result[i] = closeReason; - } else { - String name = pathParams[i].getName(); - String value = pathParameters.get(name); - try { - result[i] = Util.coerceToType(type, value); - } catch (Exception e) { - throw new DecodeException(value, sm.getString( - "pojoMethodMapping.decodePathParamFail", - value, type), e); - } - } - } - return result; - } - - - private static class MessageHandlerInfo { - - private final Method m; - private int indexString = -1; - private int indexByteArray = -1; - private int indexByteBuffer = -1; - private int indexPong = -1; - private int indexBoolean = -1; - private int indexSession = -1; - private int indexInputStream = -1; - private int indexReader = -1; - private int indexPrimitive = -1; - private Class primitiveType = null; - private Map indexPathParams = new HashMap<>(); - private int indexPayload = -1; - private DecoderMatch decoderMatch = null; - private long maxMessageSize = -1; - - public MessageHandlerInfo(Method m, List decoderEntries) { - this.m = m; - - Class[] types = m.getParameterTypes(); - Annotation[][] paramsAnnotations = m.getParameterAnnotations(); - - for (int i = 0; i < types.length; i++) { - boolean paramFound = false; - Annotation[] paramAnnotations = paramsAnnotations[i]; - for (Annotation paramAnnotation : paramAnnotations) { - if (paramAnnotation.annotationType().equals( - PathParam.class)) { - indexPathParams.put( - Integer.valueOf(i), new PojoPathParam(types[i], - ((PathParam) paramAnnotation).value())); - paramFound = true; - break; - } - } - if (paramFound) { - continue; - } - if (String.class.isAssignableFrom(types[i])) { - if (indexString == -1) { - indexString = i; - } else { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } - } else if (Reader.class.isAssignableFrom(types[i])) { - if (indexReader == -1) { - indexReader = i; - } else { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } - } else if (boolean.class == types[i]) { - if (indexBoolean == -1) { - indexBoolean = i; - } else { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateLastParam", - m.getName(), m.getDeclaringClass().getName())); - } - } else if (ByteBuffer.class.isAssignableFrom(types[i])) { - if (indexByteBuffer == -1) { - indexByteBuffer = i; - } else { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } - } else if (byte[].class == types[i]) { - if (indexByteArray == -1) { - indexByteArray = i; - } else { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } - } else if (InputStream.class.isAssignableFrom(types[i])) { - if (indexInputStream == -1) { - indexInputStream = i; - } else { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } - } else if (Util.isPrimitive(types[i])) { - if (indexPrimitive == -1) { - indexPrimitive = i; - primitiveType = types[i]; - } else { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } - } else if (Session.class.isAssignableFrom(types[i])) { - if (indexSession == -1) { - indexSession = i; - } else { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateSessionParam", - m.getName(), m.getDeclaringClass().getName())); - } - } else if (PongMessage.class.isAssignableFrom(types[i])) { - if (indexPong == -1) { - indexPong = i; - } else { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicatePongMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } - } else { - if (decoderMatch != null && decoderMatch.hasMatches()) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } - decoderMatch = new DecoderMatch(types[i], decoderEntries); - - if (decoderMatch.hasMatches()) { - indexPayload = i; - } - } - } - - // Additional checks required - if (indexString != -1) { - if (indexPayload != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } else { - indexPayload = indexString; - } - } - if (indexReader != -1) { - if (indexPayload != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } else { - indexPayload = indexReader; - } - } - if (indexByteArray != -1) { - if (indexPayload != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } else { - indexPayload = indexByteArray; - } - } - if (indexByteBuffer != -1) { - if (indexPayload != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } else { - indexPayload = indexByteBuffer; - } - } - if (indexInputStream != -1) { - if (indexPayload != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } else { - indexPayload = indexInputStream; - } - } - if (indexPrimitive != -1) { - if (indexPayload != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.duplicateMessageParam", - m.getName(), m.getDeclaringClass().getName())); - } else { - indexPayload = indexPrimitive; - } - } - if (indexPong != -1) { - if (indexPayload != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.pongWithPayload", - m.getName(), m.getDeclaringClass().getName())); - } else { - indexPayload = indexPong; - } - } - if (indexPayload == -1 && indexPrimitive == -1 && - indexBoolean != -1) { - // The boolean we found is a payload, not a last flag - indexPayload = indexBoolean; - indexPrimitive = indexBoolean; - primitiveType = Boolean.TYPE; - indexBoolean = -1; - } - if (indexPayload == -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.noPayload", - m.getName(), m.getDeclaringClass().getName())); - } - if (indexPong != -1 && indexBoolean != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.partialPong", - m.getName(), m.getDeclaringClass().getName())); - } - if(indexReader != -1 && indexBoolean != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.partialReader", - m.getName(), m.getDeclaringClass().getName())); - } - if(indexInputStream != -1 && indexBoolean != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.partialInputStream", - m.getName(), m.getDeclaringClass().getName())); - } - if (decoderMatch != null && decoderMatch.hasMatches() && - indexBoolean != -1) { - throw new IllegalArgumentException(sm.getString( - "pojoMethodMapping.partialObject", - m.getName(), m.getDeclaringClass().getName())); - } - - maxMessageSize = m.getAnnotation(OnMessage.class).maxMessageSize(); - } - - - public boolean targetsSameWebSocketMessageType(MessageHandlerInfo otherHandler) { - if (otherHandler == null) { - return false; - } - if (indexByteArray >= 0 && otherHandler.indexByteArray >= 0) { - return true; - } - if (indexByteBuffer >= 0 && otherHandler.indexByteBuffer >= 0) { - return true; - } - if (indexInputStream >= 0 && otherHandler.indexInputStream >= 0) { - return true; - } - if (indexPong >= 0 && otherHandler.indexPong >= 0) { - return true; - } - if (indexPrimitive >= 0 && otherHandler.indexPrimitive >= 0 - && primitiveType == otherHandler.primitiveType) { - return true; - } - if (indexReader >= 0 && otherHandler.indexReader >= 0) { - return true; - } - if (indexString >= 0 && otherHandler.indexString >= 0) { - return true; - } - if (decoderMatch != null && otherHandler.decoderMatch != null - && decoderMatch.getTarget().equals(otherHandler.decoderMatch.getTarget())) { - return true; - } - return false; - } - - - public Set getMessageHandlers(Object pojo, - Map pathParameters, Session session, - EndpointConfig config) { - Object[] params = new Object[m.getParameterTypes().length]; - - for (Map.Entry entry : - indexPathParams.entrySet()) { - PojoPathParam pathParam = entry.getValue(); - String valueString = pathParameters.get(pathParam.getName()); - Object value = null; - try { - value = Util.coerceToType(pathParam.getType(), valueString); - } catch (Exception e) { - DecodeException de = new DecodeException(valueString, - sm.getString( - "pojoMethodMapping.decodePathParamFail", - valueString, pathParam.getType()), e); - params = new Object[] { de }; - break; - } - params[entry.getKey().intValue()] = value; - } - - Set results = new HashSet<>(2); - if (indexBoolean == -1) { - // Basic - if (indexString != -1 || indexPrimitive != -1) { - MessageHandler mh = new PojoMessageHandlerWholeText(pojo, m, - session, config, null, params, indexPayload, false, - indexSession, maxMessageSize); - results.add(mh); - } else if (indexReader != -1) { - MessageHandler mh = new PojoMessageHandlerWholeText(pojo, m, - session, config, null, params, indexReader, true, - indexSession, maxMessageSize); - results.add(mh); - } else if (indexByteArray != -1) { - MessageHandler mh = new PojoMessageHandlerWholeBinary(pojo, - m, session, config, null, params, indexByteArray, - true, indexSession, false, maxMessageSize); - results.add(mh); - } else if (indexByteBuffer != -1) { - MessageHandler mh = new PojoMessageHandlerWholeBinary(pojo, - m, session, config, null, params, indexByteBuffer, - false, indexSession, false, maxMessageSize); - results.add(mh); - } else if (indexInputStream != -1) { - MessageHandler mh = new PojoMessageHandlerWholeBinary(pojo, - m, session, config, null, params, indexInputStream, - true, indexSession, true, maxMessageSize); - results.add(mh); - } else if (decoderMatch != null && decoderMatch.hasMatches()) { - if (decoderMatch.getBinaryDecoders().size() > 0) { - MessageHandler mh = new PojoMessageHandlerWholeBinary( - pojo, m, session, config, - decoderMatch.getBinaryDecoders(), params, - indexPayload, true, indexSession, true, - maxMessageSize); - results.add(mh); - } - if (decoderMatch.getTextDecoders().size() > 0) { - MessageHandler mh = new PojoMessageHandlerWholeText( - pojo, m, session, config, - decoderMatch.getTextDecoders(), params, - indexPayload, true, indexSession, maxMessageSize); - results.add(mh); - } - } else { - MessageHandler mh = new PojoMessageHandlerWholePong(pojo, m, - session, params, indexPong, false, indexSession); - results.add(mh); - } - } else { - // ASync - if (indexString != -1) { - MessageHandler mh = new PojoMessageHandlerPartialText(pojo, - m, session, params, indexString, false, - indexBoolean, indexSession, maxMessageSize); - results.add(mh); - } else if (indexByteArray != -1) { - MessageHandler mh = new PojoMessageHandlerPartialBinary( - pojo, m, session, params, indexByteArray, true, - indexBoolean, indexSession, maxMessageSize); - results.add(mh); - } else { - MessageHandler mh = new PojoMessageHandlerPartialBinary( - pojo, m, session, params, indexByteBuffer, false, - indexBoolean, indexSession, maxMessageSize); - results.add(mh); - } - } - return results; - } - } - - - private enum MethodType { - ON_OPEN, - ON_CLOSE, - ON_ERROR - } -} diff --git a/src/java/nginx/unit/websocket/pojo/PojoPathParam.java b/src/java/nginx/unit/websocket/pojo/PojoPathParam.java deleted file mode 100644 index 859b6d68..00000000 --- a/src/java/nginx/unit/websocket/pojo/PojoPathParam.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.pojo; - -/** - * Stores the parameter type and name for a parameter that needs to be passed to - * an onXxx method of {@link javax.websocket.Endpoint}. The name is only present - * for parameters annotated with - * {@link javax.websocket.server.PathParam}. For the - * {@link javax.websocket.Session} and {@link java.lang.Throwable} parameters, - * {@link #getName()} will always return null. - */ -public class PojoPathParam { - - private final Class type; - private final String name; - - - public PojoPathParam(Class type, String name) { - this.type = type; - this.name = name; - } - - - public Class getType() { - return type; - } - - - public String getName() { - return name; - } -} diff --git a/src/java/nginx/unit/websocket/pojo/package-info.java b/src/java/nginx/unit/websocket/pojo/package-info.java deleted file mode 100644 index 39cf80c8..00000000 --- a/src/java/nginx/unit/websocket/pojo/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * This package provides the necessary plumbing to convert an annotated POJO - * into a WebSocket {@link javax.websocket.Endpoint}. - */ -package nginx.unit.websocket.pojo; diff --git a/src/java/nginx/unit/websocket/server/Constants.java b/src/java/nginx/unit/websocket/server/Constants.java deleted file mode 100644 index 5210c4ba..00000000 --- a/src/java/nginx/unit/websocket/server/Constants.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -/** - * Internal implementation constants. - */ -public class Constants { - - public static final String BINARY_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM = - "nginx.unit.websocket.binaryBufferSize"; - public static final String TEXT_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM = - "nginx.unit.websocket.textBufferSize"; - public static final String ENFORCE_NO_ADD_AFTER_HANDSHAKE_CONTEXT_INIT_PARAM = - "nginx.unit.websocket.noAddAfterHandshake"; - - public static final String SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE = - "javax.websocket.server.ServerContainer"; - - - private Constants() { - // Hide default constructor - } -} diff --git a/src/java/nginx/unit/websocket/server/DefaultServerEndpointConfigurator.java b/src/java/nginx/unit/websocket/server/DefaultServerEndpointConfigurator.java deleted file mode 100644 index 43ffe2bc..00000000 --- a/src/java/nginx/unit/websocket/server/DefaultServerEndpointConfigurator.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.websocket.Extension; -import javax.websocket.HandshakeResponse; -import javax.websocket.server.HandshakeRequest; -import javax.websocket.server.ServerEndpointConfig; - -public class DefaultServerEndpointConfigurator - extends ServerEndpointConfig.Configurator { - - @Override - public T getEndpointInstance(Class clazz) - throws InstantiationException { - try { - return clazz.getConstructor().newInstance(); - } catch (InstantiationException e) { - throw e; - } catch (ReflectiveOperationException e) { - InstantiationException ie = new InstantiationException(); - ie.initCause(e); - throw ie; - } - } - - - @Override - public String getNegotiatedSubprotocol(List supported, - List requested) { - - for (String request : requested) { - if (supported.contains(request)) { - return request; - } - } - return ""; - } - - - @Override - public List getNegotiatedExtensions(List installed, - List requested) { - Set installedNames = new HashSet<>(); - for (Extension e : installed) { - installedNames.add(e.getName()); - } - List result = new ArrayList<>(); - for (Extension request : requested) { - if (installedNames.contains(request.getName())) { - result.add(request); - } - } - return result; - } - - - @Override - public boolean checkOrigin(String originHeaderValue) { - return true; - } - - @Override - public void modifyHandshake(ServerEndpointConfig sec, - HandshakeRequest request, HandshakeResponse response) { - // NO-OP - } - -} diff --git a/src/java/nginx/unit/websocket/server/LocalStrings.properties b/src/java/nginx/unit/websocket/server/LocalStrings.properties deleted file mode 100644 index 5bc12501..00000000 --- a/src/java/nginx/unit/websocket/server/LocalStrings.properties +++ /dev/null @@ -1,43 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -serverContainer.addNotAllowed=No further Endpoints may be registered once an attempt has been made to use one of the previously registered endpoints -serverContainer.configuratorFail=Failed to create configurator of type [{0}] for POJO of type [{1}] -serverContainer.duplicatePaths=Multiple Endpoints may not be deployed to the same path [{0}] : existing endpoint was [{1}] and new endpoint is [{2}] -serverContainer.encoderFail=Unable to create encoder of type [{0}] -serverContainer.endpointDeploy=Endpoint class [{0}] deploying to path [{1}] in ServletContext [{2}] -serverContainer.missingAnnotation=Cannot deploy POJO class [{0}] as it is not annotated with @ServerEndpoint -serverContainer.missingEndpoint=An Endpoint instance has been request for path [{0}] but no matching Endpoint class was found -serverContainer.pojoDeploy=POJO class [{0}] deploying to path [{1}] in ServletContext [{2}] -serverContainer.servletContextMismatch=Attempted to register a POJO annotated for WebSocket at path [{0}] in the ServletContext with context path [{1}] when the WebSocket ServerContainer is allocated to the ServletContext with context path [{2}] -serverContainer.servletContextMissing=No ServletContext was specified - -upgradeUtil.incompatibleRsv=Extensions were specified that have incompatible RSV bit usage - -uriTemplate.duplicateParameter=The parameter [{0}] appears more than once in the path which is not permitted -uriTemplate.emptySegment=The path [{0}] contains one or more empty segments which are is not permitted -uriTemplate.invalidPath=The path [{0}] is not valid. -uriTemplate.invalidSegment=The segment [{0}] is not valid in the provided path [{1}] - -wsFrameServer.bytesRead=Read [{0}] bytes into input buffer ready for processing -wsFrameServer.illegalReadState=Unexpected read state [{0}] -wsFrameServer.onDataAvailable=Method entry - -wsHttpUpgradeHandler.closeOnError=Closing WebSocket connection due to an error -wsHttpUpgradeHandler.destroyFailed=Failed to close WebConnection while destroying the WebSocket HttpUpgradeHandler -wsHttpUpgradeHandler.noPreInit=The preInit() method must be called to configure the WebSocket HttpUpgradeHandler before the container calls init(). Usually, this means the Servlet that created the WsHttpUpgradeHandler instance should also call preInit() -wsHttpUpgradeHandler.serverStop=The server is stopping - -wsRemoteEndpointServer.closeFailed=Failed to close the ServletOutputStream connection cleanly diff --git a/src/java/nginx/unit/websocket/server/UpgradeUtil.java b/src/java/nginx/unit/websocket/server/UpgradeUtil.java deleted file mode 100644 index 162f01c7..00000000 --- a/src/java/nginx/unit/websocket/server/UpgradeUtil.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.websocket.Endpoint; -import javax.websocket.Extension; -import javax.websocket.HandshakeResponse; -import javax.websocket.server.ServerEndpointConfig; - -import nginx.unit.Request; - -import org.apache.tomcat.util.codec.binary.Base64; -import org.apache.tomcat.util.res.StringManager; -import org.apache.tomcat.util.security.ConcurrentMessageDigest; -import nginx.unit.websocket.Constants; -import nginx.unit.websocket.Transformation; -import nginx.unit.websocket.TransformationFactory; -import nginx.unit.websocket.Util; -import nginx.unit.websocket.WsHandshakeResponse; -import nginx.unit.websocket.pojo.PojoEndpointServer; - -public class UpgradeUtil { - - private static final StringManager sm = - StringManager.getManager(UpgradeUtil.class.getPackage().getName()); - private static final byte[] WS_ACCEPT = - "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes( - StandardCharsets.ISO_8859_1); - - private UpgradeUtil() { - // Utility class. Hide default constructor. - } - - /** - * Checks to see if this is an HTTP request that includes a valid upgrade - * request to web socket. - *

- * Note: RFC 2616 does not limit HTTP upgrade to GET requests but the Java - * WebSocket spec 1.0, section 8.2 implies such a limitation and RFC - * 6455 section 4.1 requires that a WebSocket Upgrade uses GET. - * @param request The request to check if it is an HTTP upgrade request for - * a WebSocket connection - * @param response The response associated with the request - * @return true if the request includes a HTTP Upgrade request - * for the WebSocket protocol, otherwise false - */ - public static boolean isWebSocketUpgradeRequest(ServletRequest request, - ServletResponse response) { - - Request r = (Request) request.getAttribute(Request.BARE); - - return ((request instanceof HttpServletRequest) && - (response instanceof HttpServletResponse) && - (r != null) && - (r.isUpgrade())); - } - - - public static void doUpgrade(WsServerContainer sc, HttpServletRequest req, - HttpServletResponse resp, ServerEndpointConfig sec, - Map pathParams) - throws ServletException, IOException { - - - // Origin check - String origin = req.getHeader(Constants.ORIGIN_HEADER_NAME); - - if (!sec.getConfigurator().checkOrigin(origin)) { - resp.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - // Sub-protocols - List subProtocols = getTokensFromHeader(req, - Constants.WS_PROTOCOL_HEADER_NAME); - String subProtocol = sec.getConfigurator().getNegotiatedSubprotocol( - sec.getSubprotocols(), subProtocols); - - // Extensions - // Should normally only be one header but handle the case of multiple - // headers - List extensionsRequested = new ArrayList<>(); - Enumeration extHeaders = req.getHeaders(Constants.WS_EXTENSIONS_HEADER_NAME); - while (extHeaders.hasMoreElements()) { - Util.parseExtensionHeader(extensionsRequested, extHeaders.nextElement()); - } - - // Negotiation phase 1. By default this simply filters out the - // extensions that the server does not support but applications could - // use a custom configurator to do more than this. - List installedExtensions = null; - if (sec.getExtensions().size() == 0) { - installedExtensions = Constants.INSTALLED_EXTENSIONS; - } else { - installedExtensions = new ArrayList<>(); - installedExtensions.addAll(sec.getExtensions()); - installedExtensions.addAll(Constants.INSTALLED_EXTENSIONS); - } - List negotiatedExtensionsPhase1 = sec.getConfigurator().getNegotiatedExtensions( - installedExtensions, extensionsRequested); - - // Negotiation phase 2. Create the Transformations that will be applied - // to this connection. Note than an extension may be dropped at this - // point if the client has requested a configuration that the server is - // unable to support. - List transformations = createTransformations(negotiatedExtensionsPhase1); - - List negotiatedExtensionsPhase2; - if (transformations.isEmpty()) { - negotiatedExtensionsPhase2 = Collections.emptyList(); - } else { - negotiatedExtensionsPhase2 = new ArrayList<>(transformations.size()); - for (Transformation t : transformations) { - negotiatedExtensionsPhase2.add(t.getExtensionResponse()); - } - } - - WsHttpUpgradeHandler wsHandler = - req.upgrade(WsHttpUpgradeHandler.class); - - WsHandshakeRequest wsRequest = new WsHandshakeRequest(req, pathParams); - WsHandshakeResponse wsResponse = new WsHandshakeResponse(); - WsPerSessionServerEndpointConfig perSessionServerEndpointConfig = - new WsPerSessionServerEndpointConfig(sec); - sec.getConfigurator().modifyHandshake(perSessionServerEndpointConfig, - wsRequest, wsResponse); - //wsRequest.finished(); - - // Add any additional headers - for (Entry> entry : - wsResponse.getHeaders().entrySet()) { - for (String headerValue: entry.getValue()) { - resp.addHeader(entry.getKey(), headerValue); - } - } - - Endpoint ep; - try { - Class clazz = sec.getEndpointClass(); - if (Endpoint.class.isAssignableFrom(clazz)) { - ep = (Endpoint) sec.getConfigurator().getEndpointInstance( - clazz); - } else { - ep = new PojoEndpointServer(); - // Need to make path params available to POJO - perSessionServerEndpointConfig.getUserProperties().put( - nginx.unit.websocket.pojo.Constants.POJO_PATH_PARAM_KEY, pathParams); - } - } catch (InstantiationException e) { - throw new ServletException(e); - } - - wsHandler.preInit(ep, perSessionServerEndpointConfig, sc, wsRequest, - negotiatedExtensionsPhase2, subProtocol, null, pathParams, - req.isSecure()); - - wsHandler.init(null); - } - - - private static List createTransformations( - List negotiatedExtensions) { - - TransformationFactory factory = TransformationFactory.getInstance(); - - LinkedHashMap>> extensionPreferences = - new LinkedHashMap<>(); - - // Result will likely be smaller than this - List result = new ArrayList<>(negotiatedExtensions.size()); - - for (Extension extension : negotiatedExtensions) { - List> preferences = - extensionPreferences.get(extension.getName()); - - if (preferences == null) { - preferences = new ArrayList<>(); - extensionPreferences.put(extension.getName(), preferences); - } - - preferences.add(extension.getParameters()); - } - - for (Map.Entry>> entry : - extensionPreferences.entrySet()) { - Transformation transformation = factory.create(entry.getKey(), entry.getValue(), true); - if (transformation != null) { - result.add(transformation); - } - } - return result; - } - - - private static void append(StringBuilder sb, Extension extension) { - if (extension == null || extension.getName() == null || extension.getName().length() == 0) { - return; - } - - sb.append(extension.getName()); - - for (Extension.Parameter p : extension.getParameters()) { - sb.append(';'); - sb.append(p.getName()); - if (p.getValue() != null) { - sb.append('='); - sb.append(p.getValue()); - } - } - } - - - /* - * This only works for tokens. Quoted strings need more sophisticated - * parsing. - */ - private static boolean headerContainsToken(HttpServletRequest req, - String headerName, String target) { - Enumeration headers = req.getHeaders(headerName); - while (headers.hasMoreElements()) { - String header = headers.nextElement(); - String[] tokens = header.split(","); - for (String token : tokens) { - if (target.equalsIgnoreCase(token.trim())) { - return true; - } - } - } - return false; - } - - - /* - * This only works for tokens. Quoted strings need more sophisticated - * parsing. - */ - private static List getTokensFromHeader(HttpServletRequest req, - String headerName) { - List result = new ArrayList<>(); - Enumeration headers = req.getHeaders(headerName); - while (headers.hasMoreElements()) { - String header = headers.nextElement(); - String[] tokens = header.split(","); - for (String token : tokens) { - result.add(token.trim()); - } - } - return result; - } - - - private static String getWebSocketAccept(String key) { - byte[] digest = ConcurrentMessageDigest.digestSHA1( - key.getBytes(StandardCharsets.ISO_8859_1), WS_ACCEPT); - return Base64.encodeBase64String(digest); - } -} diff --git a/src/java/nginx/unit/websocket/server/UriTemplate.java b/src/java/nginx/unit/websocket/server/UriTemplate.java deleted file mode 100644 index 7877fac9..00000000 --- a/src/java/nginx/unit/websocket/server/UriTemplate.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.websocket.DeploymentException; - -import org.apache.tomcat.util.res.StringManager; - -/** - * Extracts path parameters from URIs used to create web socket connections - * using the URI template defined for the associated Endpoint. - */ -public class UriTemplate { - - private static final StringManager sm = StringManager.getManager(UriTemplate.class); - - private final String normalized; - private final List segments = new ArrayList<>(); - private final boolean hasParameters; - - - public UriTemplate(String path) throws DeploymentException { - - if (path == null || path.length() ==0 || !path.startsWith("/")) { - throw new DeploymentException( - sm.getString("uriTemplate.invalidPath", path)); - } - - StringBuilder normalized = new StringBuilder(path.length()); - Set paramNames = new HashSet<>(); - - // Include empty segments. - String[] segments = path.split("/", -1); - int paramCount = 0; - int segmentCount = 0; - - for (int i = 0; i < segments.length; i++) { - String segment = segments[i]; - if (segment.length() == 0) { - if (i == 0 || (i == segments.length - 1 && paramCount == 0)) { - // Ignore the first empty segment as the path must always - // start with '/' - // Ending with a '/' is also OK for instances used for - // matches but not for parameterised templates. - continue; - } else { - // As per EG discussion, all other empty segments are - // invalid - throw new IllegalArgumentException(sm.getString( - "uriTemplate.emptySegment", path)); - } - } - normalized.append('/'); - int index = -1; - if (segment.startsWith("{") && segment.endsWith("}")) { - index = segmentCount; - segment = segment.substring(1, segment.length() - 1); - normalized.append('{'); - normalized.append(paramCount++); - normalized.append('}'); - if (!paramNames.add(segment)) { - throw new IllegalArgumentException(sm.getString( - "uriTemplate.duplicateParameter", segment)); - } - } else { - if (segment.contains("{") || segment.contains("}")) { - throw new IllegalArgumentException(sm.getString( - "uriTemplate.invalidSegment", segment, path)); - } - normalized.append(segment); - } - this.segments.add(new Segment(index, segment)); - segmentCount++; - } - - this.normalized = normalized.toString(); - this.hasParameters = paramCount > 0; - } - - - public Map match(UriTemplate candidate) { - - Map result = new HashMap<>(); - - // Should not happen but for safety - if (candidate.getSegmentCount() != getSegmentCount()) { - return null; - } - - Iterator candidateSegments = - candidate.getSegments().iterator(); - Iterator targetSegments = segments.iterator(); - - while (candidateSegments.hasNext()) { - Segment candidateSegment = candidateSegments.next(); - Segment targetSegment = targetSegments.next(); - - if (targetSegment.getParameterIndex() == -1) { - // Not a parameter - values must match - if (!targetSegment.getValue().equals( - candidateSegment.getValue())) { - // Not a match. Stop here - return null; - } - } else { - // Parameter - result.put(targetSegment.getValue(), - candidateSegment.getValue()); - } - } - - return result; - } - - - public boolean hasParameters() { - return hasParameters; - } - - - public int getSegmentCount() { - return segments.size(); - } - - - public String getNormalizedPath() { - return normalized; - } - - - private List getSegments() { - return segments; - } - - - private static class Segment { - private final int parameterIndex; - private final String value; - - public Segment(int parameterIndex, String value) { - this.parameterIndex = parameterIndex; - this.value = value; - } - - - public int getParameterIndex() { - return parameterIndex; - } - - - public String getValue() { - return value; - } - } -} diff --git a/src/java/nginx/unit/websocket/server/WsContextListener.java b/src/java/nginx/unit/websocket/server/WsContextListener.java deleted file mode 100644 index 07137856..00000000 --- a/src/java/nginx/unit/websocket/server/WsContextListener.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -/** - * In normal usage, this {@link ServletContextListener} does not need to be - * explicitly configured as the {@link WsSci} performs all the necessary - * bootstrap and installs this listener in the {@link ServletContext}. If the - * {@link WsSci} is disabled, this listener must be added manually to every - * {@link ServletContext} that uses WebSocket to bootstrap the - * {@link WsServerContainer} correctly. - */ -public class WsContextListener implements ServletContextListener { - - @Override - public void contextInitialized(ServletContextEvent sce) { - ServletContext sc = sce.getServletContext(); - // Don't trigger WebSocket initialization if a WebSocket Server - // Container is already present - if (sc.getAttribute(Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE) == null) { - WsSci.init(sce.getServletContext(), false); - } - } - - @Override - public void contextDestroyed(ServletContextEvent sce) { - ServletContext sc = sce.getServletContext(); - Object obj = sc.getAttribute(Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE); - if (obj instanceof WsServerContainer) { - ((WsServerContainer) obj).destroy(); - } - } -} diff --git a/src/java/nginx/unit/websocket/server/WsFilter.java b/src/java/nginx/unit/websocket/server/WsFilter.java deleted file mode 100644 index abea71fc..00000000 --- a/src/java/nginx/unit/websocket/server/WsFilter.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.io.IOException; - -import javax.servlet.FilterChain; -import javax.servlet.GenericFilter; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Handles the initial HTTP connection for WebSocket connections. - */ -public class WsFilter extends GenericFilter { - - private static final long serialVersionUID = 1L; - - private transient WsServerContainer sc; - - - @Override - public void init() throws ServletException { - sc = (WsServerContainer) getServletContext().getAttribute( - Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE); - } - - - @Override - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException { - - // This filter only needs to handle WebSocket upgrade requests - if (!sc.areEndpointsRegistered() || - !UpgradeUtil.isWebSocketUpgradeRequest(request, response)) { - chain.doFilter(request, response); - return; - } - - // HTTP request with an upgrade header for WebSocket present - HttpServletRequest req = (HttpServletRequest) request; - HttpServletResponse resp = (HttpServletResponse) response; - - // Check to see if this WebSocket implementation has a matching mapping - String path; - String pathInfo = req.getPathInfo(); - if (pathInfo == null) { - path = req.getServletPath(); - } else { - path = req.getServletPath() + pathInfo; - } - WsMappingResult mappingResult = sc.findMapping(path); - - if (mappingResult == null) { - // No endpoint registered for the requested path. Let the - // application handle it (it might redirect or forward for example) - chain.doFilter(request, response); - return; - } - - UpgradeUtil.doUpgrade(sc, req, resp, mappingResult.getConfig(), - mappingResult.getPathParams()); - } -} diff --git a/src/java/nginx/unit/websocket/server/WsHandshakeRequest.java b/src/java/nginx/unit/websocket/server/WsHandshakeRequest.java deleted file mode 100644 index fa774302..00000000 --- a/src/java/nginx/unit/websocket/server/WsHandshakeRequest.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.net.URI; -import java.net.URISyntaxException; -import java.security.Principal; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import javax.servlet.http.HttpServletRequest; -import javax.websocket.server.HandshakeRequest; - -import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap; -import org.apache.tomcat.util.res.StringManager; - -/** - * Represents the request that this session was opened under. - */ -public class WsHandshakeRequest implements HandshakeRequest { - - private static final StringManager sm = StringManager.getManager(WsHandshakeRequest.class); - - private final URI requestUri; - private final Map> parameterMap; - private final String queryString; - private final Principal userPrincipal; - private final Map> headers; - private final Object httpSession; - - private volatile HttpServletRequest request; - - - public WsHandshakeRequest(HttpServletRequest request, Map pathParams) { - - this.request = request; - - queryString = request.getQueryString(); - userPrincipal = request.getUserPrincipal(); - httpSession = request.getSession(false); - requestUri = buildRequestUri(request); - - // ParameterMap - Map originalParameters = request.getParameterMap(); - Map> newParameters = - new HashMap<>(originalParameters.size()); - for (Entry entry : originalParameters.entrySet()) { - newParameters.put(entry.getKey(), - Collections.unmodifiableList( - Arrays.asList(entry.getValue()))); - } - for (Entry entry : pathParams.entrySet()) { - newParameters.put(entry.getKey(), - Collections.unmodifiableList( - Collections.singletonList(entry.getValue()))); - } - parameterMap = Collections.unmodifiableMap(newParameters); - - // Headers - Map> newHeaders = new CaseInsensitiveKeyMap<>(); - - Enumeration headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - - newHeaders.put(headerName, Collections.unmodifiableList( - Collections.list(request.getHeaders(headerName)))); - } - - headers = Collections.unmodifiableMap(newHeaders); - } - - @Override - public URI getRequestURI() { - return requestUri; - } - - @Override - public Map> getParameterMap() { - return parameterMap; - } - - @Override - public String getQueryString() { - return queryString; - } - - @Override - public Principal getUserPrincipal() { - return userPrincipal; - } - - @Override - public Map> getHeaders() { - return headers; - } - - @Override - public boolean isUserInRole(String role) { - if (request == null) { - throw new IllegalStateException(); - } - - return request.isUserInRole(role); - } - - @Override - public Object getHttpSession() { - return httpSession; - } - - /** - * Called when the HandshakeRequest is no longer required. Since an instance - * of this class retains a reference to the current HttpServletRequest that - * reference needs to be cleared as the HttpServletRequest may be reused. - * - * There is no reason for instances of this class to be accessed once the - * handshake has been completed. - */ - void finished() { - request = null; - } - - - /* - * See RequestUtil.getRequestURL() - */ - private static URI buildRequestUri(HttpServletRequest req) { - - StringBuffer uri = new StringBuffer(); - String scheme = req.getScheme(); - int port = req.getServerPort(); - if (port < 0) { - // Work around java.net.URL bug - port = 80; - } - - if ("http".equals(scheme)) { - uri.append("ws"); - } else if ("https".equals(scheme)) { - uri.append("wss"); - } else { - // Should never happen - throw new IllegalArgumentException( - sm.getString("wsHandshakeRequest.unknownScheme", scheme)); - } - - uri.append("://"); - uri.append(req.getServerName()); - - if ((scheme.equals("http") && (port != 80)) - || (scheme.equals("https") && (port != 443))) { - uri.append(':'); - uri.append(port); - } - - uri.append(req.getRequestURI()); - - if (req.getQueryString() != null) { - uri.append("?"); - uri.append(req.getQueryString()); - } - - try { - return new URI(uri.toString()); - } catch (URISyntaxException e) { - // Should never happen - throw new IllegalArgumentException( - sm.getString("wsHandshakeRequest.invalidUri", uri.toString()), e); - } - } - - public Object getAttribute(String name) - { - return request != null ? request.getAttribute(name) : null; - } -} diff --git a/src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java b/src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java deleted file mode 100644 index cc39ab73..00000000 --- a/src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpUpgradeHandler; -import javax.servlet.http.WebConnection; -import javax.websocket.CloseReason; -import javax.websocket.CloseReason.CloseCodes; -import javax.websocket.DeploymentException; -import javax.websocket.Endpoint; -import javax.websocket.EndpointConfig; -import javax.websocket.Extension; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.util.res.StringManager; - -import nginx.unit.websocket.Transformation; -import nginx.unit.websocket.WsIOException; -import nginx.unit.websocket.WsSession; - -import nginx.unit.Request; - -/** - * Servlet 3.1 HTTP upgrade handler for WebSocket connections. - */ -public class WsHttpUpgradeHandler implements HttpUpgradeHandler { - - private final Log log = LogFactory.getLog(WsHttpUpgradeHandler.class); // must not be static - private static final StringManager sm = StringManager.getManager(WsHttpUpgradeHandler.class); - - private final ClassLoader applicationClassLoader; - - private Endpoint ep; - private EndpointConfig endpointConfig; - private WsServerContainer webSocketContainer; - private WsHandshakeRequest handshakeRequest; - private List negotiatedExtensions; - private String subProtocol; - private Transformation transformation; - private Map pathParameters; - private boolean secure; - private WebConnection connection; - private WsRemoteEndpointImplServer wsRemoteEndpointServer; - private WsSession wsSession; - - - public WsHttpUpgradeHandler() { - applicationClassLoader = Thread.currentThread().getContextClassLoader(); - } - - public void preInit(Endpoint ep, EndpointConfig endpointConfig, - WsServerContainer wsc, WsHandshakeRequest handshakeRequest, - List negotiatedExtensionsPhase2, String subProtocol, - Transformation transformation, Map pathParameters, - boolean secure) { - this.ep = ep; - this.endpointConfig = endpointConfig; - this.webSocketContainer = wsc; - this.handshakeRequest = handshakeRequest; - this.negotiatedExtensions = negotiatedExtensionsPhase2; - this.subProtocol = subProtocol; - this.transformation = transformation; - this.pathParameters = pathParameters; - this.secure = secure; - } - - - @Override - public void init(WebConnection connection) { - if (ep == null) { - throw new IllegalStateException( - sm.getString("wsHttpUpgradeHandler.noPreInit")); - } - - String httpSessionId = null; - Object session = handshakeRequest.getHttpSession(); - if (session != null ) { - httpSessionId = ((HttpSession) session).getId(); - } - - nginx.unit.Context.trace("UpgradeHandler.init(" + connection + ")"); - -/* - // Need to call onOpen using the web application's class loader - // Create the frame using the application's class loader so it can pick - // up application specific config from the ServerContainerImpl - Thread t = Thread.currentThread(); - ClassLoader cl = t.getContextClassLoader(); - t.setContextClassLoader(applicationClassLoader); -*/ - try { - Request r = (Request) handshakeRequest.getAttribute(Request.BARE); - - wsRemoteEndpointServer = new WsRemoteEndpointImplServer(webSocketContainer); - wsSession = new WsSession(ep, wsRemoteEndpointServer, - webSocketContainer, handshakeRequest.getRequestURI(), - handshakeRequest.getParameterMap(), - handshakeRequest.getQueryString(), - handshakeRequest.getUserPrincipal(), httpSessionId, - negotiatedExtensions, subProtocol, pathParameters, secure, - endpointConfig, r); - - ep.onOpen(wsSession, endpointConfig); - webSocketContainer.registerSession(ep, wsSession); - } catch (DeploymentException e) { - throw new IllegalArgumentException(e); -/* - } finally { - t.setContextClassLoader(cl); -*/ - } - } - - - - @Override - public void destroy() { - if (connection != null) { - try { - connection.close(); - } catch (Exception e) { - log.error(sm.getString("wsHttpUpgradeHandler.destroyFailed"), e); - } - } - } - - - private void onError(Throwable throwable) { - // Need to call onError using the web application's class loader - Thread t = Thread.currentThread(); - ClassLoader cl = t.getContextClassLoader(); - t.setContextClassLoader(applicationClassLoader); - try { - ep.onError(wsSession, throwable); - } finally { - t.setContextClassLoader(cl); - } - } - - - private void close(CloseReason cr) { - /* - * Any call to this method is a result of a problem reading from the - * client. At this point that state of the connection is unknown. - * Attempt to send a close frame to the client and then close the socket - * immediately. There is no point in waiting for a close frame from the - * client because there is no guarantee that we can recover from - * whatever messed up state the client put the connection into. - */ - wsSession.onClose(cr); - } -} diff --git a/src/java/nginx/unit/websocket/server/WsMappingResult.java b/src/java/nginx/unit/websocket/server/WsMappingResult.java deleted file mode 100644 index a7a4c022..00000000 --- a/src/java/nginx/unit/websocket/server/WsMappingResult.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.util.Map; - -import javax.websocket.server.ServerEndpointConfig; - -class WsMappingResult { - - private final ServerEndpointConfig config; - private final Map pathParams; - - - WsMappingResult(ServerEndpointConfig config, - Map pathParams) { - this.config = config; - this.pathParams = pathParams; - } - - - ServerEndpointConfig getConfig() { - return config; - } - - - Map getPathParams() { - return pathParams; - } -} diff --git a/src/java/nginx/unit/websocket/server/WsPerSessionServerEndpointConfig.java b/src/java/nginx/unit/websocket/server/WsPerSessionServerEndpointConfig.java deleted file mode 100644 index 2be050cb..00000000 --- a/src/java/nginx/unit/websocket/server/WsPerSessionServerEndpointConfig.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import javax.websocket.Decoder; -import javax.websocket.Encoder; -import javax.websocket.Extension; -import javax.websocket.server.ServerEndpointConfig; - -/** - * Wraps the provided {@link ServerEndpointConfig} and provides a per session - * view - the difference being that the map returned by {@link - * #getUserProperties()} is unique to this instance rather than shared with the - * wrapped {@link ServerEndpointConfig}. - */ -class WsPerSessionServerEndpointConfig implements ServerEndpointConfig { - - private final ServerEndpointConfig perEndpointConfig; - private final Map perSessionUserProperties = - new ConcurrentHashMap<>(); - - WsPerSessionServerEndpointConfig(ServerEndpointConfig perEndpointConfig) { - this.perEndpointConfig = perEndpointConfig; - perSessionUserProperties.putAll(perEndpointConfig.getUserProperties()); - } - - @Override - public List> getEncoders() { - return perEndpointConfig.getEncoders(); - } - - @Override - public List> getDecoders() { - return perEndpointConfig.getDecoders(); - } - - @Override - public Map getUserProperties() { - return perSessionUserProperties; - } - - @Override - public Class getEndpointClass() { - return perEndpointConfig.getEndpointClass(); - } - - @Override - public String getPath() { - return perEndpointConfig.getPath(); - } - - @Override - public List getSubprotocols() { - return perEndpointConfig.getSubprotocols(); - } - - @Override - public List getExtensions() { - return perEndpointConfig.getExtensions(); - } - - @Override - public Configurator getConfigurator() { - return perEndpointConfig.getConfigurator(); - } -} diff --git a/src/java/nginx/unit/websocket/server/WsRemoteEndpointImplServer.java b/src/java/nginx/unit/websocket/server/WsRemoteEndpointImplServer.java deleted file mode 100644 index 6d10a3be..00000000 --- a/src/java/nginx/unit/websocket/server/WsRemoteEndpointImplServer.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.io.EOFException; -import java.io.IOException; -import java.net.SocketTimeoutException; -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; -import java.nio.channels.InterruptedByTimeoutException; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; - -import javax.websocket.SendHandler; -import javax.websocket.SendResult; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.util.res.StringManager; -import nginx.unit.websocket.Transformation; -import nginx.unit.websocket.WsRemoteEndpointImplBase; - -/** - * This is the server side {@link javax.websocket.RemoteEndpoint} implementation - * - i.e. what the server uses to send data to the client. - */ -public class WsRemoteEndpointImplServer extends WsRemoteEndpointImplBase { - - private static final StringManager sm = - StringManager.getManager(WsRemoteEndpointImplServer.class); - private final Log log = LogFactory.getLog(WsRemoteEndpointImplServer.class); // must not be static - - private volatile SendHandler handler = null; - private volatile ByteBuffer[] buffers = null; - - private volatile long timeoutExpiry = -1; - private volatile boolean close; - - public WsRemoteEndpointImplServer( - WsServerContainer serverContainer) { - } - - - @Override - protected final boolean isMasked() { - return false; - } - - @Override - protected void doWrite(SendHandler handler, long blockingWriteTimeoutExpiry, - ByteBuffer... buffers) { - } - - @Override - protected void doClose() { - if (handler != null) { - // close() can be triggered by a wide range of scenarios. It is far - // simpler just to always use a dispatch than it is to try and track - // whether or not this method was called by the same thread that - // triggered the write - clearHandler(new EOFException(), true); - } - } - - - protected long getTimeoutExpiry() { - return timeoutExpiry; - } - - - /* - * Currently this is only called from the background thread so we could just - * call clearHandler() with useDispatch == false but the method parameter - * was added in case other callers started to use this method to make sure - * that those callers think through what the correct value of useDispatch is - * for them. - */ - protected void onTimeout(boolean useDispatch) { - if (handler != null) { - clearHandler(new SocketTimeoutException(), useDispatch); - } - close(); - } - - - @Override - protected void setTransformation(Transformation transformation) { - // Overridden purely so it is visible to other classes in this package - super.setTransformation(transformation); - } - - - /** - * - * @param t The throwable associated with any error that - * occurred - * @param useDispatch Should {@link SendHandler#onResult(SendResult)} be - * called from a new thread, keeping in mind the - * requirements of - * {@link javax.websocket.RemoteEndpoint.Async} - */ - private void clearHandler(Throwable t, boolean useDispatch) { - // Setting the result marks this (partial) message as - // complete which means the next one may be sent which - // could update the value of the handler. Therefore, keep a - // local copy before signalling the end of the (partial) - // message. - SendHandler sh = handler; - handler = null; - buffers = null; - if (sh != null) { - if (useDispatch) { - OnResultRunnable r = new OnResultRunnable(sh, t); - } else { - if (t == null) { - sh.onResult(new SendResult()); - } else { - sh.onResult(new SendResult(t)); - } - } - } - } - - - private static class OnResultRunnable implements Runnable { - - private final SendHandler sh; - private final Throwable t; - - private OnResultRunnable(SendHandler sh, Throwable t) { - this.sh = sh; - this.t = t; - } - - @Override - public void run() { - if (t == null) { - sh.onResult(new SendResult()); - } else { - sh.onResult(new SendResult(t)); - } - } - } -} diff --git a/src/java/nginx/unit/websocket/server/WsSci.java b/src/java/nginx/unit/websocket/server/WsSci.java deleted file mode 100644 index cdecce27..00000000 --- a/src/java/nginx/unit/websocket/server/WsSci.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.Set; - -import javax.servlet.ServletContainerInitializer; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.annotation.HandlesTypes; -import javax.websocket.ContainerProvider; -import javax.websocket.DeploymentException; -import javax.websocket.Endpoint; -import javax.websocket.server.ServerApplicationConfig; -import javax.websocket.server.ServerEndpoint; -import javax.websocket.server.ServerEndpointConfig; - -/** - * Registers an interest in any class that is annotated with - * {@link ServerEndpoint} so that Endpoint can be published via the WebSocket - * server. - */ -@HandlesTypes({ServerEndpoint.class, ServerApplicationConfig.class, - Endpoint.class}) -public class WsSci implements ServletContainerInitializer { - - @Override - public void onStartup(Set> clazzes, ServletContext ctx) - throws ServletException { - - WsServerContainer sc = init(ctx, true); - - if (clazzes == null || clazzes.size() == 0) { - return; - } - - // Group the discovered classes by type - Set serverApplicationConfigs = new HashSet<>(); - Set> scannedEndpointClazzes = new HashSet<>(); - Set> scannedPojoEndpoints = new HashSet<>(); - - try { - // wsPackage is "javax.websocket." - String wsPackage = ContainerProvider.class.getName(); - wsPackage = wsPackage.substring(0, wsPackage.lastIndexOf('.') + 1); - for (Class clazz : clazzes) { - int modifiers = clazz.getModifiers(); - if (!Modifier.isPublic(modifiers) || - Modifier.isAbstract(modifiers)) { - // Non-public or abstract - skip it. - continue; - } - // Protect against scanning the WebSocket API JARs - if (clazz.getName().startsWith(wsPackage)) { - continue; - } - if (ServerApplicationConfig.class.isAssignableFrom(clazz)) { - serverApplicationConfigs.add( - (ServerApplicationConfig) clazz.getConstructor().newInstance()); - } - if (Endpoint.class.isAssignableFrom(clazz)) { - @SuppressWarnings("unchecked") - Class endpoint = - (Class) clazz; - scannedEndpointClazzes.add(endpoint); - } - if (clazz.isAnnotationPresent(ServerEndpoint.class)) { - scannedPojoEndpoints.add(clazz); - } - } - } catch (ReflectiveOperationException e) { - throw new ServletException(e); - } - - // Filter the results - Set filteredEndpointConfigs = new HashSet<>(); - Set> filteredPojoEndpoints = new HashSet<>(); - - if (serverApplicationConfigs.isEmpty()) { - filteredPojoEndpoints.addAll(scannedPojoEndpoints); - } else { - for (ServerApplicationConfig config : serverApplicationConfigs) { - Set configFilteredEndpoints = - config.getEndpointConfigs(scannedEndpointClazzes); - if (configFilteredEndpoints != null) { - filteredEndpointConfigs.addAll(configFilteredEndpoints); - } - Set> configFilteredPojos = - config.getAnnotatedEndpointClasses( - scannedPojoEndpoints); - if (configFilteredPojos != null) { - filteredPojoEndpoints.addAll(configFilteredPojos); - } - } - } - - try { - // Deploy endpoints - for (ServerEndpointConfig config : filteredEndpointConfigs) { - sc.addEndpoint(config); - } - // Deploy POJOs - for (Class clazz : filteredPojoEndpoints) { - sc.addEndpoint(clazz); - } - } catch (DeploymentException e) { - throw new ServletException(e); - } - } - - - static WsServerContainer init(ServletContext servletContext, - boolean initBySciMechanism) { - - WsServerContainer sc = new WsServerContainer(servletContext); - - servletContext.setAttribute( - Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE, sc); - - servletContext.addListener(new WsSessionListener(sc)); - // Can't register the ContextListener again if the ContextListener is - // calling this method - if (initBySciMechanism) { - servletContext.addListener(new WsContextListener()); - } - - return sc; - } -} diff --git a/src/java/nginx/unit/websocket/server/WsServerContainer.java b/src/java/nginx/unit/websocket/server/WsServerContainer.java deleted file mode 100644 index 069fc54f..00000000 --- a/src/java/nginx/unit/websocket/server/WsServerContainer.java +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.Map; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; - -import javax.servlet.DispatcherType; -import javax.servlet.FilterRegistration; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.websocket.CloseReason; -import javax.websocket.CloseReason.CloseCodes; -import javax.websocket.DeploymentException; -import javax.websocket.Encoder; -import javax.websocket.Endpoint; -import javax.websocket.server.ServerContainer; -import javax.websocket.server.ServerEndpoint; -import javax.websocket.server.ServerEndpointConfig; -import javax.websocket.server.ServerEndpointConfig.Configurator; - -import org.apache.tomcat.InstanceManager; -import org.apache.tomcat.util.res.StringManager; -import nginx.unit.websocket.WsSession; -import nginx.unit.websocket.WsWebSocketContainer; -import nginx.unit.websocket.pojo.PojoMethodMapping; - -/** - * Provides a per class loader (i.e. per web application) instance of a - * ServerContainer. Web application wide defaults may be configured by setting - * the following servlet context initialisation parameters to the desired - * values. - *

    - *
  • {@link Constants#BINARY_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM}
  • - *
  • {@link Constants#TEXT_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM}
  • - *
- */ -public class WsServerContainer extends WsWebSocketContainer - implements ServerContainer { - - private static final StringManager sm = StringManager.getManager(WsServerContainer.class); - - private static final CloseReason AUTHENTICATED_HTTP_SESSION_CLOSED = - new CloseReason(CloseCodes.VIOLATED_POLICY, - "This connection was established under an authenticated " + - "HTTP session that has ended."); - - private final ServletContext servletContext; - private final Map configExactMatchMap = - new ConcurrentHashMap<>(); - private final Map> configTemplateMatchMap = - new ConcurrentHashMap<>(); - private volatile boolean enforceNoAddAfterHandshake = - nginx.unit.websocket.Constants.STRICT_SPEC_COMPLIANCE; - private volatile boolean addAllowed = true; - private final Map> authenticatedSessions = new ConcurrentHashMap<>(); - private volatile boolean endpointsRegistered = false; - - WsServerContainer(ServletContext servletContext) { - - this.servletContext = servletContext; - setInstanceManager((InstanceManager) servletContext.getAttribute(InstanceManager.class.getName())); - - // Configure servlet context wide defaults - String value = servletContext.getInitParameter( - Constants.BINARY_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM); - if (value != null) { - setDefaultMaxBinaryMessageBufferSize(Integer.parseInt(value)); - } - - value = servletContext.getInitParameter( - Constants.TEXT_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM); - if (value != null) { - setDefaultMaxTextMessageBufferSize(Integer.parseInt(value)); - } - - value = servletContext.getInitParameter( - Constants.ENFORCE_NO_ADD_AFTER_HANDSHAKE_CONTEXT_INIT_PARAM); - if (value != null) { - setEnforceNoAddAfterHandshake(Boolean.parseBoolean(value)); - } - - FilterRegistration.Dynamic fr = servletContext.addFilter( - "Tomcat WebSocket (JSR356) Filter", new WsFilter()); - fr.setAsyncSupported(true); - - EnumSet types = EnumSet.of(DispatcherType.REQUEST, - DispatcherType.FORWARD); - - fr.addMappingForUrlPatterns(types, true, "/*"); - } - - - /** - * Published the provided endpoint implementation at the specified path with - * the specified configuration. {@link #WsServerContainer(ServletContext)} - * must be called before calling this method. - * - * @param sec The configuration to use when creating endpoint instances - * @throws DeploymentException if the endpoint cannot be published as - * requested - */ - @Override - public void addEndpoint(ServerEndpointConfig sec) - throws DeploymentException { - - if (enforceNoAddAfterHandshake && !addAllowed) { - throw new DeploymentException( - sm.getString("serverContainer.addNotAllowed")); - } - - if (servletContext == null) { - throw new DeploymentException( - sm.getString("serverContainer.servletContextMissing")); - } - String path = sec.getPath(); - - // Add method mapping to user properties - PojoMethodMapping methodMapping = new PojoMethodMapping(sec.getEndpointClass(), - sec.getDecoders(), path); - if (methodMapping.getOnClose() != null || methodMapping.getOnOpen() != null - || methodMapping.getOnError() != null || methodMapping.hasMessageHandlers()) { - sec.getUserProperties().put(nginx.unit.websocket.pojo.Constants.POJO_METHOD_MAPPING_KEY, - methodMapping); - } - - UriTemplate uriTemplate = new UriTemplate(path); - if (uriTemplate.hasParameters()) { - Integer key = Integer.valueOf(uriTemplate.getSegmentCount()); - SortedSet templateMatches = - configTemplateMatchMap.get(key); - if (templateMatches == null) { - // Ensure that if concurrent threads execute this block they - // both end up using the same TreeSet instance - templateMatches = new TreeSet<>( - TemplatePathMatchComparator.getInstance()); - configTemplateMatchMap.putIfAbsent(key, templateMatches); - templateMatches = configTemplateMatchMap.get(key); - } - if (!templateMatches.add(new TemplatePathMatch(sec, uriTemplate))) { - // Duplicate uriTemplate; - throw new DeploymentException( - sm.getString("serverContainer.duplicatePaths", path, - sec.getEndpointClass(), - sec.getEndpointClass())); - } - } else { - // Exact match - ServerEndpointConfig old = configExactMatchMap.put(path, sec); - if (old != null) { - // Duplicate path mappings - throw new DeploymentException( - sm.getString("serverContainer.duplicatePaths", path, - old.getEndpointClass(), - sec.getEndpointClass())); - } - } - - endpointsRegistered = true; - } - - - /** - * Provides the equivalent of {@link #addEndpoint(ServerEndpointConfig)} - * for publishing plain old java objects (POJOs) that have been annotated as - * WebSocket endpoints. - * - * @param pojo The annotated POJO - */ - @Override - public void addEndpoint(Class pojo) throws DeploymentException { - - ServerEndpoint annotation = pojo.getAnnotation(ServerEndpoint.class); - if (annotation == null) { - throw new DeploymentException( - sm.getString("serverContainer.missingAnnotation", - pojo.getName())); - } - String path = annotation.value(); - - // Validate encoders - validateEncoders(annotation.encoders()); - - // ServerEndpointConfig - ServerEndpointConfig sec; - Class configuratorClazz = - annotation.configurator(); - Configurator configurator = null; - if (!configuratorClazz.equals(Configurator.class)) { - try { - configurator = annotation.configurator().getConstructor().newInstance(); - } catch (ReflectiveOperationException e) { - throw new DeploymentException(sm.getString( - "serverContainer.configuratorFail", - annotation.configurator().getName(), - pojo.getClass().getName()), e); - } - } - if (configurator == null) { - configurator = new nginx.unit.websocket.server.DefaultServerEndpointConfigurator(); - } - sec = ServerEndpointConfig.Builder.create(pojo, path). - decoders(Arrays.asList(annotation.decoders())). - encoders(Arrays.asList(annotation.encoders())). - subprotocols(Arrays.asList(annotation.subprotocols())). - configurator(configurator). - build(); - - addEndpoint(sec); - } - - - boolean areEndpointsRegistered() { - return endpointsRegistered; - } - - - /** - * Until the WebSocket specification provides such a mechanism, this Tomcat - * proprietary method is provided to enable applications to programmatically - * determine whether or not to upgrade an individual request to WebSocket. - *

- * Note: This method is not used by Tomcat but is used directly by - * third-party code and must not be removed. - * - * @param request The request object to be upgraded - * @param response The response object to be populated with the result of - * the upgrade - * @param sec The server endpoint to use to process the upgrade request - * @param pathParams The path parameters associated with the upgrade request - * - * @throws ServletException If a configuration error prevents the upgrade - * from taking place - * @throws IOException If an I/O error occurs during the upgrade process - */ - public void doUpgrade(HttpServletRequest request, - HttpServletResponse response, ServerEndpointConfig sec, - Map pathParams) - throws ServletException, IOException { - UpgradeUtil.doUpgrade(this, request, response, sec, pathParams); - } - - - public WsMappingResult findMapping(String path) { - - // Prevent registering additional endpoints once the first attempt has - // been made to use one - if (addAllowed) { - addAllowed = false; - } - - // Check an exact match. Simple case as there are no templates. - ServerEndpointConfig sec = configExactMatchMap.get(path); - if (sec != null) { - return new WsMappingResult(sec, Collections.emptyMap()); - } - - // No exact match. Need to look for template matches. - UriTemplate pathUriTemplate = null; - try { - pathUriTemplate = new UriTemplate(path); - } catch (DeploymentException e) { - // Path is not valid so can't be matched to a WebSocketEndpoint - return null; - } - - // Number of segments has to match - Integer key = Integer.valueOf(pathUriTemplate.getSegmentCount()); - SortedSet templateMatches = - configTemplateMatchMap.get(key); - - if (templateMatches == null) { - // No templates with an equal number of segments so there will be - // no matches - return null; - } - - // List is in alphabetical order of normalised templates. - // Correct match is the first one that matches. - Map pathParams = null; - for (TemplatePathMatch templateMatch : templateMatches) { - pathParams = templateMatch.getUriTemplate().match(pathUriTemplate); - if (pathParams != null) { - sec = templateMatch.getConfig(); - break; - } - } - - if (sec == null) { - // No match - return null; - } - - return new WsMappingResult(sec, pathParams); - } - - - - public boolean isEnforceNoAddAfterHandshake() { - return enforceNoAddAfterHandshake; - } - - - public void setEnforceNoAddAfterHandshake( - boolean enforceNoAddAfterHandshake) { - this.enforceNoAddAfterHandshake = enforceNoAddAfterHandshake; - } - - - /** - * {@inheritDoc} - * - * Overridden to make it visible to other classes in this package. - */ - @Override - protected void registerSession(Endpoint endpoint, WsSession wsSession) { - super.registerSession(endpoint, wsSession); - if (wsSession.isOpen() && - wsSession.getUserPrincipal() != null && - wsSession.getHttpSessionId() != null) { - registerAuthenticatedSession(wsSession, - wsSession.getHttpSessionId()); - } - } - - - /** - * {@inheritDoc} - * - * Overridden to make it visible to other classes in this package. - */ - @Override - protected void unregisterSession(Endpoint endpoint, WsSession wsSession) { - if (wsSession.getUserPrincipal() != null && - wsSession.getHttpSessionId() != null) { - unregisterAuthenticatedSession(wsSession, - wsSession.getHttpSessionId()); - } - super.unregisterSession(endpoint, wsSession); - } - - - private void registerAuthenticatedSession(WsSession wsSession, - String httpSessionId) { - Set wsSessions = authenticatedSessions.get(httpSessionId); - if (wsSessions == null) { - wsSessions = Collections.newSetFromMap( - new ConcurrentHashMap()); - authenticatedSessions.putIfAbsent(httpSessionId, wsSessions); - wsSessions = authenticatedSessions.get(httpSessionId); - } - wsSessions.add(wsSession); - } - - - private void unregisterAuthenticatedSession(WsSession wsSession, - String httpSessionId) { - Set wsSessions = authenticatedSessions.get(httpSessionId); - // wsSessions will be null if the HTTP session has ended - if (wsSessions != null) { - wsSessions.remove(wsSession); - } - } - - - public void closeAuthenticatedSession(String httpSessionId) { - Set wsSessions = authenticatedSessions.remove(httpSessionId); - - if (wsSessions != null && !wsSessions.isEmpty()) { - for (WsSession wsSession : wsSessions) { - try { - wsSession.close(AUTHENTICATED_HTTP_SESSION_CLOSED); - } catch (IOException e) { - // Any IOExceptions during close will have been caught and the - // onError method called. - } - } - } - } - - - private static void validateEncoders(Class[] encoders) - throws DeploymentException { - - for (Class encoder : encoders) { - // Need to instantiate decoder to ensure it is valid and that - // deployment can be failed if it is not - @SuppressWarnings("unused") - Encoder instance; - try { - encoder.getConstructor().newInstance(); - } catch(ReflectiveOperationException e) { - throw new DeploymentException(sm.getString( - "serverContainer.encoderFail", encoder.getName()), e); - } - } - } - - - private static class TemplatePathMatch { - private final ServerEndpointConfig config; - private final UriTemplate uriTemplate; - - public TemplatePathMatch(ServerEndpointConfig config, - UriTemplate uriTemplate) { - this.config = config; - this.uriTemplate = uriTemplate; - } - - - public ServerEndpointConfig getConfig() { - return config; - } - - - public UriTemplate getUriTemplate() { - return uriTemplate; - } - } - - - /** - * This Comparator implementation is thread-safe so only create a single - * instance. - */ - private static class TemplatePathMatchComparator - implements Comparator { - - private static final TemplatePathMatchComparator INSTANCE = - new TemplatePathMatchComparator(); - - public static TemplatePathMatchComparator getInstance() { - return INSTANCE; - } - - private TemplatePathMatchComparator() { - // Hide default constructor - } - - @Override - public int compare(TemplatePathMatch tpm1, TemplatePathMatch tpm2) { - return tpm1.getUriTemplate().getNormalizedPath().compareTo( - tpm2.getUriTemplate().getNormalizedPath()); - } - } -} diff --git a/src/java/nginx/unit/websocket/server/WsSessionListener.java b/src/java/nginx/unit/websocket/server/WsSessionListener.java deleted file mode 100644 index 2921bd45..00000000 --- a/src/java/nginx/unit/websocket/server/WsSessionListener.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionListener; - -public class WsSessionListener implements HttpSessionListener { - - private final WsServerContainer wsServerContainer; - - - public WsSessionListener(WsServerContainer wsServerContainer) { - this.wsServerContainer = wsServerContainer; - } - - - @Override - public void sessionDestroyed(HttpSessionEvent se) { - wsServerContainer.closeAuthenticatedSession(se.getSession().getId()); - } -} diff --git a/src/java/nginx/unit/websocket/server/WsWriteTimeout.java b/src/java/nginx/unit/websocket/server/WsWriteTimeout.java deleted file mode 100644 index 2dfc4ab2..00000000 --- a/src/java/nginx/unit/websocket/server/WsWriteTimeout.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package nginx.unit.websocket.server; - -import java.util.Comparator; -import java.util.Set; -import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.atomic.AtomicInteger; - -import nginx.unit.websocket.BackgroundProcess; -import nginx.unit.websocket.BackgroundProcessManager; - -/** - * Provides timeouts for asynchronous web socket writes. On the server side we - * only have access to {@link javax.servlet.ServletOutputStream} and - * {@link javax.servlet.ServletInputStream} so there is no way to set a timeout - * for writes to the client. - */ -public class WsWriteTimeout implements BackgroundProcess { - - private final Set endpoints = - new ConcurrentSkipListSet<>(new EndpointComparator()); - private final AtomicInteger count = new AtomicInteger(0); - private int backgroundProcessCount = 0; - private volatile int processPeriod = 1; - - @Override - public void backgroundProcess() { - // This method gets called once a second. - backgroundProcessCount ++; - - if (backgroundProcessCount >= processPeriod) { - backgroundProcessCount = 0; - - long now = System.currentTimeMillis(); - for (WsRemoteEndpointImplServer endpoint : endpoints) { - if (endpoint.getTimeoutExpiry() < now) { - // Background thread, not the thread that triggered the - // write so no need to use a dispatch - endpoint.onTimeout(false); - } else { - // Endpoints are ordered by timeout expiry so if this point - // is reached there is no need to check the remaining - // endpoints - break; - } - } - } - } - - - @Override - public void setProcessPeriod(int period) { - this.processPeriod = period; - } - - - /** - * {@inheritDoc} - * - * The default value is 1 which means asynchronous write timeouts are - * processed every 1 second. - */ - @Override - public int getProcessPeriod() { - return processPeriod; - } - - - public void register(WsRemoteEndpointImplServer endpoint) { - boolean result = endpoints.add(endpoint); - if (result) { - int newCount = count.incrementAndGet(); - if (newCount == 1) { - BackgroundProcessManager.getInstance().register(this); - } - } - } - - - public void unregister(WsRemoteEndpointImplServer endpoint) { - boolean result = endpoints.remove(endpoint); - if (result) { - int newCount = count.decrementAndGet(); - if (newCount == 0) { - BackgroundProcessManager.getInstance().unregister(this); - } - } - } - - - /** - * Note: this comparator imposes orderings that are inconsistent with equals - */ - private static class EndpointComparator implements - Comparator { - - @Override - public int compare(WsRemoteEndpointImplServer o1, - WsRemoteEndpointImplServer o2) { - - long t1 = o1.getTimeoutExpiry(); - long t2 = o2.getTimeoutExpiry(); - - if (t1 < t2) { - return -1; - } else if (t1 == t2) { - return 0; - } else { - return 1; - } - } - } -} diff --git a/src/java/nginx/unit/websocket/server/package-info.java b/src/java/nginx/unit/websocket/server/package-info.java deleted file mode 100644 index 87bc85a3..00000000 --- a/src/java/nginx/unit/websocket/server/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Server-side specific implementation classes. These are in a separate package - * to make packaging a pure client JAR simpler. - */ -package nginx.unit.websocket.server; diff --git a/src/java/nxt_jni.c b/src/java/nxt_jni.c deleted file mode 100644 index 02ec1e37..00000000 --- a/src/java/nxt_jni.c +++ /dev/null @@ -1,175 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include -#include - -#include "nxt_jni.h" - - -static jclass nxt_java_NoSuchElementException_class; -static jclass nxt_java_IOException_class; -static jclass nxt_java_IllegalStateException_class; -static jclass nxt_java_File_class; -static jmethodID nxt_java_File_ctor; - -static inline char nxt_java_lowcase(char c); - - -int -nxt_java_jni_init(JNIEnv *env) -{ - jclass cls; - - cls = (*env)->FindClass(env, "java/util/NoSuchElementException"); - if (cls == NULL) { - return NXT_UNIT_ERROR; - } - - nxt_java_NoSuchElementException_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - - - cls = (*env)->FindClass(env, "java/io/IOException"); - if (cls == NULL) { - (*env)->DeleteGlobalRef(env, nxt_java_NoSuchElementException_class); - return NXT_UNIT_ERROR; - } - - nxt_java_IOException_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - - - cls = (*env)->FindClass(env, "java/lang/IllegalStateException"); - if (cls == NULL) { - (*env)->DeleteGlobalRef(env, nxt_java_NoSuchElementException_class); - (*env)->DeleteGlobalRef(env, nxt_java_IOException_class); - return NXT_UNIT_ERROR; - } - - nxt_java_IllegalStateException_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - - - cls = (*env)->FindClass(env, "java/io/File"); - if (cls == NULL) { - (*env)->DeleteGlobalRef(env, nxt_java_NoSuchElementException_class); - (*env)->DeleteGlobalRef(env, nxt_java_IOException_class); - (*env)->DeleteGlobalRef(env, nxt_java_IllegalStateException_class); - return NXT_UNIT_ERROR; - } - - nxt_java_File_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - - - nxt_java_File_ctor = (*env)->GetMethodID(env, nxt_java_File_class, "", - "(Ljava/lang/String;)V"); - if (nxt_java_File_ctor == NULL) { - (*env)->DeleteGlobalRef(env, nxt_java_NoSuchElementException_class); - (*env)->DeleteGlobalRef(env, nxt_java_IOException_class); - (*env)->DeleteGlobalRef(env, nxt_java_IllegalStateException_class); - (*env)->DeleteGlobalRef(env, nxt_java_File_class); - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -void -nxt_java_throw_NoSuchElementException(JNIEnv *env, const char *msg) -{ - (*env)->ThrowNew(env, nxt_java_NoSuchElementException_class, msg); -} - - -void -nxt_java_throw_IOException(JNIEnv *env, const char *msg) -{ - (*env)->ThrowNew(env, nxt_java_IOException_class, msg); -} - - -void -nxt_java_throw_IllegalStateException(JNIEnv *env, const char *msg) -{ - (*env)->ThrowNew(env, nxt_java_IllegalStateException_class, msg); -} - - -nxt_unit_field_t * -nxt_java_findHeader(nxt_unit_field_t *f, nxt_unit_field_t *end, - const char *name, uint8_t name_len) -{ - const char *field_name; - - for (/* void */ ; f < end; f++) { - if (f->skip != 0 || f->name_length != name_len) { - continue; - } - - field_name = nxt_unit_sptr_get(&f->name); - - if (nxt_java_strcaseeq(name, field_name, name_len)) { - return f; - } - } - - return NULL; -} - - -int -nxt_java_strcaseeq(const char *str1, const char *str2, int len) -{ - char c1, c2; - const char *end1; - - end1 = str1 + len; - - while (str1 < end1) { - c1 = nxt_java_lowcase(*str1++); - c2 = nxt_java_lowcase(*str2++); - - if (c1 != c2) { - return 0; - } - } - - return 1; -} - - -static inline char -nxt_java_lowcase(char c) -{ - return (c >= 'A' && c <= 'Z') ? c | 0x20 : c; -} - - -jstring -nxt_java_newString(JNIEnv *env, char *str, uint32_t len) -{ - char tmp; - jstring res; - - tmp = str[len]; - - if (tmp != '\0') { - str[len] = '\0'; - } - - res = (*env)->NewStringUTF(env, str); - - if (tmp != '\0') { - str[len] = tmp; - } - - return res; -} diff --git a/src/java/nxt_jni.h b/src/java/nxt_jni.h deleted file mode 100644 index 62acb752..00000000 --- a/src/java/nxt_jni.h +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JAVA_JNI_H_INCLUDED_ -#define _NXT_JAVA_JNI_H_INCLUDED_ - - -#include -#include - - -int nxt_java_jni_init(JNIEnv *env); - -void nxt_java_throw_NoSuchElementException(JNIEnv *env, const char *msg); - -void nxt_java_throw_IOException(JNIEnv *env, const char *msg); - -void nxt_java_throw_IllegalStateException(JNIEnv *env, const char *msg); - -nxt_unit_field_t *nxt_java_findHeader(nxt_unit_field_t *f, nxt_unit_field_t *e, - const char *name, uint8_t name_len); - -int nxt_java_strcaseeq(const char *str1, const char *str2, int len); - -jstring nxt_java_newString(JNIEnv *env, char *str, uint32_t len); - - -typedef struct { - uint32_t header_size; - uint32_t buf_size; - - jobject jreq; - jobject jresp; - - nxt_unit_buf_t *first; - nxt_unit_buf_t *buf; - -} nxt_java_request_data_t; - - -static inline jlong -nxt_ptr2jlong(void *ptr) -{ - return (jlong) (intptr_t) ptr; -} - -static inline void * -nxt_jlong2ptr(jlong l) -{ - return (void *) (intptr_t) l; -} - -#endif /* _NXT_JAVA_JNI_H_INCLUDED_ */ diff --git a/src/java/nxt_jni_Context.c b/src/java/nxt_jni_Context.c deleted file mode 100644 index 589e1c5b..00000000 --- a/src/java/nxt_jni_Context.c +++ /dev/null @@ -1,164 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include - -#include "nxt_jni.h" -#include "nxt_jni_Context.h" -#include "nxt_jni_URLClassLoader.h" - - -static jclass nxt_java_Context_class; -static jmethodID nxt_java_Context_start; -static jmethodID nxt_java_Context_service; -static jmethodID nxt_java_Context_stop; - -static void JNICALL nxt_java_Context_log(JNIEnv *env, jclass cls, - jlong ctx_ptr, jstring msg, jint msg_len); -static void JNICALL nxt_java_Context_trace(JNIEnv *env, jclass cls, - jlong ctx_ptr, jstring msg, jint msg_len); - - -int -nxt_java_initContext(JNIEnv *env, jobject cl) -{ - int res; - jclass cls; - - cls = nxt_java_loadClass(env, cl, "nginx.unit.Context"); - if (cls == NULL) { - nxt_unit_warn(NULL, "nginx.unit.Context not found"); - return NXT_UNIT_ERROR; - } - - nxt_java_Context_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - cls = nxt_java_Context_class; - - nxt_java_Context_start = (*env)->GetStaticMethodID(env, cls, "start", - "(Ljava/lang/String;[Ljava/net/URL;)Lnginx/unit/Context;"); - if (nxt_java_Context_start == NULL) { - nxt_unit_warn(NULL, "nginx.unit.Context.start() not found"); - goto failed; - } - - nxt_java_Context_service = (*env)->GetMethodID(env, cls, "service", - "(Lnginx/unit/Request;Lnginx/unit/Response;)V"); - if (nxt_java_Context_service == NULL) { - nxt_unit_warn(NULL, "nginx.unit.Context.service() not found"); - goto failed; - } - - nxt_java_Context_stop = (*env)->GetMethodID(env, cls, "stop", "()V"); - if (nxt_java_Context_stop == NULL) { - nxt_unit_warn(NULL, "nginx.unit.Context.stop() not found"); - goto failed; - } - - JNINativeMethod context_methods[] = { - { (char *) "log", - (char *) "(JLjava/lang/String;I)V", - nxt_java_Context_log }, - - { (char *) "trace", - (char *) "(JLjava/lang/String;I)V", - nxt_java_Context_trace }, - - }; - - res = (*env)->RegisterNatives(env, nxt_java_Context_class, - context_methods, - sizeof(context_methods) - / sizeof(context_methods[0])); - - nxt_unit_debug(NULL, "registered Context methods: %d", res); - - if (res != 0) { - nxt_unit_warn(NULL, "registering natives for Context failed"); - goto failed; - } - - return NXT_UNIT_OK; - -failed: - - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; -} - - -jobject -nxt_java_startContext(JNIEnv *env, const char *webapp, jobject classpaths) -{ - jstring webapp_str; - - webapp_str = (*env)->NewStringUTF(env, webapp); - if (webapp_str == NULL) { - return NULL; - } - - return (*env)->CallStaticObjectMethod(env, nxt_java_Context_class, - nxt_java_Context_start, webapp_str, - classpaths); -} - - -void -nxt_java_service(JNIEnv *env, jobject ctx, jobject jreq, jobject jresp) -{ - (*env)->CallVoidMethod(env, ctx, nxt_java_Context_service, jreq, jresp); -} - - -void -nxt_java_stopContext(JNIEnv *env, jobject ctx) -{ - (*env)->CallVoidMethod(env, ctx, nxt_java_Context_stop); -} - - -static void JNICALL -nxt_java_Context_log(JNIEnv *env, jclass cls, jlong ctx_ptr, jstring msg, - jint msg_len) -{ - const char *msg_str; - nxt_unit_ctx_t *ctx; - - ctx = nxt_jlong2ptr(ctx_ptr); - - msg_str = (*env)->GetStringUTFChars(env, msg, NULL); - if (msg_str == NULL) { - return; - } - - nxt_unit_log(ctx, NXT_UNIT_LOG_INFO, "%.*s", msg_len, msg_str); - - (*env)->ReleaseStringUTFChars(env, msg, msg_str); -} - - -static void JNICALL -nxt_java_Context_trace(JNIEnv *env, jclass cls, jlong ctx_ptr, jstring msg, - jint msg_len) -{ -#if (NXT_DEBUG) - const char *msg_str; - nxt_unit_ctx_t *ctx; - - ctx = nxt_jlong2ptr(ctx_ptr); - - msg_str = (*env)->GetStringUTFChars(env, msg, NULL); - if (msg_str == NULL) { - return; - } - - nxt_unit_debug(ctx, "%.*s", msg_len, msg_str); - - (*env)->ReleaseStringUTFChars(env, msg, msg_str); -#endif -} diff --git a/src/java/nxt_jni_Context.h b/src/java/nxt_jni_Context.h deleted file mode 100644 index 976c36cf..00000000 --- a/src/java/nxt_jni_Context.h +++ /dev/null @@ -1,23 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JAVA_CONTEXT_H_INCLUDED_ -#define _NXT_JAVA_CONTEXT_H_INCLUDED_ - - -#include - - -int nxt_java_initContext(JNIEnv *env, jobject cl); - -jobject nxt_java_startContext(JNIEnv *env, const char *webapp, - jobject classpaths); - -void nxt_java_service(JNIEnv *env, jobject ctx, jobject jreq, jobject jresp); - -void nxt_java_stopContext(JNIEnv *env, jobject ctx); - -#endif /* _NXT_JAVA_CONTEXT_H_INCLUDED_ */ - diff --git a/src/java/nxt_jni_HeaderNamesEnumeration.c b/src/java/nxt_jni_HeaderNamesEnumeration.c deleted file mode 100644 index eea0c387..00000000 --- a/src/java/nxt_jni_HeaderNamesEnumeration.c +++ /dev/null @@ -1,153 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include -#include -#include - -#include "nxt_jni.h" -#include "nxt_jni_URLClassLoader.h" -#include "nxt_jni_HeaderNamesEnumeration.h" - - -static jlong JNICALL nxt_java_HeaderNamesEnumeration_nextElementPos(JNIEnv *env, - jclass cls, jlong headers_ptr, jlong size, jlong pos); -static jstring JNICALL nxt_java_HeaderNamesEnumeration_nextElement(JNIEnv *env, - jclass cls, jlong headers_ptr, jlong size, jlong pos); - - -static jclass nxt_java_HeaderNamesEnumeration_class; -static jmethodID nxt_java_HeaderNamesEnumeration_ctor; - - -int -nxt_java_initHeaderNamesEnumeration(JNIEnv *env, jobject cl) -{ - int res; - jclass cls; - - cls = nxt_java_loadClass(env, cl, "nginx.unit.HeaderNamesEnumeration"); - if (cls == NULL) { - return NXT_UNIT_ERROR; - } - - nxt_java_HeaderNamesEnumeration_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - cls = nxt_java_HeaderNamesEnumeration_class; - - nxt_java_HeaderNamesEnumeration_ctor = (*env)->GetMethodID(env, cls, - "", "(JJ)V"); - if (nxt_java_HeaderNamesEnumeration_ctor == NULL) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - JNINativeMethod hnenum_methods[] = { - { (char *) "nextElementPos", - (char *) "(JJJ)J", - nxt_java_HeaderNamesEnumeration_nextElementPos }, - - { (char *) "nextElement", - (char *) "(JJJ)Ljava/lang/String;", - nxt_java_HeaderNamesEnumeration_nextElement }, - }; - - res = (*env)->RegisterNatives(env, nxt_java_HeaderNamesEnumeration_class, - hnenum_methods, - sizeof(hnenum_methods) - / sizeof(hnenum_methods[0])); - - nxt_unit_debug(NULL, "registered HeaderNamesEnumeration methods: %d", res); - - if (res != 0) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -jobject -nxt_java_newHeaderNamesEnumeration(JNIEnv *env, nxt_unit_field_t *f, - uint32_t fields_count) -{ - return (*env)->NewObject(env, - nxt_java_HeaderNamesEnumeration_class, - nxt_java_HeaderNamesEnumeration_ctor, nxt_ptr2jlong(f), - (jlong) fields_count); -} - - -static jlong JNICALL -nxt_java_HeaderNamesEnumeration_nextElementPos(JNIEnv *env, jclass cls, - jlong headers_ptr, jlong size, jlong pos) -{ - nxt_unit_field_t *f; - - f = nxt_jlong2ptr(headers_ptr); - - if (pos >= size) { - return size; - } - - if (pos > 0) { - while (pos < size - && f[pos].hash == f[pos - 1].hash - && f[pos].name_length == f[pos - 1].name_length) - { - pos++; - } - } - - return pos; -} - - -static jstring JNICALL -nxt_java_HeaderNamesEnumeration_nextElement(JNIEnv *env, jclass cls, - jlong headers_ptr, jlong size, jlong pos) -{ - char *name, tmp; - jstring res; - nxt_unit_field_t *f; - - f = nxt_jlong2ptr(headers_ptr); - - if (pos > 0) { - while (pos < size - && f[pos].hash == f[pos - 1].hash - && f[pos].name_length == f[pos - 1].name_length) - { - pos++; - } - } - - if (pos >= size) { - nxt_java_throw_NoSuchElementException(env, "pos >= size"); - - return NULL; - } - - f += pos; - - name = nxt_unit_sptr_get(&f->name); - tmp = name[f->name_length]; - - if (tmp != '\0') { - name[f->name_length] = '\0'; - } - - res = (*env)->NewStringUTF(env, name); - - if (tmp != '\0') { - name[f->name_length] = tmp; - } - - return res; -} diff --git a/src/java/nxt_jni_HeaderNamesEnumeration.h b/src/java/nxt_jni_HeaderNamesEnumeration.h deleted file mode 100644 index 90df8f54..00000000 --- a/src/java/nxt_jni_HeaderNamesEnumeration.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JAVA_HEADERNAMESENUMERATION_H_INCLUDED_ -#define _NXT_JAVA_HEADERNAMESENUMERATION_H_INCLUDED_ - - -#include -#include - - -int nxt_java_initHeaderNamesEnumeration(JNIEnv *env, jobject cl); - -jobject nxt_java_newHeaderNamesEnumeration(JNIEnv *env, nxt_unit_field_t *f, - uint32_t fields_count); - -#endif /* _NXT_JAVA_HEADERNAMESENUMERATION_H_INCLUDED_ */ diff --git a/src/java/nxt_jni_HeadersEnumeration.c b/src/java/nxt_jni_HeadersEnumeration.c deleted file mode 100644 index aaea710d..00000000 --- a/src/java/nxt_jni_HeadersEnumeration.c +++ /dev/null @@ -1,148 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include -#include -#include - -#include "nxt_jni.h" -#include "nxt_jni_URLClassLoader.h" -#include "nxt_jni_HeadersEnumeration.h" - - -static jclass nxt_java_HeadersEnumeration_class; -static jmethodID nxt_java_HeadersEnumeration_ctor; - - -static jlong JNICALL nxt_java_HeadersEnumeration_nextElementPos(JNIEnv *env, - jclass cls, jlong headers_ptr, jlong size, jlong ipos, jlong pos); - -static jstring JNICALL nxt_java_HeadersEnumeration_nextElement(JNIEnv *env, - jclass cls, jlong headers_ptr, jlong size, jlong ipos, jlong pos); - - -int -nxt_java_initHeadersEnumeration(JNIEnv *env, jobject cl) -{ - int res; - jclass cls; - - cls = nxt_java_loadClass(env, cl, "nginx.unit.HeadersEnumeration"); - if (cls == NULL) { - return NXT_UNIT_ERROR; - } - - nxt_java_HeadersEnumeration_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - cls = nxt_java_HeadersEnumeration_class; - - nxt_java_HeadersEnumeration_ctor = (*env)->GetMethodID(env, cls, - "", "(JJJ)V"); - if (nxt_java_HeadersEnumeration_ctor == NULL) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - JNINativeMethod methods[] = { - { (char *) "nextElementPos", - (char *) "(JJJJ)J", - nxt_java_HeadersEnumeration_nextElementPos }, - - { (char *) "nextElement", - (char *) "(JJJJ)Ljava/lang/String;", - nxt_java_HeadersEnumeration_nextElement }, - }; - - res = (*env)->RegisterNatives(env, nxt_java_HeadersEnumeration_class, - methods, - sizeof(methods) / sizeof(methods[0])); - - nxt_unit_debug(NULL, "registered HeadersEnumeration methods: %d", res); - - if (res != 0) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -jobject -nxt_java_newHeadersEnumeration(JNIEnv *env, nxt_unit_field_t *f, - uint32_t fields_count, uint32_t pos) -{ - return (*env)->NewObject(env, - nxt_java_HeadersEnumeration_class, - nxt_java_HeadersEnumeration_ctor, nxt_ptr2jlong(f), - (jlong) fields_count, (jlong) pos); -} - - -static jlong JNICALL -nxt_java_HeadersEnumeration_nextElementPos(JNIEnv *env, jclass cls, - jlong headers_ptr, jlong size, jlong ipos, jlong pos) -{ - nxt_unit_field_t *f, *init_field; - - f = nxt_jlong2ptr(headers_ptr); - - init_field = f + ipos; - - if (pos >= size) { - return size; - } - - f += pos; - - if (f->hash != init_field->hash - || f->name_length != init_field->name_length) - { - return size; - } - - if (!nxt_java_strcaseeq(nxt_unit_sptr_get(&f->name), - nxt_unit_sptr_get(&init_field->name), - init_field->name_length)) - { - return size; - } - - return pos; -} - - -static jstring JNICALL -nxt_java_HeadersEnumeration_nextElement(JNIEnv *env, jclass cls, - jlong headers_ptr, jlong size, jlong ipos, jlong pos) -{ - nxt_unit_field_t *f, *init_field; - - f = nxt_jlong2ptr(headers_ptr); - - init_field = f + ipos; - - if (pos >= size) { - nxt_java_throw_IOException(env, "pos >= size"); - - return NULL; - } - - f += pos; - - if (f->hash != init_field->hash - || f->name_length != init_field->name_length) - { - nxt_java_throw_IOException(env, "f->hash != hash"); - - return NULL; - } - - return nxt_java_newString(env, nxt_unit_sptr_get(&f->value), - f->value_length); -} diff --git a/src/java/nxt_jni_HeadersEnumeration.h b/src/java/nxt_jni_HeadersEnumeration.h deleted file mode 100644 index 10f9393c..00000000 --- a/src/java/nxt_jni_HeadersEnumeration.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JAVA_HEADERSENUMERATION_H_INCLUDED_ -#define _NXT_JAVA_HEADERSENUMERATION_H_INCLUDED_ - - -#include -#include - - -int nxt_java_initHeadersEnumeration(JNIEnv *env, jobject cl); - -jobject nxt_java_newHeadersEnumeration(JNIEnv *env, nxt_unit_field_t *f, - uint32_t fields_count, uint32_t pos); - -#endif /* _NXT_JAVA_HEADERSENUMERATION_H_INCLUDED_ */ diff --git a/src/java/nxt_jni_InputStream.c b/src/java/nxt_jni_InputStream.c deleted file mode 100644 index fabff685..00000000 --- a/src/java/nxt_jni_InputStream.c +++ /dev/null @@ -1,210 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include -#include - -#include "nxt_jni.h" -#include "nxt_jni_InputStream.h" -#include "nxt_jni_URLClassLoader.h" - - -static jint JNICALL nxt_java_InputStream_readLine(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray b, jint off, jint len); -static jboolean JNICALL nxt_java_InputStream_isFinished(JNIEnv *env, jclass cls, - jlong req_info_ptr); -static jint JNICALL nxt_java_InputStream_readByte(JNIEnv *env, jclass cls, - jlong req_info_ptr); -static jint JNICALL nxt_java_InputStream_read(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray b, jint off, jint len); -static jlong JNICALL nxt_java_InputStream_skip(JNIEnv *env, jclass cls, - jlong req_info_ptr, jlong n); -static jint JNICALL nxt_java_InputStream_available(JNIEnv *env, jclass cls, - jlong req_info_ptr); - - -static jclass nxt_java_InputStream_class; - - -int -nxt_java_initInputStream(JNIEnv *env, jobject cl) -{ - int res; - jclass cls; - - cls = nxt_java_loadClass(env, cl, "nginx.unit.InputStream"); - if (cls == NULL) { - return NXT_UNIT_ERROR; - } - - nxt_java_InputStream_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - - JNINativeMethod is_methods[] = { - { (char *) "readLine", - (char *) "(J[BII)I", - nxt_java_InputStream_readLine }, - - { (char *) "isFinished", - (char *) "(J)Z", - nxt_java_InputStream_isFinished }, - - { (char *) "read", - (char *) "(J)I", - nxt_java_InputStream_readByte }, - - { (char *) "read", - (char *) "(J[BII)I", - nxt_java_InputStream_read }, - - { (char *) "skip", - (char *) "(JJ)J", - nxt_java_InputStream_skip }, - - { (char *) "available", - (char *) "(J)I", - nxt_java_InputStream_available }, - }; - - res = (*env)->RegisterNatives(env, nxt_java_InputStream_class, - is_methods, - sizeof(is_methods) / sizeof(is_methods[0])); - - nxt_unit_debug(NULL, "registered InputStream methods: %d", res); - - if (res != 0) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static jint JNICALL -nxt_java_InputStream_readLine(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray out, jint off, jint len) -{ - uint8_t *data; - ssize_t res; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - data = (*env)->GetPrimitiveArrayCritical(env, out, NULL); - - res = nxt_unit_request_readline_size(req, len); - - if (res > 0) { - res = nxt_unit_request_read(req, data + off, res); - } - - nxt_unit_req_debug(req, "readLine '%.*s'", (int) res, (char *) data + off); - - (*env)->ReleasePrimitiveArrayCritical(env, out, data, 0); - - return res > 0 ? res : -1; -} - - -static jboolean JNICALL -nxt_java_InputStream_isFinished(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - return req->content_length == 0; -} - - -static jint JNICALL -nxt_java_InputStream_readByte(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - uint8_t b; - ssize_t size; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - size = nxt_unit_request_read(req, &b, 1); - - return size == 1 ? b : -1; -} - - -static jint JNICALL -nxt_java_InputStream_read(JNIEnv *env, jclass cls, jlong req_info_ptr, - jarray b, jint off, jint len) -{ - uint8_t *data; - ssize_t res; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - data = (*env)->GetPrimitiveArrayCritical(env, b, NULL); - - res = nxt_unit_request_read(req, data + off, len); - - nxt_unit_req_debug(req, "read '%.*s'", (int) res, (char *) data + off); - - (*env)->ReleasePrimitiveArrayCritical(env, b, data, 0); - - return res > 0 ? res : -1; -} - - -static jlong JNICALL -nxt_java_InputStream_skip(JNIEnv *env, jclass cls, jlong req_info_ptr, jlong n) -{ - size_t rest, b_size; - nxt_unit_buf_t *buf; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - rest = n; - - buf = req->content_buf; - - while (buf != NULL) { - b_size = buf->end - buf->free; - b_size = rest < b_size ? rest : b_size; - - buf->free += b_size; - rest -= b_size; - - if (rest == 0) { - if (buf->end == buf->free) { - buf = nxt_unit_buf_next(buf); - } - - break; - } - - buf = nxt_unit_buf_next(buf); - } - - n = n < (jlong) req->content_length ? n : (jlong) req->content_length; - - req->content_length -= n; - - return n; -} - - -static jint JNICALL -nxt_java_InputStream_available(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - return req->content_length; -} diff --git a/src/java/nxt_jni_InputStream.h b/src/java/nxt_jni_InputStream.h deleted file mode 100644 index b20b262a..00000000 --- a/src/java/nxt_jni_InputStream.h +++ /dev/null @@ -1,15 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JAVA_INPUTSTREAM_H_INCLUDED_ -#define _NXT_JAVA_INPUTSTREAM_H_INCLUDED_ - - -#include - - -int nxt_java_initInputStream(JNIEnv *env, jobject cl); - -#endif /* _NXT_JAVA_INPUTSTREAM_H_INCLUDED_ */ diff --git a/src/java/nxt_jni_OutputStream.c b/src/java/nxt_jni_OutputStream.c deleted file mode 100644 index 170b33ba..00000000 --- a/src/java/nxt_jni_OutputStream.c +++ /dev/null @@ -1,236 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include - -#include "nxt_jni.h" -#include "nxt_jni_OutputStream.h" -#include "nxt_jni_URLClassLoader.h" - - -static void JNICALL nxt_java_OutputStream_writeByte(JNIEnv *env, jclass cls, - jlong req_info_ptr, jint b); -static nxt_unit_buf_t *nxt_java_OutputStream_req_buf(JNIEnv *env, - nxt_unit_request_info_t *req); -static void JNICALL nxt_java_OutputStream_write(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray b, jint off, jint len); -static void JNICALL nxt_java_OutputStream_flush(JNIEnv *env, jclass cls, - jlong req_info_ptr); -static void JNICALL nxt_java_OutputStream_close(JNIEnv *env, jclass cls, - jlong req_info_ptr); - - -static jclass nxt_java_OutputStream_class; - - -int -nxt_java_initOutputStream(JNIEnv *env, jobject cl) -{ - int res; - jclass cls; - - cls = nxt_java_loadClass(env, cl, "nginx.unit.OutputStream"); - if (cls == NULL) { - return NXT_UNIT_ERROR; - } - - nxt_java_OutputStream_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - - cls = nxt_java_OutputStream_class; - - JNINativeMethod os_methods[] = { - { (char *) "write", - (char *) "(JI)V", - nxt_java_OutputStream_writeByte }, - - { (char *) "write", - (char *) "(J[BII)V", - nxt_java_OutputStream_write }, - - { (char *) "flush", - (char *) "(J)V", - nxt_java_OutputStream_flush }, - - { (char *) "close", - (char *) "(J)V", - nxt_java_OutputStream_close }, - }; - - res = (*env)->RegisterNatives(env, nxt_java_OutputStream_class, - os_methods, - sizeof(os_methods) / sizeof(os_methods[0])); - - nxt_unit_debug(NULL, "registered OutputStream methods: %d", res); - - if (res != 0) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static void JNICALL -nxt_java_OutputStream_writeByte(JNIEnv *env, jclass cls, jlong req_info_ptr, - jint b) -{ - nxt_unit_buf_t *buf; - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - data = req->data; - - buf = nxt_java_OutputStream_req_buf(env, req); - if (buf == NULL) { - return; - } - - *buf->free++ = b; - - if ((uint32_t) (buf->free - buf->start) >= data->buf_size) { - nxt_java_OutputStream_flush_buf(env, req); - } -} - - -int -nxt_java_OutputStream_flush_buf(JNIEnv *env, nxt_unit_request_info_t *req) -{ - int rc; - nxt_java_request_data_t *data; - - data = req->data; - - if (!nxt_unit_response_is_init(req)) { - rc = nxt_unit_response_init(req, 200, 0, 0); - if (rc != NXT_UNIT_OK) { - nxt_java_throw_IOException(env, "Failed to allocate response"); - - return rc; - } - } - - if (!nxt_unit_response_is_sent(req)) { - rc = nxt_unit_response_send(req); - if (rc != NXT_UNIT_OK) { - nxt_java_throw_IOException(env, "Failed to send response headers"); - - return rc; - } - } - - if (data->buf != NULL) { - rc = nxt_unit_buf_send(data->buf); - if (rc != NXT_UNIT_OK) { - nxt_java_throw_IOException(env, "Failed to send buffer"); - - } else { - data->buf = NULL; - } - - } else { - rc = NXT_UNIT_OK; - } - - return rc; -} - - -static nxt_unit_buf_t * -nxt_java_OutputStream_req_buf(JNIEnv *env, nxt_unit_request_info_t *req) -{ - uint32_t size; - nxt_unit_buf_t *buf; - nxt_java_request_data_t *data; - - data = req->data; - buf = data->buf; - - if (buf == NULL || buf->free >= buf->end) { - size = data->buf_size == 0 ? nxt_unit_buf_min() : data->buf_size; - - buf = nxt_unit_response_buf_alloc(req, size); - if (buf == NULL) { - nxt_java_throw_IOException(env, "Failed to allocate buffer"); - - return NULL; - } - - data->buf = buf; - } - - return buf; -} - - -static void JNICALL -nxt_java_OutputStream_write(JNIEnv *env, jclass cls, jlong req_info_ptr, - jarray b, jint off, jint len) -{ - int rc; - jint copy; - uint8_t *ptr; - nxt_unit_buf_t *buf; - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - data = req->data; - - ptr = (*env)->GetPrimitiveArrayCritical(env, b, NULL); - - while (len > 0) { - buf = nxt_java_OutputStream_req_buf(env, req); - if (buf == NULL) { - return; - } - - copy = buf->end - buf->free; - copy = copy < len ? copy : len; - - memcpy(buf->free, ptr + off, copy); - buf->free += copy; - - len -= copy; - off += copy; - - if ((uint32_t) (buf->free - buf->start) >= data->buf_size) { - rc = nxt_java_OutputStream_flush_buf(env, req); - if (rc != NXT_UNIT_OK) { - break; - } - } - } - - (*env)->ReleasePrimitiveArrayCritical(env, b, ptr, 0); -} - - -static void JNICALL -nxt_java_OutputStream_flush(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - data = req->data; - - if (data->buf != NULL && data->buf->free > data->buf->start) { - nxt_java_OutputStream_flush_buf(env, req); - } -} - - -static void JNICALL -nxt_java_OutputStream_close(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_java_OutputStream_flush_buf(env, nxt_jlong2ptr(req_info_ptr)); -} diff --git a/src/java/nxt_jni_OutputStream.h b/src/java/nxt_jni_OutputStream.h deleted file mode 100644 index 0c3c9989..00000000 --- a/src/java/nxt_jni_OutputStream.h +++ /dev/null @@ -1,17 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JAVA_OUTPUTSTREAM_H_INCLUDED_ -#define _NXT_JAVA_OUTPUTSTREAM_H_INCLUDED_ - - -#include - - -int nxt_java_initOutputStream(JNIEnv *env, jobject cl); - -int nxt_java_OutputStream_flush_buf(JNIEnv *env, nxt_unit_request_info_t *req); - -#endif /* _NXT_JAVA_OUTPUTSTREAM_H_INCLUDED_ */ diff --git a/src/java/nxt_jni_Request.c b/src/java/nxt_jni_Request.c deleted file mode 100644 index 980a26b6..00000000 --- a/src/java/nxt_jni_Request.c +++ /dev/null @@ -1,823 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include -#include -#include -#include - -#include "nxt_jni.h" -#include "nxt_jni_Request.h" -#include "nxt_jni_URLClassLoader.h" -#include "nxt_jni_HeadersEnumeration.h" -#include "nxt_jni_HeaderNamesEnumeration.h" - - -static jstring JNICALL nxt_java_Request_getHeader(JNIEnv *env, jclass cls, - jlong req_ptr, jstring name, jint name_len); -static jobject JNICALL nxt_java_Request_getHeaderNames(JNIEnv *env, jclass cls, - jlong req_ptr); -static jobject JNICALL nxt_java_Request_getHeaders(JNIEnv *env, jclass cls, - jlong req_ptr, jstring name, jint name_len); -static jint JNICALL nxt_java_Request_getIntHeader(JNIEnv *env, jclass cls, - jlong req_ptr, jstring name, jint name_len); -static jstring JNICALL nxt_java_Request_getMethod(JNIEnv *env, jclass cls, - jlong req_ptr); -static jstring JNICALL nxt_java_Request_getQueryString(JNIEnv *env, jclass cls, - jlong req_ptr); -static jstring JNICALL nxt_java_Request_getRequestURI(JNIEnv *env, jclass cls, - jlong req_ptr); -static jlong JNICALL nxt_java_Request_getContentLength(JNIEnv *env, jclass cls, - jlong req_ptr); -static jstring JNICALL nxt_java_Request_getContentType(JNIEnv *env, jclass cls, - jlong req_ptr); -static jstring JNICALL nxt_java_Request_getLocalAddr(JNIEnv *env, jclass cls, - jlong req_ptr); -static jstring JNICALL nxt_java_Request_getLocalName(JNIEnv *env, jclass cls, - jlong req_ptr); -static jint JNICALL nxt_java_Request_getLocalPort(JNIEnv *env, jclass cls, - jlong req_ptr); -static jstring JNICALL nxt_java_Request_getProtocol(JNIEnv *env, jclass cls, - jlong req_ptr); -static jstring JNICALL nxt_java_Request_getRemoteAddr(JNIEnv *env, jclass cls, - jlong req_ptr); -static jstring JNICALL nxt_java_Request_getRemoteHost(JNIEnv *env, jclass cls, - jlong req_ptr); -static jint JNICALL nxt_java_Request_getRemotePort(JNIEnv *env, jclass cls, - jlong req_ptr); -static jstring JNICALL nxt_java_Request_getScheme(JNIEnv *env, jclass cls, - jlong req_ptr); -static jstring JNICALL nxt_java_Request_getServerName(JNIEnv *env, jclass cls, - jlong req_ptr); -static jint JNICALL nxt_java_Request_getServerPort(JNIEnv *env, jclass cls, - jlong req_ptr); -static jboolean JNICALL nxt_java_Request_isSecure(JNIEnv *env, jclass cls, - jlong req_ptr); -static void JNICALL nxt_java_Request_upgrade(JNIEnv *env, jclass cls, - jlong req_info_ptr); -static jboolean JNICALL nxt_java_Request_isUpgrade(JNIEnv *env, jclass cls, - jlong req_info_ptr); -static void JNICALL nxt_java_Request_log(JNIEnv *env, jclass cls, - jlong req_info_ptr, jstring msg, jint msg_len); -static void JNICALL nxt_java_Request_trace(JNIEnv *env, jclass cls, - jlong req_info_ptr, jstring msg, jint msg_len); -static jobject JNICALL nxt_java_Request_getResponse(JNIEnv *env, jclass cls, - jlong req_info_ptr); -static void JNICALL nxt_java_Request_sendWsFrameBuf(JNIEnv *env, jclass cls, - jlong req_info_ptr, jobject buf, jint pos, jint len, jbyte opCode, jboolean last); -static void JNICALL nxt_java_Request_sendWsFrameArr(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray arr, jint pos, jint len, jbyte opCode, jboolean last); -static void JNICALL nxt_java_Request_closeWs(JNIEnv *env, jclass cls, - jlong req_info_ptr); - - -static jclass nxt_java_Request_class; -static jmethodID nxt_java_Request_ctor; -static jmethodID nxt_java_Request_processWsFrame; -static jmethodID nxt_java_Request_closeWsSession; - - -int -nxt_java_initRequest(JNIEnv *env, jobject cl) -{ - int res; - jclass cls; - - cls = nxt_java_loadClass(env, cl, "nginx.unit.Request"); - if (cls == NULL) { - return NXT_UNIT_ERROR; - } - - nxt_java_Request_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - cls = nxt_java_Request_class; - - nxt_java_Request_ctor = (*env)->GetMethodID(env, cls, "", "(Lnginx/unit/Context;JJ)V"); - if (nxt_java_Request_ctor == NULL) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - nxt_java_Request_processWsFrame = (*env)->GetMethodID(env, cls, "processWsFrame", "(Ljava/nio/ByteBuffer;BZ)V"); - if (nxt_java_Request_processWsFrame == NULL) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - nxt_java_Request_closeWsSession = (*env)->GetMethodID(env, cls, "closeWsSession", "()V"); - if (nxt_java_Request_closeWsSession == NULL) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - JNINativeMethod request_methods[] = { - { (char *) "getHeader", - (char *) "(JLjava/lang/String;I)Ljava/lang/String;", - nxt_java_Request_getHeader }, - - { (char *) "getHeaderNames", - (char *) "(J)Ljava/util/Enumeration;", - nxt_java_Request_getHeaderNames }, - - { (char *) "getHeaders", - (char *) "(JLjava/lang/String;I)Ljava/util/Enumeration;", - nxt_java_Request_getHeaders }, - - { (char *) "getIntHeader", - (char *) "(JLjava/lang/String;I)I", - nxt_java_Request_getIntHeader }, - - { (char *) "getMethod", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getMethod }, - - { (char *) "getQueryString", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getQueryString }, - - { (char *) "getRequestURI", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getRequestURI }, - - { (char *) "getContentLength", - (char *) "(J)J", - nxt_java_Request_getContentLength }, - - { (char *) "getContentType", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getContentType }, - - { (char *) "getLocalAddr", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getLocalAddr }, - - { (char *) "getLocalName", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getLocalName }, - - { (char *) "getLocalPort", - (char *) "(J)I", - nxt_java_Request_getLocalPort }, - - { (char *) "getProtocol", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getProtocol }, - - { (char *) "getRemoteAddr", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getRemoteAddr }, - - { (char *) "getRemoteHost", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getRemoteHost }, - - { (char *) "getRemotePort", - (char *) "(J)I", - nxt_java_Request_getRemotePort }, - - { (char *) "getScheme", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getScheme }, - - { (char *) "getServerName", - (char *) "(J)Ljava/lang/String;", - nxt_java_Request_getServerName }, - - { (char *) "getServerPort", - (char *) "(J)I", - nxt_java_Request_getServerPort }, - - { (char *) "isSecure", - (char *) "(J)Z", - nxt_java_Request_isSecure }, - - { (char *) "upgrade", - (char *) "(J)V", - nxt_java_Request_upgrade }, - - { (char *) "isUpgrade", - (char *) "(J)Z", - nxt_java_Request_isUpgrade }, - - { (char *) "log", - (char *) "(JLjava/lang/String;I)V", - nxt_java_Request_log }, - - { (char *) "trace", - (char *) "(JLjava/lang/String;I)V", - nxt_java_Request_trace }, - - { (char *) "getResponse", - (char *) "(J)Lnginx/unit/Response;", - nxt_java_Request_getResponse }, - - { (char *) "sendWsFrame", - (char *) "(JLjava/nio/ByteBuffer;IIBZ)V", - nxt_java_Request_sendWsFrameBuf }, - - { (char *) "sendWsFrame", - (char *) "(J[BIIBZ)V", - nxt_java_Request_sendWsFrameArr }, - - { (char *) "closeWs", - (char *) "(J)V", - nxt_java_Request_closeWs }, - - }; - - res = (*env)->RegisterNatives(env, nxt_java_Request_class, - request_methods, - sizeof(request_methods) / sizeof(request_methods[0])); - - nxt_unit_debug(NULL, "registered Request methods: %d", res); - - if (res != 0) { - nxt_unit_warn(NULL, "registering natives for Request failed"); - goto failed; - } - - res = nxt_java_initHeadersEnumeration(env, cl); - if (res != NXT_UNIT_OK) { - goto failed; - } - - res = nxt_java_initHeaderNamesEnumeration(env, cl); - if (res != NXT_UNIT_OK) { - goto failed; - } - - return NXT_UNIT_OK; - -failed: - - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; -} - - -jobject -nxt_java_newRequest(JNIEnv *env, jobject ctx, nxt_unit_request_info_t *req) -{ - return (*env)->NewObject(env, nxt_java_Request_class, - nxt_java_Request_ctor, ctx, nxt_ptr2jlong(req), - nxt_ptr2jlong(req->request)); -} - - -static jstring JNICALL -nxt_java_Request_getHeader(JNIEnv *env, jclass cls, jlong req_ptr, - jstring name, jint name_len) -{ - const char *name_str; - nxt_unit_field_t *f; - nxt_unit_request_t *r; - - name_str = (*env)->GetStringUTFChars(env, name, NULL); - if (name_str == NULL) { - return NULL; - } - - r = nxt_jlong2ptr(req_ptr); - - f = nxt_java_findHeader(r->fields, r->fields + r->fields_count, - name_str, name_len); - - (*env)->ReleaseStringUTFChars(env, name, name_str); - - if (f == NULL) { - return NULL; - } - - return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&f->value)); -} - - -static jobject JNICALL -nxt_java_Request_getHeaderNames(JNIEnv *env, jclass cls, jlong req_ptr) -{ - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - return nxt_java_newHeaderNamesEnumeration(env, r->fields, r->fields_count); -} - - -static jobject JNICALL -nxt_java_Request_getHeaders(JNIEnv *env, jclass cls, jlong req_ptr, - jstring name, jint name_len) -{ - const char *name_str; - nxt_unit_field_t *f; - nxt_unit_request_t *r; - - name_str = (*env)->GetStringUTFChars(env, name, NULL); - if (name_str == NULL) { - return NULL; - } - - r = nxt_jlong2ptr(req_ptr); - - f = nxt_java_findHeader(r->fields, r->fields + r->fields_count, - name_str, name_len); - - (*env)->ReleaseStringUTFChars(env, name, name_str); - - if (f == NULL) { - f = r->fields + r->fields_count; - } - - return nxt_java_newHeadersEnumeration(env, r->fields, r->fields_count, - f - r->fields); -} - - -static jint JNICALL -nxt_java_Request_getIntHeader(JNIEnv *env, jclass cls, jlong req_ptr, - jstring name, jint name_len) -{ - jint res; - char *value, *end; - const char *name_str; - nxt_unit_field_t *f; - nxt_unit_request_t *r; - - res = -1; - - name_str = (*env)->GetStringUTFChars(env, name, NULL); - if (name_str == NULL) { - return res; - } - - r = nxt_jlong2ptr(req_ptr); - - f = nxt_java_findHeader(r->fields, r->fields + r->fields_count, - name_str, name_len); - - (*env)->ReleaseStringUTFChars(env, name, name_str); - - if (f == NULL) { - return res; - } - - value = nxt_unit_sptr_get(&f->value); - end = value + f->value_length; - - res = strtol(value, &end, 10); - - if (end < value + f->value_length) { - // TODO throw NumberFormatException.forInputString(value) - } - - return res; -} - - -static jstring JNICALL -nxt_java_Request_getMethod(JNIEnv *env, jclass cls, jlong req_ptr) -{ - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&r->method)); -} - - -static jstring JNICALL -nxt_java_Request_getQueryString(JNIEnv *env, jclass cls, jlong req_ptr) -{ - char *query; - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - if (r->query.offset != 0) { - query = nxt_unit_sptr_get(&r->query); - return (*env)->NewStringUTF(env, query); - } - - return NULL; -} - - -static jstring JNICALL -nxt_java_Request_getRequestURI(JNIEnv *env, jclass cls, jlong req_ptr) -{ - char *target, *query; - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - target = nxt_unit_sptr_get(&r->target); - - if (r->query.offset != 0) { - query = nxt_unit_sptr_get(&r->query); - return nxt_java_newString(env, target, query - target - 1); - } - - return (*env)->NewStringUTF(env, target); -} - - -static jlong JNICALL -nxt_java_Request_getContentLength(JNIEnv *env, jclass cls, jlong req_ptr) -{ - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - return r->content_length; -} - - -static jstring JNICALL -nxt_java_Request_getContentType(JNIEnv *env, jclass cls, jlong req_ptr) -{ - nxt_unit_field_t *f; - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - if (r->content_type_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->content_type_field; - - return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&f->value)); - } - - return NULL; -} - - -static jstring JNICALL -nxt_java_Request_getLocalAddr(JNIEnv *env, jclass cls, jlong req_ptr) -{ - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - return nxt_java_newString(env, nxt_unit_sptr_get(&r->local_addr), - r->local_addr_length); -} - - -static jstring JNICALL -nxt_java_Request_getLocalName(JNIEnv *env, jclass cls, jlong req_ptr) -{ - char *local, *colon; - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - local = nxt_unit_sptr_get(&r->local_addr); - colon = memchr(local, ':', r->local_addr_length); - - if (colon == NULL) { - colon = local + r->local_addr_length; - } - - return nxt_java_newString(env, local, colon - local); -} - - -static jint JNICALL -nxt_java_Request_getLocalPort(JNIEnv *env, jclass cls, jlong req_ptr) -{ - jint res; - char *local, *colon, tmp; - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - local = nxt_unit_sptr_get(&r->local_addr); - colon = memchr(local, ':', r->local_addr_length); - - if (colon == NULL) { - return 80; - } - - tmp = local[r->local_addr_length]; - - local[r->local_addr_length] = '\0'; - - res = strtol(colon + 1, NULL, 10); - - local[r->local_addr_length] = tmp; - - return res; -} - - -static jstring JNICALL -nxt_java_Request_getProtocol(JNIEnv *env, jclass cls, jlong req_ptr) -{ - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&r->version)); -} - - -static jstring JNICALL -nxt_java_Request_getRemoteAddr(JNIEnv *env, jclass cls, jlong req_ptr) -{ - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - return nxt_java_newString(env, nxt_unit_sptr_get(&r->remote), - r->remote_length); -} - - -static jstring JNICALL -nxt_java_Request_getRemoteHost(JNIEnv *env, jclass cls, jlong req_ptr) -{ - char *remote, *colon; - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - remote = nxt_unit_sptr_get(&r->remote); - colon = memchr(remote, ':', r->remote_length); - - if (colon == NULL) { - colon = remote + r->remote_length; - } - - return nxt_java_newString(env, remote, colon - remote); -} - - -static jint JNICALL -nxt_java_Request_getRemotePort(JNIEnv *env, jclass cls, jlong req_ptr) -{ - jint res; - char *remote, *colon, tmp; - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - remote = nxt_unit_sptr_get(&r->remote); - colon = memchr(remote, ':', r->remote_length); - - if (colon == NULL) { - return 80; - } - - tmp = remote[r->remote_length]; - - remote[r->remote_length] = '\0'; - - res = strtol(colon + 1, NULL, 10); - - remote[r->remote_length] = tmp; - - return res; -} - - -static jstring JNICALL -nxt_java_Request_getScheme(JNIEnv *env, jclass cls, jlong req_ptr) -{ - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - return (*env)->NewStringUTF(env, r->tls ? "https" : "http"); -} - - -static jstring JNICALL -nxt_java_Request_getServerName(JNIEnv *env, jclass cls, jlong req_ptr) -{ - char *host, *colon; - nxt_unit_field_t *f; - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - f = nxt_java_findHeader(r->fields, r->fields + r->fields_count, - "Host", 4); - if (f != NULL) { - host = nxt_unit_sptr_get(&f->value); - - colon = memchr(host, ':', f->value_length); - - if (colon == NULL) { - colon = host + f->value_length; - } - - return nxt_java_newString(env, host, colon - host); - } - - return nxt_java_Request_getLocalName(env, cls, req_ptr); -} - - -static jint JNICALL -nxt_java_Request_getServerPort(JNIEnv *env, jclass cls, jlong req_ptr) -{ - jint res; - char *host, *colon, tmp; - nxt_unit_field_t *f; - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - f = nxt_java_findHeader(r->fields, r->fields + r->fields_count, - "Host", 4); - if (f != NULL) { - host = nxt_unit_sptr_get(&f->value); - - colon = memchr(host, ':', f->value_length); - - if (colon == NULL) { - return 80; - } - - tmp = host[f->value_length]; - - host[f->value_length] = '\0'; - - res = strtol(colon + 1, NULL, 10); - - host[f->value_length] = tmp; - - return res; - } - - return nxt_java_Request_getLocalPort(env, cls, req_ptr); -} - - -static jboolean JNICALL -nxt_java_Request_isSecure(JNIEnv *env, jclass cls, jlong req_ptr) -{ - nxt_unit_request_t *r; - - r = nxt_jlong2ptr(req_ptr); - - return r->tls != 0; -} - - -static void JNICALL -nxt_java_Request_upgrade(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - if (!nxt_unit_response_is_init(req)) { - nxt_unit_response_init(req, 101, 0, 0); - } - - (void) nxt_unit_response_upgrade(req); -} - - -static jboolean JNICALL -nxt_java_Request_isUpgrade(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - return nxt_unit_request_is_websocket_handshake(req); -} - - -static void JNICALL -nxt_java_Request_log(JNIEnv *env, jclass cls, jlong req_info_ptr, jstring msg, - jint msg_len) -{ - const char *msg_str; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - msg_str = (*env)->GetStringUTFChars(env, msg, NULL); - if (msg_str == NULL) { - return; - } - - nxt_unit_req_log(req, NXT_UNIT_LOG_INFO, "%.*s", msg_len, msg_str); - - (*env)->ReleaseStringUTFChars(env, msg, msg_str); -} - - -static void JNICALL -nxt_java_Request_trace(JNIEnv *env, jclass cls, jlong req_info_ptr, jstring msg, - jint msg_len) -{ -#if (NXT_DEBUG) - const char *msg_str; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - msg_str = (*env)->GetStringUTFChars(env, msg, NULL); - if (msg_str == NULL) { - return; - } - - nxt_unit_req_debug(req, "%.*s", msg_len, msg_str); - - (*env)->ReleaseStringUTFChars(env, msg, msg_str); -#endif -} - - -static jobject JNICALL -nxt_java_Request_getResponse(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - data = req->data; - - return data->jresp; -} - - -static void JNICALL -nxt_java_Request_sendWsFrameBuf(JNIEnv *env, jclass cls, - jlong req_info_ptr, jobject buf, jint pos, jint len, jbyte opCode, jboolean last) -{ - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - uint8_t *b = (*env)->GetDirectBufferAddress(env, buf); - - if (b != NULL) { - nxt_unit_websocket_send(req, opCode, last, b + pos, len); - - } else { - nxt_unit_req_debug(req, "sendWsFrameBuf: b == NULL"); - } -} - - -static void JNICALL -nxt_java_Request_sendWsFrameArr(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray arr, jint pos, jint len, jbyte opCode, jboolean last) -{ - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - uint8_t *b = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); - - if (b != NULL) { - if (!nxt_unit_response_is_sent(req)) { - nxt_unit_response_send(req); - } - - nxt_unit_websocket_send(req, opCode, last, b + pos, len); - - (*env)->ReleasePrimitiveArrayCritical(env, arr, b, 0); - - } else { - nxt_unit_req_debug(req, "sendWsFrameArr: b == NULL"); - } -} - - -static void JNICALL -nxt_java_Request_closeWs(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - - data = req->data; - - (*env)->DeleteGlobalRef(env, data->jresp); - (*env)->DeleteGlobalRef(env, data->jreq); - - nxt_unit_request_done(req, NXT_UNIT_OK); -} - - -void -nxt_java_Request_websocket(JNIEnv *env, jobject jreq, jobject jbuf, - uint8_t opcode, uint8_t fin) -{ - (*env)->CallVoidMethod(env, jreq, nxt_java_Request_processWsFrame, jbuf, opcode, fin); -} - - -void -nxt_java_Request_close(JNIEnv *env, jobject jreq) -{ - (*env)->CallVoidMethod(env, jreq, nxt_java_Request_closeWsSession); -} diff --git a/src/java/nxt_jni_Request.h b/src/java/nxt_jni_Request.h deleted file mode 100644 index 9187d878..00000000 --- a/src/java/nxt_jni_Request.h +++ /dev/null @@ -1,23 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JAVA_REQUEST_H_INCLUDED_ -#define _NXT_JAVA_REQUEST_H_INCLUDED_ - - -#include -#include - - -int nxt_java_initRequest(JNIEnv *env, jobject cl); - -jobject nxt_java_newRequest(JNIEnv *env, jobject ctx, nxt_unit_request_info_t *req); - -void nxt_java_Request_websocket(JNIEnv *env, jobject jreq, jobject jbuf, - uint8_t opcode, uint8_t fin); - -void nxt_java_Request_close(JNIEnv *env, jobject jreq); - -#endif /* _NXT_JAVA_REQUEST_H_INCLUDED_ */ diff --git a/src/java/nxt_jni_Response.c b/src/java/nxt_jni_Response.c deleted file mode 100644 index fa698ee8..00000000 --- a/src/java/nxt_jni_Response.c +++ /dev/null @@ -1,1106 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include -#include -#include - -#include "nxt_jni.h" -#include "nxt_jni_Response.h" -#include "nxt_jni_HeadersEnumeration.h" -#include "nxt_jni_HeaderNamesEnumeration.h" -#include "nxt_jni_OutputStream.h" -#include "nxt_jni_URLClassLoader.h" - - -static jclass nxt_java_Response_class; -static jmethodID nxt_java_Response_ctor; - - -static void JNICALL nxt_java_Response_addHeader(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name, jarray value); - -static nxt_unit_request_info_t *nxt_java_get_response_info( - jlong req_info_ptr, uint32_t extra_fields, uint32_t extra_data); - -static void JNICALL nxt_java_Response_addIntHeader(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name, jint value); - -static void nxt_java_add_int_header(nxt_unit_request_info_t *req, - const char *name, uint8_t name_len, int value); - -static jboolean JNICALL nxt_java_Response_containsHeader(JNIEnv *env, - jclass cls, jlong req_info_ptr, jarray name); - -static jstring JNICALL nxt_java_Response_getHeader(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name); - -static jobject JNICALL nxt_java_Response_getHeaderNames(JNIEnv *env, - jclass cls, jlong req_info_ptr); - -static jobject JNICALL nxt_java_Response_getHeaders(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name); - -static jint JNICALL nxt_java_Response_getStatus(JNIEnv *env, jclass cls, - jlong req_info_ptr); - -static jobject JNICALL nxt_java_Response_getRequest(JNIEnv *env, jclass cls, - jlong req_info_ptr); - -static void JNICALL nxt_java_Response_commit(JNIEnv *env, jclass cls, - jlong req_info_ptr); - -static void JNICALL nxt_java_Response_sendRedirect(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray loc); - -static int nxt_java_response_set_header(jlong req_info_ptr, - const char *name, jint name_len, const char *value, jint value_len); - -static void JNICALL nxt_java_Response_setHeader(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name, jarray value); - -static void JNICALL nxt_java_Response_removeHeader(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name); - -static int nxt_java_response_remove_header(jlong req_info_ptr, - const char *name, jint name_len); - -static void JNICALL nxt_java_Response_setIntHeader(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name, jint value); - -static void JNICALL nxt_java_Response_setStatus(JNIEnv *env, jclass cls, - jlong req_info_ptr, jint sc); - -static jstring JNICALL nxt_java_Response_getContentType(JNIEnv *env, - jclass cls, jlong req_info_ptr); - -static jboolean JNICALL nxt_java_Response_isCommitted(JNIEnv *env, jclass cls, - jlong req_info_ptr); - -static void JNICALL nxt_java_Response_reset(JNIEnv *env, jclass cls, - jlong req_info_ptr); - -static void JNICALL nxt_java_Response_resetBuffer(JNIEnv *env, jclass cls, - jlong req_info_ptr); - -static void JNICALL nxt_java_Response_setBufferSize(JNIEnv *env, jclass cls, - jlong req_info_ptr, jint size); - -static jint JNICALL nxt_java_Response_getBufferSize(JNIEnv *env, jclass cls, - jlong req_info_ptr); - -static void JNICALL nxt_java_Response_setContentLength(JNIEnv *env, jclass cls, - jlong req_info_ptr, jlong len); - -static void JNICALL nxt_java_Response_setContentType(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray type); - -static void JNICALL nxt_java_Response_removeContentType(JNIEnv *env, jclass cls, - jlong req_info_ptr); - -static void JNICALL nxt_java_Response_log(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray msg); - -static void JNICALL nxt_java_Response_trace(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray msg); - -int -nxt_java_initResponse(JNIEnv *env, jobject cl) -{ - int res; - jclass cls; - - cls = nxt_java_loadClass(env, cl, "nginx.unit.Response"); - if (cls == NULL) { - return NXT_UNIT_ERROR; - } - - nxt_java_Response_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - cls = nxt_java_Response_class; - - nxt_java_Response_ctor = (*env)->GetMethodID(env, cls, "", "(J)V"); - if (nxt_java_Response_ctor == NULL) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - JNINativeMethod resp_methods[] = { - { (char *) "addHeader", - (char *) "(J[B[B)V", - nxt_java_Response_addHeader }, - - { (char *) "addIntHeader", - (char *) "(J[BI)V", - nxt_java_Response_addIntHeader }, - - { (char *) "containsHeader", - (char *) "(J[B)Z", - nxt_java_Response_containsHeader }, - - { (char *) "getHeader", - (char *) "(J[B)Ljava/lang/String;", - nxt_java_Response_getHeader }, - - { (char *) "getHeaderNames", - (char *) "(J)Ljava/util/Enumeration;", - nxt_java_Response_getHeaderNames }, - - { (char *) "getHeaders", - (char *) "(J[B)Ljava/util/Enumeration;", - nxt_java_Response_getHeaders }, - - { (char *) "getStatus", - (char *) "(J)I", - nxt_java_Response_getStatus }, - - { (char *) "getRequest", - (char *) "(J)Lnginx/unit/Request;", - nxt_java_Response_getRequest }, - - { (char *) "commit", - (char *) "(J)V", - nxt_java_Response_commit }, - - { (char *) "sendRedirect", - (char *) "(J[B)V", - nxt_java_Response_sendRedirect }, - - { (char *) "setHeader", - (char *) "(J[B[B)V", - nxt_java_Response_setHeader }, - - { (char *) "removeHeader", - (char *) "(J[B)V", - nxt_java_Response_removeHeader }, - - { (char *) "setIntHeader", - (char *) "(J[BI)V", - nxt_java_Response_setIntHeader }, - - { (char *) "setStatus", - (char *) "(JI)V", - nxt_java_Response_setStatus }, - - { (char *) "getContentType", - (char *) "(J)Ljava/lang/String;", - nxt_java_Response_getContentType }, - - { (char *) "isCommitted", - (char *) "(J)Z", - nxt_java_Response_isCommitted }, - - { (char *) "reset", - (char *) "(J)V", - nxt_java_Response_reset }, - - { (char *) "resetBuffer", - (char *) "(J)V", - nxt_java_Response_resetBuffer }, - - { (char *) "setBufferSize", - (char *) "(JI)V", - nxt_java_Response_setBufferSize }, - - { (char *) "getBufferSize", - (char *) "(J)I", - nxt_java_Response_getBufferSize }, - - { (char *) "setContentLength", - (char *) "(JJ)V", - nxt_java_Response_setContentLength }, - - { (char *) "setContentType", - (char *) "(J[B)V", - nxt_java_Response_setContentType }, - - { (char *) "removeContentType", - (char *) "(J)V", - nxt_java_Response_removeContentType }, - - { (char *) "log", - (char *) "(J[B)V", - nxt_java_Response_log }, - - { (char *) "trace", - (char *) "(J[B)V", - nxt_java_Response_trace }, - - }; - - res = (*env)->RegisterNatives(env, nxt_java_Response_class, - resp_methods, - sizeof(resp_methods) - / sizeof(resp_methods[0])); - - nxt_unit_debug(NULL, "registered Response methods: %d", res); - - if (res != 0) { - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -jobject -nxt_java_newResponse(JNIEnv *env, nxt_unit_request_info_t *req) -{ - return (*env)->NewObject(env, nxt_java_Response_class, - nxt_java_Response_ctor, nxt_ptr2jlong(req)); -} - - -static void JNICALL -nxt_java_Response_addHeader(JNIEnv *env, jclass cls, jlong req_info_ptr, - jarray name, jarray value) -{ - int rc; - char *name_str, *value_str; - jsize name_len, value_len; - nxt_unit_request_info_t *req; - - name_len = (*env)->GetArrayLength(env, name); - value_len = (*env)->GetArrayLength(env, value); - - req = nxt_java_get_response_info(req_info_ptr, 1, name_len + value_len + 2); - if (req == NULL) { - return; - } - - name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL); - if (name_str == NULL) { - nxt_unit_req_warn(req, "addHeader: failed to get name content"); - return; - } - - value_str = (*env)->GetPrimitiveArrayCritical(env, value, NULL); - if (value_str == NULL) { - (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0); - nxt_unit_req_warn(req, "addHeader: failed to get value content"); - - return; - } - - rc = nxt_unit_response_add_field(req, name_str, name_len, - value_str, value_len); - if (rc != NXT_UNIT_OK) { - // throw - } - - (*env)->ReleasePrimitiveArrayCritical(env, value, value_str, 0); - (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0); -} - - -static nxt_unit_request_info_t * -nxt_java_get_response_info(jlong req_info_ptr, uint32_t extra_fields, - uint32_t extra_data) -{ - int rc; - char *p; - uint32_t max_size; - nxt_unit_buf_t *buf; - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - - if (nxt_unit_response_is_sent(req)) { - return NULL; - } - - data = req->data; - - if (!nxt_unit_response_is_init(req)) { - max_size = nxt_unit_buf_max(); - max_size = max_size < data->header_size ? max_size : data->header_size; - - rc = nxt_unit_response_init(req, 200, 16, max_size); - if (rc != NXT_UNIT_OK) { - return NULL; - } - } - - buf = req->response_buf; - - if (extra_fields > req->response_max_fields - - req->response->fields_count - || extra_data > (uint32_t) (buf->end - buf->free)) - { - p = buf->start + sizeof(nxt_unit_response_t) - + req->response_max_fields * sizeof(nxt_unit_field_t); - - max_size = 2 * (buf->end - p); - if (max_size > nxt_unit_buf_max()) { - nxt_unit_req_warn(req, "required max_size is too big: %"PRIu32, - max_size); - return NULL; - } - - rc = nxt_unit_response_realloc(req, 2 * req->response_max_fields, - max_size); - if (rc != NXT_UNIT_OK) { - nxt_unit_req_warn(req, "reallocation failed: %"PRIu32", %"PRIu32, - 2 * req->response_max_fields, max_size); - return NULL; - } - } - - return req; -} - - -static void JNICALL -nxt_java_Response_addIntHeader(JNIEnv *env, jclass cls, jlong req_info_ptr, - jarray name, jint value) -{ - char *name_str; - jsize name_len; - nxt_unit_request_info_t *req; - - name_len = (*env)->GetArrayLength(env, name); - - req = nxt_java_get_response_info(req_info_ptr, 1, name_len + 40); - if (req == NULL) { - return; - } - - name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL); - if (name_str == NULL) { - nxt_unit_req_warn(req, "addIntHeader: failed to get name content"); - return; - } - - nxt_java_add_int_header(req, name_str, name_len, value); - - (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0); -} - - -static void -nxt_java_add_int_header(nxt_unit_request_info_t *req, const char *name, - uint8_t name_len, int value) -{ - char *p; - nxt_unit_field_t *f; - nxt_unit_response_t *resp; - - resp = req->response; - - f = resp->fields + resp->fields_count; - p = req->response_buf->free; - - f->hash = nxt_unit_field_hash(name, name_len); - f->skip = 0; - f->name_length = name_len; - - nxt_unit_sptr_set(&f->name, p); - memcpy(p, name, name_len); - p += name_len; - - nxt_unit_sptr_set(&f->value, p); - f->value_length = snprintf(p, 40, "%d", (int) value); - p += f->value_length + 1; - - resp->fields_count++; - req->response_buf->free = p; - -} - - -static jboolean JNICALL -nxt_java_Response_containsHeader(JNIEnv *env, - jclass cls, jlong req_info_ptr, jarray name) -{ - jboolean res; - char *name_str; - jsize name_len; - nxt_unit_response_t *resp; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - if (!nxt_unit_response_is_init(req)) { - nxt_unit_req_debug(req, "containsHeader: response is not initialized"); - return 0; - } - - if (nxt_unit_response_is_sent(req)) { - nxt_unit_req_debug(req, "containsHeader: response already sent"); - return 0; - } - - name_len = (*env)->GetArrayLength(env, name); - - name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL); - if (name_str == NULL) { - nxt_unit_req_warn(req, "containsHeader: failed to get name content"); - return 0; - } - - resp = req->response; - - res = nxt_java_findHeader(resp->fields, - resp->fields + resp->fields_count, - name_str, name_len) != NULL; - - (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0); - - return res; -} - - -static jstring JNICALL -nxt_java_Response_getHeader(JNIEnv *env, jclass cls, jlong req_info_ptr, - jarray name) -{ - char *name_str; - jsize name_len; - nxt_unit_field_t *f; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - if (!nxt_unit_response_is_init(req)) { - nxt_unit_req_debug(req, "getHeader: response is not initialized"); - return NULL; - } - - if (nxt_unit_response_is_sent(req)) { - nxt_unit_req_debug(req, "getHeader: response already sent"); - return NULL; - } - - name_len = (*env)->GetArrayLength(env, name); - - name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL); - if (name_str == NULL) { - nxt_unit_req_warn(req, "getHeader: failed to get name content"); - return NULL; - } - - f = nxt_java_findHeader(req->response->fields, - req->response->fields + req->response->fields_count, - name_str, name_len); - - (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0); - - if (f == NULL) { - return NULL; - } - - return nxt_java_newString(env, nxt_unit_sptr_get(&f->value), - f->value_length); -} - - -static jobject JNICALL -nxt_java_Response_getHeaderNames(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - if (!nxt_unit_response_is_init(req)) { - nxt_unit_req_debug(req, "getHeaderNames: response is not initialized"); - return NULL; - } - - if (nxt_unit_response_is_sent(req)) { - nxt_unit_req_debug(req, "getHeaderNames: response already sent"); - return NULL; - } - - return nxt_java_newHeaderNamesEnumeration(env, req->response->fields, - req->response->fields_count); -} - - -static jobject JNICALL -nxt_java_Response_getHeaders(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name) -{ - char *name_str; - jsize name_len; - nxt_unit_field_t *f; - nxt_unit_response_t *resp; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - if (!nxt_unit_response_is_init(req)) { - nxt_unit_req_debug(req, "getHeaders: response is not initialized"); - return NULL; - } - - if (nxt_unit_response_is_sent(req)) { - nxt_unit_req_debug(req, "getHeaders: response already sent"); - return NULL; - } - - resp = req->response; - - name_len = (*env)->GetArrayLength(env, name); - - name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL); - if (name_str == NULL) { - nxt_unit_req_warn(req, "getHeaders: failed to get name content"); - return NULL; - } - - f = nxt_java_findHeader(resp->fields, resp->fields + resp->fields_count, - name_str, name_len); - - (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0); - - if (f == NULL) { - f = resp->fields + resp->fields_count; - } - - return nxt_java_newHeadersEnumeration(env, resp->fields, resp->fields_count, - f - resp->fields); -} - - -static jint JNICALL -nxt_java_Response_getStatus(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - if (!nxt_unit_response_is_init(req)) { - nxt_unit_req_debug(req, "getStatus: response is not initialized"); - return 200; - } - - if (nxt_unit_response_is_sent(req)) { - nxt_unit_req_debug(req, "getStatus: response already sent"); - return 200; - } - - return req->response->status; -} - - -static jobject JNICALL -nxt_java_Response_getRequest(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - data = req->data; - - return data->jreq; -} - - -static void JNICALL -nxt_java_Response_commit(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - nxt_java_OutputStream_flush_buf(env, req); -} - - -static void JNICALL -nxt_java_Response_sendRedirect(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray loc) -{ - int rc; - char *loc_str; - jsize loc_len; - nxt_unit_request_info_t *req; - - static const char location[] = "Location"; - static const uint32_t location_len = sizeof(location) - 1; - - req = nxt_jlong2ptr(req_info_ptr); - - if (nxt_unit_response_is_sent(req)) { - nxt_java_throw_IllegalStateException(env, "Response already sent"); - - return; - } - - loc_len = (*env)->GetArrayLength(env, loc); - - req = nxt_java_get_response_info(req_info_ptr, 1, - location_len + loc_len + 2); - if (req == NULL) { - return; - } - - loc_str = (*env)->GetPrimitiveArrayCritical(env, loc, NULL); - if (loc_str == NULL) { - nxt_unit_req_warn(req, "sendRedirect: failed to get loc content"); - return; - } - - req->response->status = 302; - - rc = nxt_java_response_set_header(req_info_ptr, location, location_len, - loc_str, loc_len); - if (rc != NXT_UNIT_OK) { - // throw - } - - (*env)->ReleasePrimitiveArrayCritical(env, loc, loc_str, 0); - - nxt_unit_response_send(req); -} - - -static int -nxt_java_response_set_header(jlong req_info_ptr, - const char *name, jint name_len, const char *value, jint value_len) -{ - int add_field; - char *dst; - nxt_unit_field_t *f, *e; - nxt_unit_response_t *resp; - nxt_unit_request_info_t *req; - - req = nxt_java_get_response_info(req_info_ptr, 0, 0); - if (req == NULL) { - return NXT_UNIT_ERROR; - } - - resp = req->response; - - f = resp->fields; - e = f + resp->fields_count; - - add_field = 1; - - for ( ;; ) { - f = nxt_java_findHeader(f, e, name, name_len); - if (f == NULL) { - break; - } - - if (add_field && f->value_length >= (uint32_t) value_len) { - dst = nxt_unit_sptr_get(&f->value); - memcpy(dst, value, value_len); - dst[value_len] = '\0'; - f->value_length = value_len; - - add_field = 0; - f->skip = 0; - - } else { - f->skip = 1; - } - - ++f; - } - - if (!add_field) { - return NXT_UNIT_OK; - } - - req = nxt_java_get_response_info(req_info_ptr, 1, name_len + value_len + 2); - if (req == NULL) { - return NXT_UNIT_ERROR; - } - - return nxt_unit_response_add_field(req, name, name_len, value, value_len); -} - - -static void JNICALL -nxt_java_Response_setHeader(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name, jarray value) -{ - int rc; - char *name_str, *value_str; - jsize name_len, value_len; - nxt_unit_request_info_t *req; - - name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL); - if (name_str == NULL) { - req = nxt_jlong2ptr(req_info_ptr); - nxt_unit_req_warn(req, "setHeader: failed to get name content"); - return; - } - - value_str = (*env)->GetPrimitiveArrayCritical(env, value, NULL); - if (value_str == NULL) { - (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0); - - req = nxt_jlong2ptr(req_info_ptr); - nxt_unit_req_warn(req, "setHeader: failed to get value content"); - - return; - } - - name_len = (*env)->GetArrayLength(env, name); - value_len = (*env)->GetArrayLength(env, value); - - rc = nxt_java_response_set_header(req_info_ptr, name_str, name_len, - value_str, value_len); - if (rc != NXT_UNIT_OK) { - // throw - } - - (*env)->ReleasePrimitiveArrayCritical(env, value, value_str, 0); - (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0); -} - - -static void JNICALL -nxt_java_Response_removeHeader(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name) -{ - int rc; - char *name_str; - jsize name_len; - nxt_unit_request_info_t *req; - - name_len = (*env)->GetArrayLength(env, name); - - name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL); - if (name_str == NULL) { - req = nxt_jlong2ptr(req_info_ptr); - nxt_unit_req_warn(req, "setHeader: failed to get name content"); - return; - } - - rc = nxt_java_response_remove_header(req_info_ptr, name_str, name_len); - if (rc != NXT_UNIT_OK) { - // throw - } - - (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0); -} - - -static int -nxt_java_response_remove_header(jlong req_info_ptr, - const char *name, jint name_len) -{ - nxt_unit_field_t *f, *e; - nxt_unit_response_t *resp; - nxt_unit_request_info_t *req; - - req = nxt_java_get_response_info(req_info_ptr, 0, 0); - if (req == NULL) { - return NXT_UNIT_ERROR; - } - - resp = req->response; - - f = resp->fields; - e = f + resp->fields_count; - - for ( ;; ) { - f = nxt_java_findHeader(f, e, name, name_len); - if (f == NULL) { - break; - } - - f->skip = 1; - - ++f; - } - - return NXT_UNIT_OK; -} - - -static void JNICALL -nxt_java_Response_setIntHeader(JNIEnv *env, jclass cls, - jlong req_info_ptr, jarray name, jint value) -{ - int value_len, rc; - char value_str[40]; - char *name_str; - jsize name_len; - - value_len = snprintf(value_str, sizeof(value_str), "%d", (int) value); - - name_len = (*env)->GetArrayLength(env, name); - - name_str = (*env)->GetPrimitiveArrayCritical(env, name, NULL); - if (name_str == NULL) { - nxt_unit_req_warn(nxt_jlong2ptr(req_info_ptr), - "setIntHeader: failed to get name content"); - return; - } - - rc = nxt_java_response_set_header(req_info_ptr, name_str, name_len, - value_str, value_len); - if (rc != NXT_UNIT_OK) { - // throw - } - - (*env)->ReleasePrimitiveArrayCritical(env, name, name_str, 0); -} - - -static void JNICALL -nxt_java_Response_setStatus(JNIEnv *env, jclass cls, jlong req_info_ptr, - jint sc) -{ - nxt_unit_request_info_t *req; - - req = nxt_java_get_response_info(req_info_ptr, 0, 0); - if (req == NULL) { - return; - } - - req->response->status = sc; -} - - -static jstring JNICALL -nxt_java_Response_getContentType(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_field_t *f; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - if (!nxt_unit_response_is_init(req)) { - nxt_unit_req_debug(req, "getContentType: response is not initialized"); - return NULL; - } - - if (nxt_unit_response_is_sent(req)) { - nxt_unit_req_debug(req, "getContentType: response already sent"); - return NULL; - } - - f = nxt_java_findHeader(req->response->fields, - req->response->fields + req->response->fields_count, - "Content-Type", sizeof("Content-Type") - 1); - - if (f == NULL) { - return NULL; - } - - return nxt_java_newString(env, nxt_unit_sptr_get(&f->value), - f->value_length); -} - - -static jboolean JNICALL -nxt_java_Response_isCommitted(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - - if (nxt_unit_response_is_sent(req)) { - return 1; - } - - return 0; -} - - -static void JNICALL -nxt_java_Response_reset(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_buf_t *buf; - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - - if (nxt_unit_response_is_sent(req)) { - nxt_java_throw_IllegalStateException(env, "Response already sent"); - - return; - } - - data = req->data; - - if (data->buf != NULL && data->buf->free > data->buf->start) { - data->buf->free = data->buf->start; - } - - if (nxt_unit_response_is_init(req)) { - req->response->status = 200; - req->response->fields_count = 0; - - buf = req->response_buf; - - buf->free = buf->start + sizeof(nxt_unit_response_t) - + req->response_max_fields * sizeof(nxt_unit_field_t); - } -} - - -static void JNICALL -nxt_java_Response_resetBuffer(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - data = req->data; - - if (data->buf != NULL && data->buf->free > data->buf->start) { - data->buf->free = data->buf->start; - } -} - - -static void JNICALL -nxt_java_Response_setBufferSize(JNIEnv *env, jclass cls, jlong req_info_ptr, - jint size) -{ - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - data = req->data; - - if (data->buf_size == (uint32_t) size) { - return; - } - - if (data->buf != NULL && data->buf->free > data->buf->start) { - nxt_java_throw_IllegalStateException(env, "Buffer is not empty"); - - return; - } - - data->buf_size = size; - - if (data->buf_size > nxt_unit_buf_max()) { - data->buf_size = nxt_unit_buf_max(); - } - - if (data->buf != NULL - && (uint32_t) (data->buf->end - data->buf->start) < data->buf_size) - { - nxt_unit_buf_free(data->buf); - - data->buf = NULL; - } -} - - -static jint JNICALL -nxt_java_Response_getBufferSize(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_unit_request_info_t *req; - nxt_java_request_data_t *data; - - req = nxt_jlong2ptr(req_info_ptr); - data = req->data; - - return data->buf_size; -} - - -static void JNICALL -nxt_java_Response_setContentLength(JNIEnv *env, jclass cls, jlong req_info_ptr, - jlong len) -{ - nxt_unit_request_info_t *req; - - req = nxt_java_get_response_info(req_info_ptr, 0, 0); - if (req == NULL) { - return; - } - - req->response->content_length = len; -} - - -static void JNICALL -nxt_java_Response_setContentType(JNIEnv *env, jclass cls, jlong req_info_ptr, - jarray type) -{ - int rc; - char *type_str; - jsize type_len; - - static const char content_type[] = "Content-Type"; - static const uint32_t content_type_len = sizeof(content_type) - 1; - - type_len = (*env)->GetArrayLength(env, type); - - type_str = (*env)->GetPrimitiveArrayCritical(env, type, NULL); - if (type_str == NULL) { - return; - } - - rc = nxt_java_response_set_header(req_info_ptr, - content_type, content_type_len, - type_str, type_len); - if (rc != NXT_UNIT_OK) { - // throw - } - - (*env)->ReleasePrimitiveArrayCritical(env, type, type_str, 0); -} - - -static void JNICALL -nxt_java_Response_removeContentType(JNIEnv *env, jclass cls, jlong req_info_ptr) -{ - nxt_java_response_remove_header(req_info_ptr, "Content-Type", - sizeof("Content-Type") - 1); -} - - -static void JNICALL -nxt_java_Response_log(JNIEnv *env, jclass cls, jlong req_info_ptr, jarray msg) -{ - char *msg_str; - jsize msg_len; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - msg_len = (*env)->GetArrayLength(env, msg); - - msg_str = (*env)->GetPrimitiveArrayCritical(env, msg, NULL); - if (msg_str == NULL) { - nxt_unit_req_warn(req, "log: failed to get msg content"); - return; - } - - nxt_unit_req_log(req, NXT_UNIT_LOG_INFO, "%.*s", msg_len, msg_str); - - (*env)->ReleasePrimitiveArrayCritical(env, msg, msg_str, 0); -} - - -static void JNICALL -nxt_java_Response_trace(JNIEnv *env, jclass cls, jlong req_info_ptr, jarray msg) -{ -#if (NXT_DEBUG) - char *msg_str; - jsize msg_len; - nxt_unit_request_info_t *req; - - req = nxt_jlong2ptr(req_info_ptr); - msg_len = (*env)->GetArrayLength(env, msg); - - msg_str = (*env)->GetPrimitiveArrayCritical(env, msg, NULL); - if (msg_str == NULL) { - nxt_unit_req_warn(req, "trace: failed to get msg content"); - return; - } - - nxt_unit_req_debug(req, "%.*s", msg_len, msg_str); - - (*env)->ReleasePrimitiveArrayCritical(env, msg, msg_str, 0); -#endif -} - diff --git a/src/java/nxt_jni_Response.h b/src/java/nxt_jni_Response.h deleted file mode 100644 index d10dba58..00000000 --- a/src/java/nxt_jni_Response.h +++ /dev/null @@ -1,18 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JAVA_RESPONSE_H_INCLUDED_ -#define _NXT_JAVA_RESPONSE_H_INCLUDED_ - - -#include -#include - - -int nxt_java_initResponse(JNIEnv *env, jobject cl); - -jobject nxt_java_newResponse(JNIEnv *env, nxt_unit_request_info_t *req); - -#endif /* _NXT_JAVA_RESPONSE_H_INCLUDED_ */ diff --git a/src/java/nxt_jni_Thread.c b/src/java/nxt_jni_Thread.c deleted file mode 100644 index 43dd90bd..00000000 --- a/src/java/nxt_jni_Thread.c +++ /dev/null @@ -1,94 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include - -#include "nxt_jni_Thread.h" - - -static jclass nxt_java_Thread_class; -static jmethodID nxt_java_Thread_currentThread; -static jmethodID nxt_java_Thread_getContextClassLoader; -static jmethodID nxt_java_Thread_setContextClassLoader; - - -int -nxt_java_initThread(JNIEnv *env) -{ - jclass cls; - - cls = (*env)->FindClass(env, "java/lang/Thread"); - if (cls == NULL) { - nxt_unit_warn(NULL, "java.lang.Thread not found"); - return NXT_UNIT_ERROR; - } - - nxt_java_Thread_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - cls = nxt_java_Thread_class; - - nxt_java_Thread_currentThread = (*env)->GetStaticMethodID(env, cls, - "currentThread", "()Ljava/lang/Thread;"); - if (nxt_java_Thread_currentThread == NULL) { - nxt_unit_warn(NULL, "java.lang.Thread.currentThread() not found"); - goto failed; - } - - nxt_java_Thread_getContextClassLoader = (*env)->GetMethodID(env, cls, - "getContextClassLoader", "()Ljava/lang/ClassLoader;"); - if (nxt_java_Thread_getContextClassLoader == NULL) { - nxt_unit_warn(NULL, "java.lang.Thread.getContextClassLoader() " - "not found"); - goto failed; - } - - nxt_java_Thread_setContextClassLoader = (*env)->GetMethodID(env, cls, - "setContextClassLoader", "(Ljava/lang/ClassLoader;)V"); - if (nxt_java_Thread_setContextClassLoader == NULL) { - nxt_unit_warn(NULL, "java.lang.Thread.setContextClassLoader() " - "not found"); - goto failed; - } - - return NXT_UNIT_OK; - -failed: - - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; -} - -void -nxt_java_setContextClassLoader(JNIEnv *env, jobject cl) -{ - jobject thread; - - thread = (*env)->CallStaticObjectMethod(env, nxt_java_Thread_class, - nxt_java_Thread_currentThread); - - if (thread == NULL) { - return; - } - - (*env)->CallVoidMethod(env, thread, nxt_java_Thread_setContextClassLoader, - cl); -} - -jobject -nxt_java_getContextClassLoader(JNIEnv *env) -{ - jobject thread; - - thread = (*env)->CallStaticObjectMethod(env, nxt_java_Thread_class, - nxt_java_Thread_currentThread); - - if (thread == NULL) { - return NULL; - } - - return (*env)->CallObjectMethod(env, thread, - nxt_java_Thread_getContextClassLoader); -} diff --git a/src/java/nxt_jni_Thread.h b/src/java/nxt_jni_Thread.h deleted file mode 100644 index 4d0b650e..00000000 --- a/src/java/nxt_jni_Thread.h +++ /dev/null @@ -1,20 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JAVA_THREAD_H_INCLUDED_ -#define _NXT_JAVA_THREAD_H_INCLUDED_ - - -#include - - -int nxt_java_initThread(JNIEnv *env); - -void nxt_java_setContextClassLoader(JNIEnv *env, jobject cl); - -jobject nxt_java_getContextClassLoader(JNIEnv *env); - -#endif /* _NXT_JAVA_THREAD_H_INCLUDED_ */ - diff --git a/src/java/nxt_jni_URLClassLoader.c b/src/java/nxt_jni_URLClassLoader.c deleted file mode 100644 index bf3ab0c3..00000000 --- a/src/java/nxt_jni_URLClassLoader.c +++ /dev/null @@ -1,187 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include - -#include "nxt_jni_URLClassLoader.h" - - -static jclass nxt_java_URLClassLoader_class; -static jmethodID nxt_java_URLClassLoader_ctor; -static jmethodID nxt_java_URLClassLoader_parent_ctor; -static jmethodID nxt_java_URLClassLoader_loadClass; -static jmethodID nxt_java_URLClassLoader_addURL; - -static jclass nxt_java_URL_class; -static jmethodID nxt_java_URL_ctor; - - -int -nxt_java_initURLClassLoader(JNIEnv *env) -{ - jclass cls; - - cls = (*env)->FindClass(env, "java/net/URLClassLoader"); - if (cls == NULL) { - nxt_unit_warn(NULL, "java.net.URLClassLoader not found"); - return NXT_UNIT_ERROR; - } - - nxt_java_URLClassLoader_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - cls = nxt_java_URLClassLoader_class; - - nxt_java_URLClassLoader_ctor = (*env)->GetMethodID(env, cls, - "", "([Ljava/net/URL;)V"); - if (nxt_java_URLClassLoader_ctor == NULL) { - nxt_unit_warn(NULL, "java.net.URLClassLoader constructor not found"); - goto failed; - } - - nxt_java_URLClassLoader_parent_ctor = (*env)->GetMethodID(env, cls, - "", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V"); - if (nxt_java_URLClassLoader_ctor == NULL) { - nxt_unit_warn(NULL, "java.net.URLClassLoader constructor not found"); - goto failed; - } - - nxt_java_URLClassLoader_loadClass = (*env)->GetMethodID(env, cls, - "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - if (nxt_java_URLClassLoader_loadClass == NULL) { - nxt_unit_warn(NULL, "java.net.URLClassLoader.loadClass not found"); - goto failed; - } - - nxt_java_URLClassLoader_addURL = (*env)->GetMethodID(env, cls, - "addURL", "(Ljava/net/URL;)V"); - if (nxt_java_URLClassLoader_addURL == NULL) { - nxt_unit_warn(NULL, "java.net.URLClassLoader.addURL not found"); - goto failed; - } - - cls = (*env)->FindClass(env, "java/net/URL"); - if (cls == NULL) { - nxt_unit_warn(NULL, "java.net.URL not found"); - return NXT_UNIT_ERROR; - } - - nxt_java_URL_class = (*env)->NewGlobalRef(env, cls); - (*env)->DeleteLocalRef(env, cls); - cls = nxt_java_URL_class; - - nxt_java_URL_ctor = (*env)->GetMethodID(env, cls, - "", "(Ljava/lang/String;)V"); - if (nxt_java_URL_ctor == NULL) { - nxt_unit_warn(NULL, "java.net.URL constructor not found"); - goto failed; - } - - return NXT_UNIT_OK; - -failed: - - (*env)->DeleteGlobalRef(env, cls); - return NXT_UNIT_ERROR; -} - - -jobject -nxt_java_newURLClassLoader(JNIEnv *env, int url_count, char **urls) -{ - jobjectArray jurls; - - jurls = nxt_java_newURLs(env, url_count, urls); - if (jurls == NULL) { - return NULL; - } - - return (*env)->NewObject(env, nxt_java_URLClassLoader_class, - nxt_java_URLClassLoader_ctor, jurls); -} - - -jobject -nxt_java_newURLClassLoader_parent(JNIEnv *env, int url_count, char **urls, - jobject parent) -{ - jobjectArray jurls; - - jurls = nxt_java_newURLs(env, url_count, urls); - if (jurls == NULL) { - return NULL; - } - - return (*env)->NewObject(env, nxt_java_URLClassLoader_class, - nxt_java_URLClassLoader_parent_ctor, jurls, - parent); -} - - -jobjectArray -nxt_java_newURLs(JNIEnv *env, int url_count, char **urls) -{ - int i; - jstring surl; - jobject jurl; - jobjectArray jurls; - - jurls = (*env)->NewObjectArray(env, url_count, nxt_java_URL_class, NULL); - if (jurls == NULL) { - return NULL; - } - - for (i = 0; i < url_count; i++) { - surl = (*env)->NewStringUTF(env, urls[i]); - if (surl == NULL) { - return NULL; - } - - jurl = (*env)->NewObject(env, nxt_java_URL_class, nxt_java_URL_ctor, - surl); - if (jurl == NULL) { - return NULL; - } - - (*env)->SetObjectArrayElement(env, jurls, i, jurl); - } - - return jurls; -} - - -jclass -nxt_java_loadClass(JNIEnv *env, jobject cl, const char *name) -{ - jstring jname; - - jname = (*env)->NewStringUTF(env, name); - if (jname == NULL) { - return NULL; - } - - return (*env)->CallObjectMethod(env, cl, nxt_java_URLClassLoader_loadClass, - jname); -} - - -void -nxt_java_addURL(JNIEnv *env, jobject cl, const char *url) -{ - jstring surl; - jobject jurl; - - surl = (*env)->NewStringUTF(env, url); - if (surl == NULL) { - return; - } - - jurl = (*env)->NewObject(env, nxt_java_URL_class, nxt_java_URL_ctor, surl); - if (jurl == NULL) { - return; - } - - (*env)->CallVoidMethod(env, cl, nxt_java_URLClassLoader_addURL, jurl); -} diff --git a/src/java/nxt_jni_URLClassLoader.h b/src/java/nxt_jni_URLClassLoader.h deleted file mode 100644 index 4cf2c0ec..00000000 --- a/src/java/nxt_jni_URLClassLoader.h +++ /dev/null @@ -1,27 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JAVA_URLCLASSLOADER_H_INCLUDED_ -#define _NXT_JAVA_URLCLASSLOADER_H_INCLUDED_ - - -#include - - -int nxt_java_initURLClassLoader(JNIEnv *env); - -jobject nxt_java_newURLClassLoader(JNIEnv *env, int url_count, char **urls); - -jobject nxt_java_newURLClassLoader_parent(JNIEnv *env, int url_count, - char **urls, jobject parent); - -jobjectArray nxt_java_newURLs(JNIEnv *env, int url_count, char **urls); - -jclass nxt_java_loadClass(JNIEnv *env, jobject cl, const char *name); - -void nxt_java_addURL(JNIEnv *env, jobject cl, const char *url); - -#endif /* _NXT_JAVA_URLCLASSLOADER_H_INCLUDED_ */ - diff --git a/src/nodejs/unit-http/README.md b/src/nodejs/unit-http/README.md deleted file mode 100644 index b6b975e4..00000000 --- a/src/nodejs/unit-http/README.md +++ /dev/null @@ -1,5 +0,0 @@ -[](https://unit.nginx.org) - -# Node.js Package for NGINX Unit - -For details, see [NGINX Unit documentation](https://unit.nginx.org). diff --git a/src/nodejs/unit-http/addon.cpp b/src/nodejs/unit-http/addon.cpp deleted file mode 100644 index 6ced9538..00000000 --- a/src/nodejs/unit-http/addon.cpp +++ /dev/null @@ -1,15 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include "unit.h" - - -napi_value -Init(napi_env env, napi_value exports) -{ - return Unit::init(env, exports); -} - -NAPI_MODULE(Unit, Init) diff --git a/src/nodejs/unit-http/binding.gyp b/src/nodejs/unit-http/binding.gyp deleted file mode 100644 index e41db7c4..00000000 --- a/src/nodejs/unit-http/binding.gyp +++ /dev/null @@ -1,21 +0,0 @@ -{ - 'targets': [{ - 'target_name': "unit-http", - 'cflags!': [ '-fno-exceptions' ], - 'cflags_cc!': [ '-fno-exceptions' ], - 'conditions': [ - ['OS=="mac"', { - 'xcode_settings': { - 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' - } - }] - ], - 'sources': ["unit.cpp", "addon.cpp"], - 'include_dirs': [ - " 999) { - throw new ERR_HTTP_INVALID_STATUS_CODE(originalStatusCode); - } - - if (typeof reason === 'string') { - this.statusMessage = reason; - - } else { - if (!this.statusMessage) { - this.statusMessage = http.STATUS_CODES[statusCode] || 'unknown'; - } - - obj = reason; - } - - this.statusCode = statusCode; - - if (obj) { - var k; - var keys = Object.keys(obj); - - for (var i = 0; i < keys.length; i++) { - k = keys[i]; - - if (k) { - this.setHeader(k, obj[k]); - } - } - } - - return this; -}; - -/* - * Some Node.js packages are known to be using this undocumented function, - * notably "compression" middleware. - */ -ServerResponse.prototype._implicitHeader = function _implicitHeader() { - this.writeHead(this.statusCode); -}; - -ServerResponse.prototype._send_headers = unit_lib.response_send_headers; - -ServerResponse.prototype._sendHeaders = function _sendHeaders() { - if (!this.headersSent) { - this._send_headers(this.statusCode, this.headers, this.headers_count, - this.headers_len); - - this.headersSent = true; - } -}; - -ServerResponse.prototype._write = unit_lib.response_write; - -ServerResponse.prototype._writeBody = function(chunk, encoding, callback) { - var contentLength = 0; - var res, o; - - this._sendHeaders(); - - if (typeof chunk === 'function') { - callback = chunk; - chunk = null; - - } else if (typeof encoding === 'function') { - callback = encoding; - encoding = null; - } - - if (chunk) { - if (typeof chunk !== 'string' && !(chunk instanceof Buffer || - chunk instanceof Uint8Array)) { - throw new TypeError( - 'First argument must be a string, Buffer, ' + - 'or Uint8Array'); - } - - if (typeof chunk === 'string') { - contentLength = Buffer.byteLength(chunk, encoding); - - if (contentLength > unit_lib.buf_min) { - chunk = Buffer.from(chunk, encoding); - - contentLength = chunk.length; - } - - } else { - contentLength = chunk.length; - } - - if (this.server._output.length > 0 || !this.socket.writable) { - o = new BufferedOutput(this, 0, chunk, encoding, callback); - this.server._output.push(o); - - return false; - } - - res = this._write(chunk, 0, contentLength); - if (res < contentLength) { - this.socket.writable = false; - this.writable = false; - - o = new BufferedOutput(this, res, chunk, encoding, callback); - this.server._output.push(o); - - return false; - } - } - - if (typeof callback === 'function') { - /* - * The callback must be called only when response.write() caller - * completes. process.nextTick() postpones the callback execution. - * - * process.nextTick() is not technically part of the event loop. - * Instead, the nextTickQueue will be processed after the current - * operation completes, regardless of the current phase of - * the event loop. All callbacks passed to process.nextTick() - * will be resolved before the event loop continues. - */ - process.nextTick(callback); - } - - return true; -}; - -ServerResponse.prototype.write = function write(chunk, encoding, callback) { - if (this.finished) { - if (typeof encoding === 'function') { - callback = encoding; - encoding = null; - } - - var err = new Error("Write after end"); - process.nextTick(() => { - this.emit('error', err); - - if (typeof callback === 'function') { - callback(err); - } - }) - } - - return this._writeBody(chunk, encoding, callback); -}; - -ServerResponse.prototype._end = unit_lib.response_end; - -ServerResponse.prototype.end = function end(chunk, encoding, callback) { - if (!this.finished) { - if (typeof encoding === 'function') { - callback = encoding; - encoding = null; - } - - this._writeBody(chunk, encoding, () => { - this._end(); - - if (typeof callback === 'function') { - callback(); - } - - this.emit("finish"); - }); - - this.finished = true; - } - - return this; -}; - -function ServerRequest(server, socket) { - Readable.call(this); - - this.server = server; - this.socket = socket; - this.connection = socket; - this._pushed_eofchunk = false; -} -util.inherits(ServerRequest, Readable); - -ServerRequest.prototype.setTimeout = function setTimeout(msecs, callback) { - this.timeout = msecs; - - if (callback) { - this.on('timeout', callback); - } - - return this; -}; - -ServerRequest.prototype.statusCode = function statusCode() { - /* Only valid for response obtained from http.ClientRequest. */ -}; - -ServerRequest.prototype.statusMessage = function statusMessage() { - /* Only valid for response obtained from http.ClientRequest. */ -}; - -ServerRequest.prototype.trailers = function trailers() { - throw new Error("Not supported"); -}; - -ServerRequest.prototype.METHODS = function METHODS() { - return http.METHODS; -}; - -ServerRequest.prototype.STATUS_CODES = function STATUS_CODES() { - return http.STATUS_CODES; -}; - -ServerRequest.prototype._request_read = unit_lib.request_read; - -ServerRequest.prototype._read = function _read(n) { - const b = this._request_read(n); - - if (b != null) { - this.push(b); - } - - if (!this._pushed_eofchunk && (b == null || b.length < n)) { - this._pushed_eofchunk = true; - this.push(null); - } -}; - - -function Server(options, requestListener) { - if (typeof options === 'function') { - requestListener = options; - options = {}; - } else { - console.warn("http.Server constructor was called with unsupported options, using default settings"); - } - - EventEmitter.call(this); - - this.unit = new unit_lib.Unit(); - this.unit.server = this; - - this.unit.createServer(); - - this.Socket = Socket; - this.ServerRequest = ServerRequest; - this.ServerResponse = ServerResponse; - this.WebSocketFrame = WebSocketFrame; - - if (requestListener) { - this.on('request', requestListener); - } - - this._upgradeListenerCount = 0; - this.on('newListener', function(ev) { - if (ev === 'upgrade'){ - this._upgradeListenerCount++; - } - }).on('removeListener', function(ev) { - if (ev === 'upgrade') { - this._upgradeListenerCount--; - } - }); - - this._output = []; - this._drain_resp = new Set(); -} - -util.inherits(Server, EventEmitter); - -Server.prototype.setTimeout = function setTimeout(msecs, callback) { - this.timeout = msecs; - - if (callback) { - this.on('timeout', callback); - } - - return this; -}; - -Server.prototype.listen = function (...args) { - this.unit.listen(); - - if (typeof args[args.length - 1] === 'function') { - this.once('listening', args[args.length - 1]); - } - - /* - * Some express.js apps use the returned server object inside the listening - * callback, so we timeout the listening event to occur after this function - * returns. - */ - setImmediate(function() { - this.emit('listening') - }.bind(this)) - - return this; -}; - -Server.prototype.address = function () { - return { - family: "IPv4", - address: "127.0.0.1", - port: 80 - } -} - -Server.prototype.emit_request = function (req, res) { - if (req._websocket_handshake && this._upgradeListenerCount > 0) { - this.emit('upgrade', req, req.socket); - - } else { - this.emit("request", req, res); - } -}; - -Server.prototype.emit_close = function () { - this.emit('close'); -}; - -Server.prototype.emit_drain = function () { - var res, o, l; - - if (this._output.length <= 0) { - return; - } - - while (this._output.length > 0) { - o = this._output[0]; - - if (typeof o.chunk === 'string') { - l = Buffer.byteLength(o.chunk, o.encoding); - - } else { - l = o.chunk.length; - } - - res = o.resp._write(o.chunk, o.offset, l); - - o.offset += res; - if (o.offset < l) { - return; - } - - this._drain_resp.add(o.resp); - - if (typeof o.callback === 'function') { - process.nextTick(o.callback); - } - - this._output.shift(); - } - - for (var resp of this._drain_resp) { - - if (resp.socket.writable) { - continue; - } - - resp.socket.writable = true; - resp.writable = true; - - process.nextTick(() => { - resp.emit("drain"); - }); - } - - this._drain_resp.clear(); -}; - -function BufferedOutput(resp, offset, chunk, encoding, callback) { - this.resp = resp; - this.offset = offset; - this.chunk = chunk; - this.encoding = encoding; - this.callback = callback; -} - -function connectionListener(socket) { -} - -module.exports = { - Server, - ServerResponse, - ServerRequest, - _connectionListener: connectionListener -}; diff --git a/src/nodejs/unit-http/loader.js b/src/nodejs/unit-http/loader.js deleted file mode 100644 index 849df3d1..00000000 --- a/src/nodejs/unit-http/loader.js +++ /dev/null @@ -1,29 +0,0 @@ -// can only be ran as part of a --require param on the node process -if (module.parent && module.parent.id === "internal/preload") { - const { Module } = require("module") - - if (!Module.prototype.require.__unit_loader) { - const http = require("./http") - const websocket = require("./websocket") - - const original = Module.prototype.require; - - Module.prototype.require = function (id) { - switch(id) { - case "http": - case "node:http": - case "unit-http": - return http - - case "websocket": - case "node:websocket": - case "unit-http/websocket": - return websocket - } - - return original.apply(this, arguments); - } - - Module.prototype.require.__unit_loader = true; - } -} diff --git a/src/nodejs/unit-http/loader.mjs b/src/nodejs/unit-http/loader.mjs deleted file mode 100644 index 01fa2920..00000000 --- a/src/nodejs/unit-http/loader.mjs +++ /dev/null @@ -1,22 +0,0 @@ -// must be ran as part of a --loader or --experimental-loader param -export async function resolve(specifier, context, defaultResolver) { - switch (specifier) { - case "websocket": - case "node:websocket": - return { - url: new URL("./websocket.js", import.meta.url).href, - format: "commonjs", - shortCircuit: true, - } - - case "http": - case "node:http": - return { - url: new URL("./http.js", import.meta.url).href, - format: "commonjs", - shortCircuit: true, - } - } - - return defaultResolver(specifier, context, defaultResolver) -} diff --git a/src/nodejs/unit-http/nxt_napi.h b/src/nodejs/unit-http/nxt_napi.h deleted file mode 100644 index d9721a40..00000000 --- a/src/nodejs/unit-http/nxt_napi.h +++ /dev/null @@ -1,839 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_NODEJS_NAPI_H_INCLUDED_ -#define _NXT_NODEJS_NAPI_H_INCLUDED_ - -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -#include "version.h" -#include - -#if NXT_VERNUM != NXT_NODE_VERNUM -#error "libunit version mismatch." -#endif - -#include -#include - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -struct nxt_napi { - - struct exception { - exception(const char *s) : str(s) { } - - const char *str; - }; - - - nxt_napi(napi_env env) : env_(env) { } - - - inline napi_value - coerce_to_string(napi_value val) - { - napi_value res; - napi_status status; - - status = napi_coerce_to_string(env_, val, &res); - if (status != napi_ok) { - throw exception("Failed to coerce to string"); - } - - return res; - } - - - inline napi_value - create_buffer(size_t size, void **data) - { - napi_value res; - napi_status status; - - status = napi_create_buffer(env_, size, data, &res); - if (status != napi_ok) { - throw exception("Failed to create buffer"); - } - - return res; - } - - - inline napi_value - create_function(const char *name, size_t len, napi_callback cb, void *data) - { - napi_value res; - napi_status status; - - status = napi_create_function(env_, name, len, cb, data, &res); - if (status != napi_ok) { - throw exception("Failed to create function"); - } - - return res; - } - - - inline napi_value - create_function(napi_callback cb) - { - return create_function(NULL, 0, cb, NULL); - } - - - inline napi_value - create_object() - { - napi_value res; - napi_status status; - - status = napi_create_object(env_, &res); - if (status != napi_ok) { - throw exception("Failed to create object"); - } - - return res; - } - - - inline napi_ref - create_reference(napi_value val, int ref_count = 1) - { - napi_ref res; - napi_status status; - - status = napi_create_reference(env_, val, ref_count, &res); - if (status != napi_ok) { - throw exception("Failed to create reference"); - } - - return res; - } - - - inline napi_value - create_string_latin1(const char *str, size_t len) - { - napi_value res; - napi_status status; - - status = napi_create_string_latin1(env_, str, len, &res); - if (status != napi_ok) { - throw exception("Failed to create latin1 string"); - } - - return res; - } - - - inline napi_value - create_string_latin1(nxt_unit_sptr_t &str, size_t len) - { - const char *p; - - p = (const char *) nxt_unit_sptr_get(&str); - - return create_string_latin1(p, len); - } - - - inline napi_value - define_class(const char *name, napi_callback ctor, size_t prop_count, - const napi_property_descriptor* props) - { - napi_value res; - napi_status status; - - status = napi_define_class(env_, name, NAPI_AUTO_LENGTH, ctor, nullptr, - prop_count, props, &res); - if (status != napi_ok) { - throw exception("Failed to define class"); - } - - return res; - } - - - inline void - delete_reference(napi_ref ref) - { - napi_delete_reference(env_, ref); - } - - - inline uint32_t - get_array_length(napi_value val) - { - uint32_t res; - napi_status status; - - status = napi_get_array_length(env_, val, &res); - if (status != napi_ok) { - throw exception("Failed to get array length"); - } - - return res; - } - - - inline void * - get_buffer_info(napi_value val, size_t &size) - { - void *res; - napi_status status; - - status = napi_get_buffer_info(env_, val, &res, &size); - if (status != napi_ok) { - throw exception("Failed to get buffer info"); - } - - return res; - } - - - inline napi_value - get_cb_info(napi_callback_info info, size_t &argc, napi_value *argv) - { - napi_value res; - napi_status status; - - status = napi_get_cb_info(env_, info, &argc, argv, &res, nullptr); - if (status != napi_ok) { - throw exception("Failed to get arguments from js"); - } - - return res; - } - - - inline napi_value - get_cb_info(napi_callback_info info) - { - napi_value res; - napi_status status; - - status = napi_get_cb_info(env_, info, nullptr, nullptr, &res, nullptr); - if (status != napi_ok) { - throw exception("Failed to get arguments from js"); - } - - return res; - } - - - inline napi_value - get_cb_info(napi_callback_info info, napi_value &arg) - { - size_t argc; - napi_value res; - - argc = 1; - res = get_cb_info(info, argc, &arg); - - if (argc != 1) { - throw exception("Wrong args count. Expected 1"); - } - - return res; - } - - - inline napi_value - get_element(napi_value obj, uint32_t i) - { - napi_value res; - napi_status status; - - status = napi_get_element(env_, obj, i, &res); - if (status != napi_ok) { - throw exception("Failed to get element"); - } - - return res; - } - - - inline napi_value - get_named_property(napi_value obj, const char *name) - { - napi_value res; - napi_status status; - - status = napi_get_named_property(env_, obj, name, &res); - if (status != napi_ok) { - throw exception("Failed to get named property"); - } - - return res; - } - - - inline napi_value - get_new_target(napi_callback_info info) - { - napi_value res; - napi_status status; - - status = napi_get_new_target(env_, info, &res); - if (status != napi_ok) { - throw exception("Failed to get new target"); - } - - return res; - } - - - inline napi_value - get_property(napi_value val, napi_value key) - { - napi_value res; - napi_status status; - - status = napi_get_property(env_, val, key, &res); - if (status != napi_ok) { - throw exception("Failed to get property"); - } - - return res; - } - - - inline napi_value - get_property_names(napi_value val) - { - napi_value res; - napi_status status; - - status = napi_get_property_names(env_, val, &res); - if (status != napi_ok) { - throw exception("Failed to get property names"); - } - - return res; - } - - - inline napi_value - get_reference_value(napi_ref ref) - { - napi_value res; - napi_status status; - - status = napi_get_reference_value(env_, ref, &res); - if (status != napi_ok) { - throw exception("Failed to get reference value"); - } - - return res; - } - - - inline nxt_unit_request_info_t * - get_request_info(napi_value obj) - { - return (nxt_unit_request_info_t *) unwrap(obj); - } - - - inline uint32_t - get_value_bool(napi_value obj) - { - bool res; - napi_status status; - - status = napi_get_value_bool(env_, obj, &res); - if (status != napi_ok) { - throw exception("Failed to get bool"); - } - - return res; - } - - - inline size_t - get_value_string_latin1(napi_value val, char *buf, size_t bufsize) - { - size_t res; - napi_status status; - - status = napi_get_value_string_latin1(env_, val, buf, bufsize, &res); - if (status != napi_ok) { - throw exception("Failed to get string latin1"); - } - - return res; - } - - - inline uint32_t - get_value_uint32(napi_value obj) - { - uint32_t res; - napi_status status; - - status = napi_get_value_uint32(env_, obj, &res); - if (status != napi_ok) { - throw exception("Failed to get uint32_t"); - } - - return res; - } - - - inline size_t - get_value_string_utf8(napi_value val, char *buf, size_t bufsize) - { - size_t res; - napi_status status; - - status = napi_get_value_string_utf8(env_, val, buf, bufsize, &res); - if (status != napi_ok) { - throw exception("Failed to get string utf8"); - } - - return res; - } - - - inline bool - is_array(napi_value val) - { - bool res; - napi_status status; - - status = napi_is_array(env_, val, &res); - if (status != napi_ok) { - throw exception("Failed to confirm value is array"); - } - - return res; - } - - - inline bool - is_buffer(napi_value val) - { - bool res; - napi_status status; - - status = napi_is_buffer(env_, val, &res); - if (status != napi_ok) { - throw exception("Failed to confirm value is buffer"); - } - - return res; - } - - - inline napi_value - make_callback(napi_async_context ctx, napi_value val, napi_value func, - int argc, const napi_value *argv) - { - napi_value res, ex; - napi_status status; - - status = napi_make_callback(env_, ctx, val, func, argc, argv, &res); - if (status != napi_ok) { - if (status != napi_pending_exception) { - throw exception("Failed to make callback"); - } - - status = napi_get_and_clear_last_exception(env_, &ex); - if (status != napi_ok) { - throw exception("Failed to get and clear last exception"); - } - - /* Logging a description of the error and call stack. */ - status = napi_fatal_exception(env_, ex); - if (status != napi_ok) { - throw exception("Failed napi_fatal_exception()"); - } - } - - return res; - } - - - inline napi_value - make_callback(napi_async_context ctx, napi_value val, napi_value func) - { - return make_callback(ctx, val, func, 0, NULL); - } - - - inline napi_value - make_callback(napi_async_context ctx, napi_value val, napi_value func, - napi_value arg1) - { - return make_callback(ctx, val, func, 1, &arg1); - } - - - inline napi_value - make_callback(napi_async_context ctx, napi_value val, napi_value func, - napi_value arg1, napi_value arg2) - { - napi_value args[2] = { arg1, arg2 }; - - return make_callback(ctx, val, func, 2, args); - } - - - inline napi_value - make_callback(napi_async_context ctx, napi_value val, napi_value func, - napi_value arg1, napi_value arg2, napi_value arg3) - { - napi_value args[3] = { arg1, arg2, arg3 }; - - return make_callback(ctx, val, func, 3, args); - } - - - inline napi_value - new_instance(napi_value ctor) - { - napi_value res; - napi_status status; - - status = napi_new_instance(env_, ctor, 0, NULL, &res); - if (status != napi_ok) { - throw exception("Failed to create instance"); - } - - return res; - } - - - inline napi_value - new_instance(napi_value ctor, napi_value param) - { - napi_value res; - napi_status status; - - status = napi_new_instance(env_, ctor, 1, ¶m, &res); - if (status != napi_ok) { - throw exception("Failed to create instance"); - } - - return res; - } - - - inline napi_value - new_instance(napi_value ctor, napi_value param1, napi_value param2) - { - napi_value res; - napi_status status; - napi_value param[2] = { param1, param2 }; - - status = napi_new_instance(env_, ctor, 2, param, &res); - if (status != napi_ok) { - throw exception("Failed to create instance"); - } - - return res; - } - - - inline void - set_element(napi_value obj, uint32_t i, napi_value val) - { - napi_status status; - - status = napi_set_element(env_, obj, i, val); - if (status != napi_ok) { - throw exception("Failed to set element"); - } - } - - - inline void - set_named_property(napi_value obj, const char *name, napi_value val) - { - napi_status status; - - status = napi_set_named_property(env_, obj, name, val); - if (status != napi_ok) { - throw exception("Failed to set named property"); - } - } - - - inline void - set_named_property(napi_value obj, const char *name, napi_callback cb) - { - set_named_property(obj, name, create_function(cb)); - } - - - inline napi_value - set_named_property(napi_value obj, const char *name, nxt_unit_sptr_t &val, - size_t len) - { - napi_value str; - - str = create_string_latin1(val, len); - - set_named_property(obj, name, str); - - return str; - } - - - template - inline void - set_named_property(napi_value obj, const char *name, T val) - { - set_named_property(obj, name, create(val)); - } - - - inline napi_value - create(int32_t val) - { - napi_value ptr; - napi_status status; - - status = napi_create_int32(env_, val, &ptr); - if (status != napi_ok) { - throw exception("Failed to create int32"); - } - - return ptr; - } - - - inline napi_value - create(uint32_t val) - { - napi_value ptr; - napi_status status; - - status = napi_create_uint32(env_, val, &ptr); - if (status != napi_ok) { - throw exception("Failed to create uint32"); - } - - return ptr; - } - - - inline napi_value - create(int64_t val) - { - napi_value ptr; - napi_status status; - - status = napi_create_int64(env_, val, &ptr); - if (status != napi_ok) { - throw exception("Failed to create int64"); - } - - return ptr; - } - - - inline void - remove_wrap(napi_ref& ref) - { - if (ref != nullptr) { - remove_wrap(get_reference_value(ref)); - ref = nullptr; - } - } - - - inline void * - remove_wrap(napi_value val) - { - void *res; - napi_status status; - - status = napi_remove_wrap(env_, val, &res); - if (status != napi_ok) { - throw exception("Failed to remove_wrap"); - } - - return res; - } - - - inline void - throw_error(const char *str) - { - napi_throw_error(env_, NULL, str); - } - - - inline void - throw_error(const exception &e) - { - napi_throw_error(env_, NULL, e.str); - } - - - inline napi_valuetype - type_of(napi_value val) - { - napi_status status; - napi_valuetype res; - - status = napi_typeof(env_, val, &res); - if (status != napi_ok) { - throw exception("Failed to get typeof"); - } - - return res; - } - - - inline void * - unwrap(napi_value val) - { - void *res; - napi_status status; - - status = napi_unwrap(env_, val, &res); - if (status != napi_ok) { - throw exception("Failed to unwrap"); - } - - return res; - } - - - inline napi_ref - wrap(napi_value val, void *obj, napi_finalize fin_cb, void *hint = nullptr) - { - napi_ref res; - napi_status status; - - status = napi_wrap(env_, val, obj, fin_cb, hint, &res); - if (status != napi_ok) { - throw exception("Failed to wrap"); - } - - return res; - } - - - inline - operator napi_env() - { - return env_; - } - - - napi_env env() - { - return env_; - } - -private: - napi_env env_; -}; - - -struct nxt_handle_scope : public nxt_napi { - nxt_handle_scope(napi_env env) : nxt_napi(env) - { - napi_status status; - - status = napi_open_handle_scope(env, &scope_); - if (status != napi_ok) { - throw exception("Failed to open handle scope"); - } - } - - ~nxt_handle_scope() - { - napi_status status; - - status = napi_close_handle_scope(env(), scope_); - if (status != napi_ok) { - throw_error("Failed to close handle scope"); - } - } - -private: - napi_handle_scope scope_; -}; - - -struct nxt_async_context : public nxt_napi { - nxt_async_context(napi_env env, const char *name) : - nxt_napi(env) - { - napi_value name_val; - napi_status status; - - name_val = create_string_latin1(name, NAPI_AUTO_LENGTH); - - status = napi_async_init(env, NULL, name_val, &context_); - if (status != napi_ok) { - throw exception("Failed to init async object"); - } - } - - operator napi_async_context() { - return context_; - } - - ~nxt_async_context() - { - napi_status status; - - status = napi_async_destroy(env(), context_); - if (status != napi_ok) { - throw_error("Failed to destroy async object"); - } - } - -private: - napi_async_context context_; -}; - - -struct nxt_callback_scope : public nxt_napi { - nxt_callback_scope(nxt_async_context& ctx) : - nxt_napi(ctx.env()) - { - napi_value resource; - napi_status status; - - resource = create_object(); - - status = napi_open_callback_scope(env(), resource, ctx, &scope_); - if (status != napi_ok) { - throw exception("Failed to open callback scope"); - } - } - - ~nxt_callback_scope() - { - napi_status status; - - status = napi_close_callback_scope(env(), scope_); - if (status != napi_ok) { - throw_error("Failed to close callback scope"); - } - } - -private: - napi_callback_scope scope_; -}; - - -#endif /* _NXT_NODEJS_NAPI_H_INCLUDED_ */ diff --git a/src/nodejs/unit-http/package.json b/src/nodejs/unit-http/package.json deleted file mode 100644 index debbd492..00000000 --- a/src/nodejs/unit-http/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "unit-http", - "version": "%%VERSION%%", - "description": "HTTP module for NGINX Unit", - "main": "http.js", - "scripts": { - "clean": "node-gyp clean", - "configure": "node-gyp configure", - "build": "node-gyp build", - "install": "node-gyp configure build" - }, - "author": "Alexander Borisov", - "license": "Apache-2.0", - "gypfile": true -} diff --git a/src/nodejs/unit-http/socket.js b/src/nodejs/unit-http/socket.js deleted file mode 100644 index b1a3abb8..00000000 --- a/src/nodejs/unit-http/socket.js +++ /dev/null @@ -1,104 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -'use strict'; - -const EventEmitter = require('events'); -const util = require('util'); -const unit_lib = require('./build/Release/unit-http'); - -function Socket(options) { - EventEmitter.call(this); - - options = options || {}; - - if (typeof options !== 'object') { - throw new TypeError('Options must be object'); - } - - if ("fd" in options) { - throw new TypeError('Working with file descriptors not supported'); - } - - /* - * For HTTP TCP socket 'readable' and 'writable' are always true. - * These options are required by Express and Koa frameworks. - */ - this.readable = true; - this.writable = true; -} -util.inherits(Socket, EventEmitter); - -Socket.prototype.bufferSize = 0; -Socket.prototype.bytesRead = 0; -Socket.prototype.bytesWritten = 0; -Socket.prototype.connecting = false; -Socket.prototype.destroyed = false; -Socket.prototype.localAddress = ""; -Socket.prototype.localPort = 0; -Socket.prototype.remoteAddress = ""; -Socket.prototype.remoteFamily = ""; -Socket.prototype.remotePort = 0; - -Socket.prototype.address = function address() { -}; - -Socket.prototype.connect = function connect(options, connectListener) { - this.once('connect', connectListener); - - this.connecting = true; - - return this; -}; - -Socket.prototype.destroy = function destroy(exception) { - this.connecting = false; - this.readable = false; - this.writable = false; - - return this; -}; - -Socket.prototype.end = function end(data, encoding, callback) { -}; - -Socket.prototype.pause = function pause() { -}; - -Socket.prototype.ref = function ref() { -}; - -Socket.prototype.resume = function resume() { -}; - -Socket.prototype.setEncoding = function setEncoding(encoding) { -}; - -Socket.prototype.setKeepAlive = function setKeepAlive(enable, initialDelay) { -}; - -Socket.prototype.setNoDelay = function setNoDelay(noDelay) { -}; - -Socket.prototype.setTimeout = function setTimeout(timeout, callback) { - if (typeof timeout !== 'number') { - throw new TypeError('Timeout must be number'); - } - - this.timeout = timeout; - - // this.on('timeout', callback); - - return this; -}; - -Socket.prototype.unref = function unref() { -}; - -Socket.prototype.write = function write(data, encoding, callback) { -}; - - -module.exports = Socket; diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp deleted file mode 100644 index 7d9395bb..00000000 --- a/src/nodejs/unit-http/unit.cpp +++ /dev/null @@ -1,1168 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include "unit.h" - -#include -#include - -#include - -#include - - -napi_ref Unit::constructor_; - - -struct port_data_t { - port_data_t(nxt_unit_ctx_t *c, nxt_unit_port_t *p); - - void process_port_msg(); - void stop(); - - template - static port_data_t *get(T *handle); - - static void read_callback(uv_poll_t *handle, int status, int events); - static void timer_callback(uv_timer_t *handle); - static void delete_data(uv_handle_t* handle); - - nxt_unit_ctx_t *ctx; - nxt_unit_port_t *port; - uv_poll_t poll; - uv_timer_t timer; - int ref_count; - bool scheduled; - bool stopped; -}; - - -struct req_data_t { - napi_ref sock_ref; - napi_ref req_ref; - napi_ref resp_ref; - napi_ref conn_ref; -}; - - -port_data_t::port_data_t(nxt_unit_ctx_t *c, nxt_unit_port_t *p) : - ctx(c), port(p), ref_count(0), scheduled(false), stopped(false) -{ - timer.type = UV_UNKNOWN_HANDLE; -} - - -void -port_data_t::process_port_msg() -{ - int rc, err; - - rc = nxt_unit_process_port_msg(ctx, port); - - if (rc != NXT_UNIT_OK) { - return; - } - - if (timer.type == UV_UNKNOWN_HANDLE) { - err = uv_timer_init(poll.loop, &timer); - if (err < 0) { - nxt_unit_warn(ctx, "Failed to init uv.poll"); - return; - } - - ref_count++; - timer.data = this; - } - - if (!scheduled && !stopped) { - uv_timer_start(&timer, timer_callback, 0, 0); - - scheduled = true; - } -} - - -void -port_data_t::stop() -{ - stopped = true; - - uv_poll_stop(&poll); - - uv_close((uv_handle_t *) &poll, delete_data); - - if (timer.type == UV_UNKNOWN_HANDLE) { - return; - } - - uv_timer_stop(&timer); - - uv_close((uv_handle_t *) &timer, delete_data); -} - - -template -port_data_t * -port_data_t::get(T *handle) -{ - return (port_data_t *) handle->data; -} - - -void -port_data_t::read_callback(uv_poll_t *handle, int status, int events) -{ - get(handle)->process_port_msg(); -} - - -void -port_data_t::timer_callback(uv_timer_t *handle) -{ - port_data_t *data; - - data = get(handle); - - data->scheduled = false; - if (data->stopped) { - return; - } - - data->process_port_msg(); -} - - -void -port_data_t::delete_data(uv_handle_t* handle) -{ - port_data_t *data; - - data = get(handle); - - if (--data->ref_count <= 0) { - delete data; - } -} - - -Unit::Unit(napi_env env, napi_value jsthis): - nxt_napi(env), - wrapper_(wrap(jsthis, this, destroy)), - unit_ctx_(nullptr) -{ - nxt_unit_debug(NULL, "Unit::Unit()"); -} - - -Unit::~Unit() -{ - delete_reference(wrapper_); - - nxt_unit_debug(NULL, "Unit::~Unit()"); -} - - -napi_value -Unit::init(napi_env env, napi_value exports) -{ - nxt_napi napi(env); - napi_value ctor; - - napi_property_descriptor unit_props[] = { - { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 }, - { "listen", 0, listen, 0, 0, 0, napi_default, 0 }, - }; - - try { - ctor = napi.define_class("Unit", create, 2, unit_props); - constructor_ = napi.create_reference(ctor); - - napi.set_named_property(exports, "Unit", ctor); - napi.set_named_property(exports, "request_read", request_read); - napi.set_named_property(exports, "response_send_headers", - response_send_headers); - napi.set_named_property(exports, "response_write", response_write); - napi.set_named_property(exports, "response_end", response_end); - napi.set_named_property(exports, "websocket_send_frame", - websocket_send_frame); - napi.set_named_property(exports, "websocket_set_sock", - websocket_set_sock); - napi.set_named_property(exports, "buf_min", nxt_unit_buf_min()); - napi.set_named_property(exports, "buf_max", nxt_unit_buf_max()); - - } catch (exception &e) { - napi.throw_error(e); - return nullptr; - } - - return exports; -} - - -void -Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint) -{ - Unit *obj = reinterpret_cast(nativeObject); - - delete obj; -} - - -napi_value -Unit::create(napi_env env, napi_callback_info info) -{ - nxt_napi napi(env); - napi_value target, ctor, instance, jsthis; - - try { - target = napi.get_new_target(info); - - if (target != nullptr) { - /* Invoked as constructor: `new Unit(...)`. */ - jsthis = napi.get_cb_info(info); - - new Unit(env, jsthis); - napi.create_reference(jsthis); - - return jsthis; - } - - /* Invoked as plain function `Unit(...)`, turn into construct call. */ - ctor = napi.get_reference_value(constructor_); - instance = napi.new_instance(ctor); - napi.create_reference(instance); - - } catch (exception &e) { - napi.throw_error(e); - return nullptr; - } - - return instance; -} - - -napi_value -Unit::create_server(napi_env env, napi_callback_info info) -{ - Unit *obj; - size_t argc; - nxt_napi napi(env); - napi_value jsthis, argv; - nxt_unit_init_t unit_init; - - argc = 1; - - try { - jsthis = napi.get_cb_info(info, argc, &argv); - obj = (Unit *) napi.unwrap(jsthis); - - } catch (exception &e) { - napi.throw_error(e); - return nullptr; - } - - memset(&unit_init, 0, sizeof(nxt_unit_init_t)); - - unit_init.data = obj; - unit_init.callbacks.request_handler = request_handler_cb; - unit_init.callbacks.websocket_handler = websocket_handler_cb; - unit_init.callbacks.close_handler = close_handler_cb; - unit_init.callbacks.shm_ack_handler = shm_ack_handler_cb; - unit_init.callbacks.add_port = add_port; - unit_init.callbacks.remove_port = remove_port; - unit_init.callbacks.quit = quit_cb; - - unit_init.request_data_size = sizeof(req_data_t); - - obj->unit_ctx_ = nxt_unit_init(&unit_init); - if (obj->unit_ctx_ == NULL) { - goto failed; - } - - return nullptr; - -failed: - - napi_throw_error(env, NULL, "Failed to create Unit object"); - - return nullptr; -} - - -napi_value -Unit::listen(napi_env env, napi_callback_info info) -{ - return nullptr; -} - - -void -Unit::request_handler_cb(nxt_unit_request_info_t *req) -{ - Unit *obj; - - obj = reinterpret_cast(req->unit->data); - - obj->request_handler(req); -} - - -void -Unit::request_handler(nxt_unit_request_info_t *req) -{ - napi_value socket, request, response, server_obj, emit_request; - - memset(req->data, 0, sizeof(req_data_t)); - - try { - nxt_handle_scope scope(env()); - - server_obj = get_server_object(); - - socket = create_socket(server_obj, req); - request = create_request(server_obj, socket, req); - response = create_response(server_obj, request, req); - - create_headers(req, request); - - emit_request = get_named_property(server_obj, "emit_request"); - - nxt_async_context async_context(env(), "request_handler"); - nxt_callback_scope async_scope(async_context); - - make_callback(async_context, server_obj, emit_request, request, - response); - - } catch (exception &e) { - nxt_unit_req_warn(req, "request_handler: %s", e.str); - } -} - - -void -Unit::websocket_handler_cb(nxt_unit_websocket_frame_t *ws) -{ - Unit *obj; - - obj = reinterpret_cast(ws->req->unit->data); - - obj->websocket_handler(ws); -} - - -void -Unit::websocket_handler(nxt_unit_websocket_frame_t *ws) -{ - napi_value frame, server_obj, process_frame, conn; - req_data_t *req_data; - - req_data = (req_data_t *) ws->req->data; - - try { - nxt_handle_scope scope(env()); - - server_obj = get_server_object(); - - frame = create_websocket_frame(server_obj, ws); - - conn = get_reference_value(req_data->conn_ref); - - process_frame = get_named_property(conn, "processFrame"); - - nxt_async_context async_context(env(), "websocket_handler"); - nxt_callback_scope async_scope(async_context); - - make_callback(async_context, conn, process_frame, frame); - - } catch (exception &e) { - nxt_unit_req_warn(ws->req, "websocket_handler: %s", e.str); - } - - nxt_unit_websocket_done(ws); -} - - -void -Unit::close_handler_cb(nxt_unit_request_info_t *req) -{ - Unit *obj; - - obj = reinterpret_cast(req->unit->data); - - obj->close_handler(req); -} - - -void -Unit::close_handler(nxt_unit_request_info_t *req) -{ - napi_value conn_handle_close, conn; - req_data_t *req_data; - - req_data = (req_data_t *) req->data; - - try { - nxt_handle_scope scope(env()); - - conn = get_reference_value(req_data->conn_ref); - - conn_handle_close = get_named_property(conn, "handleSocketClose"); - - nxt_async_context async_context(env(), "close_handler"); - nxt_callback_scope async_scope(async_context); - - make_callback(async_context, conn, conn_handle_close, - nxt_napi::create(0)); - - remove_wrap(req_data->sock_ref); - remove_wrap(req_data->req_ref); - remove_wrap(req_data->resp_ref); - remove_wrap(req_data->conn_ref); - - } catch (exception &e) { - nxt_unit_req_warn(req, "close_handler: %s", e.str); - - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - return; - } - - nxt_unit_request_done(req, NXT_UNIT_OK); -} - - -void -Unit::shm_ack_handler_cb(nxt_unit_ctx_t *ctx) -{ - Unit *obj; - - obj = reinterpret_cast(ctx->unit->data); - - obj->shm_ack_handler(ctx); -} - - -void -Unit::shm_ack_handler(nxt_unit_ctx_t *ctx) -{ - napi_value server_obj, emit_drain; - - try { - nxt_handle_scope scope(env()); - - server_obj = get_server_object(); - - emit_drain = get_named_property(server_obj, "emit_drain"); - - nxt_async_context async_context(env(), "shm_ack_handler"); - nxt_callback_scope async_scope(async_context); - - make_callback(async_context, server_obj, emit_drain); - - } catch (exception &e) { - nxt_unit_warn(ctx, "shm_ack_handler: %s", e.str); - } -} - - -int -Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) -{ - int err; - Unit *obj; - uv_loop_t *loop; - port_data_t *data; - napi_status status; - - if (port->in_fd != -1) { - if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) { - nxt_unit_warn(ctx, "fcntl(%d, O_NONBLOCK) failed: %s (%d)", - port->in_fd, strerror(errno), errno); - return -1; - } - - obj = reinterpret_cast(ctx->unit->data); - - status = napi_get_uv_event_loop(obj->env(), &loop); - if (status != napi_ok) { - nxt_unit_warn(ctx, "Failed to get uv.loop"); - return NXT_UNIT_ERROR; - } - - data = new port_data_t(ctx, port); - - err = uv_poll_init(loop, &data->poll, port->in_fd); - if (err < 0) { - nxt_unit_warn(ctx, "Failed to init uv.poll"); - delete data; - return NXT_UNIT_ERROR; - } - - err = uv_poll_start(&data->poll, UV_READABLE, - port_data_t::read_callback); - if (err < 0) { - nxt_unit_warn(ctx, "Failed to start uv.poll"); - delete data; - return NXT_UNIT_ERROR; - } - - port->data = data; - - data->ref_count++; - data->poll.data = data; - } - - return NXT_UNIT_OK; -} - - -void -Unit::remove_port(nxt_unit_t *unit, nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) -{ - port_data_t *data; - - if (port->data != NULL && ctx != NULL) { - data = (port_data_t *) port->data; - - data->stop(); - } -} - - -void -Unit::quit_cb(nxt_unit_ctx_t *ctx) -{ - Unit *obj; - - obj = reinterpret_cast(ctx->unit->data); - - obj->quit(ctx); -} - - -void -Unit::quit(nxt_unit_ctx_t *ctx) -{ - napi_value server_obj, emit_close; - - try { - nxt_handle_scope scope(env()); - - server_obj = get_server_object(); - - emit_close = get_named_property(server_obj, "emit_close"); - - nxt_async_context async_context(env(), "unit_quit"); - nxt_callback_scope async_scope(async_context); - - make_callback(async_context, server_obj, emit_close); - - } catch (exception &e) { - nxt_unit_debug(ctx, "quit: %s", e.str); - } - - nxt_unit_done(ctx); -} - - -napi_value -Unit::get_server_object() -{ - napi_value unit_obj; - - unit_obj = get_reference_value(wrapper_); - - return get_named_property(unit_obj, "server"); -} - - -void -Unit::create_headers(nxt_unit_request_info_t *req, napi_value request) -{ - char *p; - uint32_t i; - napi_value headers, raw_headers; - napi_status status; - nxt_unit_request_t *r; - - r = req->request; - - headers = create_object(); - - status = napi_create_array_with_length(env(), r->fields_count * 2, - &raw_headers); - if (status != napi_ok) { - throw exception("Failed to create array"); - } - - for (i = 0; i < r->fields_count; i++) { - append_header(r->fields + i, headers, raw_headers, i); - } - - set_named_property(request, "headers", headers); - set_named_property(request, "rawHeaders", raw_headers); - - // trim the "HTTP/" protocol prefix - p = (char *) nxt_unit_sptr_get(&r->version); - p += 5; - - set_named_property(request, "httpVersion", create_string_latin1(p, 3)); - set_named_property(request, "method", r->method, r->method_length); - set_named_property(request, "url", r->target, r->target_length); - - set_named_property(request, "_websocket_handshake", r->websocket_handshake); -} - - -inline char -lowcase(char c) -{ - return (c >= 'A' && c <= 'Z') ? (c | 0x20) : c; -} - - -inline void -Unit::append_header(nxt_unit_field_t *f, napi_value headers, - napi_value raw_headers, uint32_t idx) -{ - char *name; - uint8_t i; - napi_value str, vstr; - - name = (char *) nxt_unit_sptr_get(&f->name); - - str = create_string_latin1(name, f->name_length); - - for (i = 0; i < f->name_length; i++) { - name[i] = lowcase(name[i]); - } - - vstr = set_named_property(headers, name, f->value, f->value_length); - - set_element(raw_headers, idx * 2, str); - set_element(raw_headers, idx * 2 + 1, vstr); -} - - -napi_value -Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) -{ - napi_value constructor, res; - req_data_t *req_data; - nxt_unit_request_t *r; - - r = req->request; - - constructor = get_named_property(server_obj, "Socket"); - - res = new_instance(constructor); - - req_data = (req_data_t *) req->data; - req_data->sock_ref = wrap(res, req, sock_destroy); - - set_named_property(res, "remoteAddress", r->remote, r->remote_length); - set_named_property(res, "localAddress", r->local_addr, - r->local_addr_length); - - return res; -} - - -napi_value -Unit::create_request(napi_value server_obj, napi_value socket, - nxt_unit_request_info_t *req) -{ - napi_value constructor, res; - req_data_t *req_data; - - constructor = get_named_property(server_obj, "ServerRequest"); - - res = new_instance(constructor, server_obj, socket); - - req_data = (req_data_t *) req->data; - req_data->req_ref = wrap(res, req, req_destroy); - - return res; -} - - -napi_value -Unit::create_response(napi_value server_obj, napi_value request, - nxt_unit_request_info_t *req) -{ - napi_value constructor, res; - req_data_t *req_data; - - constructor = get_named_property(server_obj, "ServerResponse"); - - res = new_instance(constructor, request); - - req_data = (req_data_t *) req->data; - req_data->resp_ref = wrap(res, req, resp_destroy); - - return res; -} - - -napi_value -Unit::create_websocket_frame(napi_value server_obj, - nxt_unit_websocket_frame_t *ws) -{ - void *data; - napi_value constructor, res, buffer; - uint8_t sc[2]; - - constructor = get_named_property(server_obj, "WebSocketFrame"); - - res = new_instance(constructor); - - set_named_property(res, "fin", (bool) ws->header->fin); - set_named_property(res, "opcode", ws->header->opcode); - set_named_property(res, "length", (int64_t) ws->payload_len); - - if (ws->header->opcode == NXT_WEBSOCKET_OP_CLOSE) { - if (ws->payload_len >= 2) { - nxt_unit_websocket_read(ws, sc, 2); - - set_named_property(res, "closeStatus", - (((uint16_t) sc[0]) << 8) | sc[1]); - - } else { - set_named_property(res, "closeStatus", -1); - } - } - - buffer = create_buffer((size_t) ws->content_length, &data); - nxt_unit_websocket_read(ws, data, ws->content_length); - - set_named_property(res, "binaryPayload", buffer); - - return res; -} - - -napi_value -Unit::request_read(napi_env env, napi_callback_info info) -{ - void *data; - uint32_t wm; - nxt_napi napi(env); - napi_value this_arg, argv, buffer; - nxt_unit_request_info_t *req; - - try { - this_arg = napi.get_cb_info(info, argv); - - try { - req = napi.get_request_info(this_arg); - - } catch (exception &e) { - return nullptr; - } - - if (req->content_length == 0) { - return nullptr; - } - - wm = napi.get_value_uint32(argv); - - if (wm > req->content_length) { - wm = req->content_length; - } - - buffer = napi.create_buffer((size_t) wm, &data); - nxt_unit_request_read(req, data, wm); - - } catch (exception &e) { - napi.throw_error(e); - return nullptr; - } - - return buffer; -} - - -napi_value -Unit::response_send_headers(napi_env env, napi_callback_info info) -{ - int ret; - char *ptr, *name_ptr; - bool is_array; - size_t argc, name_len, value_len; - uint32_t status_code, header_len, keys_len, array_len; - uint32_t keys_count, i, j; - uint16_t hash; - nxt_napi napi(env); - napi_value this_arg, headers, keys, name, value, array_val; - napi_value array_entry; - napi_valuetype val_type; - nxt_unit_field_t *f; - nxt_unit_request_info_t *req; - napi_value argv[4]; - - argc = 4; - - try { - this_arg = napi.get_cb_info(info, argc, argv); - if (argc != 4) { - napi.throw_error("Wrong args count. Expected: " - "statusCode, headers, headers count, " - "headers length"); - return nullptr; - } - - req = napi.get_request_info(this_arg); - status_code = napi.get_value_uint32(argv[0]); - keys_count = napi.get_value_uint32(argv[2]); - header_len = napi.get_value_uint32(argv[3]); - - headers = argv[1]; - - ret = nxt_unit_response_init(req, status_code, keys_count, header_len); - if (ret != NXT_UNIT_OK) { - napi.throw_error("Failed to create response"); - return nullptr; - } - - /* - * Each name and value are 0-terminated by libunit. - * Need to add extra 2 bytes for each header. - */ - header_len += keys_count * 2; - - keys = napi.get_property_names(headers); - keys_len = napi.get_array_length(keys); - - ptr = req->response_buf->free; - - for (i = 0; i < keys_len; i++) { - name = napi.get_element(keys, i); - - array_entry = napi.get_property(headers, name); - - name = napi.get_element(array_entry, 0); - value = napi.get_element(array_entry, 1); - - name_len = napi.get_value_string_latin1(name, ptr, header_len); - name_ptr = ptr; - - ptr += name_len + 1; - header_len -= name_len + 1; - - hash = nxt_unit_field_hash(name_ptr, name_len); - - is_array = napi.is_array(value); - - if (is_array) { - array_len = napi.get_array_length(value); - - for (j = 0; j < array_len; j++) { - array_val = napi.get_element(value, j); - - val_type = napi.type_of(array_val); - - if (val_type != napi_string) { - array_val = napi.coerce_to_string(array_val); - } - - value_len = napi.get_value_string_latin1(array_val, ptr, - header_len); - - f = req->response->fields + req->response->fields_count; - f->skip = 0; - - nxt_unit_sptr_set(&f->name, name_ptr); - - f->name_length = name_len; - f->hash = hash; - - nxt_unit_sptr_set(&f->value, ptr); - f->value_length = (uint32_t) value_len; - - ptr += value_len + 1; - header_len -= value_len + 1; - - req->response->fields_count++; - } - - } else { - val_type = napi.type_of(value); - - if (val_type != napi_string) { - value = napi.coerce_to_string(value); - } - - value_len = napi.get_value_string_latin1(value, ptr, header_len); - - f = req->response->fields + req->response->fields_count; - f->skip = 0; - - nxt_unit_sptr_set(&f->name, name_ptr); - - f->name_length = name_len; - f->hash = hash; - - nxt_unit_sptr_set(&f->value, ptr); - f->value_length = (uint32_t) value_len; - - ptr += value_len + 1; - header_len -= value_len + 1; - - req->response->fields_count++; - } - } - - } catch (exception &e) { - napi.throw_error(e); - return nullptr; - } - - req->response_buf->free = ptr; - - ret = nxt_unit_response_send(req); - if (ret != NXT_UNIT_OK) { - napi.throw_error("Failed to send response"); - return nullptr; - } - - return this_arg; -} - - -napi_value -Unit::response_write(napi_env env, napi_callback_info info) -{ - int ret; - void *ptr; - size_t argc, have_buf_len; - ssize_t res_len; - uint32_t buf_start, buf_len; - nxt_napi napi(env); - napi_value this_arg; - nxt_unit_buf_t *buf; - napi_valuetype buf_type; - nxt_unit_request_info_t *req; - napi_value argv[3]; - - argc = 3; - - try { - this_arg = napi.get_cb_info(info, argc, argv); - if (argc != 3) { - throw exception("Wrong args count. Expected: " - "chunk, start, length"); - } - - req = napi.get_request_info(this_arg); - buf_type = napi.type_of(argv[0]); - buf_start = napi.get_value_uint32(argv[1]); - buf_len = napi.get_value_uint32(argv[2]) + 1; - - if (buf_type == napi_string) { - /* TODO: will work only for utf8 content-type */ - - if (req->response_buf != NULL - && req->response_buf->end >= req->response_buf->free + buf_len) - { - buf = req->response_buf; - - } else { - buf = nxt_unit_response_buf_alloc(req, buf_len); - if (buf == NULL) { - throw exception("Failed to allocate response buffer"); - } - } - - have_buf_len = napi.get_value_string_utf8(argv[0], buf->free, - buf_len); - - buf->free += have_buf_len; - - ret = nxt_unit_buf_send(buf); - if (ret == NXT_UNIT_OK) { - res_len = have_buf_len; - } - - } else { - ptr = napi.get_buffer_info(argv[0], have_buf_len); - - if (buf_start > 0) { - ptr = ((uint8_t *) ptr) + buf_start; - have_buf_len -= buf_start; - } - - res_len = nxt_unit_response_write_nb(req, ptr, have_buf_len, 0); - - ret = res_len < 0 ? -res_len : (int) NXT_UNIT_OK; - } - - if (ret != NXT_UNIT_OK) { - throw exception("Failed to send body buf"); - } - } catch (exception &e) { - napi.throw_error(e); - return nullptr; - } - - return napi.create((int64_t) res_len); -} - - -napi_value -Unit::response_end(napi_env env, napi_callback_info info) -{ - nxt_napi napi(env); - napi_value this_arg; - req_data_t *req_data; - nxt_unit_request_info_t *req; - - try { - this_arg = napi.get_cb_info(info); - - req = napi.get_request_info(this_arg); - - req_data = (req_data_t *) req->data; - - napi.remove_wrap(req_data->sock_ref); - napi.remove_wrap(req_data->req_ref); - napi.remove_wrap(req_data->resp_ref); - napi.remove_wrap(req_data->conn_ref); - - } catch (exception &e) { - napi.throw_error(e); - return nullptr; - } - - nxt_unit_request_done(req, NXT_UNIT_OK); - - return this_arg; -} - - -napi_value -Unit::websocket_send_frame(napi_env env, napi_callback_info info) -{ - int ret, iovec_len; - bool fin; - size_t buf_len; - uint32_t opcode, sc; - nxt_napi napi(env); - napi_value this_arg, frame, payload; - nxt_unit_request_info_t *req; - char status_code[2]; - struct iovec iov[2]; - - iovec_len = 0; - - try { - this_arg = napi.get_cb_info(info, frame); - - req = napi.get_request_info(this_arg); - - opcode = napi.get_value_uint32(napi.get_named_property(frame, - "opcode")); - if (opcode == NXT_WEBSOCKET_OP_CLOSE) { - sc = napi.get_value_uint32(napi.get_named_property(frame, - "closeStatus")); - status_code[0] = (sc >> 8) & 0xFF; - status_code[1] = sc & 0xFF; - - iov[iovec_len].iov_base = status_code; - iov[iovec_len].iov_len = 2; - iovec_len++; - } - - try { - fin = napi.get_value_bool(napi.get_named_property(frame, "fin")); - - } catch (exception &e) { - fin = true; - } - - payload = napi.get_named_property(frame, "binaryPayload"); - - if (napi.is_buffer(payload)) { - iov[iovec_len].iov_base = napi.get_buffer_info(payload, buf_len); - - } else { - buf_len = 0; - } - - } catch (exception &e) { - napi.throw_error(e); - return nullptr; - } - - if (buf_len > 0) { - iov[iovec_len].iov_len = buf_len; - iovec_len++; - } - - ret = nxt_unit_websocket_sendv(req, opcode, fin ? 1 : 0, iov, iovec_len); - if (ret != NXT_UNIT_OK) { - goto failed; - } - - return this_arg; - -failed: - - napi.throw_error("Failed to send frame"); - - return nullptr; -} - - -napi_value -Unit::websocket_set_sock(napi_env env, napi_callback_info info) -{ - nxt_napi napi(env); - napi_value this_arg, sock; - req_data_t *req_data; - nxt_unit_request_info_t *req; - - try { - this_arg = napi.get_cb_info(info, sock); - - req = napi.get_request_info(sock); - - req_data = (req_data_t *) req->data; - req_data->conn_ref = napi.wrap(this_arg, req, conn_destroy); - - } catch (exception &e) { - napi.throw_error(e); - return nullptr; - } - - return this_arg; -} - - -void -Unit::conn_destroy(napi_env env, void *r, void *finalize_hint) -{ - nxt_unit_req_debug(NULL, "conn_destroy: %p", r); -} - - -void -Unit::sock_destroy(napi_env env, void *r, void *finalize_hint) -{ - nxt_unit_req_debug(NULL, "sock_destroy: %p", r); -} - - -void -Unit::req_destroy(napi_env env, void *r, void *finalize_hint) -{ - nxt_unit_req_debug(NULL, "req_destroy: %p", r); -} - - -void -Unit::resp_destroy(napi_env env, void *r, void *finalize_hint) -{ - nxt_unit_req_debug(NULL, "resp_destroy: %p", r); -} diff --git a/src/nodejs/unit-http/unit.h b/src/nodejs/unit-http/unit.h deleted file mode 100644 index 1aa93073..00000000 --- a/src/nodejs/unit-http/unit.h +++ /dev/null @@ -1,87 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_NODEJS_UNIT_H_INCLUDED_ -#define _NXT_NODEJS_UNIT_H_INCLUDED_ - -#include "nxt_napi.h" - - -class Unit : public nxt_napi { -public: - static napi_value init(napi_env env, napi_value exports); - -private: - Unit(napi_env env, napi_value jsthis); - ~Unit(); - - static napi_value create(napi_env env, napi_callback_info info); - static void destroy(napi_env env, void *nativeObject, void *finalize_hint); - static void conn_destroy(napi_env env, void *nativeObject, void *finalize_hint); - static void sock_destroy(napi_env env, void *nativeObject, void *finalize_hint); - static void req_destroy(napi_env env, void *nativeObject, void *finalize_hint); - static void resp_destroy(napi_env env, void *nativeObject, void *finalize_hint); - - static napi_value create_server(napi_env env, napi_callback_info info); - static napi_value listen(napi_env env, napi_callback_info info); - static napi_value _read(napi_env env, napi_callback_info info); - - static void request_handler_cb(nxt_unit_request_info_t *req); - void request_handler(nxt_unit_request_info_t *req); - - static void websocket_handler_cb(nxt_unit_websocket_frame_t *ws); - void websocket_handler(nxt_unit_websocket_frame_t *ws); - - static void close_handler_cb(nxt_unit_request_info_t *req); - void close_handler(nxt_unit_request_info_t *req); - - static void shm_ack_handler_cb(nxt_unit_ctx_t *ctx); - void shm_ack_handler(nxt_unit_ctx_t *ctx); - - static int add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port); - static void remove_port(nxt_unit_t *unit, nxt_unit_ctx_t *ctx, - nxt_unit_port_t *port); - - static void quit_cb(nxt_unit_ctx_t *ctx); - void quit(nxt_unit_ctx_t *ctx); - - napi_value get_server_object(); - - napi_value create_socket(napi_value server_obj, - nxt_unit_request_info_t *req); - - napi_value create_request(napi_value server_obj, napi_value socket, - nxt_unit_request_info_t *req); - - napi_value create_response(napi_value server_obj, napi_value request, - nxt_unit_request_info_t *req); - - napi_value create_websocket_frame(napi_value server_obj, - nxt_unit_websocket_frame_t *ws); - - static napi_value request_read(napi_env env, napi_callback_info info); - - static napi_value response_send_headers(napi_env env, - napi_callback_info info); - - static napi_value response_write(napi_env env, napi_callback_info info); - static napi_value response_end(napi_env env, napi_callback_info info); - static napi_value websocket_send_frame(napi_env env, - napi_callback_info info); - static napi_value websocket_set_sock(napi_env env, napi_callback_info info); - - void create_headers(nxt_unit_request_info_t *req, napi_value request); - - void append_header(nxt_unit_field_t *f, napi_value headers, - napi_value raw_headers, uint32_t idx); - - static napi_ref constructor_; - - napi_ref wrapper_; - nxt_unit_ctx_t *unit_ctx_; -}; - - -#endif /* _NXT_NODEJS_UNIT_H_INCLUDED_ */ diff --git a/src/nodejs/unit-http/utils.js b/src/nodejs/unit-http/utils.js deleted file mode 100644 index e1e51b0e..00000000 --- a/src/nodejs/unit-http/utils.js +++ /dev/null @@ -1,73 +0,0 @@ -var noop = exports.noop = function(){}; - -exports.extend = function extend(dest, source) { - for (var prop in source) { - dest[prop] = source[prop]; - } -}; - -exports.eventEmitterListenerCount = - require('events').EventEmitter.listenerCount || - function(emitter, type) { return emitter.listeners(type).length; }; - -exports.bufferAllocUnsafe = Buffer.allocUnsafe ? - Buffer.allocUnsafe : - function oldBufferAllocUnsafe(size) { return new Buffer(size); }; - -exports.bufferFromString = Buffer.from ? - Buffer.from : - function oldBufferFromString(string, encoding) { - return new Buffer(string, encoding); - }; - -exports.BufferingLogger = function createBufferingLogger(identifier, uniqueID) { - try { - var logFunction = require('debug')(identifier); - } - catch(e) { - logFunction = noop; - logFunction.enabled = false; - } - - if (logFunction.enabled) { - var logger = new BufferingLogger(identifier, uniqueID, logFunction); - var debug = logger.log.bind(logger); - debug.printOutput = logger.printOutput.bind(logger); - debug.enabled = logFunction.enabled; - return debug; - } - logFunction.printOutput = noop; - return logFunction; -}; - -function BufferingLogger(identifier, uniqueID, logFunction) { - this.logFunction = logFunction; - this.identifier = identifier; - this.uniqueID = uniqueID; - this.buffer = []; -} - -BufferingLogger.prototype.log = function() { - this.buffer.push([ new Date(), Array.prototype.slice.call(arguments) ]); - return this; -}; - -BufferingLogger.prototype.clear = function() { - this.buffer = []; - return this; -}; - -BufferingLogger.prototype.printOutput = function(logFunction) { - if (!logFunction) { logFunction = this.logFunction; } - var uniqueID = this.uniqueID; - this.buffer.forEach(function(entry) { - var date = entry[0].toLocaleString(); - var args = entry[1].slice(); - var formatString = args[0]; - if (formatString !== (void 0) && formatString !== null) { - formatString = '%s - %s - ' + formatString.toString(); - args.splice(0, 1, formatString, date, uniqueID); - logFunction.apply(global, args); - } - }); -}; diff --git a/src/nodejs/unit-http/websocket.js b/src/nodejs/unit-http/websocket.js deleted file mode 100644 index 36d0e07a..00000000 --- a/src/nodejs/unit-http/websocket.js +++ /dev/null @@ -1,14 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -'use strict'; - -module.exports = { - 'server' : require('./websocket_server'), - 'router' : require('./websocket_router'), - 'frame' : require('./websocket_frame'), - 'request' : require('./websocket_request'), - 'connection' : require('./websocket_connection'), -}; diff --git a/src/nodejs/unit-http/websocket_connection.js b/src/nodejs/unit-http/websocket_connection.js deleted file mode 100644 index c04075d7..00000000 --- a/src/nodejs/unit-http/websocket_connection.js +++ /dev/null @@ -1,683 +0,0 @@ -/************************************************************************ - * Copyright 2010-2015 Brian McKelvey. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ***********************************************************************/ - -var util = require('util'); -var utils = require('./utils'); -var unit_lib = require('./build/Release/unit-http'); -var EventEmitter = require('events').EventEmitter; -var WebSocketFrame = require('./websocket_frame'); -var bufferAllocUnsafe = utils.bufferAllocUnsafe; -var bufferFromString = utils.bufferFromString; - -// Connected, fully-open, ready to send and receive frames -const STATE_OPEN = 'open'; -// Received a close frame from the remote peer -const STATE_PEER_REQUESTED_CLOSE = 'peer_requested_close'; -// Sent close frame to remote peer. No further data can be sent. -const STATE_ENDING = 'ending'; -// Connection is fully closed. No further data can be sent or received. -const STATE_CLOSED = 'closed'; - -var idCounter = 0; - -function WebSocketConnection(socket, extensions, protocol, maskOutgoingPackets, config) { - this._debug = utils.BufferingLogger('websocket:connection', ++idCounter); - this._debug('constructor'); - - if (this._debug.enabled) { - instrumentSocketForDebugging(this, socket); - } - - // Superclass Constructor - EventEmitter.call(this); - - this._pingListenerCount = 0; - this.on('newListener', function(ev) { - if (ev === 'ping'){ - this._pingListenerCount++; - } - }).on('removeListener', function(ev) { - if (ev === 'ping') { - this._pingListenerCount--; - } - }); - - this.config = config; - this.socket = socket; - this.protocol = protocol; - this.extensions = extensions; - this.remoteAddress = socket.remoteAddress; - this.closeReasonCode = -1; - this.closeDescription = null; - this.closeEventEmitted = false; - - // We have to mask outgoing packets if we're acting as a WebSocket client. - this.maskOutgoingPackets = maskOutgoingPackets; - - this.fragmentationSize = 0; // data received so far... - this.frameQueue = []; - - // Various bits of connection state - this.connected = true; - this.state = STATE_OPEN; - this.waitingForCloseResponse = false; - // Received TCP FIN, socket's readable stream is finished. - this.receivedEnd = false; - - this.closeTimeout = this.config.closeTimeout; - this.assembleFragments = this.config.assembleFragments; - this.maxReceivedMessageSize = this.config.maxReceivedMessageSize; - - this.outputBufferFull = false; - this.inputPaused = false; - this._closeTimerHandler = this.handleCloseTimer.bind(this); - - // Disable nagle algorithm? - this.socket.setNoDelay(this.config.disableNagleAlgorithm); - - // Make sure there is no socket inactivity timeout - this.socket.setTimeout(0); - - // The HTTP Client seems to subscribe to socket error events - // and re-dispatch them in such a way that doesn't make sense - // for users of our client, so we want to make sure nobody - // else is listening for error events on the socket besides us. - this.socket.removeAllListeners('error'); - - this._set_sock(this.socket); -} - -WebSocketConnection.prototype._set_sock = unit_lib.websocket_set_sock; -WebSocketConnection.prototype._end = unit_lib.response_end; - -WebSocketConnection.CLOSE_REASON_NORMAL = 1000; -WebSocketConnection.CLOSE_REASON_GOING_AWAY = 1001; -WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR = 1002; -WebSocketConnection.CLOSE_REASON_UNPROCESSABLE_INPUT = 1003; -WebSocketConnection.CLOSE_REASON_RESERVED = 1004; // Reserved value. Undefined meaning. -WebSocketConnection.CLOSE_REASON_NOT_PROVIDED = 1005; // Not to be used on the wire -WebSocketConnection.CLOSE_REASON_ABNORMAL = 1006; // Not to be used on the wire -WebSocketConnection.CLOSE_REASON_INVALID_DATA = 1007; -WebSocketConnection.CLOSE_REASON_POLICY_VIOLATION = 1008; -WebSocketConnection.CLOSE_REASON_MESSAGE_TOO_BIG = 1009; -WebSocketConnection.CLOSE_REASON_EXTENSION_REQUIRED = 1010; -WebSocketConnection.CLOSE_REASON_INTERNAL_SERVER_ERROR = 1011; -WebSocketConnection.CLOSE_REASON_TLS_HANDSHAKE_FAILED = 1015; // Not to be used on the wire - -WebSocketConnection.CLOSE_DESCRIPTIONS = { - 1000: 'Normal connection closure', - 1001: 'Remote peer is going away', - 1002: 'Protocol error', - 1003: 'Unprocessable input', - 1004: 'Reserved', - 1005: 'Reason not provided', - 1006: 'Abnormal closure, no further detail available', - 1007: 'Invalid data received', - 1008: 'Policy violation', - 1009: 'Message too big', - 1010: 'Extension requested by client is required', - 1011: 'Internal Server Error', - 1015: 'TLS Handshake Failed' -}; - -function validateCloseReason(code) { - if (code < 1000) { - // Status codes in the range 0-999 are not used - return false; - } - if (code >= 1000 && code <= 2999) { - // Codes from 1000 - 2999 are reserved for use by the protocol. Only - // a few codes are defined, all others are currently illegal. - return [1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014].indexOf(code) !== -1; - } - if (code >= 3000 && code <= 3999) { - // Reserved for use by libraries, frameworks, and applications. - // Should be registered with IANA. Interpretation of these codes is - // undefined by the WebSocket protocol. - return true; - } - if (code >= 4000 && code <= 4999) { - // Reserved for private use. Interpretation of these codes is - // undefined by the WebSocket protocol. - return true; - } - if (code >= 5000) { - return false; - } -} - -util.inherits(WebSocketConnection, EventEmitter); - -WebSocketConnection.prototype._addSocketEventListeners = function() { - this.socket.on('error', this.handleSocketError.bind(this)); - this.socket.on('end', this.handleSocketEnd.bind(this)); - this.socket.on('close', this.handleSocketClose.bind(this)); -}; - -WebSocketConnection.prototype.handleSocketError = function(error) { - this._debug('handleSocketError: %j', error); - if (this.state === STATE_CLOSED) { - // See https://github.com/theturtle32/WebSocket-Node/issues/288 - this._debug(' --- Socket \'error\' after \'close\''); - return; - } - this.closeReasonCode = WebSocketConnection.CLOSE_REASON_ABNORMAL; - this.closeDescription = 'Socket Error: ' + error.syscall + ' ' + error.code; - this.connected = false; - this.state = STATE_CLOSED; - this.fragmentationSize = 0; - if (utils.eventEmitterListenerCount(this, 'error') > 0) { - this.emit('error', error); - } - this.socket.destroy(error); - this._debug.printOutput(); - - this._end(); -}; - -WebSocketConnection.prototype.handleSocketEnd = function() { - this._debug('handleSocketEnd: received socket end. state = %s', this.state); - this.receivedEnd = true; - if (this.state === STATE_CLOSED) { - // When using the TLS module, sometimes the socket will emit 'end' - // after it emits 'close'. I don't think that's correct behavior, - // but we should deal with it gracefully by ignoring it. - this._debug(' --- Socket \'end\' after \'close\''); - return; - } - if (this.state !== STATE_PEER_REQUESTED_CLOSE && - this.state !== STATE_ENDING) { - this._debug(' --- UNEXPECTED socket end.'); - this.socket.end(); - - this._end(); - } -}; - -WebSocketConnection.prototype.handleSocketClose = function(hadError) { - this._debug('handleSocketClose: received socket close'); - this.socketHadError = hadError; - this.connected = false; - this.state = STATE_CLOSED; - // If closeReasonCode is still set to -1 at this point then we must - // not have received a close frame!! - if (this.closeReasonCode === -1) { - this.closeReasonCode = WebSocketConnection.CLOSE_REASON_ABNORMAL; - this.closeDescription = 'Connection dropped by remote peer.'; - } - this.clearCloseTimer(); - if (!this.closeEventEmitted) { - this.closeEventEmitted = true; - this._debug('-- Emitting WebSocketConnection close event'); - this.emit('close', this.closeReasonCode, this.closeDescription); - } -}; - -WebSocketConnection.prototype.close = function(reasonCode, description) { - if (this.connected) { - this._debug('close: Initating clean WebSocket close sequence.'); - if ('number' !== typeof reasonCode) { - reasonCode = WebSocketConnection.CLOSE_REASON_NORMAL; - } - if (!validateCloseReason(reasonCode)) { - throw new Error('Close code ' + reasonCode + ' is not valid.'); - } - if ('string' !== typeof description) { - description = WebSocketConnection.CLOSE_DESCRIPTIONS[reasonCode]; - } - this.closeReasonCode = reasonCode; - this.closeDescription = description; - this.setCloseTimer(); - this.sendCloseFrame(this.closeReasonCode, this.closeDescription); - this.state = STATE_ENDING; - this.connected = false; - } -}; - -WebSocketConnection.prototype.drop = function(reasonCode, description, skipCloseFrame) { - this._debug('drop'); - if (typeof(reasonCode) !== 'number') { - reasonCode = WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR; - } - - if (typeof(description) !== 'string') { - // If no description is provided, try to look one up based on the - // specified reasonCode. - description = WebSocketConnection.CLOSE_DESCRIPTIONS[reasonCode]; - } - - this._debug('Forcefully dropping connection. skipCloseFrame: %s, code: %d, description: %s', - skipCloseFrame, reasonCode, description - ); - - this.closeReasonCode = reasonCode; - this.closeDescription = description; - this.frameQueue = []; - this.fragmentationSize = 0; - if (!skipCloseFrame) { - this.sendCloseFrame(reasonCode, description); - } - this.connected = false; - this.state = STATE_CLOSED; - this.clearCloseTimer(); - - if (!this.closeEventEmitted) { - this.closeEventEmitted = true; - this._debug('Emitting WebSocketConnection close event'); - this.emit('close', this.closeReasonCode, this.closeDescription); - } - - this._debug('Drop: destroying socket'); - this.socket.destroy(); - - this._end(); -}; - -WebSocketConnection.prototype.setCloseTimer = function() { - this._debug('setCloseTimer'); - this.clearCloseTimer(); - this._debug('Setting close timer'); - this.waitingForCloseResponse = true; - this.closeTimer = setTimeout(this._closeTimerHandler, this.closeTimeout); -}; - -WebSocketConnection.prototype.clearCloseTimer = function() { - this._debug('clearCloseTimer'); - if (this.closeTimer) { - this._debug('Clearing close timer'); - clearTimeout(this.closeTimer); - this.waitingForCloseResponse = false; - this.closeTimer = null; - } -}; - -WebSocketConnection.prototype.handleCloseTimer = function() { - this._debug('handleCloseTimer'); - this.closeTimer = null; - if (this.waitingForCloseResponse) { - this._debug('Close response not received from client. Forcing socket end.'); - this.waitingForCloseResponse = false; - this.state = STATE_CLOSED; - this.socket.end(); - - this._end(); - } -}; - -WebSocketConnection.prototype.processFrame = function(frame) { - if (!this.connected) { - return; - } - - this._debug('processFrame'); - this._debug(' -- frame: %s', frame); - - // Any non-control opcode besides 0x00 (continuation) received in the - // middle of a fragmented message is illegal. - if (this.frameQueue.length !== 0 && (frame.opcode > 0x00 && frame.opcode < 0x08)) { - this.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR, - 'Illegal frame opcode 0x' + frame.opcode.toString(16) + ' ' + - 'received in middle of fragmented message.'); - return; - } - - switch(frame.opcode) { - case 0x02: // WebSocketFrame.BINARY_FRAME - this._debug('-- Binary Frame'); - if (this.assembleFragments) { - if (frame.fin) { - // Complete single-frame message received - this._debug('---- Emitting \'message\' event'); - this.emit('message', { - type: 'binary', - binaryData: frame.binaryPayload - }); - } - else { - // beginning of a fragmented message - this.frameQueue.push(frame); - this.fragmentationSize = frame.length; - } - } - break; - case 0x01: // WebSocketFrame.TEXT_FRAME - this._debug('-- Text Frame'); - if (this.assembleFragments) { - if (frame.fin) { - // Complete single-frame message received - this._debug('---- Emitting \'message\' event'); - this.emit('message', { - type: 'utf8', - utf8Data: frame.binaryPayload.toString('utf8') - }); - } - else { - // beginning of a fragmented message - this.frameQueue.push(frame); - this.fragmentationSize = frame.length; - } - } - break; - case 0x00: // WebSocketFrame.CONTINUATION - this._debug('-- Continuation Frame'); - if (this.assembleFragments) { - if (this.frameQueue.length === 0) { - this.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR, - 'Unexpected Continuation Frame'); - return; - } - - this.fragmentationSize += frame.length; - - if (this.fragmentationSize > this.maxReceivedMessageSize) { - this.drop(WebSocketConnection.CLOSE_REASON_MESSAGE_TOO_BIG, - 'Maximum message size exceeded.'); - return; - } - - this.frameQueue.push(frame); - - if (frame.fin) { - // end of fragmented message, so we process the whole - // message now. We also have to decode the utf-8 data - // for text frames after combining all the fragments. - var bytesCopied = 0; - var binaryPayload = bufferAllocUnsafe(this.fragmentationSize); - var opcode = this.frameQueue[0].opcode; - this.frameQueue.forEach(function (currentFrame) { - currentFrame.binaryPayload.copy(binaryPayload, bytesCopied); - bytesCopied += currentFrame.binaryPayload.length; - }); - this.frameQueue = []; - this.fragmentationSize = 0; - - switch (opcode) { - case 0x02: // WebSocketOpcode.BINARY_FRAME - this.emit('message', { - type: 'binary', - binaryData: binaryPayload - }); - break; - case 0x01: // WebSocketOpcode.TEXT_FRAME - this.emit('message', { - type: 'utf8', - utf8Data: binaryPayload.toString('utf8') - }); - break; - default: - this.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR, - 'Unexpected first opcode in fragmentation sequence: 0x' + opcode.toString(16)); - return; - } - } - } - break; - case 0x09: // WebSocketFrame.PING - this._debug('-- Ping Frame'); - - if (this._pingListenerCount > 0) { - // logic to emit the ping frame: this is only done when a listener is known to exist - // Expose a function allowing the user to override the default ping() behavior - var cancelled = false; - var cancel = function() { - cancelled = true; - }; - this.emit('ping', cancel, frame.binaryPayload); - - // Only send a pong if the client did not indicate that he would like to cancel - if (!cancelled) { - this.pong(frame.binaryPayload); - } - } - else { - this.pong(frame.binaryPayload); - } - - break; - case 0x0A: // WebSocketFrame.PONG - this._debug('-- Pong Frame'); - this.emit('pong', frame.binaryPayload); - break; - case 0x08: // WebSocketFrame.CONNECTION_CLOSE - this._debug('-- Close Frame'); - if (this.waitingForCloseResponse) { - // Got response to our request to close the connection. - // Close is complete, so we just hang up. - this._debug('---- Got close response from peer. Completing closing handshake.'); - this.clearCloseTimer(); - this.waitingForCloseResponse = false; - this.state = STATE_CLOSED; - this.socket.end(); - - this._end(); - return; - } - - this._debug('---- Closing handshake initiated by peer.'); - // Got request from other party to close connection. - // Send back acknowledgement and then hang up. - this.state = STATE_PEER_REQUESTED_CLOSE; - var respondCloseReasonCode; - - // Make sure the close reason provided is legal according to - // the protocol spec. Providing no close status is legal. - // WebSocketFrame sets closeStatus to -1 by default, so if it - // is still -1, then no status was provided. - if (frame.invalidCloseFrameLength) { - this.closeReasonCode = 1005; // 1005 = No reason provided. - respondCloseReasonCode = WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR; - } - else if (frame.closeStatus === -1 || validateCloseReason(frame.closeStatus)) { - this.closeReasonCode = frame.closeStatus; - respondCloseReasonCode = WebSocketConnection.CLOSE_REASON_NORMAL; - } - else { - this.closeReasonCode = frame.closeStatus; - respondCloseReasonCode = WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR; - } - - // If there is a textual description in the close frame, extract it. - if (frame.binaryPayload.length > 1) { - this.closeDescription = frame.binaryPayload.toString('utf8'); - } - else { - this.closeDescription = WebSocketConnection.CLOSE_DESCRIPTIONS[this.closeReasonCode]; - } - this._debug( - '------ Remote peer %s - code: %d - %s - close frame payload length: %d', - this.remoteAddress, this.closeReasonCode, - this.closeDescription, frame.length - ); - this._debug('------ responding to remote peer\'s close request.'); - this.drop(respondCloseReasonCode, null); - this.connected = false; - break; - default: - this._debug('-- Unrecognized Opcode %d', frame.opcode); - this.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR, - 'Unrecognized Opcode: 0x' + frame.opcode.toString(16)); - break; - } -}; - -WebSocketConnection.prototype.send = function(data, cb) { - this._debug('send'); - if (Buffer.isBuffer(data)) { - this.sendBytes(data, cb); - } - else if (typeof(data['toString']) === 'function') { - this.sendUTF(data, cb); - } - else { - throw new Error('Data provided must either be a Node Buffer or implement toString()'); - } -}; - -WebSocketConnection.prototype.sendUTF = function(data, cb) { - data = bufferFromString(data.toString(), 'utf8'); - this._debug('sendUTF: %d bytes', data.length); - - var frame = new WebSocketFrame(); - frame.opcode = 0x01; // WebSocketOpcode.TEXT_FRAME - frame.binaryPayload = data; - - this.fragmentAndSend(frame, cb); -}; - -WebSocketConnection.prototype.sendBytes = function(data, cb) { - this._debug('sendBytes'); - if (!Buffer.isBuffer(data)) { - throw new Error('You must pass a Node Buffer object to WebSocketConnection.prototype.sendBytes()'); - } - - var frame = new WebSocketFrame(); - frame.opcode = 0x02; // WebSocketOpcode.BINARY_FRAME - frame.binaryPayload = data; - - this.fragmentAndSend(frame, cb); -}; - -WebSocketConnection.prototype.ping = function(data) { - this._debug('ping'); - - var frame = new WebSocketFrame(); - frame.opcode = 0x09; // WebSocketOpcode.PING - frame.fin = true; - - if (data) { - if (!Buffer.isBuffer(data)) { - data = bufferFromString(data.toString(), 'utf8'); - } - if (data.length > 125) { - this._debug('WebSocket: Data for ping is longer than 125 bytes. Truncating.'); - data = data.slice(0,124); - } - frame.binaryPayload = data; - } - - this.sendFrame(frame); -}; - -// Pong frames have to echo back the contents of the data portion of the -// ping frame exactly, byte for byte. -WebSocketConnection.prototype.pong = function(binaryPayload) { - this._debug('pong'); - - var frame = new WebSocketFrame(); - frame.opcode = 0x0A; // WebSocketOpcode.PONG - if (Buffer.isBuffer(binaryPayload) && binaryPayload.length > 125) { - this._debug('WebSocket: Data for pong is longer than 125 bytes. Truncating.'); - binaryPayload = binaryPayload.slice(0,124); - } - frame.binaryPayload = binaryPayload; - frame.fin = true; - - this.sendFrame(frame); -}; - -WebSocketConnection.prototype.fragmentAndSend = function(frame, cb) { - this._debug('fragmentAndSend'); - if (frame.opcode > 0x07) { - throw new Error('You cannot fragment control frames.'); - } - - var threshold = this.config.fragmentationThreshold; - var length = frame.binaryPayload.length; - - // Send immediately if fragmentation is disabled or the message is not - // larger than the fragmentation threshold. - if (!this.config.fragmentOutgoingMessages || (frame.binaryPayload && length <= threshold)) { - frame.fin = true; - this.sendFrame(frame, cb); - return; - } - - var numFragments = Math.ceil(length / threshold); - var sentFragments = 0; - var sentCallback = function fragmentSentCallback(err) { - if (err) { - if (typeof cb === 'function') { - // pass only the first error - cb(err); - cb = null; - } - return; - } - ++sentFragments; - if ((sentFragments === numFragments) && (typeof cb === 'function')) { - cb(); - } - }; - for (var i=1; i <= numFragments; i++) { - var currentFrame = new WebSocketFrame(); - - // continuation opcode except for first frame. - currentFrame.opcode = (i === 1) ? frame.opcode : 0x00; - - // fin set on last frame only - currentFrame.fin = (i === numFragments); - - // length is likely to be shorter on the last fragment - var currentLength = (i === numFragments) ? length - (threshold * (i-1)) : threshold; - var sliceStart = threshold * (i-1); - - // Slice the right portion of the original payload - currentFrame.binaryPayload = frame.binaryPayload.slice(sliceStart, sliceStart + currentLength); - - this.sendFrame(currentFrame, sentCallback); - } -}; - -WebSocketConnection.prototype.sendCloseFrame = function(reasonCode, description, cb) { - if (typeof(reasonCode) !== 'number') { - reasonCode = WebSocketConnection.CLOSE_REASON_NORMAL; - } - - this._debug('sendCloseFrame state: %s, reasonCode: %d, description: %s', this.state, reasonCode, description); - - if (this.state !== STATE_OPEN && this.state !== STATE_PEER_REQUESTED_CLOSE) { return; } - - var frame = new WebSocketFrame(); - frame.fin = true; - frame.opcode = 0x08; // WebSocketOpcode.CONNECTION_CLOSE - frame.closeStatus = reasonCode; - if (typeof(description) === 'string') { - frame.binaryPayload = bufferFromString(description, 'utf8'); - } - - this.sendFrame(frame, cb); - this.socket.end(); -}; - -WebSocketConnection.prototype._send_frame = unit_lib.websocket_send_frame; - -WebSocketConnection.prototype.sendFrame = function(frame, cb) { - this._debug('sendFrame'); - - frame.mask = this.maskOutgoingPackets; - - this._send_frame(frame); - - if (typeof cb === 'function') { - cb(); - } - - var flushed = 0; // this.socket.write(frame.toBuffer(), cb); - this.outputBufferFull = !flushed; - return flushed; -}; - -module.exports = WebSocketConnection; diff --git a/src/nodejs/unit-http/websocket_frame.js b/src/nodejs/unit-http/websocket_frame.js deleted file mode 100644 index 9989937d..00000000 --- a/src/nodejs/unit-http/websocket_frame.js +++ /dev/null @@ -1,11 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -'use strict'; - -function WebSocketFrame() { -} - -module.exports = WebSocketFrame; diff --git a/src/nodejs/unit-http/websocket_request.js b/src/nodejs/unit-http/websocket_request.js deleted file mode 100644 index 450ab629..00000000 --- a/src/nodejs/unit-http/websocket_request.js +++ /dev/null @@ -1,509 +0,0 @@ -/************************************************************************ - * Copyright 2010-2015 Brian McKelvey. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ***********************************************************************/ - -var util = require('util'); -var url = require('url'); -var EventEmitter = require('events').EventEmitter; -var WebSocketConnection = require('./websocket_connection'); - -var headerValueSplitRegExp = /,\s*/; -var headerParamSplitRegExp = /;\s*/; -var headerSanitizeRegExp = /[\r\n]/g; -var xForwardedForSeparatorRegExp = /,\s*/; -var separators = [ - '(', ')', '<', '>', '@', - ',', ';', ':', '\\', '\"', - '/', '[', ']', '?', '=', - '{', '}', ' ', String.fromCharCode(9) -]; -var controlChars = [String.fromCharCode(127) /* DEL */]; -for (var i=0; i < 31; i ++) { - /* US-ASCII Control Characters */ - controlChars.push(String.fromCharCode(i)); -} - -var cookieNameValidateRegEx = /([\x00-\x20\x22\x28\x29\x2c\x2f\x3a-\x3f\x40\x5b-\x5e\x7b\x7d\x7f])/; -var cookieValueValidateRegEx = /[^\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]/; -var cookieValueDQuoteValidateRegEx = /^"[^"]*"$/; -var controlCharsAndSemicolonRegEx = /[\x00-\x20\x3b]/g; - -var cookieSeparatorRegEx = /[;,] */; - -var httpStatusDescriptions = { - 100: 'Continue', - 101: 'Switching Protocols', - 200: 'OK', - 201: 'Created', - 203: 'Non-Authoritative Information', - 204: 'No Content', - 205: 'Reset Content', - 206: 'Partial Content', - 300: 'Multiple Choices', - 301: 'Moved Permanently', - 302: 'Found', - 303: 'See Other', - 304: 'Not Modified', - 305: 'Use Proxy', - 307: 'Temporary Redirect', - 400: 'Bad Request', - 401: 'Unauthorized', - 402: 'Payment Required', - 403: 'Forbidden', - 404: 'Not Found', - 406: 'Not Acceptable', - 407: 'Proxy Authorization Required', - 408: 'Request Timeout', - 409: 'Conflict', - 410: 'Gone', - 411: 'Length Required', - 412: 'Precondition Failed', - 413: 'Request Entity Too Long', - 414: 'Request-URI Too Long', - 415: 'Unsupported Media Type', - 416: 'Requested Range Not Satisfiable', - 417: 'Expectation Failed', - 426: 'Upgrade Required', - 500: 'Internal Server Error', - 501: 'Not Implemented', - 502: 'Bad Gateway', - 503: 'Service Unavailable', - 504: 'Gateway Timeout', - 505: 'HTTP Version Not Supported' -}; - -function WebSocketRequest(socket, httpRequest, serverConfig) { - // Superclass Constructor - EventEmitter.call(this); - - this.socket = socket; - this.httpRequest = httpRequest; - this.resource = httpRequest.url; - this.remoteAddress = socket.remoteAddress; - this.remoteAddresses = [this.remoteAddress]; - this.serverConfig = serverConfig; - - // Watch for the underlying TCP socket closing before we call accept - this._socketIsClosing = false; - this._socketCloseHandler = this._handleSocketCloseBeforeAccept.bind(this); - this.socket.on('end', this._socketCloseHandler); - this.socket.on('close', this._socketCloseHandler); - - this._resolved = false; -} - -util.inherits(WebSocketRequest, EventEmitter); - -WebSocketRequest.prototype.readHandshake = function() { - var self = this; - var request = this.httpRequest; - - // Decode URL - this.resourceURL = url.parse(this.resource, true); - - this.host = request.headers['host']; - if (!this.host) { - throw new Error('Client must provide a Host header.'); - } - - this.key = request.headers['sec-websocket-key']; - if (!this.key) { - throw new Error('Client must provide a value for Sec-WebSocket-Key.'); - } - - this.webSocketVersion = parseInt(request.headers['sec-websocket-version'], 10); - - if (!this.webSocketVersion || isNaN(this.webSocketVersion)) { - throw new Error('Client must provide a value for Sec-WebSocket-Version.'); - } - - switch (this.webSocketVersion) { - case 8: - case 13: - break; - default: - var e = new Error('Unsupported websocket client version: ' + this.webSocketVersion + - 'Only versions 8 and 13 are supported.'); - e.httpCode = 426; - e.headers = { - 'Sec-WebSocket-Version': '13' - }; - throw e; - } - - if (this.webSocketVersion === 13) { - this.origin = request.headers['origin']; - } - else if (this.webSocketVersion === 8) { - this.origin = request.headers['sec-websocket-origin']; - } - - // Protocol is optional. - var protocolString = request.headers['sec-websocket-protocol']; - this.protocolFullCaseMap = {}; - this.requestedProtocols = []; - if (protocolString) { - var requestedProtocolsFullCase = protocolString.split(headerValueSplitRegExp); - requestedProtocolsFullCase.forEach(function(protocol) { - var lcProtocol = protocol.toLocaleLowerCase(); - self.requestedProtocols.push(lcProtocol); - self.protocolFullCaseMap[lcProtocol] = protocol; - }); - } - - if (!this.serverConfig.ignoreXForwardedFor && - request.headers['x-forwarded-for']) { - var immediatePeerIP = this.remoteAddress; - this.remoteAddresses = request.headers['x-forwarded-for'] - .split(xForwardedForSeparatorRegExp); - this.remoteAddresses.push(immediatePeerIP); - this.remoteAddress = this.remoteAddresses[0]; - } - - // Extensions are optional. - var extensionsString = request.headers['sec-websocket-extensions']; - this.requestedExtensions = this.parseExtensions(extensionsString); - - // Cookies are optional - var cookieString = request.headers['cookie']; - this.cookies = this.parseCookies(cookieString); -}; - -WebSocketRequest.prototype.parseExtensions = function(extensionsString) { - if (!extensionsString || extensionsString.length === 0) { - return []; - } - var extensions = extensionsString.toLocaleLowerCase().split(headerValueSplitRegExp); - extensions.forEach(function(extension, index, array) { - var params = extension.split(headerParamSplitRegExp); - var extensionName = params[0]; - var extensionParams = params.slice(1); - extensionParams.forEach(function(rawParam, index, array) { - var arr = rawParam.split('='); - var obj = { - name: arr[0], - value: arr[1] - }; - array.splice(index, 1, obj); - }); - var obj = { - name: extensionName, - params: extensionParams - }; - array.splice(index, 1, obj); - }); - return extensions; -}; - -// This function adapted from node-cookie -// https://github.com/shtylman/node-cookie -WebSocketRequest.prototype.parseCookies = function(str) { - // Sanity Check - if (!str || typeof(str) !== 'string') { - return []; - } - - var cookies = []; - var pairs = str.split(cookieSeparatorRegEx); - - pairs.forEach(function(pair) { - var eq_idx = pair.indexOf('='); - if (eq_idx === -1) { - cookies.push({ - name: pair, - value: null - }); - return; - } - - var key = pair.substr(0, eq_idx).trim(); - var val = pair.substr(++eq_idx, pair.length).trim(); - - // quoted values - if ('"' === val[0]) { - val = val.slice(1, -1); - } - - cookies.push({ - name: key, - value: decodeURIComponent(val) - }); - }); - - return cookies; -}; - -WebSocketRequest.prototype.accept = function(acceptedProtocol, allowedOrigin, cookies) { - this._verifyResolution(); - - // TODO: Handle extensions - - var protocolFullCase; - - if (acceptedProtocol) { - protocolFullCase = this.protocolFullCaseMap[acceptedProtocol.toLocaleLowerCase()]; - if (typeof(protocolFullCase) === 'undefined') { - protocolFullCase = acceptedProtocol; - } - } - else { - protocolFullCase = acceptedProtocol; - } - this.protocolFullCaseMap = null; - - var response = this.httpRequest._response; - response.statusCode = 101; - - if (protocolFullCase) { - // validate protocol - for (var i=0; i < protocolFullCase.length; i++) { - var charCode = protocolFullCase.charCodeAt(i); - var character = protocolFullCase.charAt(i); - if (charCode < 0x21 || charCode > 0x7E || separators.indexOf(character) !== -1) { - this.reject(500); - throw new Error('Illegal character "' + String.fromCharCode(character) + '" in subprotocol.'); - } - } - if (this.requestedProtocols.indexOf(acceptedProtocol) === -1) { - this.reject(500); - throw new Error('Specified protocol was not requested by the client.'); - } - - protocolFullCase = protocolFullCase.replace(headerSanitizeRegExp, ''); - response += 'Sec-WebSocket-Protocol: ' + protocolFullCase + '\r\n'; - } - this.requestedProtocols = null; - - if (allowedOrigin) { - allowedOrigin = allowedOrigin.replace(headerSanitizeRegExp, ''); - if (this.webSocketVersion === 13) { - response.setHeader('Origin', allowedOrigin); - } - else if (this.webSocketVersion === 8) { - response.setHeader('Sec-WebSocket-Origin', allowedOrigin); - } - } - - if (cookies) { - if (!Array.isArray(cookies)) { - this.reject(500); - throw new Error('Value supplied for "cookies" argument must be an array.'); - } - var seenCookies = {}; - cookies.forEach(function(cookie) { - if (!cookie.name || !cookie.value) { - this.reject(500); - throw new Error('Each cookie to set must at least provide a "name" and "value"'); - } - - // Make sure there are no \r\n sequences inserted - cookie.name = cookie.name.replace(controlCharsAndSemicolonRegEx, ''); - cookie.value = cookie.value.replace(controlCharsAndSemicolonRegEx, ''); - - if (seenCookies[cookie.name]) { - this.reject(500); - throw new Error('You may not specify the same cookie name twice.'); - } - seenCookies[cookie.name] = true; - - // token (RFC 2616, Section 2.2) - var invalidChar = cookie.name.match(cookieNameValidateRegEx); - if (invalidChar) { - this.reject(500); - throw new Error('Illegal character ' + invalidChar[0] + ' in cookie name'); - } - - // RFC 6265, Section 4.1.1 - // *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) | %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E - if (cookie.value.match(cookieValueDQuoteValidateRegEx)) { - invalidChar = cookie.value.slice(1, -1).match(cookieValueValidateRegEx); - } else { - invalidChar = cookie.value.match(cookieValueValidateRegEx); - } - if (invalidChar) { - this.reject(500); - throw new Error('Illegal character ' + invalidChar[0] + ' in cookie value'); - } - - var cookieParts = [cookie.name + '=' + cookie.value]; - - // RFC 6265, Section 4.1.1 - // 'Path=' path-value | - if(cookie.path){ - invalidChar = cookie.path.match(controlCharsAndSemicolonRegEx); - if (invalidChar) { - this.reject(500); - throw new Error('Illegal character ' + invalidChar[0] + ' in cookie path'); - } - cookieParts.push('Path=' + cookie.path); - } - - // RFC 6265, Section 4.1.2.3 - // 'Domain=' subdomain - if (cookie.domain) { - if (typeof(cookie.domain) !== 'string') { - this.reject(500); - throw new Error('Domain must be specified and must be a string.'); - } - invalidChar = cookie.domain.match(controlCharsAndSemicolonRegEx); - if (invalidChar) { - this.reject(500); - throw new Error('Illegal character ' + invalidChar[0] + ' in cookie domain'); - } - cookieParts.push('Domain=' + cookie.domain.toLowerCase()); - } - - // RFC 6265, Section 4.1.1 - //'Expires=' sane-cookie-date | Force Date object requirement by using only epoch - if (cookie.expires) { - if (!(cookie.expires instanceof Date)){ - this.reject(500); - throw new Error('Value supplied for cookie "expires" must be a vaild date object'); - } - cookieParts.push('Expires=' + cookie.expires.toGMTString()); - } - - // RFC 6265, Section 4.1.1 - //'Max-Age=' non-zero-digit *DIGIT - if (cookie.maxage) { - var maxage = cookie.maxage; - if (typeof(maxage) === 'string') { - maxage = parseInt(maxage, 10); - } - if (isNaN(maxage) || maxage <= 0 ) { - this.reject(500); - throw new Error('Value supplied for cookie "maxage" must be a non-zero number'); - } - maxage = Math.round(maxage); - cookieParts.push('Max-Age=' + maxage.toString(10)); - } - - // RFC 6265, Section 4.1.1 - //'Secure;' - if (cookie.secure) { - if (typeof(cookie.secure) !== 'boolean') { - this.reject(500); - throw new Error('Value supplied for cookie "secure" must be of type boolean'); - } - cookieParts.push('Secure'); - } - - // RFC 6265, Section 4.1.1 - //'HttpOnly;' - if (cookie.httponly) { - if (typeof(cookie.httponly) !== 'boolean') { - this.reject(500); - throw new Error('Value supplied for cookie "httponly" must be of type boolean'); - } - cookieParts.push('HttpOnly'); - } - - response.addHeader('Set-Cookie', cookieParts.join(';')); - }.bind(this)); - } - - // TODO: handle negotiated extensions - // if (negotiatedExtensions) { - // response += 'Sec-WebSocket-Extensions: ' + negotiatedExtensions.join(', ') + '\r\n'; - // } - - // Mark the request resolved now so that the user can't call accept or - // reject a second time. - this._resolved = true; - this.emit('requestResolved', this); - - var connection = new WebSocketConnection(this.socket, [], acceptedProtocol, false, this.serverConfig); - connection.webSocketVersion = this.webSocketVersion; - connection.remoteAddress = this.remoteAddress; - connection.remoteAddresses = this.remoteAddresses; - - var self = this; - - if (this._socketIsClosing) { - // Handle case when the client hangs up before we get a chance to - // accept the connection and send our side of the opening handshake. - cleanupFailedConnection(connection); - - } else { - response._sendHeaders(); - connection._addSocketEventListeners(); - } - - this.emit('requestAccepted', connection); - return connection; -}; - -WebSocketRequest.prototype.reject = function(status, reason, extraHeaders) { - this._verifyResolution(); - - // Mark the request resolved now so that the user can't call accept or - // reject a second time. - this._resolved = true; - this.emit('requestResolved', this); - - if (typeof(status) !== 'number') { - status = 403; - } - - var response = this.httpRequest._response; - - response.statusCode = status; - - if (reason) { - reason = reason.replace(headerSanitizeRegExp, ''); - response.addHeader('X-WebSocket-Reject-Reason', reason); - } - - if (extraHeaders) { - for (var key in extraHeaders) { - var sanitizedValue = extraHeaders[key].toString().replace(headerSanitizeRegExp, ''); - var sanitizedKey = key.replace(headerSanitizeRegExp, ''); - response += (sanitizedKey + ': ' + sanitizedValue + '\r\n'); - } - } - - response.end(); - - this.emit('requestRejected', this); -}; - -WebSocketRequest.prototype._handleSocketCloseBeforeAccept = function() { - this._socketIsClosing = true; - this._removeSocketCloseListeners(); -}; - -WebSocketRequest.prototype._removeSocketCloseListeners = function() { - this.socket.removeListener('end', this._socketCloseHandler); - this.socket.removeListener('close', this._socketCloseHandler); -}; - -WebSocketRequest.prototype._verifyResolution = function() { - if (this._resolved) { - throw new Error('WebSocketRequest may only be accepted or rejected one time.'); - } -}; - -function cleanupFailedConnection(connection) { - // Since we have to return a connection object even if the socket is - // already dead in order not to break the API, we schedule a 'close' - // event on the connection object to occur immediately. - process.nextTick(function() { - // WebSocketConnection.CLOSE_REASON_ABNORMAL = 1006 - // Third param: Skip sending the close frame to a dead socket - connection.drop(1006, 'TCP connection lost before handshake completed.', true); - }); -} - -module.exports = WebSocketRequest; diff --git a/src/nodejs/unit-http/websocket_router.js b/src/nodejs/unit-http/websocket_router.js deleted file mode 100644 index 4efa35d2..00000000 --- a/src/nodejs/unit-http/websocket_router.js +++ /dev/null @@ -1,157 +0,0 @@ -/************************************************************************ - * Copyright 2010-2015 Brian McKelvey. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ***********************************************************************/ - -var extend = require('./utils').extend; -var util = require('util'); -var EventEmitter = require('events').EventEmitter; -var WebSocketRouterRequest = require('./websocket_router_request'); - -function WebSocketRouter(config) { - // Superclass Constructor - EventEmitter.call(this); - - this.config = { - // The WebSocketServer instance to attach to. - server: null - }; - if (config) { - extend(this.config, config); - } - this.handlers = []; - - this._requestHandler = this.handleRequest.bind(this); - if (this.config.server) { - this.attachServer(this.config.server); - } -} - -util.inherits(WebSocketRouter, EventEmitter); - -WebSocketRouter.prototype.attachServer = function(server) { - if (server) { - this.server = server; - this.server.on('request', this._requestHandler); - } - else { - throw new Error('You must specify a WebSocketServer instance to attach to.'); - } -}; - -WebSocketRouter.prototype.detachServer = function() { - if (this.server) { - this.server.removeListener('request', this._requestHandler); - this.server = null; - } - else { - throw new Error('Cannot detach from server: not attached.'); - } -}; - -WebSocketRouter.prototype.mount = function(path, protocol, callback) { - if (!path) { - throw new Error('You must specify a path for this handler.'); - } - if (!protocol) { - protocol = '____no_protocol____'; - } - if (!callback) { - throw new Error('You must specify a callback for this handler.'); - } - - path = this.pathToRegExp(path); - if (!(path instanceof RegExp)) { - throw new Error('Path must be specified as either a string or a RegExp.'); - } - var pathString = path.toString(); - - // normalize protocol to lower-case - protocol = protocol.toLocaleLowerCase(); - - if (this.findHandlerIndex(pathString, protocol) !== -1) { - throw new Error('You may only mount one handler per path/protocol combination.'); - } - - this.handlers.push({ - 'path': path, - 'pathString': pathString, - 'protocol': protocol, - 'callback': callback - }); -}; -WebSocketRouter.prototype.unmount = function(path, protocol) { - var index = this.findHandlerIndex(this.pathToRegExp(path).toString(), protocol); - if (index !== -1) { - this.handlers.splice(index, 1); - } - else { - throw new Error('Unable to find a route matching the specified path and protocol.'); - } -}; - -WebSocketRouter.prototype.findHandlerIndex = function(pathString, protocol) { - protocol = protocol.toLocaleLowerCase(); - for (var i=0, len=this.handlers.length; i < len; i++) { - var handler = this.handlers[i]; - if (handler.pathString === pathString && handler.protocol === protocol) { - return i; - } - } - return -1; -}; - -WebSocketRouter.prototype.pathToRegExp = function(path) { - if (typeof(path) === 'string') { - if (path === '*') { - path = /^.*$/; - } - else { - path = path.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); - path = new RegExp('^' + path + '$'); - } - } - return path; -}; - -WebSocketRouter.prototype.handleRequest = function(request) { - var requestedProtocols = request.requestedProtocols; - if (requestedProtocols.length === 0) { - requestedProtocols = ['____no_protocol____']; - } - - // Find a handler with the first requested protocol first - for (var i=0; i < requestedProtocols.length; i++) { - var requestedProtocol = requestedProtocols[i].toLocaleLowerCase(); - - // find the first handler that can process this request - for (var j=0, len=this.handlers.length; j < len; j++) { - var handler = this.handlers[j]; - if (handler.path.test(request.resourceURL.pathname)) { - if (requestedProtocol === handler.protocol || - handler.protocol === '*') - { - var routerRequest = new WebSocketRouterRequest(request, requestedProtocol); - handler.callback(routerRequest); - return; - } - } - } - } - - // If we get here we were unable to find a suitable handler. - request.reject(404, 'No handler is available for the given request.'); -}; - -module.exports = WebSocketRouter; diff --git a/src/nodejs/unit-http/websocket_router_request.js b/src/nodejs/unit-http/websocket_router_request.js deleted file mode 100644 index d3e37457..00000000 --- a/src/nodejs/unit-http/websocket_router_request.js +++ /dev/null @@ -1,54 +0,0 @@ -/************************************************************************ - * Copyright 2010-2015 Brian McKelvey. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ***********************************************************************/ - -var util = require('util'); -var EventEmitter = require('events').EventEmitter; - -function WebSocketRouterRequest(webSocketRequest, resolvedProtocol) { - // Superclass Constructor - EventEmitter.call(this); - - this.webSocketRequest = webSocketRequest; - if (resolvedProtocol === '____no_protocol____') { - this.protocol = null; - } - else { - this.protocol = resolvedProtocol; - } - this.origin = webSocketRequest.origin; - this.resource = webSocketRequest.resource; - this.resourceURL = webSocketRequest.resourceURL; - this.httpRequest = webSocketRequest.httpRequest; - this.remoteAddress = webSocketRequest.remoteAddress; - this.webSocketVersion = webSocketRequest.webSocketVersion; - this.requestedExtensions = webSocketRequest.requestedExtensions; - this.cookies = webSocketRequest.cookies; -} - -util.inherits(WebSocketRouterRequest, EventEmitter); - -WebSocketRouterRequest.prototype.accept = function(origin, cookies) { - var connection = this.webSocketRequest.accept(this.protocol, origin, cookies); - this.emit('requestAccepted', connection); - return connection; -}; - -WebSocketRouterRequest.prototype.reject = function(status, reason, extraHeaders) { - this.webSocketRequest.reject(status, reason, extraHeaders); - this.emit('requestRejected', this); -}; - -module.exports = WebSocketRouterRequest; diff --git a/src/nodejs/unit-http/websocket_server.js b/src/nodejs/unit-http/websocket_server.js deleted file mode 100644 index 306f3f67..00000000 --- a/src/nodejs/unit-http/websocket_server.js +++ /dev/null @@ -1,213 +0,0 @@ -/************************************************************************ - * Copyright 2010-2015 Brian McKelvey. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ***********************************************************************/ - -var extend = require('./utils').extend; -var utils = require('./utils'); -var util = require('util'); -var EventEmitter = require('events').EventEmitter; -var WebSocketRequest = require('./websocket_request'); - -var WebSocketServer = function WebSocketServer(config) { - // Superclass Constructor - EventEmitter.call(this); - - this._handlers = { - upgrade: this.handleUpgrade.bind(this), - requestAccepted: this.handleRequestAccepted.bind(this), - requestResolved: this.handleRequestResolved.bind(this) - }; - this.connections = []; - this.pendingRequests = []; - if (config) { - this.mount(config); - } -}; - -util.inherits(WebSocketServer, EventEmitter); - -WebSocketServer.prototype.mount = function(config) { - this.config = { - // The http server instance to attach to. Required. - httpServer: null, - - // 64KiB max frame size. - maxReceivedFrameSize: 0x10000, - - // 1MiB max message size, only applicable if - // assembleFragments is true - maxReceivedMessageSize: 0x100000, - - // Outgoing messages larger than fragmentationThreshold will be - // split into multiple fragments. - fragmentOutgoingMessages: true, - - // Outgoing frames are fragmented if they exceed this threshold. - // Default is 16KiB - fragmentationThreshold: 0x4000, - - // If true, fragmented messages will be automatically assembled - // and the full message will be emitted via a 'message' event. - // If false, each frame will be emitted via a 'frame' event and - // the application will be responsible for aggregating multiple - // fragmented frames. Single-frame messages will emit a 'message' - // event in addition to the 'frame' event. - // Most users will want to leave this set to 'true' - assembleFragments: true, - - // If this is true, websocket connections will be accepted - // regardless of the path and protocol specified by the client. - // The protocol accepted will be the first that was requested - // by the client. Clients from any origin will be accepted. - // This should only be used in the simplest of cases. You should - // probably leave this set to 'false' and inspect the request - // object to make sure it's acceptable before accepting it. - autoAcceptConnections: false, - - // Whether or not the X-Forwarded-For header should be respected. - // It's important to set this to 'true' when accepting connections - // from untrusted clients, as a malicious client could spoof its - // IP address by simply setting this header. It's meant to be added - // by a trusted proxy or other intermediary within your own - // infrastructure. - // See: http://en.wikipedia.org/wiki/X-Forwarded-For - ignoreXForwardedFor: false, - - // The Nagle Algorithm makes more efficient use of network resources - // by introducing a small delay before sending small packets so that - // multiple messages can be batched together before going onto the - // wire. This however comes at the cost of latency, so the default - // is to disable it. If you don't need low latency and are streaming - // lots of small messages, you can change this to 'false' - disableNagleAlgorithm: true, - - // The number of milliseconds to wait after sending a close frame - // for an acknowledgement to come back before giving up and just - // closing the socket. - closeTimeout: 5000 - }; - extend(this.config, config); - - if (this.config.httpServer) { - if (!Array.isArray(this.config.httpServer)) { - this.config.httpServer = [this.config.httpServer]; - } - var upgradeHandler = this._handlers.upgrade; - this.config.httpServer.forEach(function(httpServer) { - httpServer.on('upgrade', upgradeHandler); - }); - } - else { - throw new Error('You must specify an httpServer on which to mount the WebSocket server.'); - } -}; - -WebSocketServer.prototype.unmount = function() { - var upgradeHandler = this._handlers.upgrade; - this.config.httpServer.forEach(function(httpServer) { - httpServer.removeListener('upgrade', upgradeHandler); - }); -}; - -WebSocketServer.prototype.closeAllConnections = function() { - this.connections.forEach(function(connection) { - connection.close(); - }); - this.pendingRequests.forEach(function(request) { - process.nextTick(function() { - request.reject(503); // HTTP 503 Service Unavailable - }); - }); -}; - -WebSocketServer.prototype.broadcast = function(data) { - if (Buffer.isBuffer(data)) { - this.broadcastBytes(data); - } - else if (typeof(data.toString) === 'function') { - this.broadcastUTF(data); - } -}; - -WebSocketServer.prototype.broadcastUTF = function(utfData) { - this.connections.forEach(function(connection) { - connection.sendUTF(utfData); - }); -}; - -WebSocketServer.prototype.broadcastBytes = function(binaryData) { - this.connections.forEach(function(connection) { - connection.sendBytes(binaryData); - }); -}; - -WebSocketServer.prototype.shutDown = function() { - this.unmount(); - this.closeAllConnections(); -}; - -WebSocketServer.prototype.handleUpgrade = function(request, socket) { - var wsRequest = new WebSocketRequest(socket, request, this.config); - try { - wsRequest.readHandshake(); - } - catch(e) { - wsRequest.reject( - e.httpCode ? e.httpCode : 400, - e.message, - e.headers - ); - return; - } - - this.pendingRequests.push(wsRequest); - - wsRequest.once('requestAccepted', this._handlers.requestAccepted); - wsRequest.once('requestResolved', this._handlers.requestResolved); - - if (!this.config.autoAcceptConnections && utils.eventEmitterListenerCount(this, 'request') > 0) { - this.emit('request', wsRequest); - } - else if (this.config.autoAcceptConnections) { - wsRequest.accept(wsRequest.requestedProtocols[0], wsRequest.origin); - } - else { - wsRequest.reject(404, 'No handler is configured to accept the connection.'); - } -}; - -WebSocketServer.prototype.handleRequestAccepted = function(connection) { - var self = this; - connection.once('close', function(closeReason, description) { - self.handleConnectionClose(connection, closeReason, description); - }); - this.connections.push(connection); - this.emit('connect', connection); -}; - -WebSocketServer.prototype.handleConnectionClose = function(connection, closeReason, description) { - var index = this.connections.indexOf(connection); - if (index !== -1) { - this.connections.splice(index, 1); - } - this.emit('close', connection, closeReason, description); -}; - -WebSocketServer.prototype.handleRequestResolved = function(request) { - var index = this.pendingRequests.indexOf(request); - if (index !== -1) { this.pendingRequests.splice(index, 1); } -}; - -module.exports = WebSocketServer; diff --git a/src/nxt_aix_send_file.c b/src/nxt_aix_send_file.c deleted file mode 100644 index 6462efd5..00000000 --- a/src/nxt_aix_send_file.c +++ /dev/null @@ -1,126 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* send_file() has been introduced in AIX 4.3.2 */ - -ssize_t nxt_aix_event_conn_io_send_file(nxt_event_conn_t *c, nxt_buf_t *b, - size_t limit); - - -ssize_t -nxt_aix_event_conn_io_send_file(nxt_event_conn_t *c, nxt_buf_t *b, size_t limit) -{ - ssize_t n; - nxt_buf_t *fb; - nxt_err_t err; - nxt_off_t file_size, sent; - nxt_uint_t nhd, ntr; - struct iovec hd[NXT_IOBUF_MAX], tr; - struct sf_parms sfp; - nxt_sendbuf_coalesce_t sb; - - sb.buf = b; - sb.iobuf = hd; - sb.nmax = NXT_IOBUF_MAX; - sb.sync = 0; - sb.size = 0; - sb.limit = limit; - - nhd = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); - - if (nhd == 0 && sb.sync) { - return 0; - } - - if (nhd > 1 || sb.buf == NULL || !nxt_buf_is_file(sb.buf)) { - return nxt_event_conn_io_writev(c, hd, nhd); - } - - fb = sb.buf; - - file_size = nxt_sendbuf_file_coalesce(&sb); - - if (file_size == 0) { - return nxt_event_conn_io_writev(c, hd, nhd); - } - - sb.iobuf = &tr; - sb.nmax = 1; - - ntr = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); - - nxt_memzero(&sfp, sizeof(struct sf_parms)); - - if (nhd != 0) { - sfp.header_data = hd[0].iov_base; - sfp.header_length = hd[0].iov_len; - } - - sfp.file_descriptor = fb->file->fd; - sfp.file_offset = fb->file_pos; - sfp.file_bytes = file_size; - - if (ntr != 0) { - sfp.trailer_data = tr.iov_base; - sfp.trailer_length = tr.iov_len; - } - - nxt_debug(c->socket.task, "send_file(%d) fd:%FD @%O:%O hd:%ui tr:%ui", - c->socket.fd, fb->file->fd, fb->file_pos, file_size, nhd, ntr); - - n = send_file(&c->socket.fd, &sfp, 0); - - err = (n == -1) ? nxt_errno : 0; - sent = sfp.bytes_sent; - - nxt_debug(c->socket.task, "send_file(%d): %d sent:%O", - c->socket.fd, n, sent); - - /* - * -1 an error has occurred, errno contains the error code; - * 0 the command has completed successfully; - * 1 the command was completed partially, some data has been - * transmitted but the command has to return for some reason, - * for example, the command was interrupted by signals. - */ - if (n == -1) { - switch (err) { - - case NXT_EAGAIN: - c->socket.write_ready = 0; - break; - - case NXT_EINTR: - break; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "send_file(%d) failed %E \"%FN\" fd:%FD @%O:%O hd:%ui tr:%ui", - c->socket.fd, err, fb->file->name, fb->file->fd, fb->file_pos, - file_size, nhd, ntr); - - return NXT_ERROR; - } - - nxt_debug(c->socket.task, "sendfile() %E", err); - - return sent; - } - - if (n == 1) { - return sent; - } - - if (sent < (nxt_off_t) sb.size) { - c->socket.write_ready = 0; - } - - return sent; -} diff --git a/src/nxt_app_log.c b/src/nxt_app_log.c deleted file mode 100644 index ae57c2a2..00000000 --- a/src/nxt_app_log.c +++ /dev/null @@ -1,139 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -static nxt_time_string_t nxt_log_error_time_cache; -static u_char *nxt_log_error_time(u_char *buf, nxt_realtime_t *now, - struct tm *tm, size_t size, const char *format); -static nxt_time_string_t nxt_log_debug_time_cache; -static u_char *nxt_log_debug_time(u_char *buf, nxt_realtime_t *now, - struct tm *tm, size_t size, const char *format); - - -void nxt_cdecl -nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) -{ - u_char *p, *end; -#if 0 - u_char *syslogmsg; -#endif - va_list args; - nxt_thread_t *thr; - nxt_time_string_t *time_cache; - u_char msg[NXT_MAX_ERROR_STR]; - - thr = nxt_thread(); - - end = msg + NXT_MAX_ERROR_STR; - - time_cache = (log->level != NXT_LOG_DEBUG) ? &nxt_log_error_time_cache: - &nxt_log_debug_time_cache; - - p = nxt_thread_time_string(thr, time_cache, msg); - -#if 0 - syslogmsg = p; -#endif - -#if 0 - nxt_fid_t fid; - const char *id; - nxt_fiber_t *fib; - - fib = nxt_fiber_self(thr); - - if (fib != NULL) { - id = "[%V] %PI#%PT#%PF "; - fid = nxt_fiber_id(fib); - - } else { - id = "[%V] %PI#%PT "; - fid = 0; - } - - p = nxt_sprintf(p, end, id, &nxt_log_levels[level], nxt_pid, - nxt_thread_tid(thr), fid); -#else - p = nxt_sprintf(p, end, "[%V] %PI#%PT ", &nxt_log_levels[level], nxt_pid, - nxt_thread_tid(thr)); -#endif - - if (log->ident != 0) { - p = nxt_sprintf(p, end, "*%D ", log->ident); - } - - va_start(args, fmt); - p = nxt_vsprintf(p, end, fmt, args); - va_end(args); - - if (level != NXT_LOG_DEBUG && log->ctx_handler != NULL) { - p = log->ctx_handler(log->ctx, p, end); - } - - if (p > end - nxt_length("\n")) { - p = end - nxt_length("\n"); - } - - *p++ = '\n'; - - (void) nxt_write_console(nxt_stderr, msg, p - msg); - -#if 0 - if (level == NXT_LOG_ALERT) { - *(p - nxt_length("\n")) = '\0'; - - /* - * The syslog LOG_ALERT level is enough, because - * LOG_EMERG level broadcasts a message to all users. - */ - nxt_write_syslog(LOG_ALERT, syslogmsg); - } -#endif -} - - -static nxt_time_string_t nxt_log_error_time_cache = { - (nxt_atomic_uint_t) -1, - nxt_log_error_time, - "%4d/%02d/%02d %02d:%02d:%02d ", - nxt_length("1970/09/28 12:00:00 "), - NXT_THREAD_TIME_LOCAL, - NXT_THREAD_TIME_SEC, -}; - - -static u_char * -nxt_log_error_time(u_char *buf, nxt_realtime_t *now, struct tm *tm, size_t size, - const char *format) -{ - return nxt_sprintf(buf, buf + size, format, - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); -} - - -static nxt_time_string_t nxt_log_debug_time_cache = { - (nxt_atomic_uint_t) -1, - nxt_log_debug_time, - "%4d/%02d/%02d %02d:%02d:%02d.%03d ", - nxt_length("1970/09/28 12:00:00.000 "), - NXT_THREAD_TIME_LOCAL, - NXT_THREAD_TIME_MSEC, -}; - - -static u_char * -nxt_log_debug_time(u_char *buf, nxt_realtime_t *now, struct tm *tm, size_t size, - const char *format) -{ - return nxt_sprintf(buf, buf + size, format, - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, - now->nsec / 1000000); -} diff --git a/src/nxt_app_nncq.h b/src/nxt_app_nncq.h deleted file mode 100644 index f9b8ce0c..00000000 --- a/src/nxt_app_nncq.h +++ /dev/null @@ -1,165 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_APP_NNCQ_H_INCLUDED_ -#define _NXT_APP_NNCQ_H_INCLUDED_ - - -/* Appilcation Numeric Naive Circular Queue */ - -#define NXT_APP_NNCQ_SIZE 131072 - -typedef uint32_t nxt_app_nncq_atomic_t; -typedef uint16_t nxt_app_nncq_cycle_t; - -typedef struct { - nxt_app_nncq_atomic_t head; - nxt_app_nncq_atomic_t entries[NXT_APP_NNCQ_SIZE]; - nxt_app_nncq_atomic_t tail; -} nxt_app_nncq_t; - - -static inline nxt_app_nncq_atomic_t -nxt_app_nncq_head(nxt_app_nncq_t const volatile *q) -{ - return q->head; -} - - -static inline nxt_app_nncq_atomic_t -nxt_app_nncq_tail(nxt_app_nncq_t const volatile *q) -{ - return q->tail; -} - - -static inline void -nxt_app_nncq_tail_cmp_inc(nxt_app_nncq_t volatile *q, nxt_app_nncq_atomic_t t) -{ - nxt_atomic_cmp_set(&q->tail, t, t + 1); -} - - -static inline nxt_app_nncq_atomic_t -nxt_app_nncq_index(nxt_app_nncq_t const volatile *q, nxt_app_nncq_atomic_t i) -{ - return i % NXT_APP_NNCQ_SIZE; -} - - -static inline nxt_app_nncq_atomic_t -nxt_app_nncq_map(nxt_app_nncq_t const volatile *q, nxt_app_nncq_atomic_t i) -{ - return i % NXT_APP_NNCQ_SIZE; -} - - -static inline nxt_app_nncq_cycle_t -nxt_app_nncq_cycle(nxt_app_nncq_t const volatile *q, nxt_app_nncq_atomic_t i) -{ - return i / NXT_APP_NNCQ_SIZE; -} - - -static inline nxt_app_nncq_cycle_t -nxt_app_nncq_next_cycle(nxt_app_nncq_t const volatile *q, - nxt_app_nncq_cycle_t i) -{ - return i + 1; -} - - -static inline nxt_app_nncq_atomic_t -nxt_app_nncq_new_entry(nxt_app_nncq_t const volatile *q, - nxt_app_nncq_cycle_t cycle, - nxt_app_nncq_atomic_t i) -{ - return cycle * NXT_APP_NNCQ_SIZE + (i % NXT_APP_NNCQ_SIZE); -} - - -static inline nxt_app_nncq_atomic_t -nxt_app_nncq_empty(nxt_app_nncq_t const volatile *q) -{ - return NXT_APP_NNCQ_SIZE; -} - - -static void -nxt_app_nncq_init(nxt_app_nncq_t volatile *q) -{ - q->head = NXT_APP_NNCQ_SIZE; - nxt_memzero((void *) q->entries, - NXT_APP_NNCQ_SIZE * sizeof(nxt_app_nncq_atomic_t)); - q->tail = NXT_APP_NNCQ_SIZE; -} - - -static void -nxt_app_nncq_enqueue(nxt_app_nncq_t volatile *q, nxt_app_nncq_atomic_t val) -{ - nxt_app_nncq_cycle_t e_cycle, t_cycle; - nxt_app_nncq_atomic_t n, t, e, j; - - for ( ;; ) { - t = nxt_app_nncq_tail(q); - j = nxt_app_nncq_map(q, t); - e = q->entries[j]; - - e_cycle = nxt_app_nncq_cycle(q, e); - t_cycle = nxt_app_nncq_cycle(q, t); - - if (e_cycle == t_cycle) { - nxt_app_nncq_tail_cmp_inc(q, t); - continue; - } - - if (nxt_app_nncq_next_cycle(q, e_cycle) != t_cycle) { - continue; - } - - n = nxt_app_nncq_new_entry(q, t_cycle, val); - - if (nxt_atomic_cmp_set(&q->entries[j], e, n)) { - break; - } - } - - nxt_app_nncq_tail_cmp_inc(q, t); -} - - -static nxt_app_nncq_atomic_t -nxt_app_nncq_dequeue(nxt_app_nncq_t volatile *q) -{ - nxt_app_nncq_cycle_t e_cycle, h_cycle; - nxt_app_nncq_atomic_t h, j, e; - - for ( ;; ) { - h = nxt_app_nncq_head(q); - j = nxt_app_nncq_map(q, h); - e = q->entries[j]; - - e_cycle = nxt_app_nncq_cycle(q, e); - h_cycle = nxt_app_nncq_cycle(q, h); - - if (e_cycle != h_cycle) { - if (nxt_app_nncq_next_cycle(q, e_cycle) == h_cycle) { - return nxt_app_nncq_empty(q); - } - - continue; - } - - if (nxt_atomic_cmp_set(&q->head, h, h + 1)) { - break; - } - } - - return nxt_app_nncq_index(q, e); -} - - -#endif /* _NXT_APP_NNCQ_H_INCLUDED_ */ diff --git a/src/nxt_app_queue.h b/src/nxt_app_queue.h deleted file mode 100644 index a1cc2f11..00000000 --- a/src/nxt_app_queue.h +++ /dev/null @@ -1,125 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_APP_QUEUE_H_INCLUDED_ -#define _NXT_APP_QUEUE_H_INCLUDED_ - - -#include - - -/* Using Numeric Naive Circular Queue as a backend. */ - -#define NXT_APP_QUEUE_SIZE NXT_APP_NNCQ_SIZE -#define NXT_APP_QUEUE_MSG_SIZE 31 - -typedef struct { - uint8_t size; - uint8_t data[NXT_APP_QUEUE_MSG_SIZE]; - uint32_t tracking; -} nxt_app_queue_item_t; - - -typedef struct { - nxt_app_nncq_atomic_t notified; - nxt_app_nncq_t free_items; - nxt_app_nncq_t queue; - nxt_app_queue_item_t items[NXT_APP_QUEUE_SIZE]; -} nxt_app_queue_t; - - -nxt_inline void -nxt_app_queue_init(nxt_app_queue_t volatile *q) -{ - nxt_app_nncq_atomic_t i; - - nxt_app_nncq_init(&q->free_items); - nxt_app_nncq_init(&q->queue); - - for (i = 0; i < NXT_APP_QUEUE_SIZE; i++) { - nxt_app_nncq_enqueue(&q->free_items, i); - } - - q->notified = 0; -} - - -nxt_inline nxt_int_t -nxt_app_queue_send(nxt_app_queue_t volatile *q, const void *p, - uint8_t size, uint32_t tracking, int *notify, uint32_t *cookie) -{ - int n; - nxt_app_queue_item_t *qi; - nxt_app_nncq_atomic_t i; - - i = nxt_app_nncq_dequeue(&q->free_items); - if (i == nxt_app_nncq_empty(&q->free_items)) { - return NXT_AGAIN; - } - - qi = (nxt_app_queue_item_t *) &q->items[i]; - - qi->size = size; - nxt_memcpy(qi->data, p, size); - qi->tracking = tracking; - *cookie = i; - - nxt_app_nncq_enqueue(&q->queue, i); - - n = nxt_atomic_cmp_set(&q->notified, 0, 1); - - if (notify != NULL) { - *notify = n; - } - - return NXT_OK; -} - - -nxt_inline void -nxt_app_queue_notification_received(nxt_app_queue_t volatile *q) -{ - q->notified = 0; -} - - -nxt_inline nxt_bool_t -nxt_app_queue_cancel(nxt_app_queue_t volatile *q, uint32_t cookie, - uint32_t tracking) -{ - nxt_app_queue_item_t *qi; - - qi = (nxt_app_queue_item_t *) &q->items[cookie]; - - return nxt_atomic_cmp_set(&qi->tracking, tracking, 0); -} - - -nxt_inline ssize_t -nxt_app_queue_recv(nxt_app_queue_t volatile *q, void *p, uint32_t *cookie) -{ - ssize_t res; - nxt_app_queue_item_t *qi; - nxt_app_nncq_atomic_t i; - - i = nxt_app_nncq_dequeue(&q->queue); - if (i == nxt_app_nncq_empty(&q->queue)) { - *cookie = 0; - return -1; - } - - qi = (nxt_app_queue_item_t *) &q->items[i]; - - res = qi->size; - nxt_memcpy(p, qi->data, qi->size); - *cookie = i; - - nxt_app_nncq_enqueue(&q->free_items, i); - - return res; -} - - -#endif /* _NXT_APP_QUEUE_H_INCLUDED_ */ diff --git a/src/nxt_application.c b/src/nxt_application.c deleted file mode 100644 index e0247bf0..00000000 --- a/src/nxt_application.c +++ /dev/null @@ -1,1287 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) Igor Sysoev - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) -#include -#endif - - -#ifdef WCOREDUMP -#define NXT_WCOREDUMP(s) WCOREDUMP(s) -#else -#define NXT_WCOREDUMP(s) 0 -#endif - - -typedef struct { - nxt_app_type_t type; - nxt_str_t version; - nxt_str_t file; - nxt_array_t *mounts; -} nxt_module_t; - - -static nxt_int_t nxt_discovery_start(nxt_task_t *task, - nxt_process_data_t *data); -static nxt_buf_t *nxt_discovery_modules(nxt_task_t *task, const char *path); -static nxt_int_t nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp, - nxt_array_t *modules, const char *name); -static void nxt_discovery_completion_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data); -static nxt_app_module_t *nxt_app_module_load(nxt_task_t *task, - const char *name); -static nxt_int_t nxt_proto_setup(nxt_task_t *task, nxt_process_t *process); -static nxt_int_t nxt_proto_start(nxt_task_t *task, nxt_process_data_t *data); -static nxt_int_t nxt_app_setup(nxt_task_t *task, nxt_process_t *process); -static nxt_int_t nxt_app_set_environment(nxt_conf_value_t *environment); -static void nxt_proto_start_process_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_proto_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -static void nxt_proto_process_created_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_proto_quit_children(nxt_task_t *task); -static nxt_process_t *nxt_proto_process_find(nxt_task_t *task, nxt_pid_t pid); -static void nxt_proto_process_add(nxt_task_t *task, nxt_process_t *process); -static nxt_process_t *nxt_proto_process_remove(nxt_task_t *task, nxt_pid_t pid); -static u_char *nxt_cstr_dup(nxt_mp_t *mp, u_char *dst, u_char *src); -static void nxt_proto_signal_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_proto_sigterm_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_proto_sigchld_handler(nxt_task_t *task, void *obj, void *data); - - -nxt_str_t nxt_server = nxt_string(NXT_SERVER); - - -static uint32_t compat[] = { - NXT_VERNUM, NXT_DEBUG, -}; - - -static nxt_lvlhsh_t nxt_proto_processes; -static nxt_queue_t nxt_proto_children; -static nxt_bool_t nxt_proto_exiting; - -static nxt_app_module_t *nxt_app; -static nxt_common_app_conf_t *nxt_app_conf; - - -static const nxt_port_handlers_t nxt_discovery_process_port_handlers = { - .quit = nxt_signal_quit_handler, - .new_port = nxt_port_new_port_handler, - .change_file = nxt_port_change_log_file_handler, - .mmap = nxt_port_mmap_handler, - .data = nxt_port_data_handler, - .remove_pid = nxt_port_remove_pid_handler, - .rpc_ready = nxt_port_rpc_handler, - .rpc_error = nxt_port_rpc_handler, -}; - - -const nxt_sig_event_t nxt_prototype_signals[] = { - nxt_event_signal(SIGHUP, nxt_proto_signal_handler), - nxt_event_signal(SIGINT, nxt_proto_sigterm_handler), - nxt_event_signal(SIGQUIT, nxt_proto_sigterm_handler), - nxt_event_signal(SIGTERM, nxt_proto_sigterm_handler), - nxt_event_signal(SIGCHLD, nxt_proto_sigchld_handler), - nxt_event_signal_end, -}; - - -static const nxt_port_handlers_t nxt_proto_process_port_handlers = { - .quit = nxt_proto_quit_handler, - .change_file = nxt_port_change_log_file_handler, - .new_port = nxt_port_new_port_handler, - .process_created = nxt_proto_process_created_handler, - .process_ready = nxt_port_process_ready_handler, - .remove_pid = nxt_port_remove_pid_handler, - .start_process = nxt_proto_start_process_handler, - .rpc_ready = nxt_port_rpc_handler, - .rpc_error = nxt_port_rpc_handler, -}; - - -static const nxt_port_handlers_t nxt_app_process_port_handlers = { - .quit = nxt_signal_quit_handler, - .rpc_ready = nxt_port_rpc_handler, - .rpc_error = nxt_port_rpc_handler, -}; - - -const nxt_process_init_t nxt_discovery_process = { - .name = "discovery", - .type = NXT_PROCESS_DISCOVERY, - .prefork = NULL, - .restart = 0, - .setup = nxt_process_core_setup, - .start = nxt_discovery_start, - .port_handlers = &nxt_discovery_process_port_handlers, - .signals = nxt_process_signals, -}; - - -const nxt_process_init_t nxt_proto_process = { - .type = NXT_PROCESS_PROTOTYPE, - .prefork = nxt_isolation_main_prefork, - .restart = 0, - .setup = nxt_proto_setup, - .start = nxt_proto_start, - .port_handlers = &nxt_proto_process_port_handlers, - .signals = nxt_prototype_signals, -}; - - -const nxt_process_init_t nxt_app_process = { - .type = NXT_PROCESS_APP, - .setup = nxt_app_setup, - .start = NULL, - .prefork = NULL, - .restart = 0, - .port_handlers = &nxt_app_process_port_handlers, - .signals = nxt_process_signals, -}; - - -static nxt_int_t -nxt_discovery_start(nxt_task_t *task, nxt_process_data_t *data) -{ - uint32_t stream; - nxt_buf_t *b; - nxt_int_t ret; - nxt_port_t *main_port, *discovery_port; - nxt_runtime_t *rt; - - nxt_log(task, NXT_LOG_INFO, "discovery started"); - - rt = task->thread->runtime; - - b = nxt_discovery_modules(task, rt->modules); - if (nxt_slow_path(b == NULL)) { - return NXT_ERROR; - } - - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - discovery_port = rt->port_by_type[NXT_PROCESS_DISCOVERY]; - - stream = nxt_port_rpc_register_handler(task, discovery_port, - nxt_discovery_quit, - nxt_discovery_quit, - main_port->pid, NULL); - - if (nxt_slow_path(stream == 0)) { - return NXT_ERROR; - } - - ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_MODULES, -1, - stream, discovery_port->id, b); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_rpc_cancel(task, discovery_port, stream); - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_buf_t * -nxt_discovery_modules(nxt_task_t *task, const char *path) -{ - char *name; - u_char *p, *end; - size_t size; - glob_t glb; - nxt_mp_t *mp; - nxt_buf_t *b; - nxt_int_t ret; - nxt_uint_t i, n, j; - nxt_array_t *modules, *mounts; - nxt_module_t *module; - nxt_fs_mount_t *mnt; - - b = NULL; - - mp = nxt_mp_create(1024, 128, 256, 32); - if (mp == NULL) { - return b; - } - - ret = glob(path, 0, NULL, &glb); - - n = glb.gl_pathc; - - if (ret != 0) { - nxt_log(task, NXT_LOG_NOTICE, - "no modules matching: \"%s\" found", path); - n = 0; - } - - modules = nxt_array_create(mp, n, sizeof(nxt_module_t)); - if (modules == NULL) { - goto fail; - } - - for (i = 0; i < n; i++) { - name = glb.gl_pathv[i]; - - ret = nxt_discovery_module(task, mp, modules, name); - if (ret != NXT_OK) { - goto fail; - } - } - - size = nxt_length("[]"); - module = modules->elts; - n = modules->nelts; - - for (i = 0; i < n; i++) { - nxt_debug(task, "module: %d %V %V", - module[i].type, &module[i].version, &module[i].file); - - size += nxt_length("{\"type\": ,"); - size += nxt_length(" \"version\": \"\","); - size += nxt_length(" \"file\": \"\","); - size += nxt_length(" \"mounts\": []},"); - - size += NXT_INT_T_LEN - + module[i].version.length - + module[i].file.length; - - mounts = module[i].mounts; - - size += mounts->nelts * nxt_length("{\"src\": \"\", \"dst\": \"\", " - "\"type\": , \"name\": \"\", " - "\"flags\": , \"data\": \"\"},"); - - mnt = mounts->elts; - - for (j = 0; j < mounts->nelts; j++) { - size += nxt_strlen(mnt[j].src) + nxt_strlen(mnt[j].dst) - + nxt_strlen(mnt[j].name) + (2 * NXT_INT_T_LEN) - + (mnt[j].data == NULL ? 0 : nxt_strlen(mnt[j].data)); - } - } - - b = nxt_buf_mem_alloc(mp, size, 0); - if (b == NULL) { - goto fail; - } - - b->completion_handler = nxt_discovery_completion_handler; - - p = b->mem.free; - end = b->mem.end; - *p++ = '['; - - for (i = 0; i < n; i++) { - mounts = module[i].mounts; - - p = nxt_sprintf(p, end, "{\"type\": %d, \"version\": \"%V\", " - "\"file\": \"%V\", \"mounts\": [", - module[i].type, &module[i].version, &module[i].file); - - mnt = mounts->elts; - for (j = 0; j < mounts->nelts; j++) { - p = nxt_sprintf(p, end, - "{\"src\": \"%s\", \"dst\": \"%s\", " - "\"name\": \"%s\", \"type\": %d, \"flags\": %d, " - "\"data\": \"%s\"},", - mnt[j].src, mnt[j].dst, mnt[j].name, mnt[j].type, - mnt[j].flags, - mnt[j].data == NULL ? (u_char *) "" : mnt[j].data); - } - - *p++ = ']'; - *p++ = '}'; - *p++ = ','; - } - - *p++ = ']'; - - if (nxt_slow_path(p > end)) { - nxt_alert(task, "discovery write past the buffer"); - goto fail; - } - - b->mem.free = p; - -fail: - - globfree(&glb); - - return b; -} - - -static nxt_int_t -nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp, nxt_array_t *modules, - const char *name) -{ - void *dl; - nxt_str_t version; - nxt_int_t ret; - nxt_uint_t i, j, n; - nxt_array_t *mounts; - nxt_module_t *module; - nxt_app_type_t type; - nxt_fs_mount_t *to; - nxt_app_module_t *app; - const nxt_fs_mount_t *from; - - /* - * Only memory allocation failure should return NXT_ERROR. - * Any module processing errors are ignored. - */ - ret = NXT_ERROR; - - dl = dlopen(name, RTLD_GLOBAL | RTLD_NOW); - - if (dl == NULL) { - nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror()); - return NXT_OK; - } - - app = dlsym(dl, "nxt_app_module"); - - if (app != NULL) { - nxt_log(task, NXT_LOG_NOTICE, "module: %V %s \"%s\"", - &app->type, app->version, name); - - if (app->compat_length != sizeof(compat) - || memcmp(app->compat, compat, sizeof(compat)) != 0) - { - nxt_log(task, NXT_LOG_NOTICE, "incompatible module %s", name); - - goto done; - } - - type = nxt_app_parse_type(app->type.start, app->type.length); - - if (type == NXT_APP_UNKNOWN) { - nxt_log(task, NXT_LOG_NOTICE, "unknown module type %V", &app->type); - - goto done; - } - - module = modules->elts; - n = modules->nelts; - - version.start = (u_char *) app->version; - version.length = nxt_strlen(app->version); - - for (i = 0; i < n; i++) { - if (type == module[i].type - && nxt_strstr_eq(&module[i].version, &version)) - { - nxt_log(task, NXT_LOG_NOTICE, - "ignoring %s module with the same " - "application language version %V %V as in %V", - name, &app->type, &version, &module[i].file); - - goto done; - } - } - - module = nxt_array_add(modules); - if (module == NULL) { - goto fail; - } - - module->type = type; - - nxt_str_dup(mp, &module->version, &version); - if (module->version.start == NULL) { - goto fail; - } - - module->file.length = nxt_strlen(name); - - module->file.start = nxt_mp_alloc(mp, module->file.length); - if (module->file.start == NULL) { - goto fail; - } - - nxt_memcpy(module->file.start, name, module->file.length); - - module->mounts = nxt_array_create(mp, app->nmounts, - sizeof(nxt_fs_mount_t)); - - if (nxt_slow_path(module->mounts == NULL)) { - goto fail; - } - - mounts = module->mounts; - - for (j = 0; j < app->nmounts; j++) { - from = &app->mounts[j]; - to = nxt_array_zero_add(mounts); - if (nxt_slow_path(to == NULL)) { - goto fail; - } - - to->src = nxt_cstr_dup(mp, to->src, from->src); - if (nxt_slow_path(to->src == NULL)) { - goto fail; - } - - to->dst = nxt_cstr_dup(mp, to->dst, from->dst); - if (nxt_slow_path(to->dst == NULL)) { - goto fail; - } - - to->name = nxt_cstr_dup(mp, to->name, from->name); - if (nxt_slow_path(to->name == NULL)) { - goto fail; - } - - to->type = from->type; - - if (from->data != NULL) { - to->data = nxt_cstr_dup(mp, to->data, from->data); - if (nxt_slow_path(to->data == NULL)) { - goto fail; - } - } - - to->flags = from->flags; - } - - } else { - nxt_alert(task, "dlsym(\"%s\"), failed: \"%s\"", name, dlerror()); - } - -done: - - ret = NXT_OK; - -fail: - - if (dlclose(dl) != 0) { - nxt_alert(task, "dlclose(\"%s\"), failed: \"%s\"", name, dlerror()); - } - - return ret; -} - - -static void -nxt_discovery_completion_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_mp_t *mp; - nxt_buf_t *b; - - b = obj; - mp = b->data; - - nxt_mp_destroy(mp); -} - - -static void -nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) -{ - nxt_signal_quit_handler(task, msg); -} - - -static nxt_int_t -nxt_proto_setup(nxt_task_t *task, nxt_process_t *process) -{ - nxt_int_t ret; - nxt_app_lang_module_t *lang; - nxt_common_app_conf_t *app_conf; - - app_conf = process->data.app; - - nxt_queue_init(&nxt_proto_children); - - nxt_app_conf = app_conf; - - lang = nxt_app_lang_module(task->thread->runtime, &app_conf->type); - if (nxt_slow_path(lang == NULL)) { - nxt_alert(task, "unknown application type: \"%V\"", &app_conf->type); - return NXT_ERROR; - } - - nxt_app = lang->module; - - if (nxt_app == NULL) { - nxt_debug(task, "application language module: %s \"%s\"", - lang->version, lang->file); - - nxt_app = nxt_app_module_load(task, lang->file); - if (nxt_slow_path(nxt_app == NULL)) { - return NXT_ERROR; - } - } - - if (nxt_slow_path(nxt_app_set_environment(app_conf->environment) - != NXT_OK)) - { - nxt_alert(task, "failed to set environment"); - return NXT_ERROR; - } - - if (nxt_app->setup != NULL) { - ret = nxt_app->setup(task, process, app_conf); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - } - -#if (NXT_HAVE_ISOLATION_ROOTFS) - if (process->isolation.rootfs != NULL) { - if (process->isolation.mounts != NULL) { - ret = nxt_isolation_prepare_rootfs(task, process); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - } - - ret = nxt_isolation_change_root(task, process); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } -#endif - - if (app_conf->working_directory != NULL - && app_conf->working_directory[0] != 0) - { - ret = chdir(app_conf->working_directory); - - if (nxt_slow_path(ret != 0)) { - nxt_log(task, NXT_LOG_WARN, "chdir(%s) failed %E", - app_conf->working_directory, nxt_errno); - - return NXT_ERROR; - } - } - - process->state = NXT_PROCESS_STATE_CREATED; - - return NXT_OK; -} - - -static nxt_int_t -nxt_proto_start(nxt_task_t *task, nxt_process_data_t *data) -{ - nxt_debug(task, "prototype waiting for clone messages"); - - return NXT_OK; -} - - -static void -nxt_proto_start_process_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - u_char *p; - nxt_int_t ret; - nxt_port_t *port; - nxt_runtime_t *rt; - nxt_process_t *process; - nxt_process_init_t *init; - - rt = task->thread->runtime; - - process = nxt_process_new(rt); - if (nxt_slow_path(process == NULL)) { - goto failed; - } - - process->mem_pool = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(process->mem_pool == NULL)) { - nxt_process_use(task, process, -1); - goto failed; - } - - process->parent_port = rt->port_by_type[NXT_PROCESS_PROTOTYPE]; - - init = nxt_process_init(process); - *init = nxt_app_process; - - process->name = nxt_mp_alloc(process->mem_pool, nxt_app_conf->name.length - + sizeof("\"\" application") + 1); - - if (nxt_slow_path(process->name == NULL)) { - nxt_process_use(task, process, -1); - - goto failed; - } - - init->start = nxt_app->start; - - init->name = (const char *) nxt_app_conf->name.start; - - p = (u_char *) process->name; - *p++ = '"'; - p = nxt_cpymem(p, nxt_app_conf->name.start, nxt_app_conf->name.length); - p = nxt_cpymem(p, "\" application", 13); - *p = '\0'; - - process->user_cred = &rt->user_cred; - - process->data.app = nxt_app_conf; - process->stream = msg->port_msg.stream; - - init->siblings = &nxt_proto_children; - - ret = nxt_process_start(task, process); - if (nxt_slow_path(ret == NXT_ERROR)) { - nxt_process_use(task, process, -1); - - goto failed; - } - - nxt_proto_process_add(task, process); - - return; - -failed: - - port = nxt_runtime_port_find(rt, msg->port_msg.pid, - msg->port_msg.reply_port); - - if (nxt_fast_path(port != NULL)) { - nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, - -1, msg->port_msg.stream, 0, NULL); - } -} - - -static void -nxt_proto_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_debug(task, "prototype quit handler"); - - nxt_proto_quit_children(task); - - nxt_proto_exiting = 1; - - if (nxt_queue_is_empty(&nxt_proto_children)) { - nxt_process_quit(task, 0); - } -} - - -static void -nxt_proto_quit_children(nxt_task_t *task) -{ - nxt_port_t *port; - nxt_process_t *process; - - nxt_queue_each(process, &nxt_proto_children, nxt_process_t, link) { - port = nxt_process_port_first(process); - - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, - -1, 0, 0, NULL); - } - nxt_queue_loop; -} - - -static void -nxt_proto_process_created_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_pid_t isolated_pid, pid; - nxt_process_t *process; - - isolated_pid = nxt_recv_msg_cmsg_pid(msg); - - process = nxt_proto_process_find(task, isolated_pid); - if (nxt_slow_path(process == NULL)) { - return; - } - - process->state = NXT_PROCESS_STATE_CREATED; - - pid = msg->port_msg.pid; - - if (process->pid != pid) { - nxt_debug(task, "app process %PI (aka %PI) is created", isolated_pid, - pid); - - process->pid = pid; - - } else { - nxt_debug(task, "app process %PI is created", isolated_pid); - } - - if (!process->registered) { - nxt_assert(!nxt_queue_is_empty(&process->ports)); - - nxt_runtime_process_add(task, process); - - nxt_port_use(task, nxt_process_port_first(process), -1); - } -} - - -static void -nxt_proto_signal_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_trace(task, "signal signo:%d (%s) received, ignored", - (int) (uintptr_t) obj, data); -} - - -static void -nxt_proto_sigterm_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_trace(task, "signal signo:%d (%s) received", - (int) (uintptr_t) obj, data); - - nxt_proto_quit_children(task); - - nxt_proto_exiting = 1; - - if (nxt_queue_is_empty(&nxt_proto_children)) { - nxt_process_quit(task, 0); - } -} - - -static void -nxt_proto_sigchld_handler(nxt_task_t *task, void *obj, void *data) -{ - int status; - nxt_err_t err; - nxt_pid_t pid; - nxt_port_t *port; - nxt_process_t *process; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - nxt_debug(task, "proto sigchld handler signo:%d (%s)", - (int) (uintptr_t) obj, data); - - for ( ;; ) { - pid = waitpid(-1, &status, WNOHANG); - - if (pid == -1) { - - switch (err = nxt_errno) { - - case NXT_ECHILD: - return; - - case NXT_EINTR: - continue; - - default: - nxt_alert(task, "waitpid() failed: %E", err); - return; - } - } - - nxt_debug(task, "waitpid(): %PI", pid); - - if (pid == 0) { - return; - } - - process = nxt_proto_process_remove(task, pid); - - if (WTERMSIG(status)) { - if (rt->is_pid_isolated) { - nxt_alert(task, "app process %PI (isolated %PI) " - "exited on signal %d%s", - process != NULL ? process->pid : 0, - pid, WTERMSIG(status), - NXT_WCOREDUMP(status) ? " (core dumped)" : ""); - - } else { - nxt_alert(task, "app process %PI exited on signal %d%s", - pid, WTERMSIG(status), - NXT_WCOREDUMP(status) ? " (core dumped)" : ""); - } - - } else { - if (rt->is_pid_isolated) { - nxt_trace(task, "app process %PI (isolated %PI) " - "exited with code %d", - process != NULL ? process->pid : 0, - pid, WEXITSTATUS(status)); - - } else { - nxt_trace(task, "app process %PI exited with code %d", - pid, WEXITSTATUS(status)); - } - } - - if (process == NULL) { - continue; - } - - if (process->registered) { - port = NULL; - - } else { - nxt_assert(!nxt_queue_is_empty(&process->ports)); - - port = nxt_process_port_first(process); - } - - if (process->state != NXT_PROCESS_STATE_CREATING) { - nxt_port_remove_notify_others(task, process); - } - - nxt_process_close_ports(task, process); - - if (port != NULL) { - nxt_port_use(task, port, -1); - } - - if (nxt_proto_exiting && nxt_queue_is_empty(&nxt_proto_children)) { - nxt_process_quit(task, 0); - return; - } - } -} - - -static nxt_app_module_t * -nxt_app_module_load(nxt_task_t *task, const char *name) -{ - char *err; - void *dl; - nxt_app_module_t *app; - - dl = dlopen(name, RTLD_GLOBAL | RTLD_LAZY); - - if (nxt_slow_path(dl == NULL)) { - err = dlerror(); - nxt_alert(task, "dlopen(\"%s\") failed: \"%s\"", - name, err != NULL ? err : "(null)"); - return NULL; - } - - app = dlsym(dl, "nxt_app_module"); - - if (nxt_slow_path(app == NULL)) { - err = dlerror(); - nxt_alert(task, "dlsym(\"%s\", \"nxt_app_module\") failed: \"%s\"", - name, err != NULL ? err : "(null)"); - - if (dlclose(dl) != 0) { - err = dlerror(); - nxt_alert(task, "dlclose(\"%s\") failed: \"%s\"", - name, err != NULL ? err : "(null)"); - } - } - - return app; -} - - -static nxt_int_t -nxt_app_set_environment(nxt_conf_value_t *environment) -{ - char *env, *p; - uint32_t next; - nxt_str_t name, value; - nxt_conf_value_t *value_obj; - - if (environment != NULL) { - next = 0; - - for ( ;; ) { - value_obj = nxt_conf_next_object_member(environment, &name, &next); - if (value_obj == NULL) { - break; - } - - nxt_conf_get_string(value_obj, &value); - - env = nxt_malloc(name.length + value.length + 2); - if (nxt_slow_path(env == NULL)) { - return NXT_ERROR; - } - - p = nxt_cpymem(env, name.start, name.length); - *p++ = '='; - p = nxt_cpymem(p, value.start, value.length); - *p = '\0'; - - if (nxt_slow_path(putenv(env) != 0)) { - return NXT_ERROR; - } - } - } - - return NXT_OK; -} - - -nxt_int_t -nxt_app_set_logs(void) -{ - nxt_int_t ret; - nxt_file_t file; - nxt_task_t *task; - nxt_thread_t *thr; - nxt_process_t *process; - nxt_runtime_t *rt; - nxt_common_app_conf_t *app_conf; - - thr = nxt_thread(); - - task = thr->task; - - rt = task->thread->runtime; - if (!rt->daemon) { - return NXT_OK; - } - - process = rt->port_by_type[NXT_PROCESS_PROTOTYPE]->process; - app_conf = process->data.app; - - if (app_conf->stdout_log != NULL) { - nxt_memzero(&file, sizeof(nxt_file_t)); - file.log_level = 1; - file.name = (u_char *) app_conf->stdout_log; - ret = nxt_file_open(task, &file, O_WRONLY | O_APPEND, O_CREAT, 0666); - if (ret == NXT_ERROR) { - return NXT_ERROR; - } - - nxt_file_stdout(&file); - nxt_file_close(task, &file); - } - - if (app_conf->stderr_log != NULL) { - nxt_memzero(&file, sizeof(nxt_file_t)); - file.log_level = 1; - file.name = (u_char *) app_conf->stderr_log; - ret = nxt_file_open(task, &file, O_WRONLY | O_APPEND, O_CREAT, 0666); - if (ret == NXT_ERROR) { - return NXT_ERROR; - } - - nxt_file_stderr(&file); - nxt_file_close(task, &file); - } - - return NXT_OK; -} - - -static u_char * -nxt_cstr_dup(nxt_mp_t *mp, u_char *dst, u_char *src) -{ - u_char *p; - size_t len; - - len = nxt_strlen(src); - - if (dst == NULL) { - dst = nxt_mp_alloc(mp, len + 1); - if (nxt_slow_path(dst == NULL)) { - return NULL; - } - } - - p = nxt_cpymem(dst, src, len); - *p = '\0'; - - return dst; -} - - -static nxt_int_t -nxt_app_setup(nxt_task_t *task, nxt_process_t *process) -{ - nxt_process_init_t *init; - - process->state = NXT_PROCESS_STATE_CREATED; - - init = nxt_process_init(process); - - return init->start(task, &process->data); -} - - -nxt_app_lang_module_t * -nxt_app_lang_module(nxt_runtime_t *rt, nxt_str_t *name) -{ - u_char *p, *end, *version; - size_t version_length; - nxt_uint_t i, n; - nxt_app_type_t type; - nxt_app_lang_module_t *lang; - - end = name->start + name->length; - version = end; - - for (p = name->start; p < end; p++) { - if (*p == ' ') { - version = p + 1; - break; - } - - if (*p >= '0' && *p <= '9') { - version = p; - break; - } - } - - type = nxt_app_parse_type(name->start, p - name->start); - - if (type == NXT_APP_UNKNOWN) { - return NULL; - } - - version_length = end - version; - - lang = rt->languages->elts; - n = rt->languages->nelts; - - for (i = 0; i < n; i++) { - - /* - * Versions are sorted in descending order - * so first match chooses the highest version. - */ - - if (lang[i].type == type - && nxt_strvers_match(lang[i].version, version, version_length)) - { - return &lang[i]; - } - } - - return NULL; -} - - -nxt_app_type_t -nxt_app_parse_type(u_char *p, size_t length) -{ - nxt_str_t str; - - str.length = length; - str.start = p; - - if (nxt_str_eq(&str, "external", 8) || nxt_str_eq(&str, "go", 2)) { - return NXT_APP_EXTERNAL; - - } else if (nxt_str_eq(&str, "python", 6)) { - return NXT_APP_PYTHON; - - } else if (nxt_str_eq(&str, "php", 3)) { - return NXT_APP_PHP; - - } else if (nxt_str_eq(&str, "perl", 4)) { - return NXT_APP_PERL; - - } else if (nxt_str_eq(&str, "ruby", 4)) { - return NXT_APP_RUBY; - - } else if (nxt_str_eq(&str, "java", 4)) { - return NXT_APP_JAVA; - - } else if (nxt_str_eq(&str, "wasm-wasi-component", 19)) { - return NXT_APP_WASM_WC; - - } else if (nxt_str_eq(&str, "wasm", 4)) { - return NXT_APP_WASM; - } - - return NXT_APP_UNKNOWN; -} - - -nxt_int_t -nxt_unit_default_init(nxt_task_t *task, nxt_unit_init_t *init, - nxt_common_app_conf_t *conf) -{ - nxt_port_t *my_port, *proto_port, *router_port; - nxt_runtime_t *rt; - - nxt_memzero(init, sizeof(nxt_unit_init_t)); - - rt = task->thread->runtime; - - proto_port = rt->port_by_type[NXT_PROCESS_PROTOTYPE]; - if (nxt_slow_path(proto_port == NULL)) { - return NXT_ERROR; - } - - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - if (nxt_slow_path(router_port == NULL)) { - return NXT_ERROR; - } - - my_port = nxt_runtime_port_find(rt, nxt_pid, 0); - if (nxt_slow_path(my_port == NULL)) { - return NXT_ERROR; - } - - init->ready_port.id.pid = proto_port->pid; - init->ready_port.id.id = proto_port->id; - init->ready_port.in_fd = -1; - init->ready_port.out_fd = proto_port->pair[1]; - - init->ready_stream = my_port->process->stream; - - init->router_port.id.pid = router_port->pid; - init->router_port.id.id = router_port->id; - init->router_port.in_fd = -1; - init->router_port.out_fd = router_port->pair[1]; - - init->read_port.id.pid = my_port->pid; - init->read_port.id.id = my_port->id; - init->read_port.in_fd = my_port->pair[0]; - init->read_port.out_fd = my_port->pair[1]; - - init->shared_port_fd = conf->shared_port_fd; - init->shared_queue_fd = conf->shared_queue_fd; - - init->log_fd = 2; - - init->shm_limit = conf->shm_limit; - init->request_limit = conf->request_limit; - - return NXT_OK; -} - - -static nxt_int_t -nxt_proto_lvlhsh_isolated_pid_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_pid_t *qpid; - nxt_process_t *process; - - process = data; - qpid = (nxt_pid_t *) lhq->key.start; - - if (*qpid == process->isolated_pid) { - return NXT_OK; - } - - return NXT_DECLINED; -} - - -static const nxt_lvlhsh_proto_t lvlhsh_processes_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_proto_lvlhsh_isolated_pid_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -nxt_inline void -nxt_proto_process_lhq_pid(nxt_lvlhsh_query_t *lhq, nxt_pid_t *pid) -{ - lhq->key_hash = nxt_murmur_hash2(pid, sizeof(nxt_pid_t)); - lhq->key.length = sizeof(nxt_pid_t); - lhq->key.start = (u_char *) pid; - lhq->proto = &lvlhsh_processes_proto; -} - - -static void -nxt_proto_process_add(nxt_task_t *task, nxt_process_t *process) -{ - nxt_runtime_t *rt; - nxt_lvlhsh_query_t lhq; - - rt = task->thread->runtime; - - nxt_proto_process_lhq_pid(&lhq, &process->isolated_pid); - - lhq.replace = 0; - lhq.value = process; - lhq.pool = rt->mem_pool; - - switch (nxt_lvlhsh_insert(&nxt_proto_processes, &lhq)) { - - case NXT_OK: - nxt_debug(task, "process (isolated %PI) added", process->isolated_pid); - - nxt_queue_insert_tail(&nxt_proto_children, &process->link); - break; - - default: - nxt_alert(task, "process (isolated %PI) failed to add", - process->isolated_pid); - break; - } -} - - -static nxt_process_t * -nxt_proto_process_remove(nxt_task_t *task, nxt_pid_t pid) -{ - nxt_runtime_t *rt; - nxt_process_t *process; - nxt_lvlhsh_query_t lhq; - - nxt_proto_process_lhq_pid(&lhq, &pid); - - rt = task->thread->runtime; - - lhq.pool = rt->mem_pool; - - switch (nxt_lvlhsh_delete(&nxt_proto_processes, &lhq)) { - - case NXT_OK: - nxt_debug(task, "process (isolated %PI) removed", pid); - - process = lhq.value; - - nxt_queue_remove(&process->link); - process->link.next = NULL; - - break; - - default: - nxt_debug(task, "process (isolated %PI) remove failed", pid); - process = NULL; - break; - } - - return process; -} - - -static nxt_process_t * -nxt_proto_process_find(nxt_task_t *task, nxt_pid_t pid) -{ - nxt_process_t *process; - nxt_lvlhsh_query_t lhq; - - nxt_proto_process_lhq_pid(&lhq, &pid); - - if (nxt_lvlhsh_find(&nxt_proto_processes, &lhq) == NXT_OK) { - process = lhq.value; - - } else { - nxt_debug(task, "process (isolated %PI) not found", pid); - - process = NULL; - } - - return process; -} diff --git a/src/nxt_application.h b/src/nxt_application.h deleted file mode 100644 index f5d7a9df..00000000 --- a/src/nxt_application.h +++ /dev/null @@ -1,177 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_APPLICATION_H_INCLUDED_ -#define _NXT_APPLICATION_H_INCLUDED_ - - -#include - -#include - - -typedef enum { - NXT_APP_EXTERNAL, - NXT_APP_PYTHON, - NXT_APP_PHP, - NXT_APP_PERL, - NXT_APP_RUBY, - NXT_APP_JAVA, - NXT_APP_WASM, - NXT_APP_WASM_WC, - - NXT_APP_UNKNOWN, -} nxt_app_type_t; - - -typedef struct nxt_app_module_s nxt_app_module_t; -typedef nxt_int_t (*nxt_application_setup_t)(nxt_task_t *task, - nxt_process_t *process, nxt_common_app_conf_t *conf); - - -typedef struct { - nxt_app_type_t type; - u_char *version; - char *file; - nxt_app_module_t *module; - nxt_array_t *mounts; /* of nxt_fs_mount_t */ -} nxt_app_lang_module_t; - - -typedef struct { - char *executable; - nxt_conf_value_t *arguments; -} nxt_external_app_conf_t; - - -typedef struct { - char *home; - nxt_conf_value_t *path; - nxt_str_t protocol; - uint32_t threads; - uint32_t thread_stack_size; - nxt_conf_value_t *targets; -} nxt_python_app_conf_t; - - -typedef struct { - nxt_conf_value_t *targets; - nxt_conf_value_t *options; -} nxt_php_app_conf_t; - - -typedef struct { - char *script; - uint32_t threads; - uint32_t thread_stack_size; -} nxt_perl_app_conf_t; - - -typedef struct { - nxt_str_t script; - uint32_t threads; - nxt_str_t hooks; -} nxt_ruby_app_conf_t; - - -typedef struct { - nxt_conf_value_t *classpath; - char *webapp; - nxt_conf_value_t *options; - char *unit_jars; - uint32_t threads; - uint32_t thread_stack_size; -} nxt_java_app_conf_t; - - -typedef struct { - const char *module; - - const char *request_handler; - const char *malloc_handler; - const char *free_handler; - - const char *module_init_handler; - const char *module_end_handler; - const char *request_init_handler; - const char *request_end_handler; - const char *response_end_handler; - - nxt_conf_value_t *access; -} nxt_wasm_app_conf_t; - - -typedef struct { - const char *component; - - nxt_conf_value_t *access; -} nxt_wasm_wc_app_conf_t; - - -struct nxt_common_app_conf_s { - nxt_str_t name; - nxt_str_t type; - nxt_str_t user; - nxt_str_t group; - - char *stdout_log; - char *stderr_log; - - char *working_directory; - nxt_conf_value_t *environment; - - nxt_conf_value_t *isolation; - nxt_conf_value_t *limits; - - size_t shm_limit; - uint32_t request_limit; - - nxt_fd_t shared_port_fd; - nxt_fd_t shared_queue_fd; - - union { - nxt_external_app_conf_t external; - nxt_python_app_conf_t python; - nxt_php_app_conf_t php; - nxt_perl_app_conf_t perl; - nxt_ruby_app_conf_t ruby; - nxt_java_app_conf_t java; - nxt_wasm_app_conf_t wasm; - nxt_wasm_wc_app_conf_t wasm_wc; - } u; - - nxt_conf_value_t *self; -}; - - -struct nxt_app_module_s { - size_t compat_length; - uint32_t *compat; - - nxt_str_t type; - const char *version; - - const nxt_fs_mount_t *mounts; - nxt_uint_t nmounts; - - nxt_application_setup_t setup; - nxt_process_start_t start; -}; - - -nxt_app_lang_module_t *nxt_app_lang_module(nxt_runtime_t *rt, nxt_str_t *name); -nxt_app_type_t nxt_app_parse_type(u_char *p, size_t length); - -NXT_EXPORT extern nxt_str_t nxt_server; -extern nxt_app_module_t nxt_external_module; - -NXT_EXPORT nxt_int_t nxt_unit_default_init(nxt_task_t *task, - nxt_unit_init_t *init, nxt_common_app_conf_t *conf); - -NXT_EXPORT nxt_int_t nxt_app_set_logs(void); - -#endif /* _NXT_APPLICATION_H_INCLIDED_ */ diff --git a/src/nxt_array.c b/src/nxt_array.c deleted file mode 100644 index 1e13c22a..00000000 --- a/src/nxt_array.c +++ /dev/null @@ -1,150 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_array_t * -nxt_array_create(nxt_mp_t *mp, nxt_uint_t n, size_t size) -{ - nxt_array_t *array; - - array = nxt_mp_alloc(mp, sizeof(nxt_array_t) + n * size); - - if (nxt_slow_path(array == NULL)) { - return NULL; - } - - array->elts = nxt_pointer_to(array, sizeof(nxt_array_t)); - array->nelts = 0; - array->size = size; - array->nalloc = n; - array->mem_pool = mp; - - return array; -} - - -void -nxt_array_destroy(nxt_array_t *array) -{ - if (array->elts != nxt_pointer_to(array, sizeof(nxt_array_t))) { - nxt_mp_free(array->mem_pool, array->elts); - } - - nxt_mp_free(array->mem_pool, array); -} - - -void * -nxt_array_add(nxt_array_t *array) -{ - void *p; - uint32_t nalloc, new_alloc; - - nalloc = array->nalloc; - - if (array->nelts == nalloc) { - - if (nalloc < 16) { - /* Allocate new array twice larger than current. */ - new_alloc = (nalloc == 0) ? 4 : nalloc * 2; - - } else { - /* Allocate new array 1.5 times larger than current. */ - new_alloc = nalloc + nalloc / 2; - } - - p = nxt_mp_alloc(array->mem_pool, array->size * new_alloc); - - if (nxt_slow_path(p == NULL)) { - return NULL; - } - - nxt_memcpy(p, array->elts, array->size * nalloc); - - if (array->elts != nxt_pointer_to(array, sizeof(nxt_array_t))) { - nxt_mp_free(array->mem_pool, array->elts); - } - - array->elts = p; - array->nalloc = new_alloc; - } - - p = nxt_pointer_to(array->elts, array->size * array->nelts); - array->nelts++; - - return p; -} - - -void * -nxt_array_zero_add(nxt_array_t *array) -{ - void *p; - - p = nxt_array_add(array); - - if (nxt_fast_path(p != NULL)) { - nxt_memzero(p, array->size); - } - - return p; -} - - -void -nxt_array_remove(nxt_array_t *array, void *elt) -{ - void *last; - - last = nxt_array_last(array); - - if (elt != last) { - nxt_memcpy(elt, last, array->size); - } - - array->nelts--; -} - - -nxt_array_t * -nxt_array_copy(nxt_mp_t *mp, nxt_array_t *dst, nxt_array_t *src) -{ - void *data; - uint32_t i, size; - - size = src->size; - - if (dst == NULL) { - dst = nxt_array_create(mp, src->nelts, size); - if (nxt_slow_path(dst == NULL)) { - return NULL; - } - } - - nxt_assert(size == dst->size); - - if (dst->nalloc >= src->nelts) { - nxt_memcpy(dst->elts, src->elts, src->nelts * size); - - } else { - nxt_memcpy(dst->elts, src->elts, dst->nelts * size); - - for (i = dst->nelts; i < src->nelts; i++) { - data = nxt_array_add(dst); - if (nxt_slow_path(data == NULL)) { - return NULL; - } - - nxt_memcpy(data, src->elts + (i * size), size); - } - } - - dst->nelts = src->nelts; - - return dst; -} diff --git a/src/nxt_array.h b/src/nxt_array.h deleted file mode 100644 index f06ff14c..00000000 --- a/src/nxt_array.h +++ /dev/null @@ -1,58 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_ARRAY_H_INCLUDED_ -#define _NXT_ARRAY_H_INCLUDED_ - - -typedef struct { - void *elts; - /* nelts has uint32_t type because it is used most often. */ - uint32_t nelts; - uint16_t size; - uint16_t nalloc; - nxt_mp_t *mem_pool; -} nxt_array_t; - - -nxt_inline void -nxt_array_init(nxt_array_t *array, nxt_mp_t *mp, size_t size) -{ - array->elts = nxt_pointer_to(array, sizeof(nxt_array_t)); - array->size = size; - array->mem_pool = mp; -} - -NXT_EXPORT nxt_array_t *nxt_array_create(nxt_mp_t *mp, nxt_uint_t n, - size_t size); -NXT_EXPORT void nxt_array_destroy(nxt_array_t *array); -NXT_EXPORT void *nxt_array_add(nxt_array_t *array); -NXT_EXPORT void *nxt_array_zero_add(nxt_array_t *array); -NXT_EXPORT void nxt_array_remove(nxt_array_t *array, void *elt); -NXT_EXPORT nxt_array_t *nxt_array_copy(nxt_mp_t *mp, nxt_array_t *dst, - nxt_array_t *src); - -#define nxt_array_last(array) \ - nxt_pointer_to((array)->elts, (array)->size * ((array)->nelts - 1)) - - -#define nxt_array_reset(array) \ - (array)->nelts = 0; - - -#define nxt_array_is_empty(array) \ - ((array)->nelts == 0) - - -nxt_inline void * -nxt_array_remove_last(nxt_array_t *array) -{ - array->nelts--; - return nxt_pointer_to(array->elts, array->size * array->nelts); -} - - -#endif /* _NXT_ARRAY_H_INCLUDED_ */ diff --git a/src/nxt_atomic.h b/src/nxt_atomic.h deleted file mode 100644 index dae999a9..00000000 --- a/src/nxt_atomic.h +++ /dev/null @@ -1,269 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_ATOMIC_H_INCLUDED_ -#define _NXT_ATOMIC_H_INCLUDED_ - - -/* - * nxt_atomic_try_lock() must set an acquire barrier on lock. - * nxt_atomic_xchg() must set an acquire barrier. - * nxt_atomic_release() must set a release barrier. - */ - -#if (NXT_HAVE_GCC_ATOMIC) /* GCC 4.1 builtin atomic operations */ - -typedef intptr_t nxt_atomic_int_t; -typedef uintptr_t nxt_atomic_uint_t; -typedef volatile nxt_atomic_uint_t nxt_atomic_t; - -/* - * __sync_bool_compare_and_swap() is a full barrier. - * __sync_lock_test_and_set() is an acquire barrier. - * __sync_lock_release() is a release barrier. - */ - -#define nxt_atomic_cmp_set(lock, cmp, set) \ - __sync_bool_compare_and_swap(lock, cmp, set) - - -#define nxt_atomic_xchg(lock, set) \ - __sync_lock_test_and_set(lock, set) - - -#define nxt_atomic_fetch_add(value, add) \ - __sync_fetch_and_add(value, add) - - -#define nxt_atomic_try_lock(lock) \ - nxt_atomic_cmp_set(lock, 0, 1) - - -#define nxt_atomic_release(lock) \ - __sync_lock_release(lock) - - -#define nxt_atomic_or_fetch(ptr, val) \ - __sync_or_and_fetch(ptr, val) - - -#define nxt_atomic_and_fetch(ptr, val) \ - __sync_and_and_fetch(ptr, val) - - -#if (__i386__ || __i386 || __amd64__ || __amd64) -#define nxt_cpu_pause() \ - __asm__ ("pause") - -#elif (__aarch64__ || __arm64__) -#define nxt_cpu_pause() \ - __asm__ ("isb") - -#else -#define nxt_cpu_pause() -#endif - - -#elif (NXT_HAVE_SOLARIS_ATOMIC) /* Solaris 10 */ - -#include - -typedef long nxt_atomic_int_t; -typedef ulong_t nxt_atomic_uint_t; -typedef volatile nxt_atomic_uint_t nxt_atomic_t; - - -#define nxt_atomic_cmp_set(lock, cmp, set) \ - (atomic_cas_ulong(lock, cmp, set) == (ulong_t) cmp) - - -#define nxt_atomic_xchg(lock, set) \ - atomic_add_swap(lock, set) - - -#define nxt_atomic_fetch_add(value, add) \ - (atomic_add_long_nv(value, add) - add) - - -#define nxt_atomic_or_fetch(ptr, val) \ - atomic_or_ulong_nv(ptr, val) - - -#define nxt_atomic_and_fetch(ptr, val) \ - atomic_and_ulong_nv(ptr, val) - - -/* - * Solaris uses SPARC Total Store Order model. In this model: - * 1) Each atomic load-store instruction behaves as if it were followed by - * #LoadLoad, #LoadStore, and #StoreStore barriers. - * 2) Each load instruction behaves as if it were followed by - * #LoadLoad and #LoadStore barriers. - * 3) Each store instruction behaves as if it were followed by - * #StoreStore barrier. - * - * In X86_64 atomic instructions set a full barrier and usual instructions - * set implicit #LoadLoad, #LoadStore, and #StoreStore barriers. - * - * An acquire barrier requires at least #LoadLoad and #LoadStore barriers - * and they are provided by atomic load-store instruction. - * - * A release barrier requires at least #LoadStore and #StoreStore barriers, - * so a lock release does not require an explicit barrier: all load - * instructions in critical section is followed by implicit #LoadStore - * barrier and all store instructions are followed by implicit #StoreStore - * barrier. - */ - -#define nxt_atomic_try_lock(lock) \ - nxt_atomic_cmp_set(lock, 0, 1) - - -#define nxt_atomic_release(lock) \ - *lock = 0; - - -/* - * The "rep; nop" is used instead of "pause" to omit the "[ PAUSE ]" hardware - * capability added by linker since Solaris ld.so.1 does not know about it: - * - * ld.so.1: ...: fatal: hardware capability unsupported: 0x2000 [ PAUSE ] - */ - -#if (__i386__ || __i386 || __amd64__ || __amd64) -#define nxt_cpu_pause() \ - __asm__ ("rep; nop") - -#else -#define nxt_cpu_pause() -#endif - - -/* elif (NXT_HAVE_MACOSX_ATOMIC) */ - -/* - * The atomic(3) interface has been introduced in MacOS 10.4 (Tiger) and - * extended in 10.5 (Leopard). However its support is omitted because: - * - * 1) the interface is still incomplete: - * *) there are OSAtomicAdd32Barrier() and OSAtomicAdd64Barrier() - * but no OSAtomicAddLongBarrier(); - * *) there is no interface for XCHG operation. - * - * 2) the interface is tuned for non-SMP systems due to omission of the - * LOCK prefix on single CPU system but nowadays MacOSX systems are at - * least dual core. Thus these indirect calls just add overhead as - * compared with inlined atomic operations which are supported by GCC - * and Clang in modern MacOSX systems. - */ - - -#elif (NXT_HAVE_XLC_ATOMIC) /* XL C/C++ V8.0 for AIX */ - -#if (NXT_64BIT) - -typedef long nxt_atomic_int_t; -typedef unsigned long nxt_atomic_uint_t; -typedef volatile nxt_atomic_int_t nxt_atomic_t; - - -nxt_inline nxt_bool_t -nxt_atomic_cmp_set(nxt_atomic_t *lock, nxt_atomic_int_t cmp, - nxt_atomic_int_t set) -{ - nxt_atomic_int_t old; - - old = cmp; - - return __compare_and_swaplp(lock, &old, set); -} - - -#define nxt_atomic_xchg(lock, set) \ - __fetch_and_swaplp(lock, set) - - -#define nxt_atomic_fetch_add(value, add) \ - __fetch_and_addlp(value, add) - - -#else /* NXT_32BIT */ - -typedef int nxt_atomic_int_t; -typedef unsigned int nxt_atomic_uint_t; -typedef volatile nxt_atomic_int_t nxt_atomic_t; - - -nxt_inline nxt_bool_t -nxt_atomic_cmp_set(nxt_atomic_t *lock, nxt_atomic_int_t cmp, - nxt_atomic_int_t set) -{ - nxt_atomic_int_t old; - - old = cmp; - - return __compare_and_swap(lock, &old, set); -} - - -#define nxt_atomic_xchg(lock, set) \ - __fetch_and_swap(lock, set) - - -#define nxt_atomic_fetch_add(value, add) \ - __fetch_and_add(value, add) - - -#endif /* NXT_32BIT*/ - - -/* - * __lwsync() is a "lwsync" instruction that sets #LoadLoad, #LoadStore, - * and #StoreStore barrier. - * - * __compare_and_swap() is a pair of "ldarx" and "stdcx" instructions. - * A "lwsync" does not set #StoreLoad barrier so it can not be used after - * this pair since a next load inside critical section can be performed - * after the "ldarx" instruction but before the "stdcx" instruction. - * However, this next load instruction will load correct data because - * otherwise the "ldarx/stdcx" pair will fail and this data will be - * discarded. Nevertheless, the "isync" instruction is used for sure. - * - * A full barrier can be set with __sync(), a "sync" instruction, but there - * is also a faster __isync(), an "isync" instruction. This instruction is - * not a memory barrier but an instruction barrier. An "isync" instruction - * causes the processor to complete execution of all previous instructions - * and then to discard instructions (which may have begun execution) following - * the "isync". After the "isync" is executed, the following instructions - * then begin execution. The "isync" is used to ensure that the loads - * following entry into a critical section are not performed (because of - * aggressive out-of-order or speculative execution in the processor) until - * the lock is granted. - */ - -nxt_inline nxt_bool_t -nxt_atomic_try_lock(nxt_atomic_t *lock) -{ - if (nxt_atomic_cmp_set(lock, 0, 1)) { - __isync(); - return 1; - } - - return 0; -} - - -#define nxt_atomic_release(lock) \ - do { __lwsync(); *lock = 0; } while (0) - - -#define nxt_cpu_pause() - - -#endif /* NXT_HAVE_XLC_ATOMIC */ - - -#endif /* _NXT_ATOMIC_H_INCLUDED_ */ diff --git a/src/nxt_buf.c b/src/nxt_buf.c deleted file mode 100644 index cbde069e..00000000 --- a/src/nxt_buf.c +++ /dev/null @@ -1,329 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static void nxt_buf_completion(nxt_task_t *task, void *obj, void *data); -static void nxt_buf_ts_completion(nxt_task_t *task, void *obj, void *data); - - -typedef struct { - nxt_work_t work; - nxt_event_engine_t *engine; -} nxt_buf_ts_t; - - -void -nxt_buf_mem_init(nxt_buf_t *b, void *start, size_t size) -{ - b->mem.start = start; - b->mem.pos = start; - b->mem.free = start; - b->mem.end = nxt_pointer_to(start, size); -} - - -nxt_buf_t * -nxt_buf_mem_alloc(nxt_mp_t *mp, size_t size, nxt_uint_t flags) -{ - nxt_buf_t *b; - - b = nxt_mp_alloc(mp, NXT_BUF_MEM_SIZE + size); - if (nxt_slow_path(b == NULL)) { - return NULL; - } - - nxt_memzero(b, NXT_BUF_MEM_SIZE); - - b->data = mp; - b->completion_handler = nxt_buf_completion; - - if (size != 0) { - b->mem.start = nxt_pointer_to(b, NXT_BUF_MEM_SIZE); - b->mem.pos = b->mem.start; - b->mem.free = b->mem.start; - b->mem.end = b->mem.start + size; - } - - return b; -} - - -nxt_buf_t * -nxt_buf_mem_ts_alloc(nxt_task_t *task, nxt_mp_t *mp, size_t size) -{ - nxt_buf_t *b; - nxt_buf_ts_t *ts; - - b = nxt_mp_alloc(mp, NXT_BUF_MEM_SIZE + sizeof(nxt_buf_ts_t) + size); - if (nxt_slow_path(b == NULL)) { - return NULL; - } - - nxt_mp_retain(mp); - - nxt_memzero(b, NXT_BUF_MEM_SIZE + sizeof(nxt_buf_ts_t)); - - b->data = mp; - b->completion_handler = nxt_buf_ts_completion; - b->is_ts = 1; - - if (size != 0) { - b->mem.start = nxt_pointer_to(b, NXT_BUF_MEM_SIZE - + sizeof(nxt_buf_ts_t)); - b->mem.pos = b->mem.start; - b->mem.free = b->mem.start; - b->mem.end = b->mem.start + size; - } - - ts = nxt_pointer_to(b, NXT_BUF_MEM_SIZE); - ts->engine = task->thread->engine; - - ts->work.handler = nxt_buf_ts_completion; - ts->work.task = task; - ts->work.obj = b; - ts->work.data = b->parent; - - return b; -} - - -nxt_buf_t * -nxt_buf_file_alloc(nxt_mp_t *mp, size_t size, nxt_uint_t flags) -{ - nxt_buf_t *b; - - b = nxt_mp_alloc(mp, NXT_BUF_FILE_SIZE + size); - if (nxt_slow_path(b == NULL)) { - return NULL; - } - - nxt_memzero(b, NXT_BUF_FILE_SIZE); - - b->data = mp; - b->completion_handler = nxt_buf_completion; - nxt_buf_set_file(b); - - if (size != 0) { - b->mem.start = nxt_pointer_to(b, NXT_BUF_FILE_SIZE); - b->mem.pos = b->mem.start; - b->mem.free = b->mem.start; - b->mem.end = b->mem.start + size; - } - - return b; -} - - -nxt_buf_t * -nxt_buf_mmap_alloc(nxt_mp_t *mp, size_t size) -{ - nxt_buf_t *b; - - b = nxt_mp_zalloc(mp, NXT_BUF_MMAP_SIZE); - - if (nxt_fast_path(b != NULL)) { - b->data = mp; - b->completion_handler = nxt_buf_completion; - - nxt_buf_set_file(b); - nxt_buf_set_mmap(b); - nxt_buf_mem_set_size(&b->mem, size); - } - - return b; -} - - -nxt_buf_t * -nxt_buf_sync_alloc(nxt_mp_t *mp, nxt_uint_t flags) -{ - nxt_buf_t *b; - - b = nxt_mp_zalloc(mp, NXT_BUF_MEM_SIZE); - - if (nxt_fast_path(b != NULL)) { - b->data = mp; - b->completion_handler = nxt_buf_completion; - - nxt_buf_set_sync(b); - b->is_nobuf = ((flags & NXT_BUF_SYNC_NOBUF) != 0); - b->is_flush = ((flags & NXT_BUF_SYNC_FLUSH) != 0); - b->is_last = ((flags & NXT_BUF_SYNC_LAST) != 0); - } - - return b; -} - - -void -nxt_buf_chain_add(nxt_buf_t **head, nxt_buf_t *in) -{ - nxt_buf_t *b, **prev; - - prev = head; - - for (b = *head; b != NULL; b = b->next) { - prev = &b->next; - } - - *prev = in; -} - - -size_t -nxt_buf_chain_length(nxt_buf_t *b) -{ - size_t length; - - length = 0; - - while (b != NULL) { - if (!nxt_buf_is_sync(b)) { - length += b->mem.free - b->mem.pos; - } - - b = b->next; - } - - return length; -} - - -static void -nxt_buf_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_mp_t *mp; - nxt_buf_t *b, *next, *parent; - - b = obj; - - nxt_debug(task, "buf completion: %p %p", b, b->mem.start); - - nxt_assert(data == b->parent); - - do { - next = b->next; - parent = b->parent; - mp = b->data; - - nxt_mp_free(mp, b); - - nxt_buf_parent_completion(task, parent); - - b = next; - } while (b != NULL); -} - - -void -nxt_buf_parent_completion(nxt_task_t *task, nxt_buf_t *parent) -{ - if (parent != NULL) { - nxt_debug(task, "parent retain:%uD", parent->retain); - - parent->retain--; - - if (parent->retain == 0) { - parent->mem.pos = parent->mem.free; - - parent->completion_handler(task, parent, parent->parent); - } - } -} - - -nxt_int_t -nxt_buf_ts_handle(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *b; - nxt_buf_ts_t *ts; - - b = obj; - - nxt_assert(b->is_ts != 0); - - ts = nxt_pointer_to(b, NXT_BUF_MEM_SIZE); - - if (ts->engine != task->thread->engine) { - - nxt_debug(task, "buf ts: %p current engine is %p, expected %p", - b, task->thread->engine, ts->engine); - - ts->work.handler = b->completion_handler; - ts->work.obj = obj; - ts->work.data = data; - - nxt_event_engine_post(ts->engine, &ts->work); - - return 1; - } - - return 0; -} - - -static void -nxt_buf_ts_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_mp_t *mp; - nxt_buf_t *b, *next, *parent; - - b = obj; - - if (nxt_buf_ts_handle(task, obj, data)) { - return; - } - - nxt_debug(task, "buf ts completion: %p %p", b, b->mem.start); - - nxt_assert(data == b->parent); - - do { - next = b->next; - parent = b->parent; - mp = b->data; - - nxt_mp_free(mp, b); - nxt_mp_release(mp); - - nxt_buf_parent_completion(task, parent); - - b = next; - } while (b != NULL); -} - - -nxt_buf_t * -nxt_buf_make_plain(nxt_mp_t *mp, nxt_buf_t *src, size_t size) -{ - nxt_buf_t *b, *i; - - if (nxt_slow_path(size == 0)) { - for (i = src; i != NULL; i = i->next) { - size += nxt_buf_used_size(i); - } - } - - b = nxt_buf_mem_alloc(mp, size, 0); - - if (nxt_slow_path(b == NULL)) { - return NULL; - } - - for (i = src; i != NULL; i = i->next) { - if (nxt_slow_path(nxt_buf_mem_free_size(&b->mem) - < nxt_buf_used_size(i))) - { - break; - } - - b->mem.free = nxt_cpymem(b->mem.free, i->mem.pos, nxt_buf_used_size(i)); - } - - return b; -} diff --git a/src/nxt_buf.h b/src/nxt_buf.h deleted file mode 100644 index f1e2879f..00000000 --- a/src/nxt_buf.h +++ /dev/null @@ -1,269 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_BUF_H_INCLUDED_ -#define _NXT_BUF_H_INCLUDED_ - - -/* - * There are four types of buffers. They are different sizes, so they - * should be allocated by appropriate nxt_buf_XXX_alloc() function. - * - * 1) Memory-only buffers, their size is less than nxt_buf_t size, it - * is equal to offsetof(nxt_buf_t, file_pos), that is it is nxt_buf_t - * without file and mmap part. The buffers are frequently used, so - * the reduction allows to save 20-32 bytes depending on platform. - * - * 2) Memory/file buffers, on Unix their size is exactly nxt_buf_t size, - * since nxt_mem_map_file_ctx_t() is empty macro. On Windows the size - * equals offsetof(nxt_buf_t, mmap), that is it is nxt_buf_t without - * memory map context part. The buffers can contain both memory and - * file pointers at once, or only memory or file pointers. - * - * 3) Memory mapped buffers are similar to the memory/file buffers. Their - * size is exactly nxt_buf_t size. The buffers can contain both memory - * and file pointers at once, or only memory or file pointers. If a - * buffer is not currently mapped in memory, its mapping size is stored - * in the mem.end field and available via nxt_buf_mem_size() macro. - * - * 4) Sync buffers, their size is the same size as memory-only buffers - * size. A sync buffer can be smaller but for memory pool cache - * purpose it is better to allocate it as frequently used memory-only - * buffer. The buffers are used to synchronize pipeline processing - * completion, because data buffers in the pipeline can be completed - * and freed before their final output will even be passed to a peer. - * For this purpose a sync buffer is allocated with the stop flag which - * stops buffer chain completion processing on the sync buffer in - * nxt_sendbuf_update() and nxt_sendbuf_completion(). - * Clearing the stop flag allows to continue completion processing. - * - * The last flag means the end of the output and must be set only - * in a sync buffer. The last flag is not permitted in memory and - * file buffers since it requires special handling while conversion - * one buffer to another. - * - * The nxt_buf_used_size() macro treats a sync buffer as a memory-only - * buffer which has NULL pointers, thus the buffer content size is zero. - * If allocated size of sync buffer would be lesser than memory-only - * buffer, then the special memory flag would be required because - * currently presence of memory part is indicated by non-NULL pointer - * to a content in memory. - * - * All types of buffers can have the flush flag that means the buffer - * should be sent as much as possible. - */ - -typedef struct { - u_char *pos; - u_char *free; - u_char *start; - u_char *end; -} nxt_buf_mem_t; - - -struct nxt_buf_s { - void *data; - nxt_work_handler_t completion_handler; - void *parent; - - /* - * The next link, flags, and nxt_buf_mem_t should - * reside together to improve cache locality. - */ - nxt_buf_t *next; - - uint32_t retain; - - uint8_t cache_hint; - - uint8_t is_file:1; - uint8_t is_mmap:1; - uint8_t is_port_mmap:1; - uint8_t is_sync:1; - uint8_t is_nobuf:1; - uint8_t is_flush:1; - uint8_t is_last:1; - uint8_t is_port_mmap_sent:1; - uint8_t is_ts:1; - - nxt_buf_mem_t mem; - - /* The file and mmap parts are not allocated by nxt_buf_mem_alloc(). */ - nxt_file_t *file; - nxt_off_t file_pos; - nxt_off_t file_end; - - /* The mmap part is not allocated by nxt_buf_file_alloc(). */ - nxt_mem_map_file_ctx_t (mmap) -}; - - -#define NXT_BUF_SYNC_SIZE offsetof(nxt_buf_t, mem.free) -#define NXT_BUF_MEM_SIZE offsetof(nxt_buf_t, file) -#define NXT_BUF_FILE_SIZE sizeof(nxt_buf_t) -#define NXT_BUF_MMAP_SIZE NXT_BUF_FILE_SIZE -#define NXT_BUF_PORT_MMAP_SIZE NXT_BUF_MEM_SIZE - - -#define NXT_BUF_SYNC_NOBUF 1 -#define NXT_BUF_SYNC_FLUSH 2 -#define NXT_BUF_SYNC_LAST 4 - - -#define nxt_buf_is_mem(b) \ - ((b)->mem.pos != NULL) - - -#define nxt_buf_is_file(b) \ - ((b)->is_file) - -#define nxt_buf_set_file(b) \ - (b)->is_file = 1 - -#define nxt_buf_clear_file(b) \ - (b)->is_file = 0 - - -#define nxt_buf_is_mmap(b) \ - ((b)->is_mmap) - -#define nxt_buf_set_mmap(b) \ - (b)->is_mmap = 1 - -#define nxt_buf_clear_mmap(b) \ - (b)->is_mmap = 0 - - -#define nxt_buf_is_port_mmap(b) \ - ((b)->is_port_mmap) - -#define nxt_buf_set_port_mmap(b) \ - (b)->is_port_mmap = 1 - -#define nxt_buf_clear_port_mmap(b) \ - (b)->is_port_mmap = 0 - - -#define nxt_buf_is_sync(b) \ - ((b)->is_sync) - -#define nxt_buf_set_sync(b) \ - (b)->is_sync = 1 - -#define nxt_buf_clear_sync(b) \ - (b)->is_sync = 0 - - -#define nxt_buf_is_nobuf(b) \ - ((b)->is_nobuf) - -#define nxt_buf_set_nobuf(b) \ - (b)->is_nobuf = 1 - -#define nxt_buf_clear_nobuf(b) \ - (b)->is_nobuf = 0 - - -#define nxt_buf_is_flush(b) \ - ((b)->is_flush) - -#define nxt_buf_set_flush(b) \ - (b)->is_flush = 1 - -#define nxt_buf_clear_flush(b) \ - (b)->is_flush = 0 - - -#define nxt_buf_is_last(b) \ - ((b)->is_last) - -#define nxt_buf_set_last(b) \ - (b)->is_last = 1 - -#define nxt_buf_clear_last(b) \ - (b)->is_last = 0 - - -#define nxt_buf_mem_set_size(bm, size) \ - do { \ - (bm)->start = 0; \ - (bm)->end = (void *) size; \ - } while (0) - - -#define nxt_buf_mem_size(bm) \ - ((bm)->end - (bm)->start) - - -#define nxt_buf_mem_used_size(bm) \ - ((bm)->free - (bm)->pos) - - -#define nxt_buf_mem_free_size(bm) \ - ((bm)->end - (bm)->free) - - -#define nxt_buf_used_size(b) \ - (nxt_buf_is_file(b) ? (b)->file_end - (b)->file_pos: \ - nxt_buf_mem_used_size(&(b)->mem)) - - -NXT_EXPORT void nxt_buf_mem_init(nxt_buf_t *b, void *start, size_t size); -NXT_EXPORT nxt_buf_t *nxt_buf_mem_alloc(nxt_mp_t *mp, size_t size, - nxt_uint_t flags); -NXT_EXPORT nxt_buf_t *nxt_buf_mem_ts_alloc(nxt_task_t *task, nxt_mp_t *mp, - size_t size); -NXT_EXPORT nxt_buf_t *nxt_buf_file_alloc(nxt_mp_t *mp, size_t size, - nxt_uint_t flags); -NXT_EXPORT nxt_buf_t *nxt_buf_mmap_alloc(nxt_mp_t *mp, size_t size); -NXT_EXPORT nxt_buf_t *nxt_buf_sync_alloc(nxt_mp_t *mp, nxt_uint_t flags); - -NXT_EXPORT nxt_int_t nxt_buf_ts_handle(nxt_task_t *task, void *obj, void *data); - -NXT_EXPORT void nxt_buf_parent_completion(nxt_task_t *task, nxt_buf_t *parent); -NXT_EXPORT nxt_buf_t *nxt_buf_make_plain(nxt_mp_t *mp, nxt_buf_t *src, - size_t size); - -nxt_inline nxt_buf_t * -nxt_buf_chk_make_plain(nxt_mp_t *mp, nxt_buf_t *src, size_t size) -{ - if (nxt_slow_path(src != NULL && src->next != NULL)) { - return nxt_buf_make_plain(mp, src, size); - } - - return src; -} - -#define nxt_buf_free(mp, b) \ - nxt_mp_free((mp), (b)) - - -NXT_EXPORT void nxt_buf_chain_add(nxt_buf_t **head, nxt_buf_t *in); -NXT_EXPORT size_t nxt_buf_chain_length(nxt_buf_t *b); - -nxt_inline nxt_buf_t * -nxt_buf_cpy(nxt_buf_t *b, const void *src, size_t length) -{ - nxt_memcpy(b->mem.free, src, length); - b->mem.free += length; - - return b; -} - -nxt_inline nxt_buf_t * -nxt_buf_cpystr(nxt_buf_t *b, const nxt_str_t *str) -{ - return nxt_buf_cpy(b, str->start, str->length); -} - - -nxt_inline void -nxt_buf_dummy_completion(nxt_task_t *task, void *obj, void *data) -{ -} - - -#endif /* _NXT_BUF_H_INCLIDED_ */ diff --git a/src/nxt_buf_pool.c b/src/nxt_buf_pool.c deleted file mode 100644 index f2be88a7..00000000 --- a/src/nxt_buf_pool.c +++ /dev/null @@ -1,185 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_int_t -nxt_buf_pool_mem_alloc(nxt_buf_pool_t *bp, size_t size) -{ - nxt_buf_t *b; - - b = bp->current; - - if (b != NULL && b->mem.free < b->mem.end) { - return NXT_OK; - } - - b = bp->free; - - if (b != NULL) { - bp->current = b; - bp->free = b->next; - b->next = NULL; - return NXT_OK; - } - - if (bp->num >= bp->max) { - return NXT_AGAIN; - } - - if (size == 0 || size >= bp->size + bp->size / 4) { - size = bp->size; - } - - b = nxt_buf_mem_alloc(bp->mem_pool, size, bp->flags); - - if (nxt_fast_path(b != NULL)) { - bp->current = b; - bp->num++; - return NXT_OK; - } - - return NXT_ERROR; -} - - -nxt_int_t -nxt_buf_pool_file_alloc(nxt_buf_pool_t *bp, size_t size) -{ - nxt_buf_t *b; - - b = bp->current; - - if (b != NULL && b->mem.free < b->mem.end) { - return NXT_OK; - } - - b = bp->free; - - if (b != NULL) { - bp->current = b; - bp->free = b->next; - b->next = NULL; - return NXT_OK; - } - - if (bp->num >= bp->max) { - return NXT_AGAIN; - } - - if (size == 0 || size >= bp->size + bp->size / 4) { - size = bp->size; - } - - b = nxt_buf_file_alloc(bp->mem_pool, size, bp->flags); - - if (nxt_fast_path(b != NULL)) { - bp->current = b; - bp->num++; - return NXT_OK; - } - - return NXT_ERROR; -} - - -nxt_int_t -nxt_buf_pool_mmap_alloc(nxt_buf_pool_t *bp, size_t size) -{ - nxt_buf_t *b; - - b = bp->current; - - if (b != NULL) { - return NXT_OK; - } - - b = bp->free; - - if (b != NULL) { - bp->current = b; - bp->free = b->next; - b->next = NULL; - return NXT_OK; - } - - if (bp->num >= bp->max) { - return NXT_AGAIN; - } - - if (size == 0 || size >= bp->size + bp->size / 4) { - size = bp->size; - } - - b = nxt_buf_mmap_alloc(bp->mem_pool, size); - - if (nxt_fast_path(b != NULL)) { - bp->mmap = 1; - bp->current = b; - bp->num++; - return NXT_OK; - } - - return NXT_ERROR; -} - - -void -nxt_buf_pool_free(nxt_buf_pool_t *bp, nxt_buf_t *b) -{ - size_t size; - - nxt_thread_log_debug("buf pool free: %p %p", b, b->mem.start); - - size = nxt_buf_mem_size(&b->mem); - - if (bp->mmap) { - nxt_mem_unmap(b->mem.start, &b->mmap, size); - } - - if (bp->destroy) { - - if (b == bp->current) { - bp->current = NULL; - } - - nxt_buf_free(bp->mem_pool, b); - - return; - } - - if (bp->mmap) { - b->mem.pos = NULL; - b->mem.free = NULL; - nxt_buf_mem_set_size(&b->mem, size); - - } else { - b->mem.pos = b->mem.start; - b->mem.free = b->mem.start; - } - - if (b != bp->current) { - b->next = bp->free; - bp->free = b; - } -} - - -void -nxt_buf_pool_destroy(nxt_buf_pool_t *bp) -{ - nxt_buf_t *b, *n; - - bp->destroy = 1; - - for (b = bp->free; b != NULL; b = n) { - n = b->next; - nxt_buf_free(bp->mem_pool, b); - } - - bp->free = b; /* NULL */ -} diff --git a/src/nxt_buf_pool.h b/src/nxt_buf_pool.h deleted file mode 100644 index 3d22d7fa..00000000 --- a/src/nxt_buf_pool.h +++ /dev/null @@ -1,75 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_BUF_POOL_H_INCLUDED_ -#define _NXT_BUF_POOL_H_INCLUDED_ - - -/* - * nxt_buf_pool_t is intended to allocate up to the "max" number - * memory, memory/file, or mmap/file buffers. A size of the buffers - * is set in the "size" field. The size however can be overridden in - * nxt_buf_pool_XXX_alloc() by the "size" argument if the argument is - * not zero and lesser than or equal to the "size" field multiplied - * by 1.25. The "flags" field is passed as the nxt_mem_buf() flags. - */ - -typedef struct { - nxt_buf_t *current; - nxt_buf_t *free; - nxt_mp_t *mem_pool; - - uint16_t num; - uint16_t max; - - uint32_t size; - - uint8_t flags; /* 2 bits */ - uint8_t destroy; /* 1 bit */ - uint8_t mmap; /* 1 bit */ -} nxt_buf_pool_t; - - -NXT_EXPORT nxt_int_t nxt_buf_pool_mem_alloc(nxt_buf_pool_t *bp, size_t size); -NXT_EXPORT nxt_int_t nxt_buf_pool_file_alloc(nxt_buf_pool_t *bp, size_t size); -NXT_EXPORT nxt_int_t nxt_buf_pool_mmap_alloc(nxt_buf_pool_t *bp, size_t size); -NXT_EXPORT void nxt_buf_pool_free(nxt_buf_pool_t *bp, nxt_buf_t *b); -NXT_EXPORT void nxt_buf_pool_destroy(nxt_buf_pool_t *bp); - - -/* There is ready free buffer. */ - -#define nxt_buf_pool_ready(bp) \ - ((bp)->free != NULL \ - || ((bp)->current != NULL \ - && (bp)->current->mem.free < (bp)->current->mem.end)) - - -/* A free buffer is allowed to be allocated. */ - -#define nxt_buf_pool_obtainable(bp) \ - ((bp)->num < (bp)->max) - - -/* There is ready free buffer or it is allowed to be allocated. */ - -#define nxt_buf_pool_available(bp) \ - (nxt_buf_pool_obtainable(bp) || nxt_buf_pool_ready(bp)) - - -/* Reserve allocation of "n" free buffers as they were allocated. */ - -#define nxt_buf_pool_reserve(bp, n) \ - (bp)->num += (n) - - -/* Release a reservation. */ - -#define nxt_buf_pool_release(bp, n) \ - (bp)->num -= (n) - - -#endif /* _NXT_BUF_POOL_H_INCLUDED_ */ diff --git a/src/nxt_capability.c b/src/nxt_capability.c deleted file mode 100644 index 9f36ab99..00000000 --- a/src/nxt_capability.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - -#if (NXT_HAVE_LINUX_CAPABILITY) - -#include -#include - - -#if (_LINUX_CAPABILITY_VERSION_3) -#define NXT_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_3 -#elif (_LINUX_CAPABILITY_VERSION_2) -#define NXT_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_2 -#else -#define NXT_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION -#endif - - -#define nxt_capget(hdrp, datap) \ - syscall(SYS_capget, hdrp, datap) -#define nxt_capset(hdrp, datap) \ - syscall(SYS_capset, hdrp, datap) - -#endif /* NXT_HAVE_LINUX_CAPABILITY */ - - -static nxt_int_t nxt_capability_specific_set(nxt_task_t *task, - nxt_capabilities_t *cap); - - -nxt_int_t -nxt_capability_set(nxt_task_t *task, nxt_capabilities_t *cap) -{ - nxt_assert(cap->setid == 0); - - if (geteuid() == 0) { - cap->setid = 1; - cap->chroot = 1; - return NXT_OK; - } - - return nxt_capability_specific_set(task, cap); -} - - -#if (NXT_HAVE_LINUX_CAPABILITY) - -static uint32_t -nxt_capability_linux_get_version(void) -{ - struct __user_cap_header_struct hdr; - - hdr.version = NXT_CAPABILITY_VERSION; - hdr.pid = nxt_pid; - - nxt_capget(&hdr, NULL); - return hdr.version; -} - - -static nxt_int_t -nxt_capability_specific_set(nxt_task_t *task, nxt_capabilities_t *cap) -{ - struct __user_cap_data_struct *val, data[2]; - struct __user_cap_header_struct hdr; - - /* - * Linux capability v1 fills an u32 struct. - * Linux capability v2 and v3 fills an u64 struct. - * We allocate data[2] for compatibility, we waste 4 bytes on v1. - * - * This is safe as we only need to check CAP_SETUID and CAP_SETGID - * that resides in the first 32-bit chunk. - */ - - val = &data[0]; - - /* - * Ask the kernel the preferred capability version - * instead of using _LINUX_CAPABILITY_VERSION from header. - * This is safer when distributing a pre-compiled Unit binary. - */ - hdr.version = nxt_capability_linux_get_version(); - hdr.pid = nxt_pid; - - if (nxt_slow_path(nxt_capget(&hdr, val) == -1)) { - nxt_alert(task, "failed to get process capabilities: %E", nxt_errno); - return NXT_ERROR; - } - - if ((val->effective & (1 << CAP_SYS_CHROOT)) != 0) { - cap->chroot = 1; - } - - if ((val->effective & (1 << CAP_SETUID)) == 0) { - return NXT_OK; - } - - if ((val->effective & (1 << CAP_SETGID)) == 0) { - return NXT_OK; - } - - cap->setid = 1; - return NXT_OK; -} - -#else - -static nxt_int_t -nxt_capability_specific_set(nxt_task_t *task, nxt_capabilities_t *cap) -{ - return NXT_OK; -} - -#endif diff --git a/src/nxt_capability.h b/src/nxt_capability.h deleted file mode 100644 index 1575d409..00000000 --- a/src/nxt_capability.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_CAPABILITY_INCLUDED_ -#define _NXT_CAPABILITY_INCLUDED_ - -typedef struct { - uint8_t setid; /* 1 bit */ - uint8_t chroot; /* 1 bit */ -} nxt_capabilities_t; - - -NXT_EXPORT nxt_int_t nxt_capability_set(nxt_task_t *task, - nxt_capabilities_t *cap); - -#endif /* _NXT_CAPABILITY_INCLUDED_ */ diff --git a/src/nxt_cert.c b/src/nxt_cert.c deleted file mode 100644 index 4a1f1496..00000000 --- a/src/nxt_cert.c +++ /dev/null @@ -1,1254 +0,0 @@ - -/* - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - - -struct nxt_cert_s { - EVP_PKEY *key; - nxt_uint_t count; - X509 *chain[]; -}; - - -typedef struct { - nxt_str_t name; - nxt_conf_value_t *value; - nxt_mp_t *mp; -} nxt_cert_info_t; - - -typedef struct { - nxt_str_t name; - nxt_fd_t fd; -} nxt_cert_item_t; - - -static nxt_cert_t *nxt_cert_fd(nxt_task_t *task, nxt_fd_t fd); -static nxt_cert_t *nxt_cert_bio(nxt_task_t *task, BIO *bio); -static int nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix); - -static nxt_conf_value_t *nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert); -static nxt_conf_value_t *nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, - nxt_bool_t issuer); -static nxt_conf_value_t *nxt_cert_alt_names_details(nxt_mp_t *mp, - STACK_OF(GENERAL_NAME) *alt_names); -static void nxt_cert_buf_completion(nxt_task_t *task, void *obj, void *data); - - -static nxt_lvlhsh_t nxt_cert_info; - - -nxt_cert_t * -nxt_cert_mem(nxt_task_t *task, nxt_buf_mem_t *mbuf) -{ - BIO *bio; - nxt_cert_t *cert; - - bio = BIO_new_mem_buf(mbuf->pos, nxt_buf_mem_used_size(mbuf)); - if (nxt_slow_path(bio == NULL)) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, "BIO_new_mem_buf() failed"); - return NULL; - } - - cert = nxt_cert_bio(task, bio); - - BIO_free(bio); - - return cert; -} - - -static nxt_cert_t * -nxt_cert_fd(nxt_task_t *task, nxt_fd_t fd) -{ - BIO *bio; - nxt_cert_t *cert; - - bio = BIO_new_fd(fd, 0); - if (nxt_slow_path(bio == NULL)) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, "BIO_new_fd() failed"); - return NULL; - } - - cert = nxt_cert_bio(task, bio); - - BIO_free(bio); - - return cert; -} - - -static nxt_cert_t * -nxt_cert_bio(nxt_task_t *task, BIO *bio) -{ - int ret, suffix, key_id; - long length, reason; - char *type, *header; - X509 *x509; - EVP_PKEY *key; - nxt_uint_t nalloc; - nxt_cert_t *cert, *new_cert; - u_char *data; - const u_char *data_copy; - PKCS8_PRIV_KEY_INFO *p8inf; - const EVP_PKEY_ASN1_METHOD *ameth; - - nalloc = 4; - - cert = nxt_zalloc(sizeof(nxt_cert_t) + nalloc * sizeof(X509 *)); - if (cert == NULL) { - return NULL; - } - - for ( ;; ) { - ret = PEM_read_bio(bio, &type, &header, &data, &length); - - if (ret == 0) { - reason = ERR_GET_REASON(ERR_peek_last_error()); - if (reason != PEM_R_NO_START_LINE) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "PEM_read_bio() failed"); - goto fail; - } - - ERR_clear_error(); - break; - } - - nxt_debug(task, "PEM type: \"%s\"", type); - - key = NULL; - x509 = NULL; -/* - EVP_CIPHER_INFO cipher; - - if (PEM_get_EVP_CIPHER_INFO(header, &cipher) != 0) { - nxt_alert(task, "encrypted PEM isn't supported"); - goto done; - } -*/ - if (nxt_strcmp(type, PEM_STRING_PKCS8) == 0) { - nxt_alert(task, "PEM PKCS8 isn't supported"); - goto done; - } - - if (nxt_strcmp(type, PEM_STRING_PKCS8INF) == 0) { - data_copy = data; - - p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &data_copy, length); - - if (p8inf == NULL) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "d2i_PKCS8_PRIV_KEY_INFO() failed"); - goto done; - } - - key = EVP_PKCS82PKEY(p8inf); - - PKCS8_PRIV_KEY_INFO_free(p8inf); - goto done; - } - - suffix = nxt_nxt_cert_pem_suffix(type, PEM_STRING_PKCS8INF); - - if (suffix != 0) { - - ameth = EVP_PKEY_asn1_find_str(NULL, type, suffix); - if (ameth == NULL) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "EVP_PKEY_asn1_find_str() failed"); - goto done; - } - - EVP_PKEY_asn1_get0_info(&key_id, NULL, NULL, NULL, NULL, ameth); - - data_copy = data; - - key = d2i_PrivateKey(key_id, NULL, &data_copy, length); - goto done; - } - - if (nxt_strcmp(type, PEM_STRING_X509) == 0 - || nxt_strcmp(type, PEM_STRING_X509_OLD) == 0) - { - data_copy = data; - - x509 = d2i_X509(NULL, &data_copy, length); - if (x509 == NULL) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "d2i_X509() failed"); - } - - goto done; - } - - if (nxt_strcmp(type, PEM_STRING_X509_TRUSTED) == 0) { - data_copy = data; - - x509 = d2i_X509_AUX(NULL, &data_copy, length); - if (x509 == NULL) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "d2i_X509_AUX() failed"); - } - - goto done; - } - - nxt_alert(task, "unsupported PEM type: \"%s\"", type); - - done: - - OPENSSL_free(data); - OPENSSL_free(header); - OPENSSL_free(type); - - if (key != NULL) { - if (cert->key != NULL) { - EVP_PKEY_free(key); - nxt_alert(task, "multiple private keys in PEM"); - goto fail; - } - - cert->key = key; - continue; - } - - if (x509 != NULL) { - - if (cert->count == nalloc) { - nalloc += 4; - - new_cert = nxt_realloc(cert, sizeof(nxt_cert_t) - + nalloc * sizeof(X509 *)); - if (new_cert == NULL) { - X509_free(x509); - goto fail; - } - - cert = new_cert; - } - - cert->chain[cert->count++] = x509; - continue; - } - - goto fail; - } - - if (cert->key == NULL) { - nxt_alert(task, "no key found"); - goto fail; - } - - if (cert->count == 0) { - nxt_alert(task, "no certificates found"); - goto fail; - } - - return cert; - -fail: - - nxt_cert_destroy(cert); - - return NULL; -} - - -static int -nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix) -{ - char *p; - nxt_uint_t pem_len, suffix_len; - - pem_len = strlen(pem_str); - suffix_len = strlen(suffix); - - if (suffix_len + 1 >= pem_len) { - return 0; - } - - p = pem_str + pem_len - suffix_len; - - if (nxt_strcmp(p, suffix) != 0) { - return 0; - } - - p--; - - if (*p != ' ') { - return 0; - } - - return p - pem_str; -} - - -void -nxt_cert_destroy(nxt_cert_t *cert) -{ - nxt_uint_t i; - - EVP_PKEY_free(cert->key); - - for (i = 0; i != cert->count; i++) { - X509_free(cert->chain[i]); - } - - nxt_free(cert); -} - - - -static nxt_int_t -nxt_cert_info_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_cert_info_t *info; - - info = data; - - if (nxt_strcasestr_eq(&lhq->key, &info->name)) { - return NXT_OK; - } - - return NXT_DECLINED; -} - - -static const nxt_lvlhsh_proto_t nxt_cert_info_hash_proto - nxt_aligned(64) = -{ - NXT_LVLHSH_DEFAULT, - nxt_cert_info_hash_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -void -nxt_cert_info_init(nxt_task_t *task, nxt_array_t *certs) -{ - uint32_t i; - nxt_cert_t *cert; - nxt_cert_item_t *items; - - for (items = certs->elts, i = 0; i < certs->nelts; i++) { - cert = nxt_cert_fd(task, items[i].fd); - - if (nxt_slow_path(cert == NULL)) { - continue; - } - - (void) nxt_cert_info_save(&items[i].name, cert); - - nxt_cert_destroy(cert); - } -} - - -nxt_int_t -nxt_cert_info_save(nxt_str_t *name, nxt_cert_t *cert) -{ - nxt_mp_t *mp; - nxt_int_t ret; - nxt_cert_info_t *info; - nxt_conf_value_t *value; - nxt_lvlhsh_query_t lhq; - - mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { - return NXT_ERROR; - } - - info = nxt_mp_get(mp, sizeof(nxt_cert_info_t)); - if (nxt_slow_path(info == NULL)) { - goto fail; - } - - name = nxt_str_dup(mp, &info->name, name); - if (nxt_slow_path(name == NULL)) { - goto fail; - } - - value = nxt_cert_details(mp, cert); - if (nxt_slow_path(value == NULL)) { - goto fail; - } - - info->mp = mp; - info->value = value; - - lhq.key_hash = nxt_djb_hash(name->start, name->length); - lhq.replace = 1; - lhq.key = *name; - lhq.value = info; - lhq.proto = &nxt_cert_info_hash_proto; - - ret = nxt_lvlhsh_insert(&nxt_cert_info, &lhq); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - if (lhq.value != info) { - info = lhq.value; - nxt_mp_destroy(info->mp); - } - - return NXT_OK; - -fail: - - nxt_mp_destroy(mp); - return NXT_ERROR; -} - - -nxt_conf_value_t * -nxt_cert_info_get(nxt_str_t *name) -{ - nxt_int_t ret; - nxt_cert_info_t *info; - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_djb_hash(name->start, name->length); - lhq.key = *name; - lhq.proto = &nxt_cert_info_hash_proto; - - ret = nxt_lvlhsh_find(&nxt_cert_info, &lhq); - if (ret != NXT_OK) { - return NULL; - } - - info = lhq.value; - - return info->value; -} - - -nxt_conf_value_t * -nxt_cert_info_get_all(nxt_mp_t *mp) -{ - uint32_t i; - nxt_cert_info_t *info; - nxt_conf_value_t *all; - nxt_lvlhsh_each_t lhe; - - nxt_lvlhsh_each_init(&lhe, &nxt_cert_info_hash_proto); - - i = 0; - - for ( ;; ) { - info = nxt_lvlhsh_each(&nxt_cert_info, &lhe); - - if (info == NULL) { - break; - } - - i++; - } - - all = nxt_conf_create_object(mp, i); - if (nxt_slow_path(all == NULL)) { - return NULL; - } - - nxt_lvlhsh_each_init(&lhe, &nxt_cert_info_hash_proto); - - i = 0; - - for ( ;; ) { - info = nxt_lvlhsh_each(&nxt_cert_info, &lhe); - - if (info == NULL) { - break; - } - - nxt_conf_set_member(all, &info->name, info->value, i); - - i++; - } - - return all; -} - - -static nxt_conf_value_t * -nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert) -{ - BIO *bio; - X509 *x509; - u_char *end; - EVP_PKEY *key; - ASN1_TIME *asn1_time; - nxt_str_t str; - nxt_int_t ret; - nxt_uint_t i; - nxt_conf_value_t *object, *chain, *element, *value; - u_char buf[256]; - - static nxt_str_t key_str = nxt_string("key"); - static nxt_str_t chain_str = nxt_string("chain"); - static nxt_str_t since_str = nxt_string("since"); - static nxt_str_t until_str = nxt_string("until"); - static nxt_str_t issuer_str = nxt_string("issuer"); - static nxt_str_t subject_str = nxt_string("subject"); - static nxt_str_t validity_str = nxt_string("validity"); - - object = nxt_conf_create_object(mp, 2); - if (nxt_slow_path(object == NULL)) { - return NULL; - } - - if (cert->key != NULL) { - key = cert->key; - - switch (EVP_PKEY_base_id(key)) { - case EVP_PKEY_RSA: - end = nxt_sprintf(buf, buf + sizeof(buf), "RSA (%d bits)", - EVP_PKEY_bits(key)); - - str.length = end - buf; - str.start = buf; - break; - - case EVP_PKEY_DH: - end = nxt_sprintf(buf, buf + sizeof(buf), "DH (%d bits)", - EVP_PKEY_bits(key)); - - str.length = end - buf; - str.start = buf; - break; - - case EVP_PKEY_EC: - nxt_str_set(&str, "ECDH"); - break; - - default: - nxt_str_set(&str, "unknown"); - } - - ret = nxt_conf_set_member_string_dup(object, mp, &key_str, &str, 0); - - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - } else { - nxt_conf_set_member_null(object, &key_str, 0); - } - - chain = nxt_conf_create_array(mp, cert->count); - if (nxt_slow_path(chain == NULL)) { - return NULL; - } - - for (i = 0; i < cert->count; i++) { - element = nxt_conf_create_object(mp, 3); - if (nxt_slow_path(element == NULL)) { - return NULL; - } - - x509 = cert->chain[i]; - - value = nxt_cert_name_details(mp, x509, 0); - if (value == NULL) { - return NULL; - } - - nxt_conf_set_member(element, &subject_str, value, 0); - - value = nxt_cert_name_details(mp, x509, 1); - if (value == NULL) { - return NULL; - } - - nxt_conf_set_member(element, &issuer_str, value, 1); - - value = nxt_conf_create_object(mp, 2); - if (nxt_slow_path(value == NULL)) { - return NULL; - } - - bio = BIO_new(BIO_s_mem()); - if (nxt_slow_path(bio == NULL)) { - return NULL; - } - - asn1_time = X509_get_notBefore(x509); - - ret = ASN1_TIME_print(bio, asn1_time); - - if (nxt_fast_path(ret == 1)) { - str.length = BIO_get_mem_data(bio, &str.start); - ret = nxt_conf_set_member_string_dup(value, mp, &since_str, &str, - 0); - } else { - ret = NXT_ERROR; - } - - BIO_free(bio); - - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - bio = BIO_new(BIO_s_mem()); - if (nxt_slow_path(bio == NULL)) { - return NULL; - } - - asn1_time = X509_get_notAfter(x509); - - ret = ASN1_TIME_print(bio, asn1_time); - - if (nxt_fast_path(ret == 1)) { - str.length = BIO_get_mem_data(bio, &str.start); - ret = nxt_conf_set_member_string_dup(value, mp, &until_str, &str, - 1); - } else { - ret = NXT_ERROR; - } - - BIO_free(bio); - - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - nxt_conf_set_member(element, &validity_str, value, 2); - - nxt_conf_set_element(chain, i, element); - } - - nxt_conf_set_member(object, &chain_str, chain, 1); - - return object; -} - - -typedef struct { - int nid; - nxt_str_t name; -} nxt_cert_nid_t; - - -static nxt_conf_value_t * -nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer) -{ - int len; - X509_NAME *x509_name; - nxt_str_t str; - nxt_int_t ret; - nxt_uint_t i, n, count; - nxt_conf_value_t *object, *names; - STACK_OF(GENERAL_NAME) *alt_names; - u_char buf[256]; - - static nxt_cert_nid_t nids[] = { - { NID_commonName, nxt_string("common_name") }, - { NID_countryName, nxt_string("country") }, - { NID_stateOrProvinceName, nxt_string("state_or_province") }, - { NID_localityName, nxt_string("locality") }, - { NID_organizationName, nxt_string("organization") }, - { NID_organizationalUnitName, nxt_string("department") }, - }; - - static nxt_str_t alt_names_str = nxt_string("alt_names"); - - count = 0; - - x509_name = issuer ? X509_get_issuer_name(x509) - : X509_get_subject_name(x509); - - for (n = 0; n != nxt_nitems(nids); n++) { - - if (X509_NAME_get_index_by_NID(x509_name, nids[n].nid, -1) < 0) { - continue; - } - - count++; - } - - alt_names = X509_get_ext_d2i(x509, issuer ? NID_issuer_alt_name - : NID_subject_alt_name, - NULL, NULL); - - if (alt_names != NULL) { - names = nxt_cert_alt_names_details(mp, alt_names); - - sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); - - if (nxt_slow_path(names == NULL)) { - return NULL; - } - - count++; - - } else { - names = NULL; - } - - object = nxt_conf_create_object(mp, count); - if (nxt_slow_path(object == NULL)) { - return NULL; - } - - for (n = 0, i = 0; n != nxt_nitems(nids) && i != count; n++) { - - len = X509_NAME_get_text_by_NID(x509_name, nids[n].nid, - (char *) buf, sizeof(buf)); - - if (n == 1 && names != NULL) { - nxt_conf_set_member(object, &alt_names_str, names, i++); - } - - if (len < 0) { - continue; - } - - str.length = len; - str.start = buf; - - ret = nxt_conf_set_member_string_dup(object, mp, &nids[n].name, - &str, i++); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - } - - return object; -} - - -static nxt_conf_value_t * -nxt_cert_alt_names_details(nxt_mp_t *mp, STACK_OF(GENERAL_NAME) *alt_names) -{ - nxt_str_t str; - nxt_int_t ret; - nxt_uint_t i, n, count; - GENERAL_NAME *name; - nxt_conf_value_t *array; - - count = sk_GENERAL_NAME_num(alt_names); - n = 0; - - for (i = 0; i != count; i++) { - name = sk_GENERAL_NAME_value(alt_names, i); - - if (name->type != GEN_DNS) { - continue; - } - - n++; - } - - array = nxt_conf_create_array(mp, n); - if (nxt_slow_path(array == NULL)) { - return NULL; - } - - for (n = 0, i = 0; n != count; n++) { - name = sk_GENERAL_NAME_value(alt_names, n); - - if (name->type != GEN_DNS) { - continue; - } - - str.length = ASN1_STRING_length(name->d.dNSName); -#if OPENSSL_VERSION_NUMBER > 0x10100000L - str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); -#else - str.start = ASN1_STRING_data(name->d.dNSName); -#endif - - ret = nxt_conf_set_element_string_dup(array, mp, i++, &str); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - } - - return array; -} - - -nxt_int_t -nxt_cert_info_delete(nxt_str_t *name) -{ - nxt_int_t ret; - nxt_cert_info_t *info; - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_djb_hash(name->start, name->length); - lhq.key = *name; - lhq.proto = &nxt_cert_info_hash_proto; - - ret = nxt_lvlhsh_delete(&nxt_cert_info, &lhq); - - if (ret == NXT_OK) { - info = lhq.value; - nxt_mp_destroy(info->mp); - } - - return ret; -} - - - -nxt_array_t * -nxt_cert_store_load(nxt_task_t *task, nxt_mp_t *mp) -{ - DIR *dir; - size_t size, alloc; - u_char *buf, *p; - nxt_str_t name; - nxt_int_t ret; - nxt_file_t file; - nxt_array_t *certs; - nxt_runtime_t *rt; - struct dirent *de; - nxt_cert_item_t *item; - - rt = task->thread->runtime; - - if (nxt_slow_path(rt->certs.start == NULL)) { - nxt_alert(task, "no certificates storage directory"); - return NULL; - } - - certs = nxt_array_create(mp, 16, sizeof(nxt_cert_item_t)); - if (nxt_slow_path(certs == NULL)) { - return NULL; - } - - buf = NULL; - alloc = 0; - - dir = opendir((char *) rt->certs.start); - if (nxt_slow_path(dir == NULL)) { - nxt_alert(task, "opendir(\"%s\") failed %E", - rt->certs.start, nxt_errno); - goto fail; - } - - for ( ;; ) { - de = readdir(dir); - if (de == NULL) { - break; - } - - nxt_debug(task, "readdir(\"%s\"): \"%s\"", rt->certs.start, de->d_name); - - name.length = nxt_strlen(de->d_name); - name.start = (u_char *) de->d_name; - - if (nxt_str_eq(&name, ".", 1) || nxt_str_eq(&name, "..", 2)) { - continue; - } - - item = nxt_array_add(certs); - if (nxt_slow_path(item == NULL)) { - goto fail; - } - - item->fd = -1; - - size = rt->certs.length + name.length + 1; - - if (size > alloc) { - size += 32; - - p = nxt_realloc(buf, size); - if (p == NULL) { - goto fail; - } - - alloc = size; - buf = p; - } - - p = nxt_cpymem(buf, rt->certs.start, rt->certs.length); - p = nxt_cpymem(p, name.start, name.length + 1); - - nxt_memzero(&file, sizeof(nxt_file_t)); - - file.name = buf; - - ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, - NXT_FILE_OWNER_ACCESS); - - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_array_remove_last(certs); - continue; - } - - item->fd = file.fd; - - if (nxt_slow_path(nxt_str_dup(mp, &item->name, &name) == NULL)) { - goto fail; - } - } - - if (buf != NULL) { - nxt_free(buf); - } - - (void) closedir(dir); - - return certs; - -fail: - - if (buf != NULL) { - nxt_free(buf); - } - - if (dir != NULL) { - (void) closedir(dir); - } - - nxt_cert_store_release(certs); - - return NULL; -} - - -void -nxt_cert_store_release(nxt_array_t *certs) -{ - uint32_t i; - nxt_cert_item_t *items; - - for (items = certs->elts, i = 0; - i < certs->nelts; - i++) - { - nxt_fd_close(items[i].fd); - } - - nxt_array_destroy(certs); -} - - -#if 0 - -void -nxt_cert_store_discovery_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - DIR *dir; - size_t size; - nxt_buf_t *b; - nxt_int_t ret; - nxt_port_t *port; - nxt_runtime_t *rt; - struct dirent *de; - - port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, - msg->port_msg.reply_port); - - if (nxt_slow_path(port == NULL)) { - return; - } - - b = NULL; - dir = NULL; - - rt = task->thread->runtime; - - if (nxt_slow_path(rt->certs.start == NULL)) { - nxt_alert(task, "no certificates storage directory"); - goto fail; - } - - dir = opendir((char *) rt->certs.start); - if (nxt_slow_path(dir == NULL)) { - nxt_alert(task, "opendir(\"%s\") failed %E", - rt->certs.start, nxt_errno); - goto fail; - } - - size = 0; - - for ( ;; ) { - de = readdir(dir); - if (de == NULL) { - break; - } - - if (de->d_type != DT_REG) { - continue; - } - - size += nxt_strlen(de->d_name) + 1; - } - - b = nxt_port_mmap_get_buf(task, port, size); - if (nxt_slow_path(b == NULL)) { - goto fail; - } - - rewinddir(dir); - - for ( ;; ) { - de = readdir(dir); - if (de == NULL) { - break; - } - - if (de->d_type != DT_REG) { - continue; - } - - size = nxt_strlen(de->d_name) + 1; - - if (nxt_slow_path(size > (size_t) nxt_buf_mem_free_size(&b->mem))) { - b->mem.free = b->mem.start; - break; - } - - b->mem.free = nxt_cpymem(b->mem.free, de->d_name, size); - } - - (void) closedir(dir); - dir = NULL; - - if (nxt_slow_path(nxt_buf_mem_free_size(&b->mem) != 0)) { - nxt_alert(task, "certificates storage directory " - "has changed while reading it"); - goto fail; - } - - ret = nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST, -1, - msg->port_msg.stream, 0, b); - - if (nxt_fast_path(ret == NXT_OK)) { - return; - } - -fail: - - if (dir != NULL) { - (void) closedir(dir); - } - - if (b != NULL) { - b->completion_handler(task, b, b->parent); - } - - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1, - msg->port_msg.stream, 0, NULL); -} - -#endif - - -void -nxt_cert_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp, - nxt_port_rpc_handler_t handler, void *ctx) -{ - uint32_t stream; - nxt_int_t ret; - nxt_buf_t *b; - nxt_port_t *main_port, *recv_port; - nxt_runtime_t *rt; - - b = nxt_buf_mem_alloc(mp, name->length + 1, 0); - if (nxt_slow_path(b == NULL)) { - goto fail; - } - - nxt_mp_retain(mp); - b->completion_handler = nxt_cert_buf_completion; - - nxt_buf_cpystr(b, name); - *b->mem.free++ = '\0'; - - rt = task->thread->runtime; - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - recv_port = rt->port_by_type[rt->type]; - - stream = nxt_port_rpc_register_handler(task, recv_port, handler, handler, - -1, ctx); - if (nxt_slow_path(stream == 0)) { - goto fail; - } - - ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_GET, -1, - stream, recv_port->id, b); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_rpc_cancel(task, recv_port, stream); - goto fail; - } - - return; - -fail: - - handler(task, NULL, ctx); -} - - -static void -nxt_cert_buf_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_mp_t *mp; - nxt_buf_t *b; - - b = obj; - mp = b->data; - nxt_assert(b->next == NULL); - - nxt_mp_free(mp, b); - nxt_mp_release(mp); -} - - -void -nxt_cert_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - u_char *p; - nxt_int_t ret; - nxt_str_t name; - nxt_file_t file; - nxt_port_t *port; - nxt_runtime_t *rt; - nxt_port_msg_type_t type; - - port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, - msg->port_msg.reply_port); - - if (nxt_slow_path(port == NULL)) { - nxt_alert(task, "process port not found (pid %PI, reply_port %d)", - msg->port_msg.pid, msg->port_msg.reply_port); - return; - } - - if (nxt_slow_path(port->type != NXT_PROCESS_CONTROLLER - && port->type != NXT_PROCESS_ROUTER)) - { - nxt_alert(task, "process %PI cannot store certificates", - msg->port_msg.pid); - return; - } - - nxt_memzero(&file, sizeof(nxt_file_t)); - - file.fd = -1; - type = NXT_PORT_MSG_RPC_ERROR; - - rt = task->thread->runtime; - - if (nxt_slow_path(rt->certs.start == NULL)) { - nxt_alert(task, "no certificates storage directory"); - goto error; - } - - name.start = msg->buf->mem.pos; - name.length = nxt_strlen(name.start); - - file.name = nxt_malloc(rt->certs.length + name.length + 1); - - if (nxt_slow_path(file.name == NULL)) { - goto error; - } - - p = nxt_cpymem(file.name, rt->certs.start, rt->certs.length); - p = nxt_cpymem(p, name.start, name.length + 1); - - ret = nxt_file_open(task, &file, NXT_FILE_RDWR, NXT_FILE_CREATE_OR_OPEN, - NXT_FILE_OWNER_ACCESS); - - nxt_free(file.name); - - if (nxt_fast_path(ret == NXT_OK)) { - type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD; - } - -error: - - (void) nxt_port_socket_write(task, port, type, file.fd, - msg->port_msg.stream, 0, NULL); -} - - -void -nxt_cert_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp) -{ - nxt_buf_t *b; - nxt_port_t *main_port; - nxt_runtime_t *rt; - - b = nxt_buf_mem_alloc(mp, name->length + 1, 0); - - if (nxt_fast_path(b != NULL)) { - nxt_buf_cpystr(b, name); - *b->mem.free++ = '\0'; - - rt = task->thread->runtime; - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - - (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CERT_DELETE, - -1, 0, 0, b); - } -} - - -void -nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - u_char *p; - nxt_str_t name; - nxt_port_t *ctl_port; - nxt_runtime_t *rt; - nxt_file_name_t *path; - - rt = task->thread->runtime; - ctl_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; - - if (nxt_slow_path(ctl_port == NULL)) { - nxt_alert(task, "controller port not found"); - return; - } - - if (nxt_slow_path(nxt_recv_msg_cmsg_pid(msg) != ctl_port->pid)) { - nxt_alert(task, "process %PI cannot delete certificates", - nxt_recv_msg_cmsg_pid(msg)); - return; - } - - if (nxt_slow_path(rt->certs.start == NULL)) { - nxt_alert(task, "no certificates storage directory"); - return; - } - - name.start = msg->buf->mem.pos; - name.length = nxt_strlen(name.start); - - path = nxt_malloc(rt->certs.length + name.length + 1); - - if (nxt_fast_path(path != NULL)) { - p = nxt_cpymem(path, rt->certs.start, rt->certs.length); - p = nxt_cpymem(p, name.start, name.length + 1); - - (void) nxt_file_delete(path); - - nxt_free(path); - } -} diff --git a/src/nxt_cert.h b/src/nxt_cert.h deleted file mode 100644 index dbaddcf9..00000000 --- a/src/nxt_cert.h +++ /dev/null @@ -1,32 +0,0 @@ - -/* - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_CERT_INCLUDED_ -#define _NXT_CERT_INCLUDED_ - - -typedef struct nxt_cert_s nxt_cert_t; - -nxt_cert_t *nxt_cert_mem(nxt_task_t *task, nxt_buf_mem_t *mbuf); -void nxt_cert_destroy(nxt_cert_t *cert); - -void nxt_cert_info_init(nxt_task_t *task, nxt_array_t *certs); -nxt_int_t nxt_cert_info_save(nxt_str_t *name, nxt_cert_t *cert); -nxt_conf_value_t *nxt_cert_info_get(nxt_str_t *name); -nxt_conf_value_t *nxt_cert_info_get_all(nxt_mp_t *mp); -nxt_int_t nxt_cert_info_delete(nxt_str_t *name); - -nxt_array_t *nxt_cert_store_load(nxt_task_t *task, nxt_mp_t *mem_pool); -void nxt_cert_store_release(nxt_array_t *certs); - -void nxt_cert_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp, - nxt_port_rpc_handler_t handler, void *ctx); -void nxt_cert_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp); - -void nxt_cert_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -void nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); - -#endif /* _NXT_CERT_INCLUDED_ */ diff --git a/src/nxt_cgroup.c b/src/nxt_cgroup.c deleted file mode 100644 index 2c404acc..00000000 --- a/src/nxt_cgroup.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) Andrew Clayton - * Copyright (C) F5, Inc. - */ - -#include - -#include - - -static int nxt_mk_cgpath_relative(nxt_task_t *task, const char *dir, - char *cgpath); -static nxt_int_t nxt_mk_cgpath(nxt_task_t *task, const char *dir, - char *cgpath); - - -nxt_int_t -nxt_cgroup_proc_add(nxt_task_t *task, nxt_process_t *process) -{ - int len; - char cgprocs[NXT_MAX_PATH_LEN]; - FILE *fp; - nxt_int_t ret; - - if (task->thread->runtime->type != NXT_PROCESS_MAIN - || nxt_process_type(process) != NXT_PROCESS_PROTOTYPE - || process->isolation.cgroup.path == NULL) - { - return NXT_OK; - } - - ret = nxt_mk_cgpath(task, process->isolation.cgroup.path, cgprocs); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NXT_ERROR; - } - - ret = nxt_fs_mkdir_all((const u_char *) cgprocs, 0777); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NXT_ERROR; - } - - len = strlen(cgprocs); - - len = snprintf(cgprocs + len, NXT_MAX_PATH_LEN - len, "/cgroup.procs"); - if (nxt_slow_path(len >= NXT_MAX_PATH_LEN - len)) { - nxt_errno = ENAMETOOLONG; - return NXT_ERROR; - } - - fp = nxt_file_fopen(task, cgprocs, "we"); - if (nxt_slow_path(fp == NULL)) { - return NXT_ERROR; - } - - setvbuf(fp, NULL, _IONBF, 0); - len = fprintf(fp, "%d\n", process->pid); - nxt_file_fclose(task, fp); - - if (nxt_slow_path(len < 0)) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -void -nxt_cgroup_cleanup(nxt_task_t *task, const nxt_process_t *process) -{ - char *ptr; - char cgroot[NXT_MAX_PATH_LEN], cgpath[NXT_MAX_PATH_LEN]; - nxt_int_t ret; - - ret = nxt_mk_cgpath(task, "", cgroot); - if (nxt_slow_path(ret == NXT_ERROR)) { - return; - } - - ret = nxt_mk_cgpath(task, process->isolation.cgroup.path, cgpath); - if (nxt_slow_path(ret == NXT_ERROR)) { - return; - } - - while (*cgpath != '\0' && strcmp(cgroot, cgpath) != 0) { - rmdir(cgpath); - ptr = strrchr(cgpath, '/'); - *ptr = '\0'; - } -} - - -static int -nxt_mk_cgpath_relative(nxt_task_t *task, const char *dir, char *cgpath) -{ - int i, len; - char *buf, *ptr; - FILE *fp; - size_t size; - ssize_t nread; - nxt_bool_t found; - - fp = nxt_file_fopen(task, "/proc/self/cgroup", "re"); - if (nxt_slow_path(fp == NULL)) { - return -1; - } - - len = -1; - buf = NULL; - found = 0; - while ((nread = getline(&buf, &size, fp)) != -1) { - if (strncmp(buf, "0::", 3) == 0) { - found = 1; - break; - } - } - - nxt_file_fclose(task, fp); - - if (!found) { - nxt_errno = ENODATA; - goto out_free_buf; - } - - buf[nread - 1] = '\0'; /* lose the trailing '\n' */ - ptr = buf; - for (i = 0; i < 2; i++) { - ptr = strchr(ptr, ':'); - if (ptr == NULL) { - nxt_errno = ENODATA; - goto out_free_buf; - } - - ptr++; - } - - len = snprintf(cgpath, NXT_MAX_PATH_LEN, NXT_CGROUP_ROOT "%s/%s", - ptr, dir); - -out_free_buf: - - nxt_free(buf); - - return len; -} - - -static nxt_int_t -nxt_mk_cgpath(nxt_task_t *task, const char *dir, char *cgpath) -{ - int len; - - /* - * If the path from the config is relative, we need to make - * the cgroup path include the main unit processes cgroup. I.e - * - * NXT_CGROUP_ROOT/

/ - */ - if (dir[0] != '/') { - len = nxt_mk_cgpath_relative(task, dir, cgpath); - } else { - len = snprintf(cgpath, NXT_MAX_PATH_LEN, NXT_CGROUP_ROOT "%s", dir); - } - - if (len == -1) { - return NXT_ERROR; - } - - if (len >= NXT_MAX_PATH_LEN) { - nxt_errno = ENAMETOOLONG; - return NXT_ERROR; - } - - return NXT_OK; -} diff --git a/src/nxt_cgroup.h b/src/nxt_cgroup.h deleted file mode 100644 index 0b9055d2..00000000 --- a/src/nxt_cgroup.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (C) Andrew Clayton - * Copyright (C) F5, Inc. - */ - -#ifndef _NXT_CGROUP_H_INCLUDED_ -#define _NXT_CGROUP_H_INCLUDED_ - - -nxt_int_t nxt_cgroup_proc_add(nxt_task_t *task, nxt_process_t *process); -void nxt_cgroup_cleanup(nxt_task_t *task, const nxt_process_t *process); - - -#endif /* _NXT_CGROUP_H_INCLUDED_ */ diff --git a/src/nxt_clang.h b/src/nxt_clang.h deleted file mode 100644 index 94638346..00000000 --- a/src/nxt_clang.h +++ /dev/null @@ -1,258 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_CLANG_H_INCLUDED_ -#define _NXT_CLANG_H_INCLUDED_ - - -#define nxt_inline static inline __attribute__((always_inline)) -#define nxt_noinline __attribute__((noinline)) -#define nxt_cdecl - - -#if (NXT_CLANG) - -/* Any __asm__ directive disables loop vectorization in GCC and Clang. */ -#define nxt_pragma_loop_disable_vectorization \ - __asm__("") - -#else - -#define nxt_pragma_loop_disable_vectorization - -#endif - - -#if (NXT_HAVE_BUILTIN_EXPECT) - -#define nxt_expect(c, x) \ - __builtin_expect((long) (x), (c)) - -#define nxt_fast_path(x) \ - nxt_expect(1, x) - -#define nxt_slow_path(x) \ - nxt_expect(0, x) - - -#else - -#define nxt_expect(c, x) \ - (x) - -#define nxt_fast_path(x) \ - (x) - -#define nxt_slow_path(x) \ - (x) - -#endif - - -#if (NXT_HAVE_BUILTIN_UNREACHABLE) - -#define nxt_unreachable() \ - __builtin_unreachable() - -#else - -#define nxt_unreachable() - -#endif - - -#if (NXT_HAVE_BUILTIN_PREFETCH) - -#define nxt_prefetch(a) \ - __builtin_prefetch(a) - -#else - -#define nxt_prefetch(a) - -#endif - - -#if (NXT_HAVE_GCC_ATTRIBUTE_VISIBILITY) - -#define NXT_EXPORT __attribute__((visibility("default"))) - -#else - -#define NXT_EXPORT - -#endif - - -#if (NXT_HAVE_GCC_ATTRIBUTE_MALLOC) - -#define NXT_MALLOC_LIKE __attribute__((__malloc__)) - -#else - -#define NXT_MALLOC_LIKE - -#endif - - -#if (NXT_HAVE_GCC_ATTRIBUTE_ALIGNED) - -#define nxt_aligned(x) __attribute__((aligned(x))) - -#else - -#define nxt_aligned(x) - -#endif - - -#if (NXT_HAVE_GCC_ATTRIBUTE_PACKED) - -#define nxt_packed __attribute__((__packed__)) - -#else - -#define nxt_packed - -#endif - - -#if (NXT_HAVE_GCC_ATTRIBUTE_UNUSED) - -#define NXT_MAYBE_UNUSED __attribute__((__unused__)) - -#else - -#define NXT_MAYBE_UNUSED - -#endif - - -#if (NXT_HAVE_BUILTIN_POPCOUNT) - -#define nxt_popcount __builtin_popcount - -#else - -nxt_inline int -nxt_popcount(unsigned int x) -{ - int count; - - for (count = 0; x != 0; count++) { - x &= x - 1; - } - - return count; -} - -#endif - - -#ifndef NXT_ALIGNMENT - -#if (NXT_SOLARIS) -#define NXT_ALIGNMENT _POINTER_ALIGNMENT /* x86_64: 8, i386: 4 */ - /* sparcv9: 8, sparcv8: 4 */ -#elif (__i386__ || __i386) -#define NXT_ALIGNMENT 4 - -#elif (__arm__) -#define NXT_ALIGNMENT 8 /* 32-bit ARM may use 64-bit load/store */ - -#elif (__ia64__) -#define NXT_ALIGNMENT 8 /* long long */ - -#else -#define NXT_ALIGNMENT NXT_PTR_SIZE -#endif - -#endif - - -#ifndef NXT_MAX_ALIGNMENT - -#if (NXT_SOLARIS) -#define NXT_MAX_ALIGNMENT _MAX_ALIGNMENT /* x86_64: 16, i386: 4 */ - /* sparcv9: 16, sparcv8: 8 */ -#elif (__i386__ || __i386) -#define NXT_MAX_ALIGNMENT 4 - -#elif (__arm__) -#define NXT_MAX_ALIGNMENT 16 - -#elif (__ia64__) -#define NXT_MAX_ALIGNMENT 16 - -#else -#define NXT_MAX_ALIGNMENT 16 -#endif - -#endif - - -#define nxt_alloca(size) \ - alloca(size) - - -#define nxt_container_of(p, type, field) \ - (type *) ((u_char *) (p) - offsetof(type, field)) - - -#define nxt_pointer_to(p, offset) \ - ((void *) ((char *) (p) + (offset))) - - -#define nxt_value_at(type, p, offset) \ - *(type *) ((u_char *) p + offset) - - -#define nxt_nitems(x) \ - (sizeof(x) / sizeof((x)[0])) - - -/* GCC and Clang use __builtin_abs() instead of libc abs(). */ - -#define nxt_abs(val) \ - abs(val) - - -#define nxt_max(val1, val2) \ - ((val1 < val2) ? (val2) : (val1)) - - -#define nxt_min(val1, val2) \ - ((val1 > val2) ? (val2) : (val1)) - - -#define nxt_bswap32(val) \ - ( ((val) >> 24) \ - | (((val) & 0x00FF0000) >> 8) \ - | (((val) & 0x0000FF00) << 8) \ - | ((val) << 24)) - - -#define nxt_is_power_of_two(value) \ - ((((value) - 1) & (value)) == 0) - - -#define nxt_align_size(d, a) \ - (((d) + ((size_t) (a) - 1)) & ~((size_t) (a) - 1)) - - -#define nxt_align_ptr(p, a) \ - (u_char *) (((uintptr_t) (p) + ((uintptr_t) (a) - 1)) \ - & ~((uintptr_t) (a) - 1)) - -#define nxt_trunc_ptr(p, a) \ - (u_char *) ((uintptr_t) (p) & ~((uintptr_t) (a) - 1)) - - -#define nxt_length(s) \ - (sizeof(s) - 1) - - -#endif /* _NXT_CLANG_H_INCLUDED_ */ diff --git a/src/nxt_clone.c b/src/nxt_clone.c deleted file mode 100644 index e78a7822..00000000 --- a/src/nxt_clone.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include - - -#if (NXT_HAVE_CLONE_NEWUSER) - -nxt_int_t nxt_clone_credential_setgroups(nxt_task_t *task, pid_t child_pid, - const char *str); -nxt_int_t nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile, - pid_t pid, nxt_int_t default_container, nxt_int_t default_host, - nxt_clone_credential_map_t *map); -nxt_int_t nxt_clone_credential_map_write(nxt_task_t *task, const char *mapfile, - pid_t pid, u_char *mapinfo); - - -nxt_int_t -nxt_clone_credential_setgroups(nxt_task_t *task, pid_t child_pid, - const char *str) -{ - int fd, n; - u_char *p, *end; - u_char path[PATH_MAX]; - - end = path + PATH_MAX; - p = nxt_sprintf(path, end, "/proc/%d/setgroups", child_pid); - *p = '\0'; - - if (nxt_slow_path(p == end)) { - nxt_alert(task, "error write past the buffer: %s", path); - return NXT_ERROR; - } - - fd = open((char *)path, O_RDWR); - - if (fd == -1) { - /* - * If the /proc/pid/setgroups doesn't exists, we are - * safe to set uid/gid maps. But if the error is anything - * other than ENOENT, then we should abort and let user know. - */ - - if (errno != ENOENT) { - nxt_alert(task, "open(%s): %E", path, nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; - } - - n = write(fd, str, strlen(str)); - close(fd); - - if (nxt_slow_path(n == -1)) { - nxt_alert(task, "write(%s): %E", path, nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; -} - - -nxt_int_t -nxt_clone_credential_map_write(nxt_task_t *task, const char *mapfile, - pid_t pid, u_char *mapinfo) -{ - int len, mapfd; - u_char *p, *end; - ssize_t n; - u_char buf[256]; - - end = buf + sizeof(buf); - - p = nxt_sprintf(buf, end, "/proc/%d/%s", pid, mapfile); - if (nxt_slow_path(p == end)) { - nxt_alert(task, "writing past the buffer"); - return NXT_ERROR; - } - - *p = '\0'; - - mapfd = open((char*)buf, O_RDWR); - if (nxt_slow_path(mapfd == -1)) { - nxt_alert(task, "failed to open proc map (%s) %E", buf, nxt_errno); - return NXT_ERROR; - } - - len = nxt_strlen(mapinfo); - - n = write(mapfd, (char *)mapinfo, len); - if (nxt_slow_path(n != len)) { - - if (n == -1 && nxt_errno == EINVAL) { - nxt_alert(task, "failed to write %s: Check kernel maximum " \ - "allowed lines %E", buf, nxt_errno); - - } else { - nxt_alert(task, "failed to write proc map (%s) %E", buf, - nxt_errno); - } - - close(mapfd); - - return NXT_ERROR; - } - - close(mapfd); - - return NXT_OK; -} - - -nxt_int_t -nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile, pid_t pid, - nxt_int_t default_container, nxt_int_t default_host, - nxt_clone_credential_map_t *map) -{ - u_char *p, *end, *mapinfo; - nxt_int_t ret, len; - nxt_uint_t i; - - /* - * uid_map one-entry size: - * alloc space for 3 numbers (32bit) plus 2 spaces and \n. - */ - len = sizeof(u_char) * (10 + 10 + 10 + 2 + 1); - - if (map->size > 0) { - len = len * map->size + 1; - - mapinfo = nxt_malloc(len); - if (nxt_slow_path(mapinfo == NULL)) { - return NXT_ERROR; - } - - p = mapinfo; - end = mapinfo + len; - - for (i = 0; i < map->size; i++) { - p = nxt_sprintf(p, end, "%L %L %L", map->map[i].container, - map->map[i].host, map->map[i].size); - - if (nxt_slow_path(p == end)) { - nxt_alert(task, "write past the mapinfo buffer"); - nxt_free(mapinfo); - return NXT_ERROR; - } - - if (i + 1 < map->size) { - *p++ = '\n'; - - } else { - *p = '\0'; - } - } - - } else { - mapinfo = nxt_malloc(len); - if (nxt_slow_path(mapinfo == NULL)) { - return NXT_ERROR; - } - - end = mapinfo + len; - p = nxt_sprintf(mapinfo, end, "%d %d 1", - default_container, default_host); - *p = '\0'; - - if (nxt_slow_path(p == end)) { - nxt_alert(task, "write past mapinfo buffer"); - nxt_free(mapinfo); - return NXT_ERROR; - } - } - - ret = nxt_clone_credential_map_write(task, mapfile, pid, mapinfo); - - nxt_free(mapinfo); - - return ret; -} - - -nxt_int_t -nxt_clone_credential_map(nxt_task_t *task, pid_t pid, - nxt_credential_t *app_creds, nxt_clone_t *clone) -{ - nxt_int_t ret; - nxt_int_t default_host_uid; - nxt_int_t default_host_gid; - const char *rule; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - if (rt->capabilities.setid) { - rule = "allow"; - - /* - * By default we don't map a privileged user - */ - default_host_uid = app_creds->uid; - default_host_gid = app_creds->base_gid; - } else { - rule = "deny"; - - default_host_uid = nxt_euid; - default_host_gid = nxt_egid; - } - - ret = nxt_clone_credential_map_set(task, "uid_map", pid, app_creds->uid, - default_host_uid, - &clone->uidmap); - - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - ret = nxt_clone_credential_setgroups(task, pid, rule); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "failed to write /proc/%d/setgroups", pid); - return NXT_ERROR; - } - - ret = nxt_clone_credential_map_set(task, "gid_map", pid, app_creds->base_gid, - default_host_gid, - &clone->gidmap); - - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -nxt_int_t -nxt_clone_vldt_credential_uidmap(nxt_task_t *task, - nxt_clone_credential_map_t *map, nxt_credential_t *creds) -{ - nxt_int_t id; - nxt_uint_t i; - nxt_runtime_t *rt; - nxt_clone_map_entry_t m; - - if (map->size == 0) { - return NXT_OK; - } - - rt = task->thread->runtime; - - if (!rt->capabilities.setid) { - if (nxt_slow_path(map->size > 1)) { - nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has %d entries " - "but unprivileged unit has a maximum of 1 map.", - map->size); - - return NXT_ERROR; - } - - id = map->map[0].host; - - if (nxt_slow_path((nxt_uid_t) id != nxt_euid)) { - nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has an entry for " - "host uid %d but unprivileged unit can only map itself " - "(uid %d) into child namespaces.", id, nxt_euid); - - return NXT_ERROR; - } - - return NXT_OK; - } - - for (i = 0; i < map->size; i++) { - m = map->map[i]; - - if (creds->uid >= (nxt_uid_t) m.container - && creds->uid < (nxt_uid_t) (m.container + m.size)) - { - return NXT_OK; - } - } - - nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has no \"container\" " - "entry for user \"%s\" (uid %d)", creds->user, creds->uid); - - return NXT_ERROR; -} - - -nxt_int_t -nxt_clone_vldt_credential_gidmap(nxt_task_t *task, - nxt_clone_credential_map_t *map, nxt_credential_t *creds) -{ - nxt_uint_t base_ok, gid_ok, gids_ok; - nxt_uint_t i, j; - nxt_runtime_t *rt; - nxt_clone_map_entry_t m; - - rt = task->thread->runtime; - - if (!rt->capabilities.setid) { - if (creds->ngroups > 0 - && !(creds->ngroups == 1 && creds->gids[0] == creds->base_gid)) { - nxt_log(task, NXT_LOG_NOTICE, - "unprivileged unit disallow supplementary groups for " - "new namespace (user \"%s\" has %d group%s).", - creds->user, creds->ngroups, - creds->ngroups > 1 ? "s" : ""); - - return NXT_ERROR; - } - - if (map->size == 0) { - return NXT_OK; - } - - if (nxt_slow_path(map->size > 1)) { - nxt_log(task, NXT_LOG_NOTICE, "\"gidmap\" field has %d entries " - "but unprivileged unit has a maximum of 1 map.", - map->size); - - return NXT_ERROR; - } - - m = map->map[0]; - - if (nxt_slow_path((nxt_gid_t) m.host != nxt_egid)) { - nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry for " - "host gid %L but unprivileged unit can only map itself " - "(gid %d) into child namespaces.", m.host, nxt_egid); - - return NXT_ERROR; - } - - if (nxt_slow_path(m.size > 1)) { - nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry with " - "\"size\": %L, but for unprivileged unit it must be 1.", - m.size); - - return NXT_ERROR; - } - - if (nxt_slow_path((nxt_gid_t) m.container != creds->base_gid)) { - nxt_log(task, NXT_LOG_ERR, - "\"gidmap\" field has no \"container\" entry for gid %d.", - creds->base_gid); - - return NXT_ERROR; - } - - return NXT_OK; - } - - if (map->size == 0) { - if (creds->ngroups > 0 - && !(creds->ngroups == 1 && creds->gids[0] == creds->base_gid)) - { - nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has no entries " - "but user \"%s\" has %d suplementary group%s.", - creds->user, creds->ngroups, - creds->ngroups > 1 ? "s" : ""); - - return NXT_ERROR; - } - - return NXT_OK; - } - - base_ok = 0; - gids_ok = 0; - - for (i = 0; i < creds->ngroups; i++) { - gid_ok = 0; - - for (j = 0; j < map->size; j++) { - m = map->map[j]; - - if (!base_ok && creds->base_gid >= (nxt_gid_t) m.container - && creds->base_gid < (nxt_gid_t) (m.container + m.size)) - { - base_ok = 1; - } - - if (creds->gids[i] >= (nxt_gid_t) m.container - && creds->gids[i] < (nxt_gid_t) (m.container + m.size)) - { - gid_ok = 1; - break; - } - } - - if (nxt_fast_path(gid_ok)) { - gids_ok++; - } - } - - if (!base_ok) { - for (i = 0; i < map->size; i++) { - m = map->map[i]; - - if (creds->base_gid >= (nxt_gid_t) m.container - && creds->base_gid < (nxt_gid_t) (m.container + m.size)) - { - base_ok = 1; - break; - } - } - } - - if (nxt_slow_path(!base_ok)) { - nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has no \"container\" " - "entry for gid %d.", creds->base_gid); - - return NXT_ERROR; - } - - if (nxt_slow_path(gids_ok < creds->ngroups)) { - nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has missing " - "suplementary gid mappings (found %d out of %d).", gids_ok, - creds->ngroups); - - return NXT_ERROR; - } - - return NXT_OK; -} - -#endif diff --git a/src/nxt_clone.h b/src/nxt_clone.h deleted file mode 100644 index bf28322f..00000000 --- a/src/nxt_clone.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_CLONE_H_INCLUDED_ -#define _NXT_CLONE_H_INCLUDED_ - - -#if (NXT_HAVE_CLONE_NEWUSER) - -typedef int64_t nxt_cred_t; - -typedef struct { - nxt_cred_t container; - nxt_cred_t host; - nxt_cred_t size; -} nxt_clone_map_entry_t; - -typedef struct { - nxt_uint_t size; - nxt_clone_map_entry_t *map; -} nxt_clone_credential_map_t; - -#endif - -typedef struct { - nxt_int_t flags; - -#if (NXT_HAVE_CLONE_NEWUSER) - nxt_clone_credential_map_t uidmap; - nxt_clone_credential_map_t gidmap; -#endif - -} nxt_clone_t; - - -#define nxt_is_clone_flag_set(flags, test) \ - ((flags & CLONE_##test) == CLONE_##test) - - -#if (NXT_HAVE_CLONE_NEWUSER) - -NXT_EXPORT nxt_int_t nxt_clone_credential_map(nxt_task_t *task, pid_t pid, - nxt_credential_t *creds, nxt_clone_t *clone); -NXT_EXPORT nxt_int_t nxt_clone_vldt_credential_uidmap(nxt_task_t *task, - nxt_clone_credential_map_t *map, nxt_credential_t *creds); -NXT_EXPORT nxt_int_t nxt_clone_vldt_credential_gidmap(nxt_task_t *task, - nxt_clone_credential_map_t *map, nxt_credential_t *creds); - -#endif - - -#endif /* _NXT_CLONE_H_INCLUDED_ */ diff --git a/src/nxt_conf.c b/src/nxt_conf.c deleted file mode 100644 index 008cb968..00000000 --- a/src/nxt_conf.c +++ /dev/null @@ -1,2658 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - * Copyright 2024, Alejandro Colomar - */ - -#include -#include - -#include -#include - - -#define NXT_CONF_MAX_SHORT_STRING 14 -#define NXT_CONF_MAX_NUMBER_LEN 14 -#define NXT_CONF_MAX_STRING NXT_INT32_T_MAX - -#define NXT_CONF_MAX_TOKEN_LEN 256 - - -typedef enum { - NXT_CONF_VALUE_NULL = 0, - NXT_CONF_VALUE_BOOLEAN, - NXT_CONF_VALUE_INTEGER, - NXT_CONF_VALUE_NUMBER, - NXT_CONF_VALUE_SHORT_STRING, - NXT_CONF_VALUE_STRING, - NXT_CONF_VALUE_ARRAY, - NXT_CONF_VALUE_OBJECT, -} nxt_conf_value_type_t; - - -typedef enum { - NXT_CONF_OP_PASS = 0, - NXT_CONF_OP_CREATE, - NXT_CONF_OP_REPLACE, - NXT_CONF_OP_DELETE, -} nxt_conf_op_action_t; - - -typedef struct nxt_conf_array_s nxt_conf_array_t; -typedef struct nxt_conf_object_s nxt_conf_object_t; - - -struct nxt_conf_value_s { - union { - uint8_t boolean; /* 1 bit. */ - u_char number[NXT_CONF_MAX_NUMBER_LEN + 1]; - - struct { - u_char start[NXT_CONF_MAX_SHORT_STRING]; - uint8_t length; - } str; - - struct { - u_char *start; - uint32_t length; - } nxt_packed string; - - nxt_conf_array_t *array; - nxt_conf_object_t *object; - } nxt_packed u; - - uint8_t type; /* 3 bits. */ -} nxt_aligned(8); - - -struct nxt_conf_array_s { - nxt_uint_t count; - nxt_conf_value_t elements[]; -}; - - -typedef struct { - nxt_conf_value_t name; - nxt_conf_value_t value; -} nxt_conf_object_member_t; - - -struct nxt_conf_object_s { - nxt_uint_t count; - nxt_conf_object_member_t members[]; -}; - - -struct nxt_conf_op_s { - uint32_t index; - uint32_t action; /* nxt_conf_op_action_t */ - void *ctx; -}; - - -typedef struct { - u_char *start; - u_char *end; - nxt_bool_t last; - u_char buf[NXT_CONF_MAX_TOKEN_LEN]; -} nxt_conf_path_parse_t; - - -static nxt_int_t nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, - nxt_str_t *token); - -static u_char *nxt_conf_json_skip_space(u_char *start, const u_char *end); -static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, - u_char *start, u_char *end, nxt_conf_json_error_t *error); -static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, - u_char *start, u_char *end, nxt_conf_json_error_t *error); -static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp, - nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member); -static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, - void *data); -static void *nxt_conf_object_hash_alloc(void *data, size_t size); -static void nxt_conf_object_hash_free(void *data, void *p); -static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, - u_char *start, u_char *end, nxt_conf_json_error_t *error); -static u_char *nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, - u_char *start, u_char *end, nxt_conf_json_error_t *error); -static u_char *nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, - u_char *start, u_char *end, nxt_conf_json_error_t *error); -static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos, - const char *detail); - -static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, - nxt_conf_value_t *dst, nxt_conf_value_t *src); -static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, - nxt_conf_value_t *dst, nxt_conf_value_t *src); -static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, - nxt_conf_value_t *dst, nxt_conf_value_t *src); - -static size_t nxt_conf_json_string_length(nxt_conf_value_t *value); -static u_char *nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value); -static size_t nxt_conf_json_array_length(nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty); -static u_char *nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty); -static size_t nxt_conf_json_object_length(nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty); -static u_char *nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty); - -static size_t nxt_conf_json_escape_length(u_char *p, size_t size); -static u_char *nxt_conf_json_escape(u_char *dst, u_char *src, size_t size); - - -#define nxt_conf_json_newline(p) \ - ((p)[0] = '\r', (p)[1] = '\n', (p) + 2) - - -nxt_inline u_char * -nxt_conf_json_indentation(u_char *p, uint32_t level) -{ - while (level) { - *p++ = '\t'; - level--; - } - - return p; -} - - -void -nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str) -{ - if (value->type == NXT_CONF_VALUE_SHORT_STRING) { - str->length = value->u.str.length; - str->start = value->u.str.start; - - } else { - str->length = value->u.string.length; - str->start = value->u.string.start; - } -} - - -nxt_str_t * -nxt_conf_get_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str) -{ - nxt_str_t s; - - nxt_conf_get_string(value, &s); - return nxt_str_dup(mp, str, &s); -} - - -void -nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str) -{ - if (str->length > NXT_CONF_MAX_SHORT_STRING) { - value->type = NXT_CONF_VALUE_STRING; - value->u.string.length = str->length; - value->u.string.start = str->start; - - } else { - value->type = NXT_CONF_VALUE_SHORT_STRING; - value->u.str.length = str->length; - - nxt_memcpy(value->u.str.start, str->start, str->length); - } -} - - -nxt_int_t -nxt_conf_set_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, - const nxt_str_t *str) -{ - nxt_str_t tmp, *ptr; - - if (str->length > NXT_CONF_MAX_SHORT_STRING) { - value->type = NXT_CONF_VALUE_STRING; - - ptr = nxt_str_dup(mp, &tmp, str); - if (nxt_slow_path(ptr == NULL)) { - return NXT_ERROR; - } - - value->u.string.length = tmp.length; - value->u.string.start = tmp.start; - - } else { - value->type = NXT_CONF_VALUE_SHORT_STRING; - value->u.str.length = str->length; - - nxt_memcpy(value->u.str.start, str->start, str->length); - } - - return NXT_OK; -} - - -double -nxt_conf_get_number(nxt_conf_value_t *value) -{ - return nxt_strtod(value->u.number, NULL); -} - - -uint8_t -nxt_conf_get_boolean(nxt_conf_value_t *value) -{ - return value->u.boolean; -} - - -nxt_uint_t -nxt_conf_object_members_count(nxt_conf_value_t *value) -{ - return value->u.object->count; -} - - -nxt_conf_value_t * -nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count) -{ - size_t size; - nxt_conf_value_t *value; - - size = sizeof(nxt_conf_value_t) - + sizeof(nxt_conf_object_t) - + count * sizeof(nxt_conf_object_member_t); - - value = nxt_mp_get(mp, size); - if (nxt_slow_path(value == NULL)) { - return NULL; - } - - value->u.object = nxt_pointer_to(value, sizeof(nxt_conf_value_t)); - value->u.object->count = count; - - value->type = NXT_CONF_VALUE_OBJECT; - - return value; -} - - -void -nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name, - const nxt_conf_value_t *value, uint32_t index) -{ - nxt_conf_object_member_t *member; - - member = &object->u.object->members[index]; - - nxt_conf_set_string(&member->name, name); - - member->value = *value; -} - - -nxt_int_t -nxt_conf_set_member_dup(nxt_conf_value_t *object, nxt_mp_t *mp, nxt_str_t *name, - nxt_conf_value_t *value, uint32_t index) -{ - nxt_conf_object_member_t *member; - - member = &object->u.object->members[index]; - - member->value = *value; - - return nxt_conf_set_string_dup(&member->name, mp, name); -} - - -void -nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name, - nxt_str_t *value, uint32_t index) -{ - nxt_conf_object_member_t *member; - - member = &object->u.object->members[index]; - - nxt_conf_set_string(&member->name, name); - - nxt_conf_set_string(&member->value, value); -} - - -nxt_int_t -nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp, - nxt_str_t *name, nxt_str_t *value, uint32_t index) -{ - nxt_conf_object_member_t *member; - - member = &object->u.object->members[index]; - - nxt_conf_set_string(&member->name, name); - - return nxt_conf_set_string_dup(&member->value, mp, value); -} - - -void -nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name, - int64_t value, uint32_t index) -{ - u_char *p, *end; - nxt_conf_object_member_t *member; - - member = &object->u.object->members[index]; - - nxt_conf_set_string(&member->name, name); - - p = member->value.u.number; - end = p + NXT_CONF_MAX_NUMBER_LEN; - - end = nxt_sprintf(p, end, "%L", value); - *end = '\0'; - - member->value.type = NXT_CONF_VALUE_INTEGER; -} - - -void -nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name, - uint32_t index) -{ - nxt_conf_object_member_t *member; - - member = &object->u.object->members[index]; - - nxt_conf_set_string(&member->name, name); - - member->value.type = NXT_CONF_VALUE_NULL; -} - - -nxt_conf_value_t * -nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count) -{ - size_t size; - nxt_conf_value_t *value; - - size = sizeof(nxt_conf_value_t) - + sizeof(nxt_conf_array_t) - + count * sizeof(nxt_conf_value_t); - - value = nxt_mp_get(mp, size); - if (nxt_slow_path(value == NULL)) { - return NULL; - } - - value->u.array = nxt_pointer_to(value, sizeof(nxt_conf_value_t)); - value->u.array->count = count; - - value->type = NXT_CONF_VALUE_ARRAY; - - return value; -} - - -void -nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index, - const nxt_conf_value_t *value) -{ - array->u.array->elements[index] = *value; -} - - -nxt_int_t -nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp, - nxt_uint_t index, nxt_str_t *value) -{ - nxt_conf_value_t *element; - - element = &array->u.array->elements[index]; - - return nxt_conf_set_string_dup(element, mp, value); -} - - -nxt_uint_t -nxt_conf_array_elements_count(nxt_conf_value_t *value) -{ - return value->u.array->count; -} - - -nxt_uint_t -nxt_conf_array_elements_count_or_1(nxt_conf_value_t *value) -{ - return (value->type == NXT_CONF_VALUE_ARRAY) ? value->u.array->count : 1; -} - - -nxt_uint_t -nxt_conf_type(nxt_conf_value_t *value) -{ - switch (value->type) { - - case NXT_CONF_VALUE_NULL: - return NXT_CONF_NULL; - - case NXT_CONF_VALUE_BOOLEAN: - return NXT_CONF_BOOLEAN; - - case NXT_CONF_VALUE_INTEGER: - return NXT_CONF_INTEGER; - - case NXT_CONF_VALUE_NUMBER: - return NXT_CONF_NUMBER; - - case NXT_CONF_VALUE_SHORT_STRING: - case NXT_CONF_VALUE_STRING: - return NXT_CONF_STRING; - - case NXT_CONF_VALUE_ARRAY: - return NXT_CONF_ARRAY; - - case NXT_CONF_VALUE_OBJECT: - return NXT_CONF_OBJECT; - } - - nxt_unreachable(); - - return 0; -} - - -nxt_conf_value_t * -nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path) -{ - nxt_str_t token; - nxt_int_t ret, index; - nxt_conf_path_parse_t parse; - - parse.start = path->start; - parse.end = path->start + path->length; - parse.last = 0; - - do { - ret = nxt_conf_path_next_token(&parse, &token); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - if (token.length == 0) { - - if (parse.last) { - break; - } - - return NULL; - } - - switch (value->type) { - - case NXT_CONF_VALUE_OBJECT: - value = nxt_conf_get_object_member(value, &token, NULL); - break; - - case NXT_CONF_VALUE_ARRAY: - index = nxt_int_parse(token.start, token.length); - - if (index < 0 || index > NXT_INT32_T_MAX) { - return NULL; - } - - value = nxt_conf_get_array_element(value, index); - break; - - default: - return NULL; - } - - if (value == NULL) { - return NULL; - } - - } while (parse.last == 0); - - return value; -} - - -static nxt_int_t -nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, nxt_str_t *token) -{ - u_char *p, *start, *end; - size_t length; - - start = parse->start + 1; - - p = start; - - while (p < parse->end && *p != '/') { - p++; - } - - parse->start = p; - parse->last = (p >= parse->end); - - length = p - start; - - if (nxt_slow_path(length > NXT_CONF_MAX_TOKEN_LEN)) { - return NXT_ERROR; - } - - end = nxt_decode_uri(parse->buf, start, length); - if (nxt_slow_path(end == NULL)) { - return NXT_ERROR; - } - - token->length = end - parse->buf; - token->start = parse->buf; - - return NXT_OK; -} - - -nxt_conf_value_t * -nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_str_t *name, - uint32_t *index) -{ - nxt_str_t str; - nxt_uint_t n; - nxt_conf_object_t *object; - nxt_conf_object_member_t *member; - - if (value->type != NXT_CONF_VALUE_OBJECT) { - return NULL; - } - - object = value->u.object; - - for (n = 0; n < object->count; n++) { - member = &object->members[n]; - - nxt_conf_get_string(&member->name, &str); - - if (nxt_strstr_eq(&str, name)) { - - if (index != NULL) { - *index = n; - } - - return &member->value; - } - } - - return NULL; -} - - -nxt_int_t -nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map, - nxt_uint_t n, void *data) -{ - double num; - nxt_str_t str, *s; - nxt_uint_t i; - nxt_conf_value_t *v; - - union { - uint8_t ui8; - int32_t i32; - int64_t i64; - int i; - ssize_t size; - off_t off; - nxt_msec_t msec; - double dbl; - nxt_str_t str; - char *cstrz; - void *v; - } *ptr; - - for (i = 0; i < n; i++) { - - v = nxt_conf_get_object_member(value, &map[i].name, NULL); - - if (v == NULL || v->type == NXT_CONF_VALUE_NULL) { - continue; - } - - ptr = nxt_pointer_to(data, map[i].offset); - - switch (map[i].type) { - - case NXT_CONF_MAP_INT8: - - if (v->type == NXT_CONF_VALUE_BOOLEAN) { - ptr->ui8 = v->u.boolean; - } - - break; - - case NXT_CONF_MAP_INT32: - case NXT_CONF_MAP_INT64: - case NXT_CONF_MAP_INT: - case NXT_CONF_MAP_SIZE: - case NXT_CONF_MAP_OFF: - case NXT_CONF_MAP_MSEC: - - if (v->type != NXT_CONF_VALUE_INTEGER) { - break; - } - - num = nxt_strtod(v->u.number, NULL); - - switch (map[i].type) { - - case NXT_CONF_MAP_INT32: - ptr->i32 = num; - break; - - case NXT_CONF_MAP_INT64: - ptr->i64 = num; - break; - - case NXT_CONF_MAP_INT: - ptr->i = num; - break; - - case NXT_CONF_MAP_SIZE: - ptr->size = num; - break; - - case NXT_CONF_MAP_OFF: - ptr->off = num; - break; - - case NXT_CONF_MAP_MSEC: - ptr->msec = (nxt_msec_t) num * 1000; - break; - - default: - nxt_unreachable(); - } - - break; - - case NXT_CONF_MAP_DOUBLE: - - if (v->type == NXT_CONF_VALUE_NUMBER) { - ptr->dbl = nxt_strtod(v->u.number, NULL); - } - - break; - - case NXT_CONF_MAP_STR: - case NXT_CONF_MAP_STR_COPY: - case NXT_CONF_MAP_CSTRZ: - - if (v->type != NXT_CONF_VALUE_SHORT_STRING - && v->type != NXT_CONF_VALUE_STRING) - { - break; - } - - nxt_conf_get_string(v, &str); - - switch (map[i].type) { - - case NXT_CONF_MAP_STR: - ptr->str = str; - break; - - case NXT_CONF_MAP_STR_COPY: - - s = nxt_str_dup(mp, &ptr->str, &str); - - if (nxt_slow_path(s == NULL)) { - return NXT_ERROR; - } - - break; - - case NXT_CONF_MAP_CSTRZ: - - ptr->cstrz = nxt_str_cstrz(mp, &str); - - if (nxt_slow_path(ptr->cstrz == NULL)) { - return NXT_ERROR; - } - - break; - - default: - nxt_unreachable(); - } - - break; - - case NXT_CONF_MAP_PTR: - - ptr->v = v; - - break; - } - } - - return NXT_OK; -} - - -nxt_conf_value_t * -nxt_conf_next_object_member(nxt_conf_value_t *value, nxt_str_t *name, - uint32_t *next) -{ - uint32_t n; - nxt_conf_object_t *object; - nxt_conf_object_member_t *member; - - if (value->type != NXT_CONF_VALUE_OBJECT) { - return NULL; - } - - n = *next; - object = value->u.object; - - if (n >= object->count) { - return NULL; - } - - member = &object->members[n]; - *next = n + 1; - - nxt_conf_get_string(&member->name, name); - - return &member->value; -} - - -nxt_conf_value_t * -nxt_conf_get_array_element(nxt_conf_value_t *value, uint32_t index) -{ - nxt_conf_array_t *array; - - if (value->type != NXT_CONF_VALUE_ARRAY) { - return NULL; - } - - array = value->u.array; - - if (index >= array->count) { - return NULL; - } - - return &array->elements[index]; -} - - -nxt_conf_value_t * -nxt_conf_get_array_element_or_itself(nxt_conf_value_t *value, uint32_t index) -{ - nxt_conf_array_t *array; - - if (value->type != NXT_CONF_VALUE_ARRAY) { - return (index == 0) ? value : NULL; - } - - array = value->u.array; - - if (index >= array->count) { - return NULL; - } - - return &array->elements[index]; -} - - -void -nxt_conf_array_qsort(nxt_conf_value_t *value, - int (*compare)(const void *, const void *)) -{ - nxt_conf_array_t *array; - - if (value->type != NXT_CONF_VALUE_ARRAY) { - return; - } - - array = value->u.array; - - nxt_qsort(array->elements, array->count, sizeof(nxt_conf_value_t), compare); -} - - -nxt_conf_op_ret_t -nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, - nxt_str_t *path, nxt_conf_value_t *value, nxt_bool_t add) -{ - nxt_str_t token; - nxt_int_t ret, index; - nxt_conf_op_t *op, **parent; - nxt_conf_value_t *node; - nxt_conf_path_parse_t parse; - nxt_conf_object_member_t *member; - - parse.start = path->start; - parse.end = path->start + path->length; - parse.last = 0; - - parent = ops; - - for ( ;; ) { - op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t)); - if (nxt_slow_path(op == NULL)) { - return NXT_CONF_OP_ERROR; - } - - *parent = op; - parent = (nxt_conf_op_t **) &op->ctx; - - ret = nxt_conf_path_next_token(&parse, &token); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_CONF_OP_ERROR; - } - - switch (root->type) { - - case NXT_CONF_VALUE_OBJECT: - node = nxt_conf_get_object_member(root, &token, &op->index); - break; - - case NXT_CONF_VALUE_ARRAY: - index = nxt_int_parse(token.start, token.length); - - if (index < 0 || index > NXT_INT32_T_MAX) { - return NXT_CONF_OP_NOT_FOUND; - } - - op->index = index; - - node = nxt_conf_get_array_element(root, index); - break; - - default: - node = NULL; - } - - if (parse.last) { - break; - } - - if (node == NULL) { - return NXT_CONF_OP_NOT_FOUND; - } - - op->action = NXT_CONF_OP_PASS; - root = node; - } - - if (value == NULL) { - - if (node == NULL) { - return NXT_CONF_OP_NOT_FOUND; - } - - op->action = NXT_CONF_OP_DELETE; - - return NXT_CONF_OP_OK; - } - - if (add) { - if (node == NULL) { - return NXT_CONF_OP_NOT_FOUND; - } - - if (node->type != NXT_CONF_VALUE_ARRAY) { - return NXT_CONF_OP_NOT_ALLOWED; - } - - op->action = NXT_CONF_OP_PASS; - - op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t)); - if (nxt_slow_path(op == NULL)) { - return NXT_CONF_OP_ERROR; - } - - *parent = op; - - op->index = node->u.array->count; - op->action = NXT_CONF_OP_CREATE; - op->ctx = value; - - return NXT_CONF_OP_OK; - } - - if (node != NULL) { - op->action = NXT_CONF_OP_REPLACE; - op->ctx = value; - - return NXT_CONF_OP_OK; - } - - op->action = NXT_CONF_OP_CREATE; - - if (root->type == NXT_CONF_VALUE_ARRAY) { - if (op->index > root->u.array->count) { - return NXT_CONF_OP_NOT_FOUND; - } - - op->ctx = value; - - } else { - member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t)); - if (nxt_slow_path(member == NULL)) { - return NXT_CONF_OP_ERROR; - } - - ret = nxt_conf_set_string_dup(&member->name, mp, &token); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_CONF_OP_ERROR; - } - - member->value = *value; - - op->index = root->u.object->count; - op->ctx = member; - } - - return NXT_CONF_OP_OK; -} - - -nxt_conf_value_t * -nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *value) -{ - nxt_int_t rc; - nxt_conf_value_t *copy; - - copy = nxt_mp_get(mp, sizeof(nxt_conf_value_t)); - if (nxt_slow_path(copy == NULL)) { - return NULL; - } - - rc = nxt_conf_copy_value(mp, op, copy, value); - - if (nxt_slow_path(rc != NXT_OK)) { - return NULL; - } - - return copy; -} - - -static nxt_int_t -nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, - nxt_conf_value_t *src) -{ - if (op != NULL - && src->type != NXT_CONF_VALUE_ARRAY - && src->type != NXT_CONF_VALUE_OBJECT) - { - return NXT_ERROR; - } - - switch (src->type) { - - case NXT_CONF_VALUE_STRING: - - dst->u.string.start = nxt_mp_nget(mp, src->u.string.length); - if (nxt_slow_path(dst->u.string.start == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy(dst->u.string.start, src->u.string.start, - src->u.string.length); - - dst->u.string.length = src->u.string.length; - - break; - - case NXT_CONF_VALUE_ARRAY: - return nxt_conf_copy_array(mp, op, dst, src); - - case NXT_CONF_VALUE_OBJECT: - return nxt_conf_copy_object(mp, op, dst, src); - - default: - dst->u = src->u; - } - - dst->type = src->type; - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, - nxt_conf_value_t *src) -{ - size_t size; - nxt_int_t rc; - nxt_uint_t s, d, count, index; - nxt_conf_op_t *pass_op; - nxt_conf_value_t *value; - - count = src->u.array->count; - - if (op != NULL) { - if (op->action == NXT_CONF_OP_CREATE) { - count++; - - } else if (op->action == NXT_CONF_OP_DELETE) { - count--; - } - } - - size = sizeof(nxt_conf_array_t) + count * sizeof(nxt_conf_value_t); - - dst->u.array = nxt_mp_get(mp, size); - if (nxt_slow_path(dst->u.array == NULL)) { - return NXT_ERROR; - } - - dst->u.array->count = count; - - s = 0; - d = 0; - - pass_op = NULL; - - /* - * This initialization is needed only to - * suppress a warning on GCC 4.8 and older. - */ - index = 0; - - do { - if (pass_op == NULL) { - index = (op == NULL) ? src->u.array->count : op->index; - } - - while (s != index) { - rc = nxt_conf_copy_value(mp, pass_op, &dst->u.array->elements[d], - &src->u.array->elements[s]); - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - s++; - d++; - } - - if (pass_op != NULL) { - pass_op = NULL; - continue; - } - - if (op != NULL) { - switch (op->action) { - case NXT_CONF_OP_PASS: - pass_op = op->ctx; - index++; - break; - - case NXT_CONF_OP_CREATE: - value = op->ctx; - dst->u.array->elements[d] = *value; - - d++; - break; - - case NXT_CONF_OP_REPLACE: - value = op->ctx; - dst->u.array->elements[d] = *value; - - s++; - d++; - break; - - case NXT_CONF_OP_DELETE: - s++; - break; - } - - op = NULL; - } - - } while (d != count); - - dst->type = src->type; - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, - nxt_conf_value_t *src) -{ - size_t size; - nxt_int_t rc; - nxt_uint_t s, d, count, index; - nxt_conf_op_t *pass_op; - nxt_conf_value_t *value; - nxt_conf_object_member_t *member; - - count = src->u.object->count; - - if (op != NULL) { - if (op->action == NXT_CONF_OP_CREATE) { - count++; - - } else if (op->action == NXT_CONF_OP_DELETE) { - count--; - } - } - - size = sizeof(nxt_conf_object_t) - + count * sizeof(nxt_conf_object_member_t); - - dst->u.object = nxt_mp_get(mp, size); - if (nxt_slow_path(dst->u.object == NULL)) { - return NXT_ERROR; - } - - dst->u.object->count = count; - - s = 0; - d = 0; - - pass_op = NULL; - - /* - * This initialization is needed only to - * suppress a warning on GCC 4.8 and older. - */ - index = 0; - - do { - if (pass_op == NULL) { - index = (op == NULL) ? src->u.object->count : op->index; - } - - while (s != index) { - rc = nxt_conf_copy_value(mp, NULL, - &dst->u.object->members[d].name, - &src->u.object->members[s].name); - - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - rc = nxt_conf_copy_value(mp, pass_op, - &dst->u.object->members[d].value, - &src->u.object->members[s].value); - - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - s++; - d++; - } - - if (pass_op != NULL) { - pass_op = NULL; - continue; - } - - if (op != NULL) { - switch (op->action) { - case NXT_CONF_OP_PASS: - pass_op = op->ctx; - index++; - break; - - case NXT_CONF_OP_CREATE: - member = op->ctx; - - rc = nxt_conf_copy_value(mp, NULL, - &dst->u.object->members[d].name, - &member->name); - - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - dst->u.object->members[d].value = member->value; - - d++; - break; - - case NXT_CONF_OP_REPLACE: - rc = nxt_conf_copy_value(mp, NULL, - &dst->u.object->members[d].name, - &src->u.object->members[s].name); - - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - value = op->ctx; - - dst->u.object->members[d].value = *value; - - s++; - d++; - break; - - case NXT_CONF_OP_DELETE: - s++; - break; - } - - op = NULL; - } - - } while (d != count); - - dst->type = src->type; - - return NXT_OK; -} - - -nxt_conf_value_t * -nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end, - nxt_conf_json_error_t *error) -{ - u_char *p; - nxt_conf_value_t *value; - - value = nxt_mp_get(mp, sizeof(nxt_conf_value_t)); - if (nxt_slow_path(value == NULL)) { - return NULL; - } - - p = nxt_conf_json_skip_space(start, end); - - if (nxt_slow_path(p == end)) { - - nxt_conf_json_parse_error(error, start, - "An empty JSON payload isn't allowed. It must be either a literal " - "(null, true, or false), a number, a string (in double quotes " - "\"\"), an array (with brackets []), or an object (with braces {})." - ); - - return NULL; - } - - p = nxt_conf_json_parse_value(mp, value, p, end, error); - - if (nxt_slow_path(p == NULL)) { - return NULL; - } - - p = nxt_conf_json_skip_space(p, end); - - if (nxt_slow_path(p != end)) { - - nxt_conf_json_parse_error(error, p, - "Unexpected character after the end of a valid JSON value." - ); - - return NULL; - } - - return value; -} - - -static u_char * -nxt_conf_json_skip_space(u_char *start, const u_char *end) -{ - u_char *p, ch; - - enum { - sw_normal = 0, - sw_after_slash, - sw_single_comment, - sw_multi_comment, - sw_after_asterisk, - } state; - - state = sw_normal; - - for (p = start; nxt_fast_path(p != end); p++) { - ch = *p; - - switch (state) { - - case sw_normal: - switch (ch) { - case ' ': - case '\t': - case '\n': - case '\r': - continue; - case '/': - start = p; - state = sw_after_slash; - continue; - } - - break; - - case sw_after_slash: - switch (ch) { - case '/': - state = sw_single_comment; - continue; - case '*': - state = sw_multi_comment; - continue; - } - - break; - - case sw_single_comment: - if (ch == '\n') { - state = sw_normal; - } - - continue; - - case sw_multi_comment: - if (ch == '*') { - state = sw_after_asterisk; - } - - continue; - - case sw_after_asterisk: - switch (ch) { - case '/': - state = sw_normal; - continue; - case '*': - continue; - } - - state = sw_multi_comment; - continue; - } - - break; - } - - if (nxt_slow_path(state != sw_normal)) { - return start; - } - - return p; -} - - -static u_char * -nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, - u_char *end, nxt_conf_json_error_t *error) -{ - u_char ch, *p; - - ch = *start; - - switch (ch) { - case '{': - return nxt_conf_json_parse_object(mp, value, start, end, error); - - case '[': - return nxt_conf_json_parse_array(mp, value, start, end, error); - - case '"': - return nxt_conf_json_parse_string(mp, value, start, end, error); - - case 't': - if (nxt_fast_path(end - start >= 4 - && memcmp(start, "true", 4) == 0)) - { - value->u.boolean = 1; - value->type = NXT_CONF_VALUE_BOOLEAN; - - return start + 4; - } - - goto error; - - case 'f': - if (nxt_fast_path(end - start >= 5 - && memcmp(start, "false", 5) == 0)) - { - value->u.boolean = 0; - value->type = NXT_CONF_VALUE_BOOLEAN; - - return start + 5; - } - - goto error; - - case 'n': - if (nxt_fast_path(end - start >= 4 - && memcmp(start, "null", 4) == 0)) - { - value->type = NXT_CONF_VALUE_NULL; - return start + 4; - } - - goto error; - - case '-': - if (nxt_fast_path(end - start > 1)) { - ch = start[1]; - break; - } - - goto error; - } - - if (nxt_fast_path((ch - '0') <= 9)) { - p = nxt_conf_json_parse_number(mp, value, start, end, error); - - if (nxt_slow_path(p == NULL)) { - return NULL; - } - - if (p == end) { - return end; - } - - switch (*p) { - case ' ': - case '\t': - case '\r': - case '\n': - case ',': - case '}': - case ']': - case '{': - case '[': - case '"': - case '/': - return p; - } - } - -error: - - nxt_conf_json_parse_error(error, start, - "A valid JSON value is expected here. It must be either a literal " - "(null, true, or false), a number, a string (in double quotes \"\"), " - "an array (with brackets []), or an object (with braces {})." - ); - - return NULL; -} - - -static const nxt_lvlhsh_proto_t nxt_conf_object_hash_proto - nxt_aligned(64) = -{ - NXT_LVLHSH_DEFAULT, - nxt_conf_object_hash_test, - nxt_conf_object_hash_alloc, - nxt_conf_object_hash_free, -}; - - -static u_char * -nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, - u_char *end, nxt_conf_json_error_t *error) -{ - u_char *p, *name; - nxt_mp_t *mp_temp; - nxt_int_t rc; - nxt_uint_t count; - nxt_lvlhsh_t hash; - nxt_lvlhsh_each_t lhe; - nxt_conf_object_t *object; - nxt_conf_object_member_t *member, *element; - - mp_temp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp_temp == NULL)) { - return NULL; - } - - nxt_lvlhsh_init(&hash); - - count = 0; - p = start; - - for ( ;; ) { - p = nxt_conf_json_skip_space(p + 1, end); - - if (nxt_slow_path(p == end)) { - - nxt_conf_json_parse_error(error, p, - "Unexpected end of JSON payload. There's an object without " - "a closing brace (})." - ); - - goto error; - } - - if (*p != '"') { - if (nxt_fast_path(*p == '}')) { - break; - } - - nxt_conf_json_parse_error(error, p, - "A double quote (\") is expected here. There must be a valid " - "JSON object member starts with a name, which is a string " - "enclosed in double quotes." - ); - - goto error; - } - - name = p; - - count++; - - member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t)); - if (nxt_slow_path(member == NULL)) { - goto error; - } - - p = nxt_conf_json_parse_string(mp, &member->name, p, end, error); - - if (nxt_slow_path(p == NULL)) { - goto error; - } - - rc = nxt_conf_object_hash_add(mp_temp, &hash, member); - - if (nxt_slow_path(rc != NXT_OK)) { - - if (rc == NXT_DECLINED) { - nxt_conf_json_parse_error(error, name, - "Duplicate object member. All JSON object members must " - "have unique names." - ); - } - - goto error; - } - - p = nxt_conf_json_skip_space(p, end); - - if (nxt_slow_path(p == end)) { - - nxt_conf_json_parse_error(error, p, - "Unexpected end of JSON payload. There's an object member " - "without a value." - ); - - goto error; - } - - if (nxt_slow_path(*p != ':')) { - - nxt_conf_json_parse_error(error, p, - "A colon (:) is expected here. There must be a colon after " - "a JSON member name." - ); - - goto error; - } - - p = nxt_conf_json_skip_space(p + 1, end); - - if (nxt_slow_path(p == end)) { - - nxt_conf_json_parse_error(error, p, - "Unexpected end of JSON payload. There's an object member " - "without a value." - ); - - goto error; - } - - p = nxt_conf_json_parse_value(mp, &member->value, p, end, error); - - if (nxt_slow_path(p == NULL)) { - goto error; - } - - p = nxt_conf_json_skip_space(p, end); - - if (nxt_slow_path(p == end)) { - - nxt_conf_json_parse_error(error, p, - "Unexpected end of JSON payload. There's an object without " - "a closing brace (})." - ); - - goto error; - } - - if (*p != ',') { - if (nxt_fast_path(*p == '}')) { - break; - } - - nxt_conf_json_parse_error(error, p, - "Either a closing brace (}) or a comma (,) is expected here. " - "Each JSON object must be enclosed in braces and its members " - "must be separated by commas." - ); - - goto error; - } - } - - object = nxt_mp_get(mp, sizeof(nxt_conf_object_t) - + count * sizeof(nxt_conf_object_member_t)); - if (nxt_slow_path(object == NULL)) { - goto error; - } - - value->u.object = object; - value->type = NXT_CONF_VALUE_OBJECT; - - object->count = count; - member = object->members; - - nxt_lvlhsh_each_init(&lhe, &nxt_conf_object_hash_proto); - - for ( ;; ) { - element = nxt_lvlhsh_each(&hash, &lhe); - - if (element == NULL) { - break; - } - - *member++ = *element; - } - - nxt_mp_destroy(mp_temp); - - return p + 1; - -error: - - nxt_mp_destroy(mp_temp); - return NULL; -} - - -static nxt_int_t -nxt_conf_object_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *lvlhsh, - nxt_conf_object_member_t *member) -{ - nxt_lvlhsh_query_t lhq; - - nxt_conf_get_string(&member->name, &lhq.key); - - lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); - lhq.replace = 0; - lhq.value = member; - lhq.proto = &nxt_conf_object_hash_proto; - lhq.pool = mp; - - return nxt_lvlhsh_insert(lvlhsh, &lhq); -} - - -static nxt_int_t -nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_str_t str; - nxt_conf_object_member_t *member; - - member = data; - - nxt_conf_get_string(&member->name, &str); - - return nxt_strstr_eq(&lhq->key, &str) ? NXT_OK : NXT_DECLINED; -} - - -static void * -nxt_conf_object_hash_alloc(void *data, size_t size) -{ - return nxt_mp_align(data, size, size); -} - - -static void -nxt_conf_object_hash_free(void *data, void *p) -{ - nxt_mp_free(data, p); -} - - -static u_char * -nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, - u_char *end, nxt_conf_json_error_t *error) -{ - u_char *p; - nxt_mp_t *mp_temp; - nxt_uint_t count; - nxt_list_t *list; - nxt_conf_array_t *array; - nxt_conf_value_t *element; - - mp_temp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp_temp == NULL)) { - return NULL; - } - - list = nxt_list_create(mp_temp, 8, sizeof(nxt_conf_value_t)); - if (nxt_slow_path(list == NULL)) { - goto error; - } - - count = 0; - p = start; - - for ( ;; ) { - p = nxt_conf_json_skip_space(p + 1, end); - - if (nxt_slow_path(p == end)) { - - nxt_conf_json_parse_error(error, p, - "Unexpected end of JSON payload. There's an array without " - "a closing bracket (])." - ); - - goto error; - } - - if (*p == ']') { - break; - } - - count++; - - element = nxt_list_add(list); - if (nxt_slow_path(element == NULL)) { - goto error; - } - - p = nxt_conf_json_parse_value(mp, element, p, end, error); - - if (nxt_slow_path(p == NULL)) { - goto error; - } - - p = nxt_conf_json_skip_space(p, end); - - if (nxt_slow_path(p == end)) { - - nxt_conf_json_parse_error(error, p, - "Unexpected end of JSON payload. There's an array without " - "a closing bracket (])." - ); - - goto error; - } - - if (*p != ',') { - if (nxt_fast_path(*p == ']')) { - break; - } - - nxt_conf_json_parse_error(error, p, - "Either a closing bracket (]) or a comma (,) is expected " - "here. Each array must be enclosed in brackets and its " - "members must be separated by commas." - ); - - goto error; - } - } - - array = nxt_mp_get(mp, sizeof(nxt_conf_array_t) - + count * sizeof(nxt_conf_value_t)); - if (nxt_slow_path(array == NULL)) { - goto error; - } - - value->u.array = array; - value->type = NXT_CONF_VALUE_ARRAY; - - array->count = count; - element = array->elements; - - nxt_list_each(value, list) { - *element++ = *value; - } nxt_list_loop; - - nxt_mp_destroy(mp_temp); - - return p + 1; - -error: - - nxt_mp_destroy(mp_temp); - return NULL; -} - - -static u_char * -nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, - u_char *end, nxt_conf_json_error_t *error) -{ - u_char *p, ch, *last, *s; - size_t size, surplus; - uint32_t utf, utf_high; - nxt_uint_t i; - enum { - sw_usual = 0, - sw_escape, - sw_encoded1, - sw_encoded2, - sw_encoded3, - sw_encoded4, - } state; - - start++; - - state = 0; - surplus = 0; - - for (p = start; nxt_fast_path(p != end); p++) { - ch = *p; - - switch (state) { - - case sw_usual: - - if (ch == '"') { - break; - } - - if (ch == '\\') { - state = sw_escape; - continue; - } - - if (nxt_fast_path(ch >= ' ')) { - continue; - } - - nxt_conf_json_parse_error(error, p, - "Unexpected character. All control characters in a JSON " - "string must be escaped." - ); - - return NULL; - - case sw_escape: - - switch (ch) { - case '"': - case '\\': - case '/': - case 'n': - case 'r': - case 't': - case 'b': - case 'f': - surplus++; - state = sw_usual; - continue; - - case 'u': - /* - * Basic unicode 6 bytes "\uXXXX" in JSON - * and up to 3 bytes in UTF-8. - * - * Surrogate pair: 12 bytes "\uXXXX\uXXXX" in JSON - * and 3 or 4 bytes in UTF-8. - */ - surplus += 3; - state = sw_encoded1; - continue; - } - - nxt_conf_json_parse_error(error, p - 1, - "Unexpected backslash. A literal backslash in a JSON string " - "must be escaped with a second backslash (\\\\)." - ); - - return NULL; - - case sw_encoded1: - case sw_encoded2: - case sw_encoded3: - case sw_encoded4: - - if (nxt_fast_path((ch >= '0' && ch <= '9') - || (ch >= 'A' && ch <= 'F') - || (ch >= 'a' && ch <= 'f'))) - { - state = (state == sw_encoded4) ? sw_usual : state + 1; - continue; - } - - nxt_conf_json_parse_error(error, p, - "Invalid escape sequence. An escape sequence in a JSON " - "string must start with a backslash, followed by the lowercase " - "letter u, followed by four hexadecimal digits (\\uXXXX)." - ); - - return NULL; - } - - break; - } - - if (nxt_slow_path(p == end)) { - - nxt_conf_json_parse_error(error, p, - "Unexpected end of JSON payload. There's a string without " - "a final double quote (\")." - ); - - return NULL; - } - - /* Points to the ending quote mark. */ - last = p; - - size = last - start - surplus; - - if (size > NXT_CONF_MAX_SHORT_STRING) { - - if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) { - - nxt_conf_json_parse_error(error, start, - "The string is too long. Such a long JSON string value " - "is not supported." - ); - - return NULL; - } - - value->type = NXT_CONF_VALUE_STRING; - - value->u.string.start = nxt_mp_nget(mp, size); - if (nxt_slow_path(value->u.string.start == NULL)) { - return NULL; - } - - value->u.string.length = size; - - s = value->u.string.start; - - } else { - value->type = NXT_CONF_VALUE_SHORT_STRING; - value->u.str.length = size; - - s = value->u.str.start; - } - - if (surplus == 0) { - nxt_memcpy(s, start, size); - return last + 1; - } - - p = start; - - do { - ch = *p++; - - if (ch != '\\') { - *s++ = ch; - continue; - } - - ch = *p++; - - switch (ch) { - case '"': - case '\\': - case '/': - *s++ = ch; - continue; - - case 'n': - *s++ = '\n'; - continue; - - case 'r': - *s++ = '\r'; - continue; - - case 't': - *s++ = '\t'; - continue; - - case 'b': - *s++ = '\b'; - continue; - - case 'f': - *s++ = '\f'; - continue; - } - - utf = 0; - utf_high = 0; - - for ( ;; ) { - for (i = 0; i < 4; i++) { - utf = (utf << 4) | (p[i] >= 'A' ? 10 + ((p[i] & ~0x20) - 'A') - : p[i] - '0'); - } - - p += 4; - - if (utf_high != 0) { - if (nxt_slow_path(utf < 0xDC00 || utf > 0xDFFF)) { - - nxt_conf_json_parse_error(error, p - 12, - "Invalid JSON encoding sequence. This 12-byte " - "sequence composes an illegal UTF-16 surrogate pair." - ); - - return NULL; - } - - utf = ((utf_high - 0xD800) << 10) + (utf - 0xDC00) + 0x10000; - - break; - } - - if (utf < 0xD800 || utf > 0xDFFF) { - break; - } - - if (utf > 0xDBFF || p[0] != '\\' || p[1] != 'u') { - - nxt_conf_json_parse_error(error, p - 6, - "Invalid JSON encoding sequence. This 6-byte sequence " - "does not represent a valid UTF character." - ); - - return NULL; - } - - p += 2; - - utf_high = utf; - utf = 0; - } - - s = nxt_utf8_encode(s, utf); - - } while (p != last); - - if (size > NXT_CONF_MAX_SHORT_STRING) { - value->u.string.length = s - value->u.string.start; - - } else { - value->u.str.length = s - value->u.str.start; - } - - return last + 1; -} - - -static u_char * -nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, - u_char *end, nxt_conf_json_error_t *error) -{ - u_char *p, *s, ch, c, *dot_pos; - size_t size; - double num; - - s = start; - ch = *s; - - if (ch == '-') { - s++; - } - - dot_pos = NULL; - - for (p = s; nxt_fast_path(p != end); p++) { - ch = *p; - - /* Values below '0' become >= 208. */ - c = ch - '0'; - - if (c > 9) { - if (ch == '.' && nxt_fast_path(dot_pos == NULL)) { - dot_pos = p; - continue; - } - - break; - } - } - - if (dot_pos != NULL) { - if (nxt_slow_path(p - dot_pos <= 1)) { - nxt_conf_json_parse_error(error, s, - "The number is invalid. A fraction part in JSON numbers " - "must contain at least one digit." - ); - - return NULL; - } - - } else { - dot_pos = p; - } - - if (nxt_slow_path(dot_pos - s > 1 && *start == '0')) { - nxt_conf_json_parse_error(error, s, - "The number is invalid. Leading zeros are not allowed in JSON " - "numbers." - ); - - return NULL; - } - - if (ch == 'e' || ch == 'E') { - p++; - s = p; - - if (nxt_fast_path(s != end)) { - ch = *s; - - if (ch == '-' || ch == '+') { - s++; - } - - for (p = s; nxt_fast_path(p != end); p++) { - ch = *p; - - /* Values below '0' become >= 208. */ - c = ch - '0'; - - if (c > 9) { - break; - } - } - } - - if (nxt_slow_path(p == s)) { - nxt_conf_json_parse_error(error, start, - "The number is invalid. An exponent part in JSON numbers " - "must contain at least one digit." - ); - - return NULL; - } - } - - size = p - start; - - if (size > NXT_CONF_MAX_NUMBER_LEN) { - nxt_conf_json_parse_error(error, start, - "The number is too long. Such a long JSON number value " - "is not supported." - ); - - return NULL; - } - - nxt_memcpy(value->u.number, start, size); - value->u.number[size] = '\0'; - - nxt_errno = 0; - end = NULL; - - num = nxt_strtod(value->u.number, &end); - - if (nxt_slow_path(nxt_errno == NXT_ERANGE - || fabs(num) > (double) NXT_INT64_T_MAX)) - { - nxt_conf_json_parse_error(error, start, - "The number is out of representable range. Such JSON number " - "value is not supported." - ); - - return NULL; - } - - if (nxt_slow_path(end == NULL || *end != '\0')) { - nxt_thread_log_alert("strtod(\"%s\", %s) failed %E", value->u.number, - end == NULL ? (u_char *) "NULL" : end, nxt_errno); - return NULL; - } - - value->type = (num == trunc(num)) ? NXT_CONF_VALUE_INTEGER - : NXT_CONF_VALUE_NUMBER; - - return p; -} - - -static void -nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos, - const char *detail) -{ - if (error == NULL) { - return; - } - - error->pos = pos; - error->detail = (u_char *) detail; -} - - -size_t -nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty) -{ - switch (value->type) { - - case NXT_CONF_VALUE_NULL: - return nxt_length("null"); - - case NXT_CONF_VALUE_BOOLEAN: - return value->u.boolean ? nxt_length("true") : nxt_length("false"); - - case NXT_CONF_VALUE_INTEGER: - case NXT_CONF_VALUE_NUMBER: - return nxt_strlen(value->u.number); - - case NXT_CONF_VALUE_SHORT_STRING: - case NXT_CONF_VALUE_STRING: - return nxt_conf_json_string_length(value); - - case NXT_CONF_VALUE_ARRAY: - return nxt_conf_json_array_length(value, pretty); - - case NXT_CONF_VALUE_OBJECT: - return nxt_conf_json_object_length(value, pretty); - } - - nxt_unreachable(); - - return 0; -} - - -u_char * -nxt_conf_json_print(u_char *p, nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty) -{ - switch (value->type) { - - case NXT_CONF_VALUE_NULL: - return nxt_cpymem(p, "null", 4); - - case NXT_CONF_VALUE_BOOLEAN: - return value->u.boolean ? nxt_cpymem(p, "true", 4) - : nxt_cpymem(p, "false", 5); - - case NXT_CONF_VALUE_INTEGER: - case NXT_CONF_VALUE_NUMBER: - return nxt_cpystr(p, value->u.number); - - case NXT_CONF_VALUE_SHORT_STRING: - case NXT_CONF_VALUE_STRING: - return nxt_conf_json_print_string(p, value); - - case NXT_CONF_VALUE_ARRAY: - return nxt_conf_json_print_array(p, value, pretty); - - case NXT_CONF_VALUE_OBJECT: - return nxt_conf_json_print_object(p, value, pretty); - } - - nxt_unreachable(); - - return p; -} - - -static size_t -nxt_conf_json_string_length(nxt_conf_value_t *value) -{ - nxt_str_t str; - - nxt_conf_get_string(value, &str); - - return 2 + nxt_conf_json_escape_length(str.start, str.length); -} - - -static u_char * -nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value) -{ - nxt_str_t str; - - nxt_conf_get_string(value, &str); - - *p++ = '"'; - - p = nxt_conf_json_escape(p, str.start, str.length); - - *p++ = '"'; - - return p; -} - - -static size_t -nxt_conf_json_array_length(nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty) -{ - size_t len; - nxt_uint_t n; - nxt_conf_array_t *array; - - array = value->u.array; - - /* [] */ - len = 2; - - if (pretty != NULL) { - pretty->level++; - } - - value = array->elements; - - for (n = 0; n < array->count; n++) { - len += nxt_conf_json_length(&value[n], pretty); - - if (pretty != NULL) { - /* Indentation and new line. */ - len += pretty->level + 2; - } - } - - if (pretty != NULL) { - pretty->level--; - - if (n != 0) { - /* Indentation and new line. */ - len += pretty->level + 2; - } - } - - /* Reserve space for "n" commas. */ - return len + n; -} - - -static u_char * -nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty) -{ - nxt_uint_t n; - nxt_conf_array_t *array; - - array = value->u.array; - - *p++ = '['; - - if (array->count != 0) { - value = array->elements; - - if (pretty != NULL) { - p = nxt_conf_json_newline(p); - - pretty->level++; - p = nxt_conf_json_indentation(p, pretty->level); - } - - p = nxt_conf_json_print(p, &value[0], pretty); - - for (n = 1; n < array->count; n++) { - *p++ = ','; - - if (pretty != NULL) { - p = nxt_conf_json_newline(p); - p = nxt_conf_json_indentation(p, pretty->level); - - pretty->more_space = 0; - } - - p = nxt_conf_json_print(p, &value[n], pretty); - } - - if (pretty != NULL) { - p = nxt_conf_json_newline(p); - - pretty->level--; - p = nxt_conf_json_indentation(p, pretty->level); - - pretty->more_space = 1; - } - } - - *p++ = ']'; - - return p; -} - - -static size_t -nxt_conf_json_object_length(nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty) -{ - size_t len; - nxt_uint_t n; - nxt_conf_object_t *object; - nxt_conf_object_member_t *member; - - object = value->u.object; - - /* {} */ - len = 2; - - if (pretty != NULL) { - pretty->level++; - } - - member = object->members; - - for (n = 0; n < object->count; n++) { - len += nxt_conf_json_string_length(&member[n].name) + 1 - + nxt_conf_json_length(&member[n].value, pretty) + 1; - - if (pretty != NULL) { - /* - * Indentation, space after ":", new line, and possible - * additional empty line between non-empty objects. - */ - len += pretty->level + 1 + 2 + 2; - } - } - - if (pretty != NULL) { - pretty->level--; - - /* Indentation and new line. */ - len += pretty->level + 2; - } - - return len; -} - - -static u_char * -nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty) -{ - nxt_uint_t n; - nxt_conf_object_t *object; - nxt_conf_object_member_t *member; - - object = value->u.object; - - *p++ = '{'; - - if (object->count != 0) { - - if (pretty != NULL) { - p = nxt_conf_json_newline(p); - pretty->level++; - } - - member = object->members; - - n = 0; - - for ( ;; ) { - if (pretty != NULL) { - p = nxt_conf_json_indentation(p, pretty->level); - } - - p = nxt_conf_json_print_string(p, &member[n].name); - - *p++ = ':'; - - if (pretty != NULL) { - *p++ = ' '; - } - - p = nxt_conf_json_print(p, &member[n].value, pretty); - - n++; - - if (n == object->count) { - break; - } - - *p++ = ','; - - if (pretty != NULL) { - p = nxt_conf_json_newline(p); - - if (pretty->more_space) { - pretty->more_space = 0; - p = nxt_conf_json_newline(p); - } - } - } - - if (pretty != NULL) { - p = nxt_conf_json_newline(p); - - pretty->level--; - p = nxt_conf_json_indentation(p, pretty->level); - - pretty->more_space = 1; - } - } - - *p++ = '}'; - - return p; -} - - -static size_t -nxt_conf_json_escape_length(u_char *p, size_t size) -{ - u_char ch; - size_t len; - - len = size; - - while (size) { - ch = *p++; - - if (ch == '\\' || ch == '"') { - len++; - - } else if (ch <= 0x1F) { - - switch (ch) { - case '\n': - case '\r': - case '\t': - case '\b': - case '\f': - len++; - break; - - default: - len += sizeof("\\u001F") - 2; - } - } - - size--; - } - - return len; -} - - -static u_char * -nxt_conf_json_escape(u_char *dst, u_char *src, size_t size) -{ - u_char ch; - - while (size) { - ch = *src++; - - if (ch > 0x1F) { - - if (ch == '\\' || ch == '"') { - *dst++ = '\\'; - } - - *dst++ = ch; - - } else { - *dst++ = '\\'; - - switch (ch) { - case '\n': - *dst++ = 'n'; - break; - - case '\r': - *dst++ = 'r'; - break; - - case '\t': - *dst++ = 't'; - break; - - case '\b': - *dst++ = 'b'; - break; - - case '\f': - *dst++ = 'f'; - break; - - default: - *dst++ = 'u'; *dst++ = '0'; *dst++ = '0'; - *dst++ = '0' + (ch >> 4); - - ch &= 0xF; - - *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10); - } - } - - size--; - } - - return dst; -} - - -void -nxt_conf_json_position(u_char *start, const u_char *pos, nxt_uint_t *line, - nxt_uint_t *column) -{ - u_char *p; - ssize_t symbols; - nxt_uint_t lines; - - lines = 1; - - for (p = start; p != pos; p++) { - - if (*p != '\n') { - continue; - } - - lines++; - start = p + 1; - } - - symbols = nxt_utf8_length(start, p - start); - - if (symbols != -1) { - *line = lines; - *column = 1 + symbols; - } -} diff --git a/src/nxt_conf.h b/src/nxt_conf.h deleted file mode 100644 index 626b6d4d..00000000 --- a/src/nxt_conf.h +++ /dev/null @@ -1,156 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - * Copyright 2024, Alejandro Colomar - */ - -#ifndef _NXT_CONF_INCLUDED_ -#define _NXT_CONF_INCLUDED_ - - -typedef enum { - NXT_CONF_NULL = 0, - NXT_CONF_BOOLEAN, - NXT_CONF_INTEGER, - NXT_CONF_NUMBER, - NXT_CONF_STRING, - NXT_CONF_ARRAY, - NXT_CONF_OBJECT, -} nxt_conf_type_t; - - -typedef enum { - NXT_CONF_OP_OK = 0, - NXT_CONF_OP_NOT_FOUND, - NXT_CONF_OP_NOT_ALLOWED, - NXT_CONF_OP_ERROR, -} nxt_conf_op_ret_t; - - -typedef struct nxt_conf_value_s nxt_conf_value_t; -typedef struct nxt_conf_op_s nxt_conf_op_t; - - -typedef struct { - u_char *pos; - u_char *detail; -} nxt_conf_json_error_t; - - -typedef enum { - NXT_CONF_MAP_INT8, - NXT_CONF_MAP_INT32, - NXT_CONF_MAP_INT64, - NXT_CONF_MAP_INT, - NXT_CONF_MAP_SIZE, - NXT_CONF_MAP_OFF, - NXT_CONF_MAP_MSEC, - NXT_CONF_MAP_DOUBLE, - NXT_CONF_MAP_STR, - NXT_CONF_MAP_STR_COPY, - NXT_CONF_MAP_CSTRZ, - NXT_CONF_MAP_PTR, -} nxt_conf_map_type_t; - - -typedef struct { - nxt_str_t name; - nxt_conf_map_type_t type; - size_t offset; -} nxt_conf_map_t; - - -typedef struct { - uint32_t level; - uint8_t more_space; /* 1 bit. */ -} nxt_conf_json_pretty_t; - - -typedef struct { - nxt_conf_value_t *conf; - nxt_mp_t *pool; - nxt_str_t error; - void *ctx; - nxt_tstr_state_t *tstr_state; - nxt_mp_t *conf_pool; - nxt_uint_t ver; -} nxt_conf_validation_t; - - -NXT_EXPORT nxt_uint_t nxt_conf_type(nxt_conf_value_t *value); - -NXT_EXPORT nxt_conf_value_t *nxt_conf_get_path(nxt_conf_value_t *value, - nxt_str_t *path); -NXT_EXPORT nxt_conf_value_t *nxt_conf_get_object_member(nxt_conf_value_t *value, - nxt_str_t *name, uint32_t *index); -NXT_EXPORT nxt_conf_value_t *nxt_conf_next_object_member( - nxt_conf_value_t *value, nxt_str_t *name, uint32_t *next); -NXT_EXPORT nxt_conf_value_t *nxt_conf_get_array_element(nxt_conf_value_t *value, - uint32_t index); -NXT_EXPORT nxt_conf_value_t *nxt_conf_get_array_element_or_itself( - nxt_conf_value_t *value, uint32_t index); - -NXT_EXPORT nxt_int_t nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, - nxt_conf_map_t *map, nxt_uint_t n, void *data); - -nxt_conf_op_ret_t nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, - nxt_conf_value_t *root, nxt_str_t *path, nxt_conf_value_t *value, - nxt_bool_t add); -nxt_conf_value_t *nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, - nxt_conf_value_t *value); - -nxt_conf_value_t *nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end, - nxt_conf_json_error_t *error); - -#define nxt_conf_json_parse_str(mp, str) \ - nxt_conf_json_parse(mp, (str)->start, (str)->start + (str)->length, NULL) - -size_t nxt_conf_json_length(nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty); -u_char *nxt_conf_json_print(u_char *p, nxt_conf_value_t *value, - nxt_conf_json_pretty_t *pretty); -void nxt_conf_json_position(u_char *start, const u_char *pos, nxt_uint_t *line, - nxt_uint_t *column); - -nxt_int_t nxt_conf_validate(nxt_conf_validation_t *vldt); - -NXT_EXPORT void nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str); -NXT_EXPORT nxt_str_t *nxt_conf_get_string_dup(nxt_conf_value_t *value, - nxt_mp_t *mp, nxt_str_t *str); -NXT_EXPORT void nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str); -NXT_EXPORT nxt_int_t nxt_conf_set_string_dup(nxt_conf_value_t *value, - nxt_mp_t *mp, const nxt_str_t *str); -NXT_EXPORT double nxt_conf_get_number(nxt_conf_value_t *value); -NXT_EXPORT uint8_t nxt_conf_get_boolean(nxt_conf_value_t *value); - -// FIXME reimplement and reorder functions below -NXT_EXPORT nxt_uint_t nxt_conf_object_members_count(nxt_conf_value_t *value); -nxt_conf_value_t *nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count); -void nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name, - const nxt_conf_value_t *value, uint32_t index); -nxt_int_t nxt_conf_set_member_dup(nxt_conf_value_t *object, nxt_mp_t *mp, - nxt_str_t *name, nxt_conf_value_t *value, uint32_t index); -void nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name, - nxt_str_t *value, uint32_t index); -nxt_int_t nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp, - nxt_str_t *name, nxt_str_t *value, uint32_t index); -void nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name, - int64_t value, uint32_t index); -void nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name, - uint32_t index); - -nxt_conf_value_t *nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count); -void nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index, - const nxt_conf_value_t *value); -nxt_int_t nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp, - nxt_uint_t index, nxt_str_t *value); -NXT_EXPORT nxt_uint_t nxt_conf_array_elements_count(nxt_conf_value_t *value); -NXT_EXPORT nxt_uint_t nxt_conf_array_elements_count_or_1( - nxt_conf_value_t *value); -void nxt_conf_array_qsort(nxt_conf_value_t *value, - int (*compare)(const void *, const void *)); - - -#endif /* _NXT_CONF_INCLUDED_ */ diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c deleted file mode 100644 index 2099f887..00000000 --- a/src/nxt_conf_validation.c +++ /dev/null @@ -1,3437 +0,0 @@ - -/* - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - * Copyright 2024, Alejandro Colomar - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -typedef enum { - NXT_CONF_VLDT_NULL = 1 << NXT_CONF_NULL, - NXT_CONF_VLDT_BOOLEAN = 1 << NXT_CONF_BOOLEAN, - NXT_CONF_VLDT_INTEGER = 1 << NXT_CONF_INTEGER, - NXT_CONF_VLDT_NUMBER = (1 << NXT_CONF_NUMBER) | NXT_CONF_VLDT_INTEGER, - NXT_CONF_VLDT_STRING = 1 << NXT_CONF_STRING, - NXT_CONF_VLDT_ARRAY = 1 << NXT_CONF_ARRAY, - NXT_CONF_VLDT_OBJECT = 1 << NXT_CONF_OBJECT, -} nxt_conf_vldt_type_t; - -#define NXT_CONF_VLDT_ANY_TYPE (NXT_CONF_VLDT_NULL \ - |NXT_CONF_VLDT_BOOLEAN \ - |NXT_CONF_VLDT_NUMBER \ - |NXT_CONF_VLDT_STRING \ - |NXT_CONF_VLDT_ARRAY \ - |NXT_CONF_VLDT_OBJECT) - - -typedef enum { - NXT_CONF_VLDT_REQUIRED = 1 << 0, - NXT_CONF_VLDT_TSTR = 1 << 1, -} nxt_conf_vldt_flags_t; - - -typedef nxt_int_t (*nxt_conf_vldt_handler_t)(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, - void *data); -typedef nxt_int_t (*nxt_conf_vldt_member_t)(nxt_conf_validation_t *vldt, - nxt_str_t *name, - nxt_conf_value_t *value); -typedef nxt_int_t (*nxt_conf_vldt_element_t)(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); - - -typedef struct nxt_conf_vldt_object_s nxt_conf_vldt_object_t; - -struct nxt_conf_vldt_object_s { - nxt_str_t name; - nxt_conf_vldt_type_t type:32; - nxt_conf_vldt_flags_t flags:32; - nxt_conf_vldt_handler_t validator; - - union { - nxt_conf_vldt_object_t *members; - nxt_conf_vldt_object_t *next; - nxt_conf_vldt_member_t object; - nxt_conf_vldt_element_t array; - const char *string; - } u; -}; - - -#define NXT_CONF_VLDT_NEXT(next) { .u.members = next } -#define NXT_CONF_VLDT_END { .name = nxt_null_string } - - -static nxt_int_t nxt_conf_vldt_type(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value, nxt_conf_vldt_type_t type); -static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt, - const char *fmt, ...); -static nxt_int_t nxt_conf_vldt_var(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_str_t *value); -static nxt_int_t nxt_conf_vldt_if(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -nxt_inline nxt_int_t nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) - NXT_MAYBE_UNUSED; - -static nxt_int_t nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value); -#if (NXT_TLS) -static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -#if (NXT_HAVE_OPENSSL_CONF_CMD) -static nxt_int_t nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -#endif -static nxt_int_t nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_tls_cache_size(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_tls_timeout(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -#if (NXT_HAVE_OPENSSL_TLSEXT) -static nxt_int_t nxt_conf_vldt_ticket_key(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_ticket_key_element(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -#endif -#endif -static nxt_int_t nxt_conf_vldt_action(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_return(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_share(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_share_element(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_python(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_python_prefix(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_threads(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_route(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets( - nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set( - nxt_conf_validation_t *vldt, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set_member( - nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_match_encoded_patterns( - nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_match_encoded_pattern( - nxt_conf_validation_t *vldt, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_match_patterns_set_member( - nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_response_header(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_object(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_targets_exclusive( - nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_targets(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_target(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_php(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_server(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_access_log(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); - -static nxt_int_t nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); - -#if (NXT_HAVE_CLONE_NEWUSER) -static nxt_int_t nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -static nxt_int_t nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -#endif - -#if (NXT_HAVE_CGROUP) -static nxt_int_t nxt_conf_vldt_cgroup_path(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -#endif - -#if (NXT_HAVE_NJS) -static nxt_int_t nxt_conf_vldt_js_module(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data); -static nxt_int_t nxt_conf_vldt_js_module_element(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value); -#endif - - -static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_http_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_websocket_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_static_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_forwarded_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_client_ip_members[]; -#if (NXT_TLS) -static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_session_members[]; -#endif -static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_python_target_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_php_common_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_php_options_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_php_target_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_access_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_app_limits_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_app_processes_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_app_isolation_members[]; -static nxt_conf_vldt_object_t nxt_conf_vldt_app_namespaces_members[]; -#if (NXT_HAVE_CGROUP) -static nxt_conf_vldt_object_t nxt_conf_vldt_app_cgroup_members[]; -#endif -#if (NXT_HAVE_ISOLATION_ROOTFS) -static nxt_conf_vldt_object_t nxt_conf_vldt_app_automount_members[]; -#endif -static nxt_conf_vldt_object_t nxt_conf_vldt_access_log_members[]; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_root_members[] = { - { - .name = nxt_string("settings"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_setting_members, - }, { - .name = nxt_string("listeners"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object_iterator, - .u.object = nxt_conf_vldt_listener, - }, { - .name = nxt_string("routes"), - .type = NXT_CONF_VLDT_ARRAY | NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_routes, - }, { - .name = nxt_string("applications"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object_iterator, - .u.object = nxt_conf_vldt_app, - }, { - .name = nxt_string("upstreams"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object_iterator, - .u.object = nxt_conf_vldt_upstream, - }, { - .name = nxt_string("access_log"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_access_log, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[] = { - { - .name = nxt_string("http"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_http_members, -#if (NXT_HAVE_NJS) - }, { - .name = nxt_string("js_module"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_js_module, -#endif - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_http_members[] = { - { - .name = nxt_string("header_read_timeout"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("body_read_timeout"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("send_timeout"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("idle_timeout"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("large_header_buffer_size"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("large_header_buffers"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("body_buffer_size"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("max_body_size"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("body_temp_path"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("discard_unsafe_fields"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, { - .name = nxt_string("websocket"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_websocket_members, - }, { - .name = nxt_string("static"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_static_members, - }, { - .name = nxt_string("log_route"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, { - .name = nxt_string("server_version"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_websocket_members[] = { - { - .name = nxt_string("read_timeout"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - - .name = nxt_string("keepalive_interval"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("max_frame_size"), - .type = NXT_CONF_VLDT_INTEGER, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_static_members[] = { - { - .name = nxt_string("mime_types"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_mtypes, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { - { - .name = nxt_string("pass"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_pass, - .flags = NXT_CONF_VLDT_TSTR, - }, { - .name = nxt_string("application"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_app_name, - }, { - .name = nxt_string("forwarded"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_forwarded, - }, { - .name = nxt_string("client_ip"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_client_ip_members - }, - -#if (NXT_TLS) - { - .name = nxt_string("tls"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_tls_members, - }, -#endif - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_forwarded_members[] = { - { - .name = nxt_string("client_ip"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("protocol"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("source"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_addrs, - .flags = NXT_CONF_VLDT_REQUIRED - }, { - .name = nxt_string("recursive"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_client_ip_members[] = { - { - .name = nxt_string("source"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_addrs, - .flags = NXT_CONF_VLDT_REQUIRED - }, { - .name = nxt_string("header"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED - }, { - .name = nxt_string("recursive"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, - - NXT_CONF_VLDT_END -}; - - -#if (NXT_TLS) - -static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = { - { - .name = nxt_string("certificate"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .flags = NXT_CONF_VLDT_REQUIRED, - .validator = nxt_conf_vldt_certificate, - }, { - .name = nxt_string("conf_commands"), - .type = NXT_CONF_VLDT_OBJECT, -#if (NXT_HAVE_OPENSSL_CONF_CMD) - .validator = nxt_conf_vldt_object_conf_commands, -#else - .validator = nxt_conf_vldt_unsupported, - .u.string = "conf_commands", -#endif - }, { - .name = nxt_string("session"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_session_members, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_session_members[] = { - { - .name = nxt_string("cache_size"), - .type = NXT_CONF_VLDT_INTEGER, - .validator = nxt_conf_vldt_tls_cache_size, - }, { - .name = nxt_string("timeout"), - .type = NXT_CONF_VLDT_INTEGER, - .validator = nxt_conf_vldt_tls_timeout, - }, { - .name = nxt_string("tickets"), - .type = NXT_CONF_VLDT_STRING - | NXT_CONF_VLDT_ARRAY - | NXT_CONF_VLDT_BOOLEAN, -#if (NXT_HAVE_OPENSSL_TLSEXT) - .validator = nxt_conf_vldt_ticket_key, -#else - .validator = nxt_conf_vldt_unsupported, - .u.string = "tickets", -#endif - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_int_t -nxt_conf_vldt_tls_cache_size(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - int64_t cache_size; - - cache_size = nxt_conf_get_number(value); - - if (cache_size < 0) { - return nxt_conf_vldt_error(vldt, "The \"cache_size\" number must not " - "be negative."); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_tls_timeout(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - int64_t timeout; - - timeout = nxt_conf_get_number(value); - - if (timeout <= 0) { - return nxt_conf_vldt_error(vldt, "The \"timeout\" number must be " - "greater than zero."); - } - - return NXT_OK; -} - -#endif - -#if (NXT_HAVE_OPENSSL_TLSEXT) - -static nxt_int_t -nxt_conf_vldt_ticket_key(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - if (nxt_conf_type(value) == NXT_CONF_BOOLEAN) { - return NXT_OK; - } - - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - return nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_ticket_key_element); - } - - /* NXT_CONF_STRING */ - - return nxt_conf_vldt_ticket_key_element(vldt, value); -} - - -static nxt_int_t -nxt_conf_vldt_ticket_key_element(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - ssize_t ret; - nxt_str_t key; - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"key\" array must " - "contain only string values."); - } - - nxt_conf_get_string(value, &key); - - ret = nxt_base64_decode(NULL, key.start, key.length); - if (ret == NXT_ERROR) { - return nxt_conf_vldt_error(vldt, "Invalid Base64 format for the ticket " - "key \"%V\".", &key); - } - - if (ret != 48 && ret != 80) { - return nxt_conf_vldt_error(vldt, "Invalid length %d of the ticket " - "key \"%V\". Must be 48 or 80 bytes.", - ret, &key); - } - - return NXT_OK; -} - -#endif - - -static nxt_conf_vldt_object_t nxt_conf_vldt_route_members[] = { - { - .name = nxt_string("match"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_match_members, - }, { - .name = nxt_string("action"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_action, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = { - { - .name = nxt_string("method"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_patterns, - .u.string = "method", - }, { - .name = nxt_string("scheme"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_match_scheme_pattern, - }, { - .name = nxt_string("host"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_patterns, - .u.string = "host", - }, { - .name = nxt_string("source"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_addrs, - }, { - .name = nxt_string("destination"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_addrs, - }, { - .name = nxt_string("uri"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_encoded_patterns, - .u.string = "uri" - }, { - .name = nxt_string("query"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_encoded_patterns, - .u.string = "query" - }, { - .name = nxt_string("arguments"), - .type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_encoded_patterns_sets, - }, { - .name = nxt_string("headers"), - .type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_patterns_sets, - .u.string = "headers" - }, { - .name = nxt_string("cookies"), - .type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_patterns_sets, - .u.string = "cookies" - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_action_common_members[] = { - { - .name = nxt_string("rewrite"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_TSTR, - }, - { - .name = nxt_string("response_headers"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object_iterator, - .u.object = nxt_conf_vldt_response_header, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_pass_action_members[] = { - { - .name = nxt_string("pass"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_pass, - .flags = NXT_CONF_VLDT_TSTR, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_return_action_members[] = { - { - .name = nxt_string("return"), - .type = NXT_CONF_VLDT_INTEGER, - .validator = nxt_conf_vldt_return, - }, { - .name = nxt_string("location"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_TSTR, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_share_action_members[] = { - { - .name = nxt_string("share"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_share, - }, { - .name = nxt_string("index"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("types"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_match_patterns, - }, { - .name = nxt_string("fallback"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_action, - }, { - .name = nxt_string("chroot"), - .type = NXT_CONF_VLDT_STRING, -#if !(NXT_HAVE_OPENAT2) - .validator = nxt_conf_vldt_unsupported, - .u.string = "chroot", -#endif - .flags = NXT_CONF_VLDT_TSTR, - }, { - .name = nxt_string("follow_symlinks"), - .type = NXT_CONF_VLDT_BOOLEAN, -#if !(NXT_HAVE_OPENAT2) - .validator = nxt_conf_vldt_unsupported, - .u.string = "follow_symlinks", -#endif - }, { - .name = nxt_string("traverse_mounts"), - .type = NXT_CONF_VLDT_BOOLEAN, -#if !(NXT_HAVE_OPENAT2) - .validator = nxt_conf_vldt_unsupported, - .u.string = "traverse_mounts", -#endif - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_proxy_action_members[] = { - { - .name = nxt_string("proxy"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_proxy, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_external_members[] = { - { - .name = nxt_string("executable"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("arguments"), - .type = NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_array_iterator, - .u.array = nxt_conf_vldt_argument, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_python_common_members[] = { - { - .name = nxt_string("home"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("path"), - .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_python_path, - }, { - .name = nxt_string("protocol"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_python_protocol, - }, { - .name = nxt_string("threads"), - .type = NXT_CONF_VLDT_INTEGER, - .validator = nxt_conf_vldt_threads, - }, { - .name = nxt_string("thread_stack_size"), - .type = NXT_CONF_VLDT_INTEGER, - .validator = nxt_conf_vldt_thread_stack_size, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) -}; - -static nxt_conf_vldt_object_t nxt_conf_vldt_python_members[] = { - { - .name = nxt_string("module"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_targets_exclusive, - .u.string = "module", - }, { - .name = nxt_string("callable"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_targets_exclusive, - .u.string = "callable", - }, { - .name = nxt_string("prefix"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_targets_exclusive, - .u.string = "prefix", - }, { - .name = nxt_string("targets"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_targets, - .u.members = nxt_conf_vldt_python_target_members - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_python_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_python_target_members[] = { - { - .name = nxt_string("module"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("callable"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("prefix"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_python_prefix, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_python_notargets_members[] = { - { - .name = nxt_string("module"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("callable"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("prefix"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_python_prefix, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_python_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_php_members[] = { - { - .name = nxt_string("root"), - .type = NXT_CONF_VLDT_ANY_TYPE, - .validator = nxt_conf_vldt_targets_exclusive, - .u.string = "root", - }, { - .name = nxt_string("script"), - .type = NXT_CONF_VLDT_ANY_TYPE, - .validator = nxt_conf_vldt_targets_exclusive, - .u.string = "script", - }, { - .name = nxt_string("index"), - .type = NXT_CONF_VLDT_ANY_TYPE, - .validator = nxt_conf_vldt_targets_exclusive, - .u.string = "index", - }, { - .name = nxt_string("targets"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_targets, - .u.members = nxt_conf_vldt_php_target_members - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_php_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_php_common_members[] = { - { - .name = nxt_string("options"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_php_options_members, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_php_options_members[] = { - { - .name = nxt_string("file"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("admin"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object_iterator, - .u.object = nxt_conf_vldt_php_option, - }, { - .name = nxt_string("user"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object_iterator, - .u.object = nxt_conf_vldt_php_option, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_php_target_members[] = { - { - .name = nxt_string("root"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("script"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("index"), - .type = NXT_CONF_VLDT_STRING, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_php_notargets_members[] = { - { - .name = nxt_string("root"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("script"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("index"), - .type = NXT_CONF_VLDT_STRING, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_php_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_perl_members[] = { - { - .name = nxt_string("script"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("threads"), - .type = NXT_CONF_VLDT_INTEGER, - .validator = nxt_conf_vldt_threads, - }, { - .name = nxt_string("thread_stack_size"), - .type = NXT_CONF_VLDT_INTEGER, - .validator = nxt_conf_vldt_thread_stack_size, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_ruby_members[] = { - { - .name = nxt_string("script"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("threads"), - .type = NXT_CONF_VLDT_INTEGER, - .validator = nxt_conf_vldt_threads, - }, { - .name = nxt_string("hooks"), - .type = NXT_CONF_VLDT_STRING - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_java_members[] = { - { - .name = nxt_string("classpath"), - .type = NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_array_iterator, - .u.array = nxt_conf_vldt_java_classpath, - }, { - .name = nxt_string("webapp"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("options"), - .type = NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_array_iterator, - .u.array = nxt_conf_vldt_java_option, - }, { - .name = nxt_string("unit_jars"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("threads"), - .type = NXT_CONF_VLDT_INTEGER, - .validator = nxt_conf_vldt_threads, - }, { - .name = nxt_string("thread_stack_size"), - .type = NXT_CONF_VLDT_INTEGER, - .validator = nxt_conf_vldt_thread_stack_size, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_members[] = { - { - .name = nxt_string("module"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("request_handler"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - },{ - .name = nxt_string("malloc_handler"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("free_handler"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("module_init_handler"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("module_end_handler"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("request_init_handler"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("request_end_handler"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("response_end_handler"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("access"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_wasm_access_members, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_wc_members[] = { - { - .name = nxt_string("component"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("access"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_wasm_access_members, - }, - - NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_access_members[] = { - { - .name = nxt_string("filesystem"), - .type = NXT_CONF_VLDT_ARRAY, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[] = { - { - .name = nxt_string("type"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("limits"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_app_limits_members, - }, { - .name = nxt_string("processes"), - .type = NXT_CONF_VLDT_INTEGER | NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_processes, - .u.members = nxt_conf_vldt_app_processes_members, - }, { - .name = nxt_string("user"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("group"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("working_directory"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("environment"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object_iterator, - .u.object = nxt_conf_vldt_environment, - }, { - .name = nxt_string("isolation"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_isolation, - .u.members = nxt_conf_vldt_app_isolation_members, - }, { - .name = nxt_string("stdout"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("stderr"), - .type = NXT_CONF_VLDT_STRING, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_app_limits_members[] = { - { - .name = nxt_string("timeout"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("requests"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("shm"), - .type = NXT_CONF_VLDT_INTEGER, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_app_processes_members[] = { - { - .name = nxt_string("spare"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("max"), - .type = NXT_CONF_VLDT_INTEGER, - }, { - .name = nxt_string("idle_timeout"), - .type = NXT_CONF_VLDT_INTEGER, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_app_isolation_members[] = { - { - .name = nxt_string("namespaces"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_clone_namespaces, - .u.members = nxt_conf_vldt_app_namespaces_members, - }, - -#if (NXT_HAVE_CLONE_NEWUSER) - { - .name = nxt_string("uidmap"), - .type = NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_array_iterator, - .u.array = nxt_conf_vldt_clone_uidmap, - }, { - .name = nxt_string("gidmap"), - .type = NXT_CONF_VLDT_ARRAY, - .validator = nxt_conf_vldt_array_iterator, - .u.array = nxt_conf_vldt_clone_gidmap, - }, -#endif - -#if (NXT_HAVE_ISOLATION_ROOTFS) - { - .name = nxt_string("rootfs"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("automount"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_app_automount_members, - }, -#endif - -#if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) - { - .name = nxt_string("new_privs"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, -#endif - -#if (NXT_HAVE_CGROUP) - { - .name = nxt_string("cgroup"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object, - .u.members = nxt_conf_vldt_app_cgroup_members, - }, -#endif - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_app_namespaces_members[] = { - -#if (NXT_HAVE_CLONE_NEWUSER) - { - .name = nxt_string("credential"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, -#endif - -#if (NXT_HAVE_CLONE_NEWPID) - { - .name = nxt_string("pid"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, -#endif - -#if (NXT_HAVE_CLONE_NEWNET) - { - .name = nxt_string("network"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, -#endif - -#if (NXT_HAVE_CLONE_NEWNS) - { - .name = nxt_string("mount"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, -#endif - -#if (NXT_HAVE_CLONE_NEWUTS) - { - .name = nxt_string("uname"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, -#endif - -#if (NXT_HAVE_CLONE_NEWCGROUP) - { - .name = nxt_string("cgroup"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, -#endif - - NXT_CONF_VLDT_END -}; - - -#if (NXT_HAVE_ISOLATION_ROOTFS) - -static nxt_conf_vldt_object_t nxt_conf_vldt_app_automount_members[] = { - { - .name = nxt_string("language_deps"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, { - .name = nxt_string("tmpfs"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, { - .name = nxt_string("procfs"), - .type = NXT_CONF_VLDT_BOOLEAN, - }, - - NXT_CONF_VLDT_END -}; - -#endif - - -#if (NXT_HAVE_CGROUP) - -static nxt_conf_vldt_object_t nxt_conf_vldt_app_cgroup_members[] = { - { - .name = nxt_string("path"), - .type = NXT_CONF_VLDT_STRING, - .flags = NXT_CONF_VLDT_REQUIRED, - .validator = nxt_conf_vldt_cgroup_path, - }, - - NXT_CONF_VLDT_END -}; - -#endif - - -#if (NXT_HAVE_CLONE_NEWUSER) - -static nxt_conf_vldt_object_t nxt_conf_vldt_app_procmap_members[] = { - { - .name = nxt_string("container"), - .type = NXT_CONF_VLDT_INTEGER, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("host"), - .type = NXT_CONF_VLDT_INTEGER, - .flags = NXT_CONF_VLDT_REQUIRED, - }, { - .name = nxt_string("size"), - .type = NXT_CONF_VLDT_INTEGER, - .flags = NXT_CONF_VLDT_REQUIRED, - }, - - NXT_CONF_VLDT_END -}; - -#endif - - -static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_members[] = { - { - .name = nxt_string("servers"), - .type = NXT_CONF_VLDT_OBJECT, - .validator = nxt_conf_vldt_object_iterator, - .u.object = nxt_conf_vldt_server, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_server_members[] = { - { - .name = nxt_string("weight"), - .type = NXT_CONF_VLDT_NUMBER, - .validator = nxt_conf_vldt_server_weight, - }, - - NXT_CONF_VLDT_END -}; - - -static nxt_conf_vldt_object_t nxt_conf_vldt_access_log_members[] = { - { - .name = nxt_string("path"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("format"), - .type = NXT_CONF_VLDT_STRING, - }, { - .name = nxt_string("if"), - .type = NXT_CONF_VLDT_STRING, - .validator = nxt_conf_vldt_if, - }, - - NXT_CONF_VLDT_END -}; - - -nxt_int_t -nxt_conf_validate(nxt_conf_validation_t *vldt) -{ - nxt_int_t ret; - u_char error[NXT_MAX_ERROR_STR]; - - vldt->tstr_state = nxt_tstr_state_new(vldt->pool, 1); - if (nxt_slow_path(vldt->tstr_state == NULL)) { - return NXT_ERROR; - } - - ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT); - if (ret != NXT_OK) { - return ret; - } - - ret = nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members); - if (ret != NXT_OK) { - return ret; - } - - ret = nxt_tstr_state_done(vldt->tstr_state, error); - if (ret != NXT_OK) { - ret = nxt_conf_vldt_error(vldt, "%s", error); - return ret; - } - - return NXT_OK; -} - - -#define NXT_CONF_VLDT_ANY_TYPE_STR \ - "either a null, a boolean, an integer, " \ - "a number, a string, an array, or an object" - - -static nxt_int_t -nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value, nxt_conf_vldt_type_t type) -{ - u_char *p; - nxt_str_t expected; - nxt_bool_t comma; - nxt_uint_t value_type, n, t; - u_char buf[nxt_length(NXT_CONF_VLDT_ANY_TYPE_STR)]; - - static nxt_str_t type_name[] = { - nxt_string("a null"), - nxt_string("a boolean"), - nxt_string("an integer number"), - nxt_string("a fractional number"), - nxt_string("a string"), - nxt_string("an array"), - nxt_string("an object"), - }; - - value_type = nxt_conf_type(value); - - if ((1 << value_type) & type) { - return NXT_OK; - } - - p = buf; - - n = nxt_popcount(type); - - if (n > 1) { - p = nxt_cpymem(p, "either ", 7); - } - - comma = (n > 2); - - for ( ;; ) { - t = __builtin_ffs(type) - 1; - - p = nxt_cpymem(p, type_name[t].start, type_name[t].length); - - n--; - - if (n == 0) { - break; - } - - if (comma) { - *p++ = ','; - } - - if (n == 1) { - p = nxt_cpymem(p, " or", 3); - } - - *p++ = ' '; - - type = type & ~(1 << t); - } - - expected.length = p - buf; - expected.start = buf; - - if (name == NULL) { - return nxt_conf_vldt_error(vldt, - "The configuration must be %V, but not %V.", - &expected, &type_name[value_type]); - } - - return nxt_conf_vldt_error(vldt, - "The \"%V\" value must be %V, but not %V.", - name, &expected, &type_name[value_type]); -} - - -static nxt_int_t -nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...) -{ - u_char *p, *end; - size_t size; - va_list args; - u_char error[NXT_MAX_ERROR_STR]; - - va_start(args, fmt); - end = nxt_vsprintf(error, error + NXT_MAX_ERROR_STR, fmt, args); - va_end(args); - - size = end - error; - - p = nxt_mp_nget(vldt->pool, size); - if (p == NULL) { - return NXT_ERROR; - } - - nxt_memcpy(p, error, size); - - vldt->error.length = size; - vldt->error.start = p; - - return NXT_DECLINED; -} - - -nxt_inline nxt_int_t -nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - return nxt_conf_vldt_error(vldt, "Unit is built without the \"%s\" " - "option support.", data); -} - - -static nxt_int_t -nxt_conf_vldt_var(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_str_t *value) -{ - u_char error[NXT_MAX_ERROR_STR]; - - if (nxt_tstr_test(vldt->tstr_state, value, error) != NXT_OK) { - return nxt_conf_vldt_error(vldt, "%s in the \"%V\" value.", - error, name); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_if(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_str_t str; - - static nxt_str_t if_str = nxt_string("if"); - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"if\" must be a string"); - } - - nxt_conf_get_string(value, &str); - - if (str.length == 0) { - return NXT_OK; - } - - if (str.start[0] == '!') { - str.start++; - str.length--; - } - - if (nxt_is_tstr(&str)) { - return nxt_conf_vldt_var(vldt, &if_str, &str); - } - - return NXT_OK; -} - - -typedef struct { - nxt_mp_t *pool; - nxt_str_t *type; - nxt_lvlhsh_t hash; -} nxt_conf_vldt_mtypes_ctx_t; - - -static nxt_int_t -nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_int_t ret; - nxt_conf_vldt_mtypes_ctx_t ctx; - - ctx.pool = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(ctx.pool == NULL)) { - return NXT_ERROR; - } - - nxt_lvlhsh_init(&ctx.hash); - - vldt->ctx = &ctx; - - ret = nxt_conf_vldt_object_iterator(vldt, value, - &nxt_conf_vldt_mtypes_type); - - vldt->ctx = NULL; - - nxt_mp_destroy(ctx.pool); - - return ret; -} - - -static nxt_int_t -nxt_conf_vldt_mtypes_type(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value) -{ - nxt_int_t ret; - nxt_conf_vldt_mtypes_ctx_t *ctx; - - ret = nxt_conf_vldt_type(vldt, name, value, - NXT_CONF_VLDT_STRING|NXT_CONF_VLDT_ARRAY); - if (ret != NXT_OK) { - return ret; - } - - ctx = vldt->ctx; - - ctx->type = nxt_mp_get(ctx->pool, sizeof(nxt_str_t)); - if (nxt_slow_path(ctx->type == NULL)) { - return NXT_ERROR; - } - - *ctx->type = *name; - - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - return nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_mtypes_extension); - } - - /* NXT_CONF_STRING */ - - return nxt_conf_vldt_mtypes_extension(vldt, value); -} - - -static nxt_int_t -nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - nxt_str_t exten, *dup_type; - nxt_conf_vldt_mtypes_ctx_t *ctx; - - ctx = vldt->ctx; - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"%V\" MIME type array must " - "contain only strings.", ctx->type); - } - - nxt_conf_get_string(value, &exten); - - if (exten.length == 0) { - return nxt_conf_vldt_error(vldt, "An empty file extension for " - "the \"%V\" MIME type.", ctx->type); - } - - dup_type = nxt_http_static_mtype_get(&ctx->hash, &exten); - - if (dup_type->length != 0) { - return nxt_conf_vldt_error(vldt, "The \"%V\" file extension has been " - "declared for \"%V\" and \"%V\" " - "MIME types at the same time.", - &exten, dup_type, ctx->type); - } - - return nxt_http_static_mtypes_hash_add(ctx->pool, &ctx->hash, &exten, - ctx->type); -} - - -static nxt_int_t -nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value) -{ - nxt_int_t ret; - nxt_str_t str; - nxt_sockaddr_t *sa; - - if (nxt_slow_path(nxt_str_dup(vldt->pool, &str, name) == NULL)) { - return NXT_ERROR; - } - - sa = nxt_sockaddr_parse(vldt->pool, &str); - if (nxt_slow_path(sa == NULL)) { - return nxt_conf_vldt_error(vldt, - "The listener address \"%V\" is invalid.", - name); - } - - ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); - if (ret != NXT_OK) { - return ret; - } - - return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members); -} - - -static nxt_int_t -nxt_conf_vldt_action(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_uint_t i; - nxt_conf_value_t *action; - nxt_conf_vldt_object_t *members; - - static struct { - nxt_str_t name; - nxt_conf_vldt_object_t *members; - - } actions[] = { - { nxt_string("pass"), nxt_conf_vldt_pass_action_members }, - { nxt_string("return"), nxt_conf_vldt_return_action_members }, - { nxt_string("share"), nxt_conf_vldt_share_action_members }, - { nxt_string("proxy"), nxt_conf_vldt_proxy_action_members }, - }; - - members = NULL; - - for (i = 0; i < nxt_nitems(actions); i++) { - action = nxt_conf_get_object_member(value, &actions[i].name, NULL); - - if (action == NULL) { - continue; - } - - if (members != NULL) { - return nxt_conf_vldt_error(vldt, "The \"action\" object must have " - "just one of \"pass\", \"return\", " - "\"share\", or \"proxy\" options set."); - } - - members = actions[i].members; - } - - if (members == NULL) { - return nxt_conf_vldt_error(vldt, "The \"action\" object must have " - "either \"pass\", \"return\", \"share\", " - "or \"proxy\" option set."); - } - - return nxt_conf_vldt_object(vldt, value, members); -} - - -static nxt_int_t -nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_str_t pass; - nxt_int_t ret; - nxt_str_t segments[3]; - - static nxt_str_t targets_str = nxt_string("targets"); - - nxt_conf_get_string(value, &pass); - - ret = nxt_http_pass_segments(vldt->pool, &pass, segments, 3); - - if (ret != NXT_OK) { - if (ret == NXT_DECLINED) { - return nxt_conf_vldt_error(vldt, "Request \"pass\" value \"%V\" " - "is invalid.", &pass); - } - - return NXT_ERROR; - } - - if (nxt_str_eq(&segments[0], "applications", 12)) { - - if (segments[1].length == 0) { - goto error; - } - - value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL); - - if (value == NULL) { - goto error; - } - - value = nxt_conf_get_object_member(value, &segments[1], NULL); - - if (value == NULL) { - goto error; - } - - if (segments[2].length > 0) { - value = nxt_conf_get_object_member(value, &targets_str, NULL); - - if (value == NULL) { - goto error; - } - - value = nxt_conf_get_object_member(value, &segments[2], NULL); - - if (value == NULL) { - goto error; - } - } - - return NXT_OK; - } - - if (nxt_str_eq(&segments[0], "upstreams", 9)) { - - if (segments[1].length == 0 || segments[2].length != 0) { - goto error; - } - - value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL); - - if (value == NULL) { - goto error; - } - - value = nxt_conf_get_object_member(value, &segments[1], NULL); - - if (value == NULL) { - goto error; - } - - return NXT_OK; - } - - if (nxt_str_eq(&segments[0], "routes", 6)) { - - if (segments[2].length != 0) { - goto error; - } - - value = nxt_conf_get_object_member(vldt->conf, &segments[0], NULL); - - if (value == NULL) { - goto error; - } - - if (segments[1].length == 0) { - if (nxt_conf_type(value) != NXT_CONF_ARRAY) { - goto error; - } - - return NXT_OK; - } - - if (nxt_conf_type(value) != NXT_CONF_OBJECT) { - goto error; - } - - value = nxt_conf_get_object_member(value, &segments[1], NULL); - - if (value == NULL) { - goto error; - } - - return NXT_OK; - } - -error: - - return nxt_conf_vldt_error(vldt, "Request \"pass\" points to invalid " - "location \"%V\".", &pass); -} - - -static nxt_int_t -nxt_conf_vldt_return(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - int64_t status; - - status = nxt_conf_get_number(value); - - if (status < NXT_HTTP_INVALID || status > NXT_HTTP_STATUS_MAX) { - return nxt_conf_vldt_error(vldt, "The \"return\" value is out of " - "allowed HTTP status code range 0-999."); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_share(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - if (nxt_conf_array_elements_count(value) == 0) { - return nxt_conf_vldt_error(vldt, "The \"share\" array " - "must contain at least one element."); - } - - return nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_share_element); - } - - /* NXT_CONF_STRING */ - - return nxt_conf_vldt_share_element(vldt, value); -} - - -static nxt_int_t -nxt_conf_vldt_share_element(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - nxt_str_t str; - - static nxt_str_t share = nxt_string("share"); - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"share\" array must " - "contain only string values."); - } - - nxt_conf_get_string(value, &str); - - if (nxt_is_tstr(&str)) { - return nxt_conf_vldt_var(vldt, &share, &str); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_str_t name, *ret; - nxt_sockaddr_t *sa; - - ret = nxt_conf_get_string_dup(value, vldt->pool, &name); - if (nxt_slow_path(ret == NULL)) { - return NXT_ERROR; - } - - if (nxt_str_start(&name, "http://", 7)) { - name.length -= 7; - name.start += 7; - - sa = nxt_sockaddr_parse(vldt->pool, &name); - if (sa != NULL) { - return NXT_OK; - } - } - - return nxt_conf_vldt_error(vldt, "The \"proxy\" address is invalid \"%V\"", - &name); -} - - -static nxt_int_t -nxt_conf_vldt_python(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_conf_value_t *targets; - - static nxt_str_t targets_str = nxt_string("targets"); - - targets = nxt_conf_get_object_member(value, &targets_str, NULL); - - if (targets != NULL) { - return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_python_members); - } - - return nxt_conf_vldt_object(vldt, value, - nxt_conf_vldt_python_notargets_members); -} - - -static nxt_int_t -nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - return nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_python_path_element); - } - - /* NXT_CONF_STRING */ - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"path\" array must contain " - "only string values."); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - nxt_str_t proto; - - static const nxt_str_t wsgi = nxt_string("wsgi"); - static const nxt_str_t asgi = nxt_string("asgi"); - - nxt_conf_get_string(value, &proto); - - if (nxt_strstr_eq(&proto, &wsgi) || nxt_strstr_eq(&proto, &asgi)) { - return NXT_OK; - } - - return nxt_conf_vldt_error(vldt, "The \"protocol\" can either be " - "\"wsgi\" or \"asgi\"."); -} - - -static nxt_int_t -nxt_conf_vldt_python_prefix(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - nxt_str_t prefix; - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"prefix\" must be a string " - "beginning with \"/\"."); - } - - nxt_conf_get_string(value, &prefix); - - if (!nxt_strchr_start(&prefix, '/')) { - return nxt_conf_vldt_error(vldt, "The \"prefix\" must be a string " - "beginning with \"/\"."); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_threads(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - int64_t threads; - - threads = nxt_conf_get_number(value); - - if (threads < 1) { - return nxt_conf_vldt_error(vldt, "The \"threads\" number must be " - "equal to or greater than 1."); - } - - if (threads > NXT_INT32_T_MAX) { - return nxt_conf_vldt_error(vldt, "The \"threads\" number must " - "not exceed %d.", NXT_INT32_T_MAX); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - int64_t size, min_size; - - size = nxt_conf_get_number(value); - min_size = sysconf(_SC_THREAD_STACK_MIN); - - if (size < min_size) { - return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number " - "must be equal to or greater than %d.", - min_size); - } - - if ((size % nxt_pagesize) != 0) { - return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number " - "must be a multiple of the system page size (%d).", - nxt_pagesize); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_routes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - return nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_route); - } - - /* NXT_CONF_OBJECT */ - - return nxt_conf_vldt_object_iterator(vldt, value, - &nxt_conf_vldt_routes_member); -} - - -static nxt_int_t -nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value) -{ - nxt_int_t ret; - - ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_ARRAY); - - if (ret != NXT_OK) { - return ret; - } - - return nxt_conf_vldt_array_iterator(vldt, value, &nxt_conf_vldt_route); -} - - -static nxt_int_t -nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) -{ - if (nxt_conf_type(value) != NXT_CONF_OBJECT) { - return nxt_conf_vldt_error(vldt, "The \"routes\" array must contain " - "only object values."); - } - - return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_route_members); -} - - -static nxt_int_t -nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - nxt_int_t ret; - - vldt->ctx = data; - - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - ret = nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_match_pattern); - - } else { - /* NXT_CONF_STRING */ - ret = nxt_conf_vldt_match_pattern(vldt, value); - } - - vldt->ctx = NULL; - - return ret; -} - - -static nxt_int_t -nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - nxt_str_t pattern; - nxt_uint_t i, first, last; -#if (NXT_HAVE_REGEX) - nxt_regex_t *re; - nxt_regex_err_t err; -#endif - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" " - "must be strings.", vldt->ctx); - } - - nxt_conf_get_string(value, &pattern); - - if (pattern.length == 0) { - return NXT_OK; - } - - first = (pattern.start[0] == '!'); - - if (first < pattern.length && pattern.start[first] == '~') { -#if (NXT_HAVE_REGEX) - pattern.start += first + 1; - pattern.length -= first + 1; - - re = nxt_regex_compile(vldt->pool, &pattern, &err); - if (nxt_slow_path(re == NULL)) { - if (err.offset < pattern.length) { - return nxt_conf_vldt_error(vldt, "Invalid regular expression: " - "%s at offset %d", - err.msg, err.offset); - } - - return nxt_conf_vldt_error(vldt, "Invalid regular expression: %s", - err.msg); - } - - return NXT_OK; -#else - return nxt_conf_vldt_error(vldt, "Unit is built without support of " - "regular expressions: \"--no-regex\" " - "./configure option was set."); -#endif - } - - last = pattern.length - 1; - - for (i = first; i < last; i++) { - if (pattern.start[i] == '*' && pattern.start[i + 1] == '*') { - return nxt_conf_vldt_error(vldt, "The \"match\" pattern must " - "not contain double \"*\" markers."); - } - } - - return NXT_OK; -} - - -static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets( - nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data) -{ - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - return nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_match_encoded_patterns_set); - } - - /* NXT_CONF_OBJECT */ - - return nxt_conf_vldt_match_encoded_patterns_set(vldt, value); -} - - -static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set( - nxt_conf_validation_t *vldt, nxt_conf_value_t *value) -{ - if (nxt_conf_type(value) != NXT_CONF_OBJECT) { - return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " - "\"arguments\" must be an object."); - } - - return nxt_conf_vldt_object_iterator(vldt, value, - &nxt_conf_vldt_match_encoded_patterns_set_member); -} - - -static nxt_int_t -nxt_conf_vldt_match_encoded_patterns_set_member(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value) -{ - u_char *p, *end; - - if (nxt_slow_path(name->length == 0)) { - return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must " - "not contain empty member names."); - } - - p = nxt_mp_nget(vldt->pool, name->length); - if (nxt_slow_path(p == NULL)) { - return NXT_ERROR; - } - - end = nxt_decode_uri(p, name->start, name->length); - if (nxt_slow_path(end == NULL)) { - return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " - "\"arguments\" is encoded but is invalid."); - } - - return nxt_conf_vldt_match_encoded_patterns(vldt, value, - (void *) "arguments"); -} - - -static nxt_int_t -nxt_conf_vldt_match_encoded_patterns(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - nxt_int_t ret; - - vldt->ctx = data; - - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - ret = nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_match_encoded_pattern); - - } else { - /* NXT_CONF_STRING */ - ret = nxt_conf_vldt_match_encoded_pattern(vldt, value); - } - - vldt->ctx = NULL; - - return ret; -} - - -static nxt_int_t -nxt_conf_vldt_match_encoded_pattern(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - u_char *p, *end; - nxt_int_t ret; - nxt_str_t pattern; - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" " - "must be a string.", vldt->ctx); - } - - ret = nxt_conf_vldt_match_pattern(vldt, value); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - nxt_conf_get_string(value, &pattern); - - p = nxt_mp_nget(vldt->pool, pattern.length); - if (nxt_slow_path(p == NULL)) { - return NXT_ERROR; - } - - end = nxt_decode_uri(p, pattern.start, pattern.length); - if (nxt_slow_path(end == NULL)) { - return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"%s\" " - "is encoded but is invalid.", vldt->ctx); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - return nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_match_addr); - } - - return nxt_conf_vldt_match_addr(vldt, value); -} - - -static nxt_int_t -nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - nxt_http_route_addr_pattern_t pattern; - - switch (nxt_http_route_addr_pattern_parse(vldt->pool, &pattern, value)) { - - case NXT_OK: - return NXT_OK; - - case NXT_ADDR_PATTERN_PORT_ERROR: - return nxt_conf_vldt_error(vldt, "The \"address\" port an invalid " - "port."); - - case NXT_ADDR_PATTERN_CV_TYPE_ERROR: - return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " - "\"address\" must be a string."); - - case NXT_ADDR_PATTERN_LENGTH_ERROR: - return nxt_conf_vldt_error(vldt, "The \"address\" is too short."); - - case NXT_ADDR_PATTERN_FORMAT_ERROR: - return nxt_conf_vldt_error(vldt, "The \"address\" format is invalid."); - - case NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR: - return nxt_conf_vldt_error(vldt, "The \"address\" range is " - "overlapping."); - - case NXT_ADDR_PATTERN_CIDR_ERROR: - return nxt_conf_vldt_error(vldt, "The \"address\" has an invalid CIDR " - "prefix."); - - case NXT_ADDR_PATTERN_NO_IPv6_ERROR: - return nxt_conf_vldt_error(vldt, "The \"address\" does not support " - "IPv6 with your configuration."); - - case NXT_ADDR_PATTERN_NO_UNIX_ERROR: - return nxt_conf_vldt_error(vldt, "The \"address\" does not support " - "UNIX domain sockets with your " - "configuration."); - - default: - return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown " - "format."); - } -} - - -static nxt_int_t -nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - nxt_str_t scheme; - - static const nxt_str_t http = nxt_string("http"); - static const nxt_str_t https = nxt_string("https"); - - nxt_conf_get_string(value, &scheme); - - if (nxt_strcasestr_eq(&scheme, &http) - || nxt_strcasestr_eq(&scheme, &https)) - { - return NXT_OK; - } - - return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be " - "\"http\" or \"https\"."); -} - - -static nxt_int_t -nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - nxt_int_t ret; - - vldt->ctx = data; - - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - ret = nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_match_patterns_set); - - } else { - /* NXT_CONF_OBJECT */ - ret = nxt_conf_vldt_match_patterns_set(vldt, value); - } - - vldt->ctx = NULL; - - return ret; -} - - -static nxt_int_t -nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - if (nxt_conf_type(value) != NXT_CONF_OBJECT) { - return nxt_conf_vldt_error(vldt, "The \"match\" patterns for " - "\"%s\" must be objects.", vldt->ctx); - } - - return nxt_conf_vldt_object_iterator(vldt, value, - &nxt_conf_vldt_match_patterns_set_member); -} - - -static nxt_int_t -nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt, - nxt_str_t *name, nxt_conf_value_t *value) -{ - if (name->length == 0) { - return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must " - "not contain empty member names."); - } - - return nxt_conf_vldt_match_patterns(vldt, value, vldt->ctx); -} - - -#if (NXT_TLS) - -static nxt_int_t -nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - if (nxt_conf_array_elements_count(value) == 0) { - return nxt_conf_vldt_error(vldt, "The \"certificate\" array " - "must contain at least one element."); - } - - return nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_certificate_element); - } - - /* NXT_CONF_STRING */ - - return nxt_conf_vldt_certificate_element(vldt, value); -} - - -static nxt_int_t -nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - nxt_str_t name; - nxt_conf_value_t *cert; - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"certificate\" array must " - "contain only string values."); - } - - nxt_conf_get_string(value, &name); - - cert = nxt_cert_info_get(&name); - - if (cert == NULL) { - return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.", - &name); - } - - return NXT_OK; -} - - -#if (NXT_HAVE_OPENSSL_CONF_CMD) - -static nxt_int_t -nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - uint32_t index; - nxt_int_t ret; - nxt_str_t name; - nxt_conf_value_t *member; - - index = 0; - - for ( ;; ) { - member = nxt_conf_next_object_member(value, &name, &index); - - if (member == NULL) { - break; - } - - ret = nxt_conf_vldt_type(vldt, &name, member, NXT_CONF_VLDT_STRING); - if (ret != NXT_OK) { - return ret; - } - } - - return NXT_OK; -} - -#endif - -#endif - - -static nxt_int_t -nxt_conf_vldt_response_header(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value) -{ - nxt_uint_t type; - - static nxt_str_t content_length = nxt_string("Content-Length"); - - if (name->length == 0) { - return nxt_conf_vldt_error(vldt, "The response header name " - "must not be empty."); - } - - if (nxt_strstr_eq(name, &content_length)) { - return nxt_conf_vldt_error(vldt, "The \"Content-Length\" response " - "header value is not supported"); - } - - type = nxt_conf_type(value); - - if (type == NXT_CONF_STRING || type == NXT_CONF_NULL) { - return NXT_OK; - } - - return nxt_conf_vldt_error(vldt, "The \"%V\" response header value " - "must either be a string or a null", name); -} - - -static nxt_int_t -nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_str_t name; - nxt_conf_value_t *apps, *app; - - static nxt_str_t apps_str = nxt_string("applications"); - - nxt_conf_get_string(value, &name); - - apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL); - - if (nxt_slow_path(apps == NULL)) { - goto error; - } - - app = nxt_conf_get_object_member(apps, &name, NULL); - - if (nxt_slow_path(app == NULL)) { - goto error; - } - - return NXT_OK; - -error: - - return nxt_conf_vldt_error(vldt, "Listening socket is assigned for " - "a non existing application \"%V\".", - &name); -} - - -static nxt_int_t -nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_conf_value_t *client_ip, *protocol; - - static nxt_str_t client_ip_str = nxt_string("client_ip"); - static nxt_str_t protocol_str = nxt_string("protocol"); - - client_ip = nxt_conf_get_object_member(value, &client_ip_str, NULL); - protocol = nxt_conf_get_object_member(value, &protocol_str, NULL); - - if (client_ip == NULL && protocol == NULL) { - return nxt_conf_vldt_error(vldt, "The \"forwarded\" object must have " - "either \"client_ip\" or \"protocol\" " - "option set."); - } - - return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_forwarded_members); -} - - -static nxt_int_t -nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value) -{ - nxt_int_t ret; - nxt_str_t type; - nxt_thread_t *thread; - nxt_conf_value_t *type_value; - nxt_app_lang_module_t *lang; - - static nxt_str_t type_str = nxt_string("type"); - - static struct { - nxt_conf_vldt_handler_t validator; - nxt_conf_vldt_object_t *members; - - } types[] = { - { nxt_conf_vldt_object, nxt_conf_vldt_external_members }, - { nxt_conf_vldt_python, NULL }, - { nxt_conf_vldt_php, NULL }, - { nxt_conf_vldt_object, nxt_conf_vldt_perl_members }, - { nxt_conf_vldt_object, nxt_conf_vldt_ruby_members }, - { nxt_conf_vldt_object, nxt_conf_vldt_java_members }, - { nxt_conf_vldt_object, nxt_conf_vldt_wasm_members }, - { nxt_conf_vldt_object, nxt_conf_vldt_wasm_wc_members }, - }; - - ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); - - if (ret != NXT_OK) { - return ret; - } - - type_value = nxt_conf_get_object_member(value, &type_str, NULL); - - if (type_value == NULL) { - return nxt_conf_vldt_error(vldt, - "Application must have the \"type\" property set."); - } - - ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING); - - if (ret != NXT_OK) { - return ret; - } - - nxt_conf_get_string(type_value, &type); - - thread = nxt_thread(); - - lang = nxt_app_lang_module(thread->runtime, &type); - if (lang == NULL) { - return nxt_conf_vldt_error(vldt, - "The module to run \"%V\" is not found " - "among the available application modules.", - &type); - } - - return types[lang->type].validator(vldt, value, types[lang->type].members); -} - - -static nxt_int_t -nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - uint32_t index; - nxt_int_t ret; - nxt_str_t name, var; - nxt_conf_value_t *member; - nxt_conf_vldt_object_t *vals; - - vals = data; - - for ( ;; ) { - if (vals->name.length == 0) { - - if (vals->u.members != NULL) { - vals = vals->u.members; - continue; - } - - break; - } - - if (vals->flags & NXT_CONF_VLDT_REQUIRED) { - member = nxt_conf_get_object_member(value, &vals->name, NULL); - - if (member == NULL) { - return nxt_conf_vldt_error(vldt, "Required parameter \"%V\" " - "is missing.", &vals->name); - } - } - - vals++; - } - - index = 0; - - for ( ;; ) { - member = nxt_conf_next_object_member(value, &name, &index); - - if (member == NULL) { - return NXT_OK; - } - - vals = data; - - for ( ;; ) { - if (vals->name.length == 0) { - - if (vals->u.members != NULL) { - vals = vals->u.members; - continue; - } - - return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".", - &name); - } - - if (!nxt_strstr_eq(&vals->name, &name)) { - vals++; - continue; - } - - if (vals->flags & NXT_CONF_VLDT_TSTR - && nxt_conf_type(member) == NXT_CONF_STRING) - { - nxt_conf_get_string(member, &var); - - if (nxt_is_tstr(&var)) { - ret = nxt_conf_vldt_var(vldt, &name, &var); - if (ret != NXT_OK) { - return ret; - } - - break; - } - } - - ret = nxt_conf_vldt_type(vldt, &name, member, vals->type); - if (ret != NXT_OK) { - return ret; - } - - if (vals->validator != NULL) { - ret = vals->validator(vldt, member, vals->u.members); - - if (ret != NXT_OK) { - return ret; - } - } - - break; - } - } -} - - -typedef struct { - int64_t spare; - int64_t max; - int64_t idle_timeout; -} nxt_conf_vldt_processes_conf_t; - - -static nxt_conf_map_t nxt_conf_vldt_processes_conf_map[] = { - { - nxt_string("spare"), - NXT_CONF_MAP_INT64, - offsetof(nxt_conf_vldt_processes_conf_t, spare), - }, - - { - nxt_string("max"), - NXT_CONF_MAP_INT64, - offsetof(nxt_conf_vldt_processes_conf_t, max), - }, - - { - nxt_string("idle_timeout"), - NXT_CONF_MAP_INT64, - offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout), - }, -}; - - -static nxt_int_t -nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - int64_t int_value; - nxt_int_t ret; - nxt_conf_vldt_processes_conf_t proc; - - if (nxt_conf_type(value) == NXT_CONF_INTEGER) { - int_value = nxt_conf_get_number(value); - - if (int_value < 1) { - return nxt_conf_vldt_error(vldt, "The \"processes\" number must be " - "equal to or greater than 1."); - } - - if (int_value > NXT_INT32_T_MAX) { - return nxt_conf_vldt_error(vldt, "The \"processes\" number must " - "not exceed %d.", NXT_INT32_T_MAX); - } - - return NXT_OK; - } - - ret = nxt_conf_vldt_object(vldt, value, data); - if (ret != NXT_OK) { - return ret; - } - - proc.spare = 0; - proc.max = 1; - proc.idle_timeout = 15; - - ret = nxt_conf_map_object(vldt->pool, value, - nxt_conf_vldt_processes_conf_map, - nxt_nitems(nxt_conf_vldt_processes_conf_map), - &proc); - if (ret != NXT_OK) { - return ret; - } - - if (proc.spare < 0) { - return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be " - "negative."); - } - - if (proc.spare > NXT_INT32_T_MAX) { - return nxt_conf_vldt_error(vldt, "The \"spare\" number must not " - "exceed %d.", NXT_INT32_T_MAX); - } - - if (proc.max < 1) { - return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal " - "to or greater than 1."); - } - - if (proc.max > NXT_INT32_T_MAX) { - return nxt_conf_vldt_error(vldt, "The \"max\" number must not " - "exceed %d.", NXT_INT32_T_MAX); - } - - if (proc.max < proc.spare) { - return nxt_conf_vldt_error(vldt, "The \"spare\" number must be " - "less than or equal to \"max\"."); - } - - if (proc.idle_timeout < 0) { - return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " - "be negative."); - } - - if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) { - return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not " - "exceed %d.", NXT_INT32_T_MAX / 1000); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - uint32_t index; - nxt_int_t ret; - nxt_str_t name; - nxt_conf_value_t *member; - nxt_conf_vldt_member_t validator; - - validator = (nxt_conf_vldt_member_t) data; - index = 0; - - for ( ;; ) { - member = nxt_conf_next_object_member(value, &name, &index); - if (member == NULL) { - return NXT_OK; - } - - ret = validator(vldt, &name, member); - if (ret != NXT_OK) { - return ret; - } - } -} - - -static nxt_int_t -nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - uint32_t index; - nxt_int_t ret; - nxt_conf_value_t *element; - nxt_conf_vldt_element_t validator; - - validator = (nxt_conf_vldt_element_t) data; - - for (index = 0; /* void */ ; index++) { - element = nxt_conf_get_array_element(value, index); - - if (element == NULL) { - return NXT_OK; - } - - ret = validator(vldt, element); - - if (ret != NXT_OK) { - return ret; - } - } -} - - -static nxt_int_t -nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value) -{ - nxt_str_t str; - - if (name->length == 0) { - return nxt_conf_vldt_error(vldt, - "The environment name must not be empty."); - } - - if (memchr(name->start, '\0', name->length) != NULL) { - return nxt_conf_vldt_error(vldt, "The environment name must not " - "contain null character."); - } - - if (memchr(name->start, '=', name->length) != NULL) { - return nxt_conf_vldt_error(vldt, "The environment name must not " - "contain '=' character."); - } - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be " - "a string.", name); - } - - nxt_conf_get_string(value, &str); - - if (memchr(str.start, '\0', str.length) != NULL) { - return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must " - "not contain null character.", name); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_targets_exclusive(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - return nxt_conf_vldt_error(vldt, "The \"%s\" option is mutually exclusive " - "with the \"targets\" object.", data); -} - - -static nxt_int_t -nxt_conf_vldt_targets(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_int_t ret; - nxt_uint_t n; - - n = nxt_conf_object_members_count(value); - - if (n > 254) { - return nxt_conf_vldt_error(vldt, "The \"targets\" object must not " - "contain more than 254 members."); - } - - vldt->ctx = data; - - ret = nxt_conf_vldt_object_iterator(vldt, value, &nxt_conf_vldt_target); - - vldt->ctx = NULL; - - return ret; -} - - -static nxt_int_t -nxt_conf_vldt_target(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value) -{ - if (name->length == 0) { - return nxt_conf_vldt_error(vldt, - "The target name must not be empty."); - } - - if (nxt_conf_type(value) != NXT_CONF_OBJECT) { - return nxt_conf_vldt_error(vldt, "The \"%V\" target must be " - "an object.", name); - } - - return nxt_conf_vldt_object(vldt, value, vldt->ctx); -} - - -#if (NXT_HAVE_CGROUP) - -static nxt_int_t -nxt_conf_vldt_cgroup_path(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - char path[NXT_MAX_PATH_LEN]; - nxt_str_t cgpath; - - nxt_conf_get_string(value, &cgpath); - if (cgpath.length >= NXT_MAX_PATH_LEN - strlen(NXT_CGROUP_ROOT) - 1) { - return nxt_conf_vldt_error(vldt, "The cgroup path \"%V\" is too long.", - &cgpath); - } - - sprintf(path, "/%*s/", (int) cgpath.length, cgpath.start); - - if (cgpath.length == 0 || strstr(path, "/../") != NULL) { - return nxt_conf_vldt_error(vldt, - "The cgroup path \"%V\" is invalid.", - &cgpath); - } - - return NXT_OK; -} - -#endif - - -static nxt_int_t -nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - return nxt_conf_vldt_object(vldt, value, data); -} - - -static nxt_int_t -nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - return nxt_conf_vldt_object(vldt, value, data); -} - - -#if (NXT_HAVE_CLONE_NEWUSER) - -static nxt_int_t -nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) -{ - nxt_int_t ret; - - if (nxt_conf_type(value) != NXT_CONF_OBJECT) { - return nxt_conf_vldt_error(vldt, "The \"uidmap\" array " - "must contain only object values."); - } - - ret = nxt_conf_vldt_object(vldt, value, - (void *) nxt_conf_vldt_app_procmap_members); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) -{ - nxt_int_t ret; - - if (nxt_conf_type(value) != NXT_CONF_OBJECT) { - return nxt_conf_vldt_error(vldt, "The \"gidmap\" array " - "must contain only object values."); - } - - ret = nxt_conf_vldt_object(vldt, value, - (void *) nxt_conf_vldt_app_procmap_members); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - return NXT_OK; -} - -#endif - - -static nxt_int_t -nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) -{ - nxt_str_t str; - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"arguments\" array " - "must contain only string values."); - } - - nxt_conf_get_string(value, &str); - - if (memchr(str.start, '\0', str.length) != NULL) { - return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not " - "contain strings with null character."); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_php(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_conf_value_t *targets; - - static nxt_str_t targets_str = nxt_string("targets"); - - targets = nxt_conf_get_object_member(value, &targets_str, NULL); - - if (targets != NULL) { - return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_php_members); - } - - return nxt_conf_vldt_object(vldt, value, - nxt_conf_vldt_php_notargets_members); -} - - -static nxt_int_t -nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value) -{ - if (name->length == 0) { - return nxt_conf_vldt_error(vldt, - "The PHP option name must not be empty."); - } - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be " - "a string.", name); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - nxt_str_t str; - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"classpath\" array " - "must contain only string values."); - } - - nxt_conf_get_string(value, &str); - - if (memchr(str.start, '\0', str.length) != NULL) { - return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not " - "contain strings with null character."); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) -{ - nxt_str_t str; - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"options\" array " - "must contain only string values."); - } - - nxt_conf_get_string(value, &str); - - if (memchr(str.start, '\0', str.length) != NULL) { - return nxt_conf_vldt_error(vldt, "The \"options\" array must not " - "contain strings with null character."); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_upstream(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value) -{ - nxt_int_t ret; - nxt_conf_value_t *conf; - - static nxt_str_t servers = nxt_string("servers"); - - ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); - - if (ret != NXT_OK) { - return ret; - } - - ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_upstream_members); - - if (ret != NXT_OK) { - return ret; - } - - conf = nxt_conf_get_object_member(value, &servers, NULL); - if (conf == NULL) { - return nxt_conf_vldt_error(vldt, "The \"%V\" upstream must contain " - "\"servers\" object value.", name); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name, - nxt_conf_value_t *value) -{ - nxt_int_t ret; - nxt_str_t str; - nxt_sockaddr_t *sa; - - ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT); - if (ret != NXT_OK) { - return ret; - } - - if (nxt_slow_path(nxt_str_dup(vldt->pool, &str, name) == NULL)) { - return NXT_ERROR; - } - - sa = nxt_sockaddr_parse(vldt->pool, &str); - if (sa == NULL) { - return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid " - "server address.", name); - } - - return nxt_conf_vldt_object(vldt, value, - nxt_conf_vldt_upstream_server_members); -} - - -static nxt_int_t -nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value, void *data) -{ - double num_value; - - num_value = nxt_conf_get_number(value); - - if (num_value < 0) { - return nxt_conf_vldt_error(vldt, "The \"weight\" number must be " - "positive."); - } - - if (num_value > 1000000) { - return nxt_conf_vldt_error(vldt, "The \"weight\" number must " - "not exceed 1,000,000"); - } - - return NXT_OK; -} - - -#if (NXT_HAVE_NJS) - -static nxt_int_t -nxt_conf_vldt_js_module(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - if (nxt_conf_type(value) == NXT_CONF_ARRAY) { - return nxt_conf_vldt_array_iterator(vldt, value, - &nxt_conf_vldt_js_module_element); - } - - /* NXT_CONF_STRING */ - - return nxt_conf_vldt_js_module_element(vldt, value); -} - - -static nxt_int_t -nxt_conf_vldt_js_module_element(nxt_conf_validation_t *vldt, - nxt_conf_value_t *value) -{ - nxt_str_t name; - nxt_conf_value_t *module; - - if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, "The \"js_module\" array must " - "contain only string values."); - } - - nxt_conf_get_string(value, &name); - - module = nxt_script_info_get(&name); - if (module == NULL) { - return nxt_conf_vldt_error(vldt, "JS module \"%V\" is not found.", - &name); - } - - return NXT_OK; -} - -#endif - - -typedef struct { - nxt_str_t path; - nxt_str_t format; -} nxt_conf_vldt_access_log_conf_t; - - -static nxt_conf_map_t nxt_conf_vldt_access_log_map[] = { - { - nxt_string("path"), - NXT_CONF_MAP_STR, - offsetof(nxt_conf_vldt_access_log_conf_t, path), - }, - - { - nxt_string("format"), - NXT_CONF_MAP_STR, - offsetof(nxt_conf_vldt_access_log_conf_t, format), - }, -}; - - -static nxt_int_t -nxt_conf_vldt_access_log(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, - void *data) -{ - nxt_int_t ret; - nxt_conf_vldt_access_log_conf_t conf; - - static nxt_str_t format_str = nxt_string("format"); - - if (nxt_conf_type(value) == NXT_CONF_STRING) { - return NXT_OK; - } - - ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_access_log_members); - if (ret != NXT_OK) { - return ret; - } - - nxt_memzero(&conf, sizeof(nxt_conf_vldt_access_log_conf_t)); - - ret = nxt_conf_map_object(vldt->pool, value, - nxt_conf_vldt_access_log_map, - nxt_nitems(nxt_conf_vldt_access_log_map), - &conf); - if (ret != NXT_OK) { - return ret; - } - - if (conf.path.length == 0) { - return nxt_conf_vldt_error(vldt, - "The \"path\" string must not be empty."); - } - - if (nxt_is_tstr(&conf.format)) { - return nxt_conf_vldt_var(vldt, &format_str, &conf.format); - } - - return NXT_OK; -} diff --git a/src/nxt_conn.c b/src/nxt_conn.c deleted file mode 100644 index 498d7d5c..00000000 --- a/src/nxt_conn.c +++ /dev/null @@ -1,185 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_conn_io_t nxt_unix_conn_io = { - .connect = nxt_conn_io_connect, - .accept = nxt_conn_io_accept, - - .read = nxt_conn_io_read, - .recvbuf = nxt_conn_io_recvbuf, - .recv = nxt_conn_io_recv, - - .write = nxt_conn_io_write, - .sendbuf = nxt_conn_io_sendbuf, - -#if (NXT_HAVE_LINUX_SENDFILE) - .old_sendbuf = nxt_linux_event_conn_io_sendfile, -#elif (NXT_HAVE_FREEBSD_SENDFILE) - .old_sendbuf = nxt_freebsd_event_conn_io_sendfile, -#elif (NXT_HAVE_MACOSX_SENDFILE) - .old_sendbuf = nxt_macosx_event_conn_io_sendfile, -#elif (NXT_HAVE_SOLARIS_SENDFILEV) - .old_sendbuf = nxt_solaris_event_conn_io_sendfilev, -#elif (NXT_HAVE_AIX_SEND_FILE) - .old_sendbuf = nxt_aix_event_conn_io_send_file, -#elif (NXT_HAVE_HPUX_SENDFILE) - .old_sendbuf = nxt_hpux_event_conn_io_sendfile, -#else - .old_sendbuf = nxt_event_conn_io_sendbuf, -#endif - - .writev = nxt_event_conn_io_writev, - .send = nxt_event_conn_io_send, -}; - - -nxt_conn_t * -nxt_conn_create(nxt_mp_t *mp, nxt_task_t *task) -{ - nxt_conn_t *c; - nxt_thread_t *thr; - - c = nxt_mp_zget(mp, sizeof(nxt_conn_t)); - if (nxt_slow_path(c == NULL)) { - return NULL; - } - - c->mem_pool = mp; - - c->socket.fd = -1; - - c->socket.log = &c->log; - c->log = *task->log; - - /* The while loop skips possible uint32_t overflow. */ - - while (c->log.ident == 0) { - c->log.ident = nxt_task_next_ident(); - } - - thr = nxt_thread(); - thr->engine->connections++; - - c->task.thread = thr; - c->task.log = &c->log; - c->task.ident = c->log.ident; - c->socket.task = &c->task; - c->read_timer.task = &c->task; - c->write_timer.task = &c->task; - - c->io = thr->engine->event.io; - c->max_chunk = NXT_INT32_T_MAX; - c->sendfile = NXT_CONN_SENDFILE_UNSET; - - c->socket.read_work_queue = &thr->engine->fast_work_queue; - c->socket.write_work_queue = &thr->engine->fast_work_queue; - - nxt_conn_timer_init(&c->read_timer, c, c->socket.read_work_queue); - nxt_conn_timer_init(&c->write_timer, c, c->socket.write_work_queue); - - nxt_log_debug(&c->log, "connections: %uD", thr->engine->connections); - - return c; -} - - -void -nxt_conn_free(nxt_task_t *task, nxt_conn_t *c) -{ - nxt_mp_t *mp; - - task->thread->engine->connections--; - - mp = c->mem_pool; - nxt_mp_release(mp); -} - - -void -nxt_conn_timer(nxt_event_engine_t *engine, nxt_conn_t *c, - const nxt_conn_state_t *state, nxt_timer_t *timer) -{ - nxt_msec_t value; - - if (state->timer_value != NULL) { - value = state->timer_value(c, state->timer_data); - - if (value != 0) { - timer->handler = state->timer_handler; - nxt_timer_add(engine, timer, value); - } - } -} - - -void -nxt_conn_work_queue_set(nxt_conn_t *c, nxt_work_queue_t *wq) -{ - c->read_work_queue = wq; - c->write_work_queue = wq; - c->read_timer.work_queue = wq; - c->write_timer.work_queue = wq; -} - - -nxt_sockaddr_t * -nxt_conn_local_addr(nxt_task_t *task, nxt_conn_t *c) -{ - int ret; - size_t size, length; - socklen_t socklen; - nxt_sockaddr_t *sa; - - if (c->local != NULL) { - return c->local; - } - - /* AF_UNIX should not get in here. */ - - switch (c->remote->u.sockaddr.sa_family) { -#if (NXT_INET6) - case AF_INET6: - socklen = sizeof(struct sockaddr_in6); - length = NXT_INET6_ADDR_STR_LEN; - size = offsetof(nxt_sockaddr_t, u) + socklen + length; - break; -#endif - case AF_INET: - default: - socklen = sizeof(struct sockaddr_in); - length = NXT_INET_ADDR_STR_LEN; - size = offsetof(nxt_sockaddr_t, u) + socklen + length; - break; - } - - sa = nxt_mp_get(c->mem_pool, size); - if (nxt_slow_path(sa == NULL)) { - return NULL; - } - - sa->socklen = socklen; - sa->length = length; - - ret = getsockname(c->socket.fd, &sa->u.sockaddr, &socklen); - if (nxt_slow_path(ret != 0)) { - nxt_alert(task, "getsockname(%d) failed", c->socket.fd); - return NULL; - } - - c->local = sa; - - nxt_sockaddr_text(sa); - - /* - * TODO: here we can adjust the end of non-freeable block - * in c->mem_pool to the end of actual sockaddr length. - */ - - return sa; -} diff --git a/src/nxt_conn.h b/src/nxt_conn.h deleted file mode 100644 index 5717d3c9..00000000 --- a/src/nxt_conn.h +++ /dev/null @@ -1,364 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_CONN_H_INCLUDED_ -#define _NXT_CONN_H_INCLUDED_ - - -typedef ssize_t (*nxt_conn_io_read_t)(nxt_task_t *task, nxt_conn_t *c); -typedef nxt_msec_t (*nxt_conn_timer_value_t)(nxt_conn_t *c, uintptr_t data); - - -typedef struct { - nxt_work_handler_t ready_handler; - nxt_work_handler_t close_handler; - nxt_work_handler_t error_handler; - - nxt_conn_io_read_t io_read_handler; - - nxt_work_handler_t timer_handler; - nxt_conn_timer_value_t timer_value; - uintptr_t timer_data; - - uint8_t timer_autoreset; -} nxt_conn_state_t; - - -typedef struct { - double average; - size_t limit; - size_t limit_after; - size_t max_limit; - nxt_msec_t last; -} nxt_event_write_rate_t; - - -typedef struct { - - nxt_work_handler_t connect; - nxt_work_handler_t accept; - - /* - * The read() with NULL c->read buffer waits readiness of a connection - * to avoid allocation of read buffer if the connection will time out - * or will be closed with error. The kqueue-specific read() can also - * detect case if a client did not sent anything and has just closed the - * connection without errors. In the latter case state's close_handler - * is called. - */ - nxt_work_handler_t read; - - ssize_t (*recvbuf)(nxt_conn_t *c, nxt_buf_t *b); - - ssize_t (*recv)(nxt_conn_t *c, void *buf, - size_t size, nxt_uint_t flags); - - /* The write() is an interface to write a buffer chain. */ - nxt_work_handler_t write; - - /* - * The sendbuf() is an interface for OS-specific sendfile - * implementations or simple writev(). - */ - ssize_t (*sendbuf)(nxt_task_t *task, - nxt_sendbuf_t *sb); - /* - * The sendbuf() is an interface for OS-specific sendfile - * implementations or simple writev(). - */ - ssize_t (*old_sendbuf)(nxt_conn_t *c, nxt_buf_t *b, - size_t limit); - /* - * The writev() is an interface to write several nxt_iobuf_t buffers. - */ - ssize_t (*writev)(nxt_conn_t *c, - nxt_iobuf_t *iob, nxt_uint_t niob); - /* - * The send() is an interface to write a single buffer. SSL/TLS - * libraries' send() interface handles also the libraries' errors. - */ - ssize_t (*send)(nxt_conn_t *c, void *buf, - size_t size); - - nxt_work_handler_t shutdown; -} nxt_conn_io_t; - - -/* - * The nxt_listen_event_t is separated from nxt_listen_socket_t - * because nxt_listen_socket_t is one per process whilst each worker - * thread uses own nxt_listen_event_t. - */ -typedef struct { - /* Must be the first field. */ - nxt_fd_event_t socket; - - nxt_task_t task; - - uint32_t ready; - uint32_t batch; - uint32_t count; - - /* An accept() interface is cached to minimize memory accesses. */ - nxt_work_handler_t accept; - - nxt_listen_socket_t *listen; - nxt_conn_t *next; - nxt_work_queue_t *work_queue; - - nxt_timer_t timer; - - nxt_queue_link_t link; -} nxt_listen_event_t; - - -struct nxt_conn_s { - /* - * Must be the first field, since nxt_fd_event_t - * and nxt_conn_t are used interchangeably. - */ - nxt_fd_event_t socket; - - nxt_buf_t *read; - const nxt_conn_state_t *read_state; - nxt_work_queue_t *read_work_queue; - nxt_timer_t read_timer; - - nxt_buf_t *write; - const nxt_conn_state_t *write_state; - nxt_work_queue_t *write_work_queue; - nxt_event_write_rate_t *rate; - nxt_timer_t write_timer; - - nxt_off_t sent; - uint32_t max_chunk; - uint32_t nbytes; - - nxt_conn_io_t *io; - - union { -#if (NXT_TLS) - void *tls; -#endif - nxt_thread_pool_t *thread_pool; - } u; - - nxt_mp_t *mem_pool; - - nxt_task_t task; - nxt_log_t log; - - nxt_listen_event_t *listen; - - nxt_sockaddr_t *remote; - nxt_sockaddr_t *local; - const char *action; - - uint8_t block_read; /* 1 bit */ - uint8_t block_write; /* 1 bit */ - uint8_t delayed; /* 1 bit */ - uint8_t idle; /* 1 bit */ - -#define NXT_CONN_SENDFILE_OFF 0 -#define NXT_CONN_SENDFILE_ON 1 -#define NXT_CONN_SENDFILE_UNSET 3 - - uint8_t sendfile; /* 2 bits */ - uint8_t tcp_nodelay; /* 1 bit */ - - nxt_queue_link_t link; -}; - - -#define nxt_conn_timer_init(ev, c, wq) \ - do { \ - (ev)->work_queue = (wq); \ - (ev)->log = &(c)->log; \ - (ev)->bias = NXT_TIMER_DEFAULT_BIAS; \ - } while (0) - - -#define nxt_read_timer_conn(ev) \ - nxt_timer_data(ev, nxt_conn_t, read_timer) - - -#define nxt_write_timer_conn(ev) \ - nxt_timer_data(ev, nxt_conn_t, write_timer) - - -#if (NXT_HAVE_UNIX_DOMAIN) - -#define nxt_conn_tcp_nodelay_on(task, c) \ - do { \ - nxt_int_t ret; \ - \ - if ((c)->remote->u.sockaddr.sa_family != AF_UNIX) { \ - ret = nxt_socket_setsockopt(task, (c)->socket.fd, IPPROTO_TCP, \ - TCP_NODELAY, 1); \ - \ - (c)->tcp_nodelay = (ret == NXT_OK); \ - } \ - } while (0) - - -#else - -#define nxt_conn_tcp_nodelay_on(task, c) \ - do { \ - nxt_int_t ret; \ - \ - ret = nxt_socket_setsockopt(task, (c)->socket.fd, IPPROTO_TCP, \ - TCP_NODELAY, 1); \ - \ - (c)->tcp_nodelay = (ret == NXT_OK); \ - } while (0) - -#endif - - -NXT_EXPORT nxt_conn_t *nxt_conn_create(nxt_mp_t *mp, nxt_task_t *task); -NXT_EXPORT void nxt_conn_free(nxt_task_t *task, nxt_conn_t *c); -NXT_EXPORT void nxt_conn_close(nxt_event_engine_t *engine, nxt_conn_t *c); - -NXT_EXPORT void nxt_conn_timer(nxt_event_engine_t *engine, nxt_conn_t *c, - const nxt_conn_state_t *state, nxt_timer_t *tev); -NXT_EXPORT void nxt_conn_work_queue_set(nxt_conn_t *c, nxt_work_queue_t *wq); -NXT_EXPORT nxt_sockaddr_t *nxt_conn_local_addr(nxt_task_t *task, - nxt_conn_t *c); - -void nxt_conn_sys_socket(nxt_task_t *task, void *obj, void *data); -void nxt_conn_io_connect(nxt_task_t *task, void *obj, void *data); -nxt_int_t nxt_conn_socket(nxt_task_t *task, nxt_conn_t *c); -void nxt_conn_connect_test(nxt_task_t *task, void *obj, void *data); -void nxt_conn_connect_error(nxt_task_t *task, void *obj, void *data); - -NXT_EXPORT nxt_listen_event_t *nxt_listen_event(nxt_task_t *task, - nxt_listen_socket_t *ls); -void nxt_conn_io_accept(nxt_task_t *task, void *obj, void *data); -NXT_EXPORT void nxt_conn_accept(nxt_task_t *task, nxt_listen_event_t *lev, - nxt_conn_t *c); -void nxt_conn_accept_error(nxt_task_t *task, nxt_listen_event_t *lev, - const char *accept_syscall, nxt_err_t err); - -void nxt_conn_wait(nxt_conn_t *c); - -void nxt_conn_io_read(nxt_task_t *task, void *obj, void *data); -ssize_t nxt_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); -ssize_t nxt_conn_io_recv(nxt_conn_t *c, void *buf, size_t size, - nxt_uint_t flags); - -void nxt_conn_io_write(nxt_task_t *task, void *obj, void *data); -ssize_t nxt_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb); -ssize_t nxt_conn_io_writev(nxt_task_t *task, nxt_sendbuf_t *sb, - nxt_iobuf_t *iob, nxt_uint_t niob); -ssize_t nxt_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf, - size_t size); - -size_t nxt_event_conn_write_limit(nxt_conn_t *c); -nxt_bool_t nxt_event_conn_write_delayed(nxt_event_engine_t *engine, - nxt_conn_t *c, size_t sent); -ssize_t nxt_event_conn_io_writev(nxt_conn_t *c, nxt_iobuf_t *iob, - nxt_uint_t niob); -ssize_t nxt_event_conn_io_send(nxt_conn_t *c, void *buf, size_t size); - -NXT_EXPORT void nxt_event_conn_job_sendfile(nxt_task_t *task, - nxt_conn_t *c); - - -#define nxt_conn_connect(engine, c) \ - nxt_work_queue_add(&engine->socket_work_queue, nxt_conn_sys_socket, \ - c->socket.task, c, c->socket.data) - - -#define nxt_conn_read(engine, c) \ - do { \ - nxt_event_engine_t *e = engine; \ - \ - c->socket.read_work_queue = &e->read_work_queue; \ - \ - nxt_work_queue_add(&e->read_work_queue, c->io->read, \ - c->socket.task, c, c->socket.data); \ - } while (0) - - -#define nxt_conn_write(engine, c) \ - do { \ - nxt_event_engine_t *e = engine; \ - \ - c->socket.write_work_queue = &e->write_work_queue; \ - \ - nxt_work_queue_add(&e->write_work_queue, c->io->write, \ - c->socket.task, c, c->socket.data); \ - } while (0) - - -#define nxt_conn_idle(engine, c) \ - do { \ - nxt_event_engine_t *e = engine; \ - \ - nxt_queue_insert_head(&e->idle_connections, &c->link); \ - \ - c->idle = 1; \ - e->idle_conns_cnt++; \ - } while (0) - - -#define nxt_conn_active(engine, c) \ - do { \ - nxt_event_engine_t *e = engine; \ - \ - nxt_queue_remove(&c->link); \ - \ - e->idle_conns_cnt -= c->idle; \ - } while (0) - - -extern nxt_conn_io_t nxt_unix_conn_io; - - -typedef struct { - /* - * Client and peer connections are not embedded because already - * existent connections can be switched to the event connection proxy. - */ - nxt_conn_t *client; - nxt_conn_t *peer; - nxt_buf_t *client_buffer; - nxt_buf_t *peer_buffer; - - size_t client_buffer_size; - size_t peer_buffer_size; - - nxt_msec_t client_wait_timeout; - nxt_msec_t connect_timeout; - nxt_msec_t reconnect_timeout; - nxt_msec_t peer_wait_timeout; - nxt_msec_t client_write_timeout; - nxt_msec_t peer_write_timeout; - - uint8_t connected; /* 1 bit */ - uint8_t delayed; /* 1 bit */ - uint8_t retries; /* 8 bits */ - uint8_t retain; /* 2 bits */ - - nxt_work_handler_t completion_handler; -} nxt_conn_proxy_t; - - -NXT_EXPORT nxt_conn_proxy_t *nxt_conn_proxy_create(nxt_conn_t *c); -NXT_EXPORT void nxt_conn_proxy(nxt_task_t *task, nxt_conn_proxy_t *p); - - -/* STUB */ -#define nxt_event_conn_t nxt_conn_t -#define nxt_event_conn_state_t nxt_conn_state_t -#define nxt_event_conn_proxy_t nxt_conn_proxy_t -#define nxt_event_conn_read nxt_conn_read -#define nxt_event_conn_write nxt_conn_write -#define nxt_event_conn_close nxt_conn_close - - -#endif /* _NXT_CONN_H_INCLUDED_ */ diff --git a/src/nxt_conn_accept.c b/src/nxt_conn_accept.c deleted file mode 100644 index 720c7b64..00000000 --- a/src/nxt_conn_accept.c +++ /dev/null @@ -1,386 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * A listen socket handler calls an event facility specific io_accept() - * method. The method accept()s a new connection and then calls - * nxt_event_conn_accept() to handle the new connection and to prepare - * for a next connection to avoid just dropping next accept()ed socket - * if no more connections allowed. If there are no available connections - * an idle connection would be closed. If there are no idle connections - * then new connections will not be accept()ed for 1 second. - */ - - -static nxt_conn_t *nxt_conn_accept_alloc(nxt_task_t *task, - nxt_listen_event_t *lev); -static void nxt_conn_listen_handler(nxt_task_t *task, void *obj, - void *data); -static nxt_conn_t *nxt_conn_accept_next(nxt_task_t *task, - nxt_listen_event_t *lev); -static void nxt_conn_accept_close_idle(nxt_task_t *task, - nxt_listen_event_t *lev); -static void nxt_conn_accept_close_idle_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_listen_event_error(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_listen_timer_handler(nxt_task_t *task, void *obj, - void *data); - - -nxt_listen_event_t * -nxt_listen_event(nxt_task_t *task, nxt_listen_socket_t *ls) -{ - nxt_listen_event_t *lev; - nxt_event_engine_t *engine; - - lev = nxt_zalloc(sizeof(nxt_listen_event_t)); - - if (nxt_fast_path(lev != NULL)) { - lev->socket.fd = ls->socket; - - engine = task->thread->engine; - lev->batch = engine->batch; - lev->count = 1; - - lev->socket.read_work_queue = &engine->accept_work_queue; - lev->socket.read_handler = nxt_conn_listen_handler; - lev->socket.error_handler = nxt_conn_listen_event_error; - lev->socket.log = &nxt_main_log; - - lev->accept = engine->event.io->accept; - - lev->listen = ls; - lev->work_queue = &engine->read_work_queue; - - lev->timer.work_queue = &engine->fast_work_queue; - lev->timer.handler = nxt_conn_listen_timer_handler; - lev->timer.log = &nxt_main_log; - - lev->task.thread = task->thread; - lev->task.log = &nxt_main_log; - lev->task.ident = nxt_task_next_ident(); - lev->socket.task = &lev->task; - lev->timer.task = &lev->task; - - if (nxt_conn_accept_alloc(task, lev) != NULL) { - nxt_fd_event_enable_accept(engine, &lev->socket); - - nxt_queue_insert_tail(&engine->listen_connections, &lev->link); - } - - return lev; - } - - return NULL; -} - - -static nxt_conn_t * -nxt_conn_accept_alloc(nxt_task_t *task, nxt_listen_event_t *lev) -{ - nxt_mp_t *mp; - nxt_conn_t *c; - nxt_event_engine_t *engine; - - engine = task->thread->engine; - - if (engine->connections < engine->max_connections) { - - mp = nxt_mp_create(1024, 128, 256, 32); - - if (nxt_fast_path(mp != NULL)) { - c = nxt_conn_create(mp, lev->socket.task); - if (nxt_slow_path(c == NULL)) { - nxt_mp_destroy(mp); - - return NULL; - } - - c->socket.read_work_queue = lev->socket.read_work_queue; - c->socket.write_ready = 1; - - c->remote = nxt_sockaddr_cache_alloc(engine, lev->listen); - if (nxt_fast_path(c->remote != NULL)) { - lev->next = c; - return c; - } - - nxt_conn_free(task, c); - } - } - - return NULL; -} - - -static void -nxt_conn_listen_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_listen_event_t *lev; - - lev = obj; - lev->ready = lev->batch; - - lev->accept(task, lev, data); -} - - -void -nxt_conn_io_accept(nxt_task_t *task, void *obj, void *data) -{ - socklen_t socklen; - nxt_conn_t *c; - nxt_socket_t s; - struct sockaddr *sa; - nxt_listen_event_t *lev; - - lev = obj; - c = lev->next; - - lev->ready--; - lev->socket.read_ready = (lev->ready != 0); - - sa = &c->remote->u.sockaddr; - socklen = c->remote->socklen; - /* - * The returned socklen is ignored here, because sockaddr_in and - * sockaddr_in6 socklens are not changed. As to unspecified sockaddr_un - * it is 3 byte length and already prepared, because old BSDs return zero - * socklen and do not update the sockaddr_un at all; Linux returns 2 byte - * socklen and updates only the sa_family part; other systems copy 3 bytes - * and truncate surplus zero part. Only bound sockaddr_un will be really - * truncated here. - */ - s = accept(lev->socket.fd, sa, &socklen); - - if (s == -1) { - nxt_conn_accept_error(task, lev, "accept", nxt_socket_errno); - return; - } - - c->socket.fd = s; - -#if (NXT_LINUX) - /* - * Linux does not inherit non-blocking mode - * from listen socket for accept()ed socket. - */ - if (nxt_slow_path(nxt_socket_nonblocking(task, s) != NXT_OK)) { - nxt_socket_close(task, s); - } - -#endif - - nxt_debug(task, "accept(%d): %d", lev->socket.fd, s); - - nxt_conn_accept(task, lev, c); -} - - -void -nxt_conn_accept(nxt_task_t *task, nxt_listen_event_t *lev, nxt_conn_t *c) -{ - nxt_conn_t *next; - nxt_event_engine_t *engine; - - nxt_sockaddr_text(c->remote); - - nxt_debug(task, "client: %*s", - (size_t) c->remote->address_length, - nxt_sockaddr_address(c->remote)); - - engine = task->thread->engine; - - engine->accepted_conns_cnt++; - - nxt_conn_idle(engine, c); - - c->listen = lev; - lev->count++; - lev->next = NULL; - c->socket.data = NULL; - - c->read_work_queue = lev->work_queue; - c->write_work_queue = lev->work_queue; - - if (lev->listen->read_after_accept) { - - //c->socket.read_ready = 1; -// lev->listen->handler(task, c, lev); - nxt_work_queue_add(c->read_work_queue, lev->listen->handler, - &c->task, c, lev); - - } else { - nxt_work_queue_add(c->write_work_queue, lev->listen->handler, - &c->task, c, lev); - } - - next = nxt_conn_accept_next(task, lev); - - if (next != NULL && lev->socket.read_ready) { - nxt_work_queue_add(lev->socket.read_work_queue, - lev->accept, task, lev, next); - } -} - - -static nxt_conn_t * -nxt_conn_accept_next(nxt_task_t *task, nxt_listen_event_t *lev) -{ - nxt_conn_t *c; - - c = lev->next; - - if (c == NULL) { - c = nxt_conn_accept_alloc(task, lev); - - if (nxt_slow_path(c == NULL)) { - nxt_conn_accept_close_idle(task, lev); - } - } - - return c; -} - - -static void -nxt_conn_accept_close_idle(nxt_task_t *task, nxt_listen_event_t *lev) -{ - nxt_event_engine_t *engine; - - engine = task->thread->engine; - - nxt_work_queue_add(&engine->close_work_queue, - nxt_conn_accept_close_idle_handler, task, NULL, NULL); - - nxt_timer_add(engine, &lev->timer, 100); - - nxt_fd_event_disable_read(engine, &lev->socket); - - nxt_alert(task, "new connections are not accepted within 100ms"); -} - - -static void -nxt_conn_accept_close_idle_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_uint_t times; - nxt_conn_t *c; - nxt_queue_t *idle; - nxt_queue_link_t *link, *next; - nxt_event_engine_t *engine; - - static nxt_log_moderation_t nxt_idle_close_log_moderation = { - NXT_LOG_INFO, 2, "idle connections closed", NXT_LOG_MODERATION - }; - - times = 10; - engine = task->thread->engine; - idle = &engine->idle_connections; - - for (link = nxt_queue_last(idle); - link != nxt_queue_head(idle); - link = next) - { - next = nxt_queue_next(link); - - c = nxt_queue_link_data(link, nxt_conn_t, link); - - nxt_debug(c->socket.task, "idle connection: %d rdy:%d", - c->socket.fd, c->socket.read_ready); - - if (!c->socket.read_ready) { - nxt_log_moderate(&nxt_idle_close_log_moderation, NXT_LOG_INFO, - task->log, "no available connections, " - "close idle connection"); - - c->read_state->close_handler(c->socket.task, c, c->socket.data); - - times--; - - if (times == 0) { - break; - } - } - } -} - - -void -nxt_conn_accept_error(nxt_task_t *task, nxt_listen_event_t *lev, - const char *accept_syscall, nxt_err_t err) -{ - static nxt_log_moderation_t nxt_accept_log_moderation = { - NXT_LOG_INFO, 2, "accept() failed", NXT_LOG_MODERATION - }; - - lev->socket.read_ready = 0; - - switch (err) { - - case NXT_EAGAIN: - nxt_debug(task, "%s(%d) %E", accept_syscall, lev->socket.fd, err); - return; - - case ECONNABORTED: - nxt_log_moderate(&nxt_accept_log_moderation, NXT_LOG_WARN, - task->log, "%s(%d) failed %E", - accept_syscall, lev->socket.fd, err); - return; - - case EMFILE: - case ENFILE: - case ENOBUFS: - case ENOMEM: - nxt_alert(task, "%s(%d) failed %E", - accept_syscall, lev->socket.fd, err); - - nxt_conn_accept_close_idle(task, lev); - return; - - default: - nxt_alert(task, "%s(%d) failed %E", - accept_syscall, lev->socket.fd, err); - return; - } -} - - -static void -nxt_conn_listen_timer_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - nxt_listen_event_t *lev; - - timer = obj; - - lev = nxt_timer_data(timer, nxt_listen_event_t, timer); - - c = nxt_conn_accept_next(task, lev); - if (c == NULL) { - return; - } - - nxt_fd_event_enable_accept(task->thread->engine, &lev->socket); - - lev->accept(task, lev, c); -} - - -static void -nxt_conn_listen_event_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_fd_event_t *ev; - - ev = obj; - - nxt_alert(task, "accept(%d) event error", ev->fd); -} diff --git a/src/nxt_conn_close.c b/src/nxt_conn_close.c deleted file mode 100644 index bdd66951..00000000 --- a/src/nxt_conn_close.c +++ /dev/null @@ -1,174 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static void nxt_conn_shutdown_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_conn_close_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_conn_close_timer_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_close_error_ignore(nxt_task_t *task, void *obj, - void *data); - - -void -nxt_conn_close(nxt_event_engine_t *engine, nxt_conn_t *c) -{ - int ret; - nxt_work_queue_t *wq; - nxt_work_handler_t handler; - - static const struct linger linger_off = { - .l_onoff = 1, - .l_linger = 0, - }; - - nxt_debug(c->socket.task, "conn close fd:%d, to:%d", - c->socket.fd, c->socket.timedout); - - /* - * Disable all pending write operations because on success they - * will incorrectly call a ready handler set for nxt_conn_close(). - */ - c->write = NULL; - - if (c->socket.timedout) { - /* - * Resetting of timed out connection on close - * releases kernel memory associated with socket. - * This also causes sending TCP/IP RST to a peer. - */ - ret = setsockopt(c->socket.fd, SOL_SOCKET, SO_LINGER, &linger_off, - sizeof(struct linger)); - - if (nxt_slow_path(ret != 0)) { - nxt_alert(c->socket.task, "setsockopt(%d, SO_LINGER) failed %E", - c->socket.fd, nxt_socket_errno); - } - } - - /* - * Event errors should be ignored here to avoid repeated nxt_conn_close() - * calls. nxt_conn_close_handler() or nxt_conn_close_timer_handler() - * will eventually close socket. - */ - c->socket.error_handler = nxt_conn_close_error_ignore; - - if (c->socket.error == 0 && !c->socket.closed && !c->socket.shutdown) { - wq = &engine->shutdown_work_queue; - handler = nxt_conn_shutdown_handler; - - } else { - wq = &engine->close_work_queue; - handler = nxt_conn_close_handler; - } - - nxt_work_queue_add(wq, handler, c->socket.task, c, engine); -} - - -static void -nxt_conn_shutdown_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_event_engine_t *engine; - - c = obj; - engine = data; - - nxt_debug(task, "conn shutdown handler fd:%d", c->socket.fd); - - c->socket.shutdown = 1; - - nxt_socket_shutdown(task, c->socket.fd, SHUT_RDWR); - - nxt_work_queue_add(&engine->close_work_queue, nxt_conn_close_handler, - task, c, engine); -} - - -static void -nxt_conn_close_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_uint_t events_pending, timers_pending; - nxt_conn_t *c; - nxt_event_engine_t *engine; - - c = obj; - engine = data; - - nxt_debug(task, "conn close handler fd:%d", c->socket.fd); - - /* - * Socket should be closed only after all pending socket event operations - * will be processed by the kernel. This could be achieved with zero-timer - * handler. Pending timer operations associated with the socket are - * processed before going to the kernel. - */ - - timers_pending = nxt_timer_delete(engine, &c->read_timer); - timers_pending += nxt_timer_delete(engine, &c->write_timer); - - events_pending = nxt_fd_event_close(engine, &c->socket); - - if (events_pending == 0) { - nxt_socket_close(task, c->socket.fd); - c->socket.fd = -1; - - if (c->idle) { - engine->closed_conns_cnt++; - } - - if (timers_pending == 0) { - nxt_work_queue_add(&engine->fast_work_queue, - c->write_state->ready_handler, - task, c, c->socket.data); - return; - } - } - - c->write_timer.handler = nxt_conn_close_timer_handler; - c->write_timer.work_queue = &engine->fast_work_queue; - - nxt_timer_add(engine, &c->write_timer, 0); -} - - -static void -nxt_conn_close_timer_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - nxt_event_engine_t *engine; - - timer = obj; - - c = nxt_write_timer_conn(timer); - - nxt_debug(task, "conn close timer handler fd:%d", c->socket.fd); - - engine = task->thread->engine; - - if (c->socket.fd != -1) { - nxt_socket_close(task, c->socket.fd); - c->socket.fd = -1; - - if (c->idle) { - engine->closed_conns_cnt++; - } - } - - nxt_work_queue_add(&engine->fast_work_queue, c->write_state->ready_handler, - task, c, c->socket.data); -} - - -static void -nxt_conn_close_error_ignore(nxt_task_t *task, void *obj, void *data) -{ - nxt_debug(task, "conn close error ignore"); -} diff --git a/src/nxt_conn_connect.c b/src/nxt_conn_connect.c deleted file mode 100644 index 220fb5f9..00000000 --- a/src/nxt_conn_connect.c +++ /dev/null @@ -1,203 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static nxt_err_t nxt_conn_connect_test_error(nxt_task_t *task, nxt_conn_t *c); - - -void -nxt_conn_sys_socket(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_work_handler_t handler; - - c = obj; - - if (nxt_conn_socket(task, c) == NXT_OK) { - c->socket.write_work_queue = c->write_work_queue; - handler = c->io->connect; - - } else { - handler = c->write_state->error_handler; - } - - nxt_work_queue_add(&task->thread->engine->connect_work_queue, - handler, task, c, data); -} - - -void -nxt_conn_io_connect(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_work_handler_t handler; - nxt_event_engine_t *engine; - const nxt_conn_state_t *state; - - c = obj; - - state = c->write_state; - - switch (nxt_socket_connect(task, c->socket.fd, c->remote)) { - - case NXT_OK: - c->socket.write_ready = 1; - handler = state->ready_handler; - break; - - case NXT_AGAIN: - c->socket.write_handler = nxt_conn_connect_test; - c->socket.error_handler = nxt_conn_connect_error; - - engine = task->thread->engine; - - nxt_conn_timer(engine, c, state, &c->write_timer); - - nxt_fd_event_enable_write(engine, &c->socket); - return; - - case NXT_DECLINED: - handler = state->close_handler; - break; - - default: /* NXT_ERROR */ - handler = state->error_handler; - break; - } - - nxt_work_queue_add(c->write_work_queue, handler, task, c, data); -} - - -nxt_int_t -nxt_conn_socket(nxt_task_t *task, nxt_conn_t *c) -{ - nxt_uint_t family; - nxt_socket_t s; - - nxt_debug(task, "event conn socket"); - - family = c->remote->u.sockaddr.sa_family; - - s = nxt_socket_create(task, family, c->remote->type, 0, NXT_NONBLOCK); - - if (nxt_slow_path(s == -1)) { - return NXT_ERROR; - } - - c->sendfile = 1; - -#if (NXT_HAVE_UNIX_DOMAIN && NXT_SOLARIS) - - if (family == AF_UNIX) { - /* Solaris AF_UNIX does not support sendfilev(). */ - c->sendfile = 0; - } - -#endif - - c->socket.fd = s; - - c->socket.task = task; - c->read_timer.task = task; - c->write_timer.task = task; - - if (c->local != NULL) { - if (nxt_slow_path(nxt_socket_bind(task, s, c->local) != NXT_OK)) { - nxt_socket_close(task, s); - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -void -nxt_conn_connect_test(nxt_task_t *task, void *obj, void *data) -{ - nxt_err_t err; - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "event connect test fd:%d", c->socket.fd); - - nxt_fd_event_block_write(task->thread->engine, &c->socket); - - if (c->write_state->timer_autoreset) { - nxt_timer_disable(task->thread->engine, &c->write_timer); - } - - err = nxt_conn_connect_test_error(task, c); - - if (err == 0) { - nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler, - task, c, data); - } else { - nxt_conn_connect_error(task, c, data); - } -} - - -void -nxt_conn_connect_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_err_t err; - nxt_conn_t *c; - nxt_work_handler_t handler; - const nxt_conn_state_t *state; - - c = obj; - err = c->socket.error; - - if (err == 0) { - err = nxt_conn_connect_test_error(task, c); - } - - state = c->write_state; - - switch (err) { - - case NXT_ECONNREFUSED: -#if (NXT_LINUX) - case NXT_EAGAIN: - /* - * Linux returns EAGAIN instead of ECONNREFUSED - * for UNIX sockets if a listen queue is full. - */ -#endif - handler = state->close_handler; - break; - - default: - handler = state->error_handler; - break; - } - - nxt_work_queue_add(c->write_work_queue, handler, task, c, data); -} - - -static nxt_err_t -nxt_conn_connect_test_error(nxt_task_t *task, nxt_conn_t *c) -{ - nxt_err_t err; - - err = nxt_socket_error(c->socket.fd); - - if (err != 0) { - c->socket.error = err; - - nxt_log(task, nxt_socket_error_level(err), "connect(%d, %*s) failed %E", - c->socket.fd, (size_t) c->remote->length, - nxt_sockaddr_start(c->remote), err); - } - - return err; -} diff --git a/src/nxt_conn_proxy.c b/src/nxt_conn_proxy.c deleted file mode 100644 index 055a288d..00000000 --- a/src/nxt_conn_proxy.c +++ /dev/null @@ -1,987 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static void nxt_conn_proxy_client_buffer_alloc(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_proxy_peer_connect(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_proxy_connected(nxt_task_t *task, void *obj, void *data); -static void nxt_conn_proxy_peer_read(nxt_task_t *task, void *obj, void *data); -static void nxt_conn_proxy_client_read_ready(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_proxy_peer_read_ready(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_proxy_read_process(nxt_task_t *task, nxt_conn_proxy_t *p, - nxt_conn_t *source, nxt_conn_t *sink); -static void nxt_conn_proxy_write_add(nxt_conn_t *c, nxt_buf_t *b); -static void nxt_conn_proxy_read(nxt_task_t *task, void *obj, void *data); -static void nxt_conn_proxy_client_write_ready(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_proxy_peer_write_ready(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_proxy_write_process(nxt_task_t *task, nxt_conn_proxy_t *p, - nxt_conn_t *sink, nxt_conn_t *source); -static void nxt_conn_proxy_read_add(nxt_conn_t *c, nxt_buf_t *b); -static void nxt_conn_proxy_close(nxt_task_t *task, void *obj, void *data); -static void nxt_conn_proxy_error(nxt_task_t *task, void *obj, void *data); -static void nxt_conn_proxy_read_timeout(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_proxy_write_timeout(nxt_task_t *task, void *obj, - void *data); -static nxt_msec_t nxt_conn_proxy_timeout_value(nxt_conn_t *c, uintptr_t data); -static void nxt_conn_proxy_refused(nxt_task_t *task, void *obj, void *data); -static void nxt_conn_proxy_reconnect_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_conn_proxy_shutdown(nxt_task_t *task, nxt_conn_proxy_t *p, - nxt_conn_t *source, nxt_conn_t *sink); -static void nxt_conn_proxy_read_error(nxt_task_t *task, void *obj, void *data); -static void nxt_conn_proxy_write_error(nxt_task_t *task, void *obj, void *data); -static void nxt_conn_proxy_complete(nxt_task_t *task, nxt_conn_proxy_t *p); -static void nxt_conn_proxy_completion(nxt_task_t *task, void *obj, void *data); - - -static const nxt_conn_state_t nxt_conn_proxy_client_wait_state; -static const nxt_conn_state_t nxt_conn_proxy_client_first_read_state; -static const nxt_conn_state_t nxt_conn_proxy_peer_connect_state; -static const nxt_conn_state_t nxt_conn_proxy_peer_wait_state; -static const nxt_conn_state_t nxt_conn_proxy_client_read_state; -static const nxt_conn_state_t nxt_conn_proxy_peer_read_state; -static const nxt_conn_state_t nxt_conn_proxy_client_write_state; -static const nxt_conn_state_t nxt_conn_proxy_peer_write_state; - - -nxt_conn_proxy_t * -nxt_conn_proxy_create(nxt_conn_t *client) -{ - nxt_conn_t *peer; - nxt_thread_t *thr; - nxt_conn_proxy_t *p; - - p = nxt_mp_zget(client->mem_pool, sizeof(nxt_conn_proxy_t)); - if (nxt_slow_path(p == NULL)) { - return NULL; - } - - peer = nxt_conn_create(client->mem_pool, client->socket.task); - if (nxt_slow_path(peer == NULL)) { - return NULL; - } - - thr = nxt_thread(); - - client->read_work_queue = &thr->engine->read_work_queue; - client->write_work_queue = &thr->engine->write_work_queue; - client->socket.read_work_queue = &thr->engine->read_work_queue; - client->socket.write_work_queue = &thr->engine->write_work_queue; - peer->socket.read_work_queue = &thr->engine->read_work_queue; - peer->socket.write_work_queue = &thr->engine->write_work_queue; - - peer->socket.data = client->socket.data; - - peer->read_work_queue = client->read_work_queue; - peer->write_work_queue = client->write_work_queue; - peer->read_timer.work_queue = client->read_work_queue; - peer->write_timer.work_queue = client->write_work_queue; - - p->client = client; - p->peer = peer; - - return p; -} - - -void -nxt_conn_proxy(nxt_task_t *task, nxt_conn_proxy_t *p) -{ - nxt_conn_t *peer; - - /* - * Peer read event: not connected, disabled. - * Peer write event: not connected, disabled. - */ - - if (p->client_wait_timeout == 0) { - /* - * Peer write event: waiting for connection - * to be established with connect_timeout. - */ - peer = p->peer; - peer->write_state = &nxt_conn_proxy_peer_connect_state; - - nxt_conn_connect(task->thread->engine, peer); - } - - /* - * Client read event: waiting for client data with - * client_wait_timeout before buffer allocation. - */ - p->client->read_state = &nxt_conn_proxy_client_wait_state; - - nxt_conn_wait(p->client); -} - - -static const nxt_conn_state_t nxt_conn_proxy_client_wait_state - nxt_aligned(64) = -{ - .ready_handler = nxt_conn_proxy_client_buffer_alloc, - .close_handler = nxt_conn_proxy_close, - .error_handler = nxt_conn_proxy_error, - - .timer_handler = nxt_conn_proxy_read_timeout, - .timer_value = nxt_conn_proxy_timeout_value, - .timer_data = offsetof(nxt_conn_proxy_t, client_wait_timeout), -}; - - -static void -nxt_conn_proxy_client_buffer_alloc(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *b; - nxt_conn_t *client; - nxt_conn_proxy_t *p; - - client = obj; - p = data; - - nxt_debug(task, "conn proxy client first read fd:%d", client->socket.fd); - - b = nxt_buf_mem_alloc(client->mem_pool, p->client_buffer_size, 0); - if (nxt_slow_path(b == NULL)) { - /* An error completion. */ - nxt_conn_proxy_complete(task, p); - return; - } - - p->client_buffer = b; - client->read = b; - - if (p->peer->socket.fd != -1) { - /* - * Client read event: waiting, no timeout. - * Client write event: blocked. - * Peer read event: disabled. - * Peer write event: waiting for connection to be established - * or blocked after the connection has established. - */ - client->read_state = &nxt_conn_proxy_client_read_state; - - } else { - /* - * Client read event: waiting for data with client_wait_timeout - * before connecting to a peer. - * Client write event: blocked. - * Peer read event: not connected, disabled. - * Peer write event: not connected, disabled. - */ - client->read_state = &nxt_conn_proxy_client_first_read_state; - } - - nxt_conn_read(task->thread->engine, client); -} - - -static const nxt_conn_state_t nxt_conn_proxy_client_first_read_state - nxt_aligned(64) = -{ - .ready_handler = nxt_conn_proxy_peer_connect, - .close_handler = nxt_conn_proxy_close, - .error_handler = nxt_conn_proxy_error, - - .timer_handler = nxt_conn_proxy_read_timeout, - .timer_value = nxt_conn_proxy_timeout_value, - .timer_data = offsetof(nxt_conn_proxy_t, client_wait_timeout), - .timer_autoreset = 1, -}; - - -static void -nxt_conn_proxy_peer_connect(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *client; - nxt_conn_proxy_t *p; - - client = obj; - p = data; - - /* - * Client read event: waiting, no timeout. - * Client write event: blocked. - * Peer read event: disabled. - * Peer write event: waiting for connection to be established - * with connect_timeout. - */ - client->read_state = &nxt_conn_proxy_client_read_state; - - p->peer->write_state = &nxt_conn_proxy_peer_connect_state; - - nxt_conn_connect(task->thread->engine, p->peer); -} - - -static const nxt_conn_state_t nxt_conn_proxy_peer_connect_state - nxt_aligned(64) = -{ - .ready_handler = nxt_conn_proxy_connected, - .close_handler = nxt_conn_proxy_refused, - .error_handler = nxt_conn_proxy_error, - - .timer_handler = nxt_conn_proxy_write_timeout, - .timer_value = nxt_conn_proxy_timeout_value, - .timer_data = offsetof(nxt_conn_proxy_t, connect_timeout), - .timer_autoreset = 1, -}; - - -static void -nxt_conn_proxy_connected(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *client, *peer; - nxt_conn_proxy_t *p; - - peer = obj; - p = data; - - nxt_debug(task, "conn proxy connected fd:%d", peer->socket.fd); - - p->connected = 1; - - nxt_conn_tcp_nodelay_on(task, peer); - nxt_conn_tcp_nodelay_on(task, p->client); - - /* Peer read event: waiting with peer_wait_timeout. */ - - peer->read_state = &nxt_conn_proxy_peer_wait_state; - peer->write_state = &nxt_conn_proxy_peer_write_state; - - nxt_conn_wait(peer); - - if (p->client_buffer != NULL) { - client = p->client; - - client->read_state = &nxt_conn_proxy_client_read_state; - client->write_state = &nxt_conn_proxy_client_write_state; - /* - * Send a client read data to the connected peer. - * Client write event: blocked. - */ - nxt_conn_proxy_read_process(task, p, client, peer); - } -} - - -static const nxt_conn_state_t nxt_conn_proxy_peer_wait_state - nxt_aligned(64) = -{ - .ready_handler = nxt_conn_proxy_peer_read, - .close_handler = nxt_conn_proxy_close, - .error_handler = nxt_conn_proxy_error, - - .timer_handler = nxt_conn_proxy_read_timeout, - .timer_value = nxt_conn_proxy_timeout_value, - .timer_data = offsetof(nxt_conn_proxy_t, peer_wait_timeout), -}; - - -static void -nxt_conn_proxy_peer_read(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *b; - nxt_conn_t *peer; - nxt_conn_proxy_t *p; - - peer = obj; - p = data; - - nxt_debug(task, "conn proxy peer read fd:%d", peer->socket.fd); - - b = nxt_buf_mem_alloc(peer->mem_pool, p->peer_buffer_size, 0); - if (nxt_slow_path(b == NULL)) { - /* An error completion. */ - nxt_conn_proxy_complete(task, p); - return; - } - - p->peer_buffer = b; - peer->read = b; - - p->client->write_state = &nxt_conn_proxy_client_write_state; - peer->read_state = &nxt_conn_proxy_peer_read_state; - peer->write_state = &nxt_conn_proxy_peer_write_state; - - /* - * Client read event: waiting, no timeout. - * Client write event: blocked. - * Peer read event: waiting with possible peer_wait_timeout. - * Peer write event: blocked. - */ - nxt_conn_read(task->thread->engine, peer); -} - - -static const nxt_conn_state_t nxt_conn_proxy_client_read_state - nxt_aligned(64) = -{ - .ready_handler = nxt_conn_proxy_client_read_ready, - .close_handler = nxt_conn_proxy_close, - .error_handler = nxt_conn_proxy_read_error, -}; - - -static void -nxt_conn_proxy_client_read_ready(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *client; - nxt_conn_proxy_t *p; - - client = obj; - p = data; - - nxt_debug(task, "conn proxy client read ready fd:%d", client->socket.fd); - - nxt_conn_proxy_read_process(task, p, client, p->peer); -} - - -static const nxt_conn_state_t nxt_conn_proxy_peer_read_state - nxt_aligned(64) = -{ - .ready_handler = nxt_conn_proxy_peer_read_ready, - .close_handler = nxt_conn_proxy_close, - .error_handler = nxt_conn_proxy_read_error, -}; - - -static void -nxt_conn_proxy_peer_read_ready(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *peer; - nxt_conn_proxy_t *p; - - peer = obj; - p = data; - - nxt_debug(task, "conn proxy peer read ready fd:%d", peer->socket.fd); - - nxt_conn_proxy_read_process(task, p, peer, p->client); -} - - -static void -nxt_conn_proxy_read_process(nxt_task_t *task, nxt_conn_proxy_t *p, - nxt_conn_t *source, nxt_conn_t *sink) -{ - nxt_buf_t *rb, *wb; - - if (sink->socket.error != 0) { - nxt_debug(task, "conn proxy sink fd:%d error:%d", - sink->socket.fd, sink->socket.error); - - nxt_conn_proxy_write_error(task, sink, sink->socket.data); - return; - } - - while (source->read != NULL) { - - rb = source->read; - - if (rb->mem.pos != rb->mem.free) { - - /* Add a read part to a write chain. */ - - wb = nxt_buf_mem_alloc(source->mem_pool, 0, 0); - if (wb == NULL) { - /* An error completion. */ - nxt_conn_proxy_complete(task, p); - return; - } - - wb->mem.pos = rb->mem.pos; - wb->mem.free = rb->mem.free; - wb->mem.start = rb->mem.pos; - wb->mem.end = rb->mem.free; - - rb->mem.pos = rb->mem.free; - rb->mem.start = rb->mem.free; - - nxt_conn_proxy_write_add(sink, wb); - } - - if (rb->mem.start != rb->mem.end) { - nxt_work_queue_add(source->read_work_queue, nxt_conn_proxy_read, - task, source, source->socket.data); - break; - } - - source->read = rb->next; - nxt_buf_free(source->mem_pool, rb); - } - - if (p->connected) { - nxt_conn_write(task->thread->engine, sink); - } -} - - -static void -nxt_conn_proxy_write_add(nxt_conn_t *c, nxt_buf_t *b) -{ - nxt_buf_t *first, *second, *prev; - - first = c->write; - - if (first == NULL) { - c->write = b; - return; - } - - /* - * A event conn proxy maintains a buffer per each direction. - * The buffer is divided by read and write parts. These parts are - * linked in buffer chains. There can be no more than two buffers - * in write chain at any time, because an added buffer is coalesced - * with the last buffer if possible. - */ - - second = first->next; - - if (second == NULL) { - - if (first->mem.end != b->mem.start) { - first->next = b; - return; - } - - /* - * The first buffer is just before the added buffer, so - * expand the first buffer to the end of the added buffer. - */ - prev = first; - - } else { - if (second->mem.end != b->mem.start) { - nxt_thread_log_alert("event conn proxy write: second buffer end:%p " - "is not equal to added buffer start:%p", - second->mem.end, b->mem.start); - return; - } - - /* - * "second->mem.end == b->mem.start" must be always true here, - * that is the second buffer is just before the added buffer, - * so expand the second buffer to the end of added buffer. - */ - prev = second; - } - - prev->mem.free = b->mem.end; - prev->mem.end = b->mem.end; - - nxt_buf_free(c->mem_pool, b); -} - - -static void -nxt_conn_proxy_read(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *source, *sink; - nxt_conn_proxy_t *p; - - source = obj; - p = data; - - nxt_debug(task, "conn proxy read fd:%d", source->socket.fd); - - if (!source->socket.closed) { - sink = (source == p->client) ? p->peer : p->client; - - if (sink->socket.error == 0) { - nxt_conn_read(task->thread->engine, source); - } - } -} - - -static const nxt_conn_state_t nxt_conn_proxy_client_write_state - nxt_aligned(64) = -{ - .ready_handler = nxt_conn_proxy_client_write_ready, - .error_handler = nxt_conn_proxy_write_error, - - .timer_handler = nxt_conn_proxy_write_timeout, - .timer_value = nxt_conn_proxy_timeout_value, - .timer_data = offsetof(nxt_conn_proxy_t, client_write_timeout), - .timer_autoreset = 1, -}; - - -static void -nxt_conn_proxy_client_write_ready(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *client; - nxt_conn_proxy_t *p; - - client = obj; - p = data; - - nxt_debug(task, "conn proxy client write ready fd:%d", client->socket.fd); - - nxt_conn_proxy_write_process(task, p, client, p->peer); -} - - -static const nxt_conn_state_t nxt_conn_proxy_peer_write_state - nxt_aligned(64) = -{ - .ready_handler = nxt_conn_proxy_peer_write_ready, - .error_handler = nxt_conn_proxy_write_error, - - .timer_handler = nxt_conn_proxy_write_timeout, - .timer_value = nxt_conn_proxy_timeout_value, - .timer_data = offsetof(nxt_conn_proxy_t, peer_write_timeout), - .timer_autoreset = 1, -}; - - -static void -nxt_conn_proxy_peer_write_ready(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *peer; - nxt_conn_proxy_t *p; - - peer = obj; - p = data; - - nxt_debug(task, "conn proxy peer write ready fd:%d", peer->socket.fd); - - nxt_conn_proxy_write_process(task, p, peer, p->client); -} - - -static void -nxt_conn_proxy_write_process(nxt_task_t *task, nxt_conn_proxy_t *p, - nxt_conn_t *sink, nxt_conn_t *source) -{ - nxt_buf_t *rb, *wb; - - while (sink->write != NULL) { - - wb = sink->write; - - if (nxt_buf_is_sync(wb)) { - - /* A sync buffer marks the end of stream. */ - - sink->write = NULL; - nxt_buf_free(sink->mem_pool, wb); - nxt_conn_proxy_shutdown(task, p, source, sink); - return; - } - - if (wb->mem.start != wb->mem.pos) { - - /* Add a written part to a read chain. */ - - rb = nxt_buf_mem_alloc(sink->mem_pool, 0, 0); - if (rb == NULL) { - /* An error completion. */ - nxt_conn_proxy_complete(task, p); - return; - } - - rb->mem.pos = wb->mem.start; - rb->mem.free = wb->mem.start; - rb->mem.start = wb->mem.start; - rb->mem.end = wb->mem.pos; - - wb->mem.start = wb->mem.pos; - - nxt_conn_proxy_read_add(source, rb); - } - - if (wb->mem.pos != wb->mem.free) { - nxt_conn_write(task->thread->engine, sink); - - break; - } - - sink->write = wb->next; - nxt_buf_free(sink->mem_pool, wb); - } - - nxt_work_queue_add(source->read_work_queue, nxt_conn_proxy_read, - task, source, source->socket.data); -} - - -static void -nxt_conn_proxy_read_add(nxt_conn_t *c, nxt_buf_t *b) -{ - nxt_buf_t *first, *second; - - first = c->read; - - if (first == NULL) { - c->read = b; - return; - } - - /* - * A event conn proxy maintains a buffer per each direction. - * The buffer is divided by read and write parts. These parts are - * linked in buffer chains. There can be no more than two buffers - * in read chain at any time, because an added buffer is coalesced - * with the last buffer if possible. The first and the second - * buffers are also coalesced if possible. - */ - - second = first->next; - - if (second == NULL) { - - if (first->mem.start == b->mem.end) { - /* - * The added buffer is just before the first buffer, so expand - * the first buffer to the beginning of the added buffer. - */ - first->mem.pos = b->mem.start; - first->mem.free = b->mem.start; - first->mem.start = b->mem.start; - - } else if (first->mem.end == b->mem.start) { - /* - * The added buffer is just after the first buffer, so - * expand the first buffer to the end of the added buffer. - */ - first->mem.end = b->mem.end; - - } else { - first->next = b; - return; - } - - } else { - if (second->mem.end != b->mem.start) { - nxt_thread_log_alert("event conn proxy read: second buffer end:%p " - "is not equal to added buffer start:%p", - second->mem.end, b->mem.start); - return; - } - - /* - * The added buffer is just after the second buffer, so - * expand the second buffer to the end of the added buffer. - */ - second->mem.end = b->mem.end; - - if (first->mem.start == second->mem.end) { - /* - * The second buffer is just before the first buffer, so expand - * the first buffer to the beginning of the second buffer. - */ - first->mem.pos = second->mem.start; - first->mem.free = second->mem.start; - first->mem.start = second->mem.start; - first->next = NULL; - - nxt_buf_free(c->mem_pool, second); - } - } - - nxt_buf_free(c->mem_pool, b); -} - - -static void -nxt_conn_proxy_close(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *b; - nxt_conn_t *source, *sink; - nxt_conn_proxy_t *p; - - source = obj; - p = data; - - nxt_debug(task, "conn proxy close fd:%d", source->socket.fd); - - sink = (source == p->client) ? p->peer : p->client; - - if (sink->write == NULL) { - nxt_conn_proxy_shutdown(task, p, source, sink); - return; - } - - b = nxt_buf_sync_alloc(source->mem_pool, 0); - if (b == NULL) { - /* An error completion. */ - nxt_conn_proxy_complete(task, p); - return; - } - - nxt_buf_chain_add(&sink->write, b); -} - - -static void -nxt_conn_proxy_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_conn_proxy_t *p; - - c = obj; - p = data; - - nxt_debug(task, "conn proxy error fd:%d", c->socket.fd); - - nxt_conn_proxy_close(task, c, p); -} - - -static void -nxt_conn_proxy_read_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - - timer = obj; - - c = nxt_read_timer_conn(timer); - c->socket.timedout = 1; - c->socket.closed = 1; - - nxt_debug(task, "conn proxy read timeout fd:%d", c->socket.fd); - - nxt_conn_proxy_close(task, c, c->socket.data); -} - - -static void -nxt_conn_proxy_write_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - - timer = obj; - - c = nxt_write_timer_conn(timer); - c->socket.timedout = 1; - c->socket.closed = 1; - - nxt_debug(task, "conn proxy write timeout fd:%d", c->socket.fd); - - nxt_conn_proxy_close(task, c, c->socket.data); -} - - -static nxt_msec_t -nxt_conn_proxy_timeout_value(nxt_conn_t *c, uintptr_t data) -{ - return nxt_value_at(nxt_msec_t, c->socket.data, data); -} - - -static void -nxt_conn_proxy_refused(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *peer; - nxt_conn_proxy_t *p; - - peer = obj; - p = data; - - nxt_debug(task, "conn proxy refused fd:%d", peer->socket.fd); - - if (p->retries == 0) { - /* An error completion. */ - nxt_conn_proxy_complete(task, p); - return; - } - - p->retries--; - - nxt_socket_close(task, peer->socket.fd); - peer->socket.fd = -1; - peer->socket.error = 0; - - p->delayed = 1; - - peer->write_timer.handler = nxt_conn_proxy_reconnect_handler; - nxt_timer_add(task->thread->engine, &peer->write_timer, - p->reconnect_timeout); -} - - -static void -nxt_conn_proxy_reconnect_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *peer; - nxt_timer_t *timer; - nxt_conn_proxy_t *p; - - timer = obj; - - nxt_debug(task, "conn proxy reconnect timer"); - - peer = nxt_write_timer_conn(timer); - p = peer->socket.data; - - if (p->client->socket.closed) { - nxt_conn_proxy_complete(task, p); - return; - } - - p->delayed = 0; - - peer->write_state = &nxt_conn_proxy_peer_connect_state; - /* - * Peer read event: disabled. - * Peer write event: waiting for connection with connect_timeout. - */ - nxt_conn_connect(task->thread->engine, peer); -} - - -static void -nxt_conn_proxy_shutdown(nxt_task_t *task, nxt_conn_proxy_t *p, - nxt_conn_t *source, nxt_conn_t *sink) -{ - nxt_buf_t *b; - - nxt_debug(source->socket.task, - "conn proxy shutdown source fd:%d cl:%d err:%d", - source->socket.fd, source->socket.closed, source->socket.error); - - nxt_debug(sink->socket.task, - "conn proxy shutdown sink fd:%d cl:%d err:%d", - sink->socket.fd, sink->socket.closed, sink->socket.error); - - if (!p->connected || p->delayed) { - nxt_conn_proxy_complete(task, p); - return; - } - - if (sink->socket.error == 0 && !sink->socket.closed) { - sink->socket.shutdown = 1; - nxt_socket_shutdown(task, sink->socket.fd, SHUT_WR); - } - - if (sink->socket.error != 0 - || (sink->socket.closed && source->write == NULL)) - { - /* The opposite direction also has been already closed. */ - nxt_conn_proxy_complete(task, p); - return; - } - - nxt_debug(source->socket.task, "free source buffer"); - - /* Free the direction's buffer. */ - b = (source == p->client) ? p->client_buffer : p->peer_buffer; - nxt_mp_free(source->mem_pool, b); -} - - -static void -nxt_conn_proxy_read_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_conn_proxy_t *p; - - c = obj; - p = data; - - nxt_debug(task, "conn proxy read error fd:%d", c->socket.fd); - - nxt_conn_proxy_close(task, c, p); -} - - -static void -nxt_conn_proxy_write_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *source, *sink; - nxt_conn_proxy_t *p; - - sink = obj; - p = data; - - nxt_debug(task, "conn proxy write error fd:%d", sink->socket.fd); - - /* Clear data for the direction sink. */ - sink->write = NULL; - - /* Block the direction source. */ - source = (sink == p->client) ? p->peer : p->client; - nxt_fd_event_block_read(task->thread->engine, &source->socket); - - if (source->write == NULL) { - /* - * There is no data for the opposite direction and - * the next read from the sink will most probably fail. - */ - nxt_conn_proxy_complete(task, p); - } -} - - -static const nxt_conn_state_t nxt_conn_proxy_close_state - nxt_aligned(64) = -{ - .ready_handler = nxt_conn_proxy_completion, -}; - - -static void -nxt_conn_proxy_complete(nxt_task_t *task, nxt_conn_proxy_t *p) -{ - nxt_event_engine_t *engine; - - engine = task->thread->engine; - - nxt_debug(p->client->socket.task, "conn proxy complete %d:%d", - p->client->socket.fd, p->peer->socket.fd); - - if (p->delayed) { - p->delayed = 0; - nxt_queue_remove(&p->peer->link); - } - - if (p->client->socket.fd != -1) { - p->retain = 1; - p->client->write_state = &nxt_conn_proxy_close_state; - nxt_conn_close(engine, p->client); - } - - if (p->peer->socket.fd != -1) { - p->retain++; - p->peer->write_state = &nxt_conn_proxy_close_state; - nxt_conn_close(engine, p->peer); - } -} - - -static void -nxt_conn_proxy_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_proxy_t *p; - - p = data; - - nxt_debug(p->client->socket.task, "conn proxy completion %d:%d:%d", - p->retain, p->client->socket.fd, p->peer->socket.fd); - - p->retain--; - - if (p->retain == 0) { - nxt_mp_free(p->client->mem_pool, p->client_buffer); - nxt_mp_free(p->client->mem_pool, p->peer_buffer); - - p->completion_handler(task, p, NULL); - } -} diff --git a/src/nxt_conn_read.c b/src/nxt_conn_read.c deleted file mode 100644 index 3285abcd..00000000 --- a/src/nxt_conn_read.c +++ /dev/null @@ -1,252 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -void -nxt_conn_wait(nxt_conn_t *c) -{ - nxt_event_engine_t *engine; - const nxt_conn_state_t *state; - - nxt_debug(c->socket.task, "conn wait fd:%d rdy:%d", - c->socket.fd, c->socket.read_ready); - - engine = c->socket.task->thread->engine; - state = c->read_state; - - if (c->socket.read_ready) { - nxt_work_queue_add(&engine->fast_work_queue, state->ready_handler, - c->socket.task, c, c->socket.data); - return; - } - - c->socket.read_handler = state->ready_handler; - c->socket.error_handler = state->error_handler; - - nxt_conn_timer(engine, c, state, &c->read_timer); - - nxt_fd_event_enable_read(engine, &c->socket); -} - - -void -nxt_conn_io_read(nxt_task_t *task, void *obj, void *data) -{ - ssize_t n; - nxt_conn_t *c; - nxt_event_engine_t *engine; - nxt_work_handler_t handler; - const nxt_conn_state_t *state; - - c = obj; - - nxt_debug(task, "conn read fd:%d rdy:%d cl:%d er:%d bl:%d", - c->socket.fd, c->socket.read_ready, c->socket.closed, - c->socket.error, c->block_read); - - if (c->socket.error != 0 || c->block_read) { - return; - } - - engine = task->thread->engine; - - /* - * Here c->io->read() is assigned instead of direct nxt_conn_io_read() - * because the function can be called by nxt_kqueue_conn_io_read(). - */ - c->socket.read_handler = c->io->read; - state = c->read_state; - c->socket.error_handler = state->error_handler; - - if (c->socket.read_ready) { - - if (state->io_read_handler == NULL) { - n = c->io->recvbuf(c, c->read); - - } else { - n = state->io_read_handler(task, c); - /* The state can be changed by io_read_handler. */ - state = c->read_state; - } - - if (n > 0) { - c->nbytes = n; - - nxt_recvbuf_update(c->read, n); - - nxt_fd_event_block_read(engine, &c->socket); - - if (state->timer_autoreset) { - nxt_timer_disable(engine, &c->read_timer); - } - - nxt_work_queue_add(c->read_work_queue, - state->ready_handler, task, c, data); - return; - } - - if (n != NXT_AGAIN) { - /* n == 0 or n == NXT_ERROR. */ - handler = (n == 0) ? state->close_handler : state->error_handler; - - nxt_fd_event_block_read(engine, &c->socket); - nxt_timer_disable(engine, &c->read_timer); - - nxt_work_queue_add(&engine->fast_work_queue, - handler, task, c, data); - return; - } - - /* n == NXT_AGAIN. */ - - if (c->socket.read_ready) { - /* - * SSL/TLS library can return NXT_AGAIN if renegotiation - * occured during read operation, it toggled write event - * internally so only read timer should be set. - */ - if (!c->read_timer.enabled) { - nxt_conn_timer(engine, c, state, &c->read_timer); - } - - return; - } - } - - if (nxt_fd_event_is_disabled(c->socket.read)) { - nxt_fd_event_enable_read(engine, &c->socket); - } - - if (state->timer_autoreset || !c->read_timer.enabled) { - nxt_conn_timer(engine, c, state, &c->read_timer); - } -} - - -ssize_t -nxt_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b) -{ - ssize_t n; - nxt_err_t err; - nxt_uint_t niov; - struct iovec iov[NXT_IOBUF_MAX]; - nxt_recvbuf_coalesce_t rb; - - rb.buf = b; - rb.iobuf = iov; - rb.nmax = NXT_IOBUF_MAX; - rb.size = 0; - - niov = nxt_recvbuf_mem_coalesce(&rb); - - if (niov == 1) { - /* Disposal of surplus kernel iovec copy-in operation. */ - return nxt_conn_io_recv(c, iov->iov_base, iov->iov_len, 0); - } - - for ( ;; ) { - n = readv(c->socket.fd, iov, niov); - - err = (n == -1) ? nxt_socket_errno : 0; - - nxt_debug(c->socket.task, "readv(%d, %ui): %z", c->socket.fd, niov, n); - - if (n > 0) { - if ((size_t) n < rb.size) { - c->socket.read_ready = 0; - } - - return n; - } - - if (n == 0) { - c->socket.closed = 1; - c->socket.read_ready = 0; - return n; - } - - /* n == -1 */ - - switch (err) { - - case NXT_EAGAIN: - nxt_debug(c->socket.task, "readv() %E", err); - c->socket.read_ready = 0; - return NXT_AGAIN; - - case NXT_EINTR: - nxt_debug(c->socket.task, "readv() %E", err); - continue; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "readv(%d, %ui) failed %E", c->socket.fd, niov, err); - - return NXT_ERROR; - } - } -} - - -ssize_t -nxt_conn_io_recv(nxt_conn_t *c, void *buf, size_t size, nxt_uint_t flags) -{ - ssize_t n; - nxt_err_t err; - - for ( ;; ) { - n = recv(c->socket.fd, buf, size, flags); - - err = (n == -1) ? nxt_socket_errno : 0; - - nxt_debug(c->socket.task, "recv(%d, %p, %uz, 0x%ui): %z", - c->socket.fd, buf, size, flags, n); - - if (n > 0) { - if ((size_t) n < size && (flags & MSG_PEEK) == 0) { - c->socket.read_ready = 0; - } - - return n; - } - - if (n == 0) { - c->socket.closed = 1; - - if ((flags & MSG_PEEK) == 0) { - c->socket.read_ready = 0; - } - - return n; - } - - /* n == -1 */ - - switch (err) { - - case NXT_EAGAIN: - nxt_debug(c->socket.task, "recv() %E", err); - c->socket.read_ready = 0; - - return NXT_AGAIN; - - case NXT_EINTR: - nxt_debug(c->socket.task, "recv() %E", err); - continue; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "recv(%d, %p, %uz, %ui) failed %E", - c->socket.fd, buf, size, flags, err); - - return NXT_ERROR; - } - } -} diff --git a/src/nxt_conn_write.c b/src/nxt_conn_write.c deleted file mode 100644 index 7d0a579f..00000000 --- a/src/nxt_conn_write.c +++ /dev/null @@ -1,544 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static void nxt_conn_write_timer_handler(nxt_task_t *task, void *obj, - void *data); -static ssize_t nxt_conn_io_sendfile(nxt_task_t *task, nxt_sendbuf_t *sb); -static ssize_t nxt_sendfile(int fd, int s, off_t pos, size_t size); - - -void -nxt_conn_io_write(nxt_task_t *task, void *obj, void *data) -{ - ssize_t ret; - nxt_buf_t *b; - nxt_conn_t *c; - nxt_sendbuf_t sb; - nxt_event_engine_t *engine; - - c = obj; - - nxt_debug(task, "conn write fd:%d er:%d bl:%d", - c->socket.fd, c->socket.error, c->block_write); - - if (c->socket.error != 0 || c->block_write) { - goto error; - } - - if (!c->socket.write_ready || c->write == NULL) { - return; - } - - engine = task->thread->engine; - - c->socket.write_handler = nxt_conn_io_write; - c->socket.error_handler = c->write_state->error_handler; - - b = c->write; - - sb.socket = c->socket.fd; - sb.error = 0; - sb.sent = 0; - sb.size = 0; - sb.buf = b; -#if (NXT_TLS) - sb.tls = c->u.tls; -#endif - sb.limit = 10 * 1024 * 1024; - sb.ready = 1; - sb.sync = 0; - - do { - ret = c->io->sendbuf(task, &sb); - - c->socket.write_ready = sb.ready; - c->socket.error = sb.error; - - if (ret < 0) { - /* ret == NXT_AGAIN || ret == NXT_ERROR. */ - break; - } - - sb.sent += ret; - sb.limit -= ret; - - b = nxt_sendbuf_update(b, ret); - - if (b == NULL) { - nxt_fd_event_block_write(engine, &c->socket); - break; - } - - sb.buf = b; - - if (!c->socket.write_ready) { - ret = NXT_AGAIN; - break; - } - - } while (sb.limit != 0); - - nxt_debug(task, "event conn: %z sent:%O", ret, sb.sent); - - if (sb.sent != 0) { - if (c->write_state->timer_autoreset) { - nxt_timer_disable(engine, &c->write_timer); - } - } - - if (ret != NXT_ERROR) { - - if (sb.limit == 0) { - /* - * Postpone writing until next event poll to allow to - * process other received events and to get new events. - */ - c->write_timer.handler = nxt_conn_write_timer_handler; - nxt_timer_add(engine, &c->write_timer, 0); - - } else if (ret == NXT_AGAIN) { - /* - * SSL libraries can require to toggle either write or read - * event if renegotiation occurs during SSL write operation. - * This case is handled on the c->io->send() level. Timer - * can be set here because it should be set only for write - * direction. - */ - nxt_conn_timer(engine, c, c->write_state, &c->write_timer); - - if (nxt_fd_event_is_disabled(c->socket.write)) { - nxt_fd_event_enable_write(engine, &c->socket); - } - } - } - - if (ret == 0 || sb.sent != 0) { - /* - * ret == 0 means a sync buffer was processed. - * ret == NXT_ERROR is ignored here if some data was sent, - * the error will be handled on the next nxt_conn_write() call. - */ - c->sent += sb.sent; - nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler, - task, c, data); - return; - } - - if (ret != NXT_ERROR) { - return; - } - - nxt_fd_event_block_write(engine, &c->socket); - -error: - - nxt_work_queue_add(c->write_work_queue, c->write_state->error_handler, - task, c, data); -} - - -static void -nxt_conn_write_timer_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - - timer = obj; - - nxt_debug(task, "conn write timer"); - - c = nxt_write_timer_conn(timer); - c->delayed = 0; - - c->io->write(task, c, c->socket.data); -} - - -ssize_t -nxt_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb) -{ - nxt_uint_t niov; - struct iovec iov[NXT_IOBUF_MAX]; - - niov = nxt_sendbuf_mem_coalesce0(task, sb, iov, NXT_IOBUF_MAX); - - if (niov == 0 && sb->sync) { - return 0; - } - - /* - * XXX Temporary fix for - */ - if (niov == 0 && sb->buf == NULL) { - return 0; - } - - if (niov == 0 && nxt_buf_is_file(sb->buf)) { - return nxt_conn_io_sendfile(task, sb); - } - - return nxt_conn_io_writev(task, sb, iov, niov); -} - - -static ssize_t -nxt_conn_io_sendfile(nxt_task_t *task, nxt_sendbuf_t *sb) -{ - size_t size; - ssize_t n; - nxt_buf_t *b; - nxt_err_t err; - - b = sb->buf; - - for ( ;; ) { - size = b->file_end - b->file_pos; - - n = nxt_sendfile(b->file->fd, sb->socket, b->file_pos, size); - - err = (n == -1) ? nxt_errno : 0; - - nxt_debug(task, "sendfile(%FD, %d, @%O, %uz): %z", - b->file->fd, sb->socket, b->file_pos, size, n); - - if (n > 0) { - if (n < (ssize_t) size) { - sb->ready = 0; - } - - return n; - } - - if (nxt_slow_path(n == 0)) { - nxt_alert(task, "sendfile() reported that file was truncated at %O", - b->file_pos); - - return NXT_ERROR; - } - - /* n == -1 */ - - switch (err) { - - case NXT_EAGAIN: - sb->ready = 0; - nxt_debug(task, "sendfile() %E", err); - - return NXT_AGAIN; - - case NXT_EINTR: - nxt_debug(task, "sendfile() %E", err); - continue; - - default: - sb->error = err; - nxt_log(task, nxt_socket_error_level(err), - "sendfile(%FD, %d, @%O, %uz) failed %E", - b->file->fd, sb->socket, b->file_pos, size, err); - - return NXT_ERROR; - } - } -} - - -static ssize_t -nxt_sendfile(int fd, int s, off_t pos, size_t size) -{ - ssize_t res; - -#if (NXT_HAVE_MACOSX_SENDFILE) - - off_t sent = size; - - int rc = sendfile(fd, s, pos, &sent, NULL, 0); - - res = (rc == 0 || sent > 0) ? sent : -1; - -#elif (NXT_HAVE_FREEBSD_SENDFILE) - - off_t sent = 0; - - int rc = sendfile(fd, s, pos, size, NULL, &sent, 0); - - res = (rc == 0 || sent > 0) ? sent : -1; - -#elif (NXT_HAVE_LINUX_SENDFILE) - - res = sendfile(s, fd, &pos, size); - -#else - - int err; - void *map; - off_t page_off; - - page_off = pos % nxt_pagesize; - - map = nxt_mem_mmap(NULL, size + page_off, PROT_READ, MAP_SHARED, fd, - pos - page_off); - if (nxt_slow_path(map == MAP_FAILED)) { - return -1; - } - - res = write(s, nxt_pointer_to(map, page_off), size); - - /* Backup and restore errno to catch socket errors in the upper level. */ - err = errno; - nxt_mem_munmap(map, size + page_off); - errno = err; - -#endif - - return res; -} - - -ssize_t -nxt_conn_io_writev(nxt_task_t *task, nxt_sendbuf_t *sb, struct iovec *iov, - nxt_uint_t niov) -{ - ssize_t n; - nxt_err_t err; - - if (niov == 1) { - /* Disposal of surplus kernel iovec copy-in operation. */ - return nxt_conn_io_send(task, sb, iov[0].iov_base, iov[0].iov_len); - } - - for ( ;; ) { - n = writev(sb->socket, iov, niov); - - err = (n == -1) ? nxt_socket_errno : 0; - - nxt_debug(task, "writev(%d, %ui): %z", sb->socket, niov, n); - - if (n > 0) { - return n; - } - - /* n == -1 */ - - switch (err) { - - case NXT_EAGAIN: - sb->ready = 0; - nxt_debug(task, "writev() %E", err); - - return NXT_AGAIN; - - case NXT_EINTR: - nxt_debug(task, "writev() %E", err); - continue; - - default: - sb->error = err; - nxt_log(task, nxt_socket_error_level(err), - "writev(%d, %ui) failed %E", sb->socket, niov, err); - - return NXT_ERROR; - } - } -} - - -ssize_t -nxt_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf, size_t size) -{ - ssize_t n; - nxt_err_t err; - - for ( ;; ) { - n = send(sb->socket, buf, size, 0); - - err = (n == -1) ? nxt_socket_errno : 0; - - nxt_debug(task, "send(%d, %p, %uz): %z", sb->socket, buf, size, n); - - if (n > 0) { - return n; - } - - /* n == -1 */ - - switch (err) { - - case NXT_EAGAIN: - sb->ready = 0; - nxt_debug(task, "send() %E", err); - - return NXT_AGAIN; - - case NXT_EINTR: - nxt_debug(task, "send() %E", err); - continue; - - default: - sb->error = err; - nxt_log(task, nxt_socket_error_level(err), - "send(%d, %p, %uz) failed %E", sb->socket, buf, size, err); - - return NXT_ERROR; - } - } -} - - -/* Obsolete interfaces. */ - -size_t -nxt_event_conn_write_limit(nxt_conn_t *c) -{ - ssize_t limit, correction; - nxt_event_write_rate_t *rate; - - rate = c->rate; - - if (rate == NULL) { - return c->max_chunk; - } - - limit = rate->limit; - correction = limit - (size_t) rate->average; - - nxt_debug(c->socket.task, "event conn correction:%z average:%0.3f", - correction, rate->average); - - limit += correction; - - if (limit <= 0) { - return 0; - } - - if (rate->limit_after != 0) { - limit += rate->limit_after; - limit = nxt_min((size_t) limit, rate->max_limit); - } - - return nxt_min((size_t) limit, c->max_chunk); -} - - -nxt_bool_t -nxt_event_conn_write_delayed(nxt_event_engine_t *engine, nxt_conn_t *c, - size_t sent) -{ - return 0; -} - - -ssize_t -nxt_event_conn_io_sendbuf(nxt_conn_t *c, nxt_buf_t *b, size_t limit) -{ - nxt_uint_t niob; - struct iovec iob[NXT_IOBUF_MAX]; - nxt_sendbuf_coalesce_t sb; - - sb.buf = b; - sb.iobuf = iob; - sb.nmax = NXT_IOBUF_MAX; - sb.sync = 0; - sb.size = 0; - sb.limit = limit; - - niob = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); - - if (niob == 0 && sb.sync) { - return 0; - } - - return nxt_event_conn_io_writev(c, iob, niob); -} - - -ssize_t -nxt_event_conn_io_writev(nxt_conn_t *c, nxt_iobuf_t *iob, nxt_uint_t niob) -{ - ssize_t n; - nxt_err_t err; - - if (niob == 1) { - /* Disposal of surplus kernel iovec copy-in operation. */ - return nxt_event_conn_io_send(c, iob->iov_base, iob->iov_len); - } - - for ( ;; ) { - n = writev(c->socket.fd, iob, niob); - - err = (n == -1) ? nxt_socket_errno : 0; - - nxt_debug(c->socket.task, "writev(%d, %ui): %z", c->socket.fd, niob, n); - - if (n > 0) { - return n; - } - - /* n == -1 */ - - switch (err) { - - case NXT_EAGAIN: - nxt_debug(c->socket.task, "writev() %E", err); - c->socket.write_ready = 0; - return NXT_AGAIN; - - case NXT_EINTR: - nxt_debug(c->socket.task, "writev() %E", err); - continue; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "writev(%d, %ui) failed %E", c->socket.fd, niob, err); - return NXT_ERROR; - } - } -} - - -ssize_t -nxt_event_conn_io_send(nxt_conn_t *c, void *buf, size_t size) -{ - ssize_t n; - nxt_err_t err; - - for ( ;; ) { - n = send(c->socket.fd, buf, size, 0); - - err = (n == -1) ? nxt_socket_errno : 0; - - nxt_debug(c->socket.task, "send(%d, %p, %uz): %z", - c->socket.fd, buf, size, n); - - if (n > 0) { - return n; - } - - /* n == -1 */ - - switch (err) { - - case NXT_EAGAIN: - nxt_debug(c->socket.task, "send() %E", err); - c->socket.write_ready = 0; - return NXT_AGAIN; - - case NXT_EINTR: - nxt_debug(c->socket.task, "send() %E", err); - continue; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "send(%d, %p, %uz) failed %E", - c->socket.fd, buf, size, err); - return NXT_ERROR; - } - } -} diff --git a/src/nxt_controller.c b/src/nxt_controller.c deleted file mode 100644 index eb814321..00000000 --- a/src/nxt_controller.c +++ /dev/null @@ -1,2665 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include - - -typedef struct { - nxt_conf_value_t *root; - nxt_mp_t *pool; -} nxt_controller_conf_t; - - -typedef struct { - nxt_http_request_parse_t parser; - size_t length; - nxt_controller_conf_t conf; - nxt_conn_t *conn; - nxt_queue_link_t link; -} nxt_controller_request_t; - - -typedef struct { - nxt_uint_t status; - nxt_conf_value_t *conf; - - u_char *title; - nxt_str_t detail; - ssize_t offset; - nxt_uint_t line; - nxt_uint_t column; -} nxt_controller_response_t; - - -static nxt_int_t nxt_controller_prefork(nxt_task_t *task, - nxt_process_t *process, nxt_mp_t *mp); -static nxt_int_t nxt_controller_file_read(nxt_task_t *task, const char *name, - nxt_str_t *str, nxt_mp_t *mp); -static nxt_int_t nxt_controller_start(nxt_task_t *task, - nxt_process_data_t *data); -static void nxt_controller_process_new_port_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_controller_send_current_conf(nxt_task_t *task); -static void nxt_controller_router_ready_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_controller_remove_pid_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static nxt_int_t nxt_controller_conf_default(void); -static void nxt_controller_conf_init_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_controller_flush_requests(nxt_task_t *task); -static nxt_int_t nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *conf, nxt_port_rpc_handler_t handler, void *data); - -static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data); -static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data); -static nxt_msec_t nxt_controller_conn_timeout_value(nxt_conn_t *c, - uintptr_t data); -static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj, - void *data); -static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, - void *data); -static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj, - void *data); -static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data); -static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj, - void *data); -static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, - void *data); -static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data); -static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data); - -static nxt_int_t nxt_controller_request_content_length(void *ctx, - nxt_http_field_t *field, uintptr_t data); - -static void nxt_controller_process_request(nxt_task_t *task, - nxt_controller_request_t *req); -static void nxt_controller_process_config(nxt_task_t *task, - nxt_controller_request_t *req, nxt_str_t *path); -static nxt_bool_t nxt_controller_check_postpone_request(nxt_task_t *task); -static void nxt_controller_process_status(nxt_task_t *task, - nxt_controller_request_t *req); -static void nxt_controller_status_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_controller_status_response(nxt_task_t *task, - nxt_controller_request_t *req, nxt_str_t *path); -#if (NXT_TLS) -static void nxt_controller_process_cert(nxt_task_t *task, - nxt_controller_request_t *req, nxt_str_t *path); -static void nxt_controller_process_cert_save(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static nxt_bool_t nxt_controller_cert_in_use(nxt_str_t *name); -static void nxt_controller_cert_cleanup(nxt_task_t *task, void *obj, - void *data); -#endif -#if (NXT_HAVE_NJS) -static void nxt_controller_process_script(nxt_task_t *task, - nxt_controller_request_t *req, nxt_str_t *path); -static void nxt_controller_process_script_save(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static nxt_bool_t nxt_controller_script_in_use(nxt_str_t *name); -static void nxt_controller_script_cleanup(nxt_task_t *task, void *obj, - void *data); -#endif -static void nxt_controller_process_control(nxt_task_t *task, - nxt_controller_request_t *req, nxt_str_t *path); -static void nxt_controller_app_restart_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_controller_conf_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_controller_conf_store(nxt_task_t *task, - nxt_conf_value_t *conf); -static void nxt_controller_response(nxt_task_t *task, - nxt_controller_request_t *req, nxt_controller_response_t *resp); -static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now, - struct tm *tm, size_t size, const char *format); - - -static nxt_http_field_proc_t nxt_controller_request_fields[] = { - { nxt_string("Content-Length"), - &nxt_controller_request_content_length, 0 }, -}; - -static nxt_lvlhsh_t nxt_controller_fields_hash; - -static nxt_uint_t nxt_controller_listening; -static nxt_uint_t nxt_controller_router_ready; -static nxt_controller_conf_t nxt_controller_conf; -static nxt_queue_t nxt_controller_waiting_requests; -static nxt_bool_t nxt_controller_waiting_init_conf; -static nxt_conf_value_t *nxt_controller_status; - - -static const nxt_event_conn_state_t nxt_controller_conn_read_state; -static const nxt_event_conn_state_t nxt_controller_conn_body_read_state; -static const nxt_event_conn_state_t nxt_controller_conn_write_state; -static const nxt_event_conn_state_t nxt_controller_conn_close_state; - - -static const nxt_port_handlers_t nxt_controller_process_port_handlers = { - .quit = nxt_signal_quit_handler, - .new_port = nxt_controller_process_new_port_handler, - .change_file = nxt_port_change_log_file_handler, - .mmap = nxt_port_mmap_handler, - .process_ready = nxt_controller_router_ready_handler, - .data = nxt_port_data_handler, - .remove_pid = nxt_controller_remove_pid_handler, - .rpc_ready = nxt_port_rpc_handler, - .rpc_error = nxt_port_rpc_handler, -}; - - -const nxt_process_init_t nxt_controller_process = { - .name = "controller", - .type = NXT_PROCESS_CONTROLLER, - .prefork = nxt_controller_prefork, - .restart = 1, - .setup = nxt_process_core_setup, - .start = nxt_controller_start, - .port_handlers = &nxt_controller_process_port_handlers, - .signals = nxt_process_signals, -}; - - -static nxt_int_t -nxt_controller_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp) -{ - nxt_str_t ver; - nxt_int_t ret, num; - nxt_runtime_t *rt; - nxt_controller_init_t ctrl_init; - - nxt_log(task, NXT_LOG_INFO, "controller started"); - - rt = task->thread->runtime; - - nxt_memzero(&ctrl_init, sizeof(nxt_controller_init_t)); - - /* - * Since configuration version has only been introduced in 1.26, - * set the default version to 1.25. - */ - nxt_conf_ver = 12500; - - ret = nxt_controller_file_read(task, rt->conf, &ctrl_init.conf, mp); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NXT_ERROR; - } - - if (ret == NXT_OK) { - ret = nxt_controller_file_read(task, rt->ver, &ver, mp); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NXT_ERROR; - } - - if (ret == NXT_OK) { - num = nxt_int_parse(ver.start, ver.length); - - if (nxt_slow_path(num < 0)) { - nxt_alert(task, "failed to restore previous configuration: " - "invalid version string \"%V\"", &ver); - - nxt_str_null(&ctrl_init.conf); - - } else { - nxt_conf_ver = num; - } - } - } - -#if (NXT_TLS) - ctrl_init.certs = nxt_cert_store_load(task, mp); - - nxt_mp_cleanup(mp, nxt_controller_cert_cleanup, task, ctrl_init.certs, rt); -#endif - -#if (NXT_HAVE_NJS) - ctrl_init.scripts = nxt_script_store_load(task, mp); - - nxt_mp_cleanup(mp, nxt_controller_script_cleanup, task, ctrl_init.scripts, - rt); -#endif - - process->data.controller = ctrl_init; - - return NXT_OK; -} - - -static nxt_int_t -nxt_controller_file_read(nxt_task_t *task, const char *name, nxt_str_t *str, - nxt_mp_t *mp) -{ - ssize_t n; - nxt_int_t ret; - nxt_file_t file; - nxt_file_info_t fi; - - nxt_memzero(&file, sizeof(nxt_file_t)); - - file.name = (nxt_file_name_t *) name; - - ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); - - if (ret == NXT_OK) { - ret = nxt_file_info(&file, &fi); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - if (nxt_fast_path(nxt_is_file(&fi))) { - str->length = nxt_file_size(&fi); - str->start = nxt_mp_nget(mp, str->length); - if (nxt_slow_path(str->start == NULL)) { - goto fail; - } - - n = nxt_file_read(&file, str->start, str->length, 0); - if (nxt_slow_path(n != (ssize_t) str->length)) { - goto fail; - } - - nxt_file_close(task, &file); - - return NXT_OK; - } - - nxt_file_close(task, &file); - } - - return NXT_DECLINED; - -fail: - - nxt_file_close(task, &file); - - return NXT_ERROR; -} - - -#if (NXT_TLS) - -static void -nxt_controller_cert_cleanup(nxt_task_t *task, void *obj, void *data) -{ - pid_t main_pid; - nxt_array_t *certs; - nxt_runtime_t *rt; - - certs = obj; - rt = data; - - main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid; - - if (nxt_pid == main_pid && certs != NULL) { - nxt_cert_store_release(certs); - } -} - -#endif - - -static nxt_int_t -nxt_controller_start(nxt_task_t *task, nxt_process_data_t *data) -{ - nxt_mp_t *mp; - nxt_int_t ret; - nxt_str_t *json; - nxt_conf_value_t *conf; - nxt_conf_validation_t vldt; - nxt_controller_init_t *init; - - ret = nxt_http_fields_hash(&nxt_controller_fields_hash, - nxt_controller_request_fields, - nxt_nitems(nxt_controller_request_fields)); - - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - nxt_queue_init(&nxt_controller_waiting_requests); - - init = &data->controller; - -#if (NXT_TLS) - if (init->certs != NULL) { - nxt_cert_info_init(task, init->certs); - nxt_cert_store_release(init->certs); - } -#endif - -#if (NXT_HAVE_NJS) - if (init->scripts != NULL) { - nxt_script_info_init(task, init->scripts); - nxt_script_store_release(init->scripts); - } -#endif - - json = &init->conf; - - if (json->start == NULL) { - return NXT_OK; - } - - mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { - return NXT_ERROR; - } - - conf = nxt_conf_json_parse_str(mp, json); - if (nxt_slow_path(conf == NULL)) { - nxt_alert(task, "failed to restore previous configuration: " - "file is corrupted or not enough memory"); - - nxt_mp_destroy(mp); - return NXT_OK; - } - - nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); - - vldt.pool = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(vldt.pool == NULL)) { - nxt_mp_destroy(mp); - return NXT_ERROR; - } - - vldt.conf = conf; - vldt.conf_pool = mp; - vldt.ver = nxt_conf_ver; - - ret = nxt_conf_validate(&vldt); - - if (nxt_slow_path(ret != NXT_OK)) { - - if (ret == NXT_DECLINED) { - nxt_alert(task, "the previous configuration is invalid: %V", - &vldt.error); - - nxt_mp_destroy(vldt.pool); - nxt_mp_destroy(mp); - - return NXT_OK; - } - - /* ret == NXT_ERROR */ - - return NXT_ERROR; - } - - nxt_mp_destroy(vldt.pool); - - nxt_controller_conf.root = conf; - nxt_controller_conf.pool = mp; - - return NXT_OK; -} - - -static void -nxt_controller_process_new_port_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg) -{ - nxt_port_new_port_handler(task, msg); - - if (msg->u.new_port->type != NXT_PROCESS_ROUTER - || !nxt_controller_router_ready) - { - return; - } - - nxt_controller_send_current_conf(task); -} - - -static void -nxt_controller_send_current_conf(nxt_task_t *task) -{ - nxt_int_t rc; - nxt_runtime_t *rt; - nxt_conf_value_t *conf; - - conf = nxt_controller_conf.root; - - if (conf != NULL) { - rc = nxt_controller_conf_send(task, nxt_controller_conf.pool, conf, - nxt_controller_conf_init_handler, NULL); - - if (nxt_fast_path(rc == NXT_OK)) { - nxt_controller_waiting_init_conf = 1; - - return; - } - - nxt_mp_destroy(nxt_controller_conf.pool); - - if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { - nxt_abort(); - } - } - - if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { - nxt_abort(); - } - - rt = task->thread->runtime; - - if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) { - nxt_abort(); - } - - nxt_controller_listening = 1; - - nxt_controller_flush_requests(task); -} - - -static void -nxt_controller_router_ready_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg) -{ - nxt_port_t *router_port; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - nxt_controller_router_ready = 1; - - if (router_port != NULL) { - nxt_controller_send_current_conf(task); - } -} - - -static void -nxt_controller_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_pid_t pid; - nxt_process_t *process; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - nxt_assert(nxt_buf_used_size(msg->buf) == sizeof(pid)); - - nxt_memcpy(&pid, msg->buf->mem.pos, sizeof(pid)); - - process = nxt_runtime_process_find(rt, pid); - if (process != NULL && nxt_process_type(process) == NXT_PROCESS_ROUTER) { - nxt_controller_router_ready = 0; - } - - nxt_port_remove_pid_handler(task, msg); -} - - -static nxt_int_t -nxt_controller_conf_default(void) -{ - nxt_mp_t *mp; - nxt_conf_value_t *conf; - - static const nxt_str_t json = nxt_string( - "{ \"listeners\": {}, \"routes\": [], \"applications\": {} }" - ); - - mp = nxt_mp_create(1024, 128, 256, 32); - - if (nxt_slow_path(mp == NULL)) { - return NXT_ERROR; - } - - conf = nxt_conf_json_parse_str(mp, &json); - - if (nxt_slow_path(conf == NULL)) { - return NXT_ERROR; - } - - nxt_controller_conf.root = conf; - nxt_controller_conf.pool = mp; - - return NXT_OK; -} - - -static void -nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_runtime_t *rt; - - nxt_controller_waiting_init_conf = 0; - - if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) { - nxt_alert(task, "failed to apply previous configuration"); - - nxt_mp_destroy(nxt_controller_conf.pool); - - if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { - nxt_abort(); - } - } - - if (nxt_controller_listening == 0) { - rt = task->thread->runtime; - - if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) - == NULL)) - { - nxt_abort(); - } - - nxt_controller_listening = 1; - } - - nxt_controller_flush_requests(task); -} - - -static void -nxt_controller_flush_requests(nxt_task_t *task) -{ - nxt_queue_t queue; - nxt_controller_request_t *req; - - nxt_queue_init(&queue); - nxt_queue_add(&queue, &nxt_controller_waiting_requests); - - nxt_queue_init(&nxt_controller_waiting_requests); - - nxt_queue_each(req, &queue, nxt_controller_request_t, link) { - nxt_controller_process_request(task, req); - } nxt_queue_loop; -} - - -static nxt_int_t -nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *conf, - nxt_port_rpc_handler_t handler, void *data) -{ - void *mem; - u_char *end; - size_t size; - uint32_t stream; - nxt_fd_t fd; - nxt_int_t rc; - nxt_buf_t *b; - nxt_port_t *router_port, *controller_port; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - nxt_assert(router_port != NULL); - nxt_assert(nxt_controller_router_ready); - - controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; - - size = nxt_conf_json_length(conf, NULL); - - b = nxt_buf_mem_alloc(mp, sizeof(size_t), 0); - if (nxt_slow_path(b == NULL)) { - return NXT_ERROR; - } - - fd = nxt_shm_open(task, size); - if (nxt_slow_path(fd == -1)) { - return NXT_ERROR; - } - - mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (nxt_slow_path(mem == MAP_FAILED)) { - goto fail; - } - - end = nxt_conf_json_print(mem, conf, NULL); - - nxt_mem_munmap(mem, size); - - size = end - (u_char *) mem; - - b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t)); - - stream = nxt_port_rpc_register_handler(task, controller_port, - handler, handler, - router_port->pid, data); - if (nxt_slow_path(stream == 0)) { - goto fail; - } - - rc = nxt_port_socket_write(task, router_port, - NXT_PORT_MSG_DATA_LAST | NXT_PORT_MSG_CLOSE_FD, - fd, stream, controller_port->id, b); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_port_rpc_cancel(task, controller_port, stream); - - goto fail; - } - - return NXT_OK; - -fail: - - nxt_fd_close(fd); - - return NXT_ERROR; -} - - -nxt_int_t -nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt) -{ - nxt_listen_socket_t *ls; - - ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t)); - if (ls == NULL) { - return NXT_ERROR; - } - - ls->sockaddr = rt->controller_listen; - - nxt_listen_socket_remote_size(ls); - - ls->socket = -1; - ls->backlog = NXT_LISTEN_BACKLOG; - ls->read_after_accept = 1; - ls->flags = NXT_NONBLOCK; - -#if 0 - /* STUB */ - wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t)); - if (wq == NULL) { - return NXT_ERROR; - } - nxt_work_queue_name(wq, "listen"); - /**/ - - ls->work_queue = wq; -#endif - ls->handler = nxt_controller_conn_init; - -#if (NXT_HAVE_UNIX_DOMAIN) - if (ls->sockaddr->u.sockaddr.sa_family == AF_UNIX) { - const char *path = ls->sockaddr->u.sockaddr_un.sun_path; - - nxt_fs_mkdir_parent((const u_char *) path, 0755); - } -#endif - - if (nxt_listen_socket_create(task, rt->mem_pool, ls) != NXT_OK) { - return NXT_ERROR; - } - - rt->controller_socket = ls; - - return NXT_OK; -} - - -static void -nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *b; - nxt_conn_t *c; - nxt_event_engine_t *engine; - nxt_controller_request_t *r; - - c = obj; - - nxt_debug(task, "controller conn init fd:%d", c->socket.fd); - - r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t)); - if (nxt_slow_path(r == NULL)) { - nxt_controller_conn_free(task, c, NULL); - return; - } - - r->conn = c; - - if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool) - != NXT_OK)) - { - nxt_controller_conn_free(task, c, NULL); - return; - } - - r->parser.encoded_slashes = 1; - - b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0); - if (nxt_slow_path(b == NULL)) { - nxt_controller_conn_free(task, c, NULL); - return; - } - - c->read = b; - c->socket.data = r; - c->socket.read_ready = 1; - c->read_state = &nxt_controller_conn_read_state; - - engine = task->thread->engine; - c->read_work_queue = &engine->read_work_queue; - c->write_work_queue = &engine->write_work_queue; - - nxt_conn_read(engine, c); -} - - -static const nxt_event_conn_state_t nxt_controller_conn_read_state - nxt_aligned(64) = -{ - .ready_handler = nxt_controller_conn_read, - .close_handler = nxt_controller_conn_close, - .error_handler = nxt_controller_conn_read_error, - - .timer_handler = nxt_controller_conn_read_timeout, - .timer_value = nxt_controller_conn_timeout_value, - .timer_data = 300 * 1000, -}; - - -static void -nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data) -{ - size_t preread; - nxt_buf_t *b; - nxt_int_t rc; - nxt_conn_t *c; - nxt_controller_request_t *r; - - c = obj; - r = data; - - nxt_debug(task, "controller conn read"); - - nxt_queue_remove(&c->link); - nxt_queue_self(&c->link); - - b = c->read; - - rc = nxt_http_parse_request(&r->parser, &b->mem); - - if (nxt_slow_path(rc != NXT_DONE)) { - - if (rc == NXT_AGAIN) { - if (nxt_buf_mem_free_size(&b->mem) == 0) { - nxt_log(task, NXT_LOG_ERR, "too long request headers"); - nxt_controller_conn_close(task, c, r); - return; - } - - nxt_conn_read(task->thread->engine, c); - return; - } - - /* rc == NXT_ERROR */ - - nxt_log(task, NXT_LOG_ERR, "parsing error"); - - nxt_controller_conn_close(task, c, r); - return; - } - - rc = nxt_http_fields_process(r->parser.fields, &nxt_controller_fields_hash, - r); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_controller_conn_close(task, c, r); - return; - } - - preread = nxt_buf_mem_used_size(&b->mem); - - nxt_debug(task, "controller request header parsing complete, " - "body length: %uz, preread: %uz", - r->length, preread); - - if (preread >= r->length) { - nxt_controller_process_request(task, r); - return; - } - - if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) { - b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0); - if (nxt_slow_path(b == NULL)) { - nxt_controller_conn_free(task, c, NULL); - return; - } - - b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread); - - c->read = b; - } - - c->read_state = &nxt_controller_conn_body_read_state; - - nxt_conn_read(task->thread->engine, c); -} - - -static nxt_msec_t -nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data) -{ - return (nxt_msec_t) data; -} - - -static void -nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "controller conn read error"); - - nxt_controller_conn_close(task, c, data); -} - - -static void -nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_timer_t *timer; - nxt_conn_t *c; - - timer = obj; - - c = nxt_read_timer_conn(timer); - c->socket.timedout = 1; - c->socket.closed = 1; - - nxt_debug(task, "controller conn read timeout"); - - nxt_controller_conn_close(task, c, data); -} - - -static const nxt_event_conn_state_t nxt_controller_conn_body_read_state - nxt_aligned(64) = -{ - .ready_handler = nxt_controller_conn_body_read, - .close_handler = nxt_controller_conn_close, - .error_handler = nxt_controller_conn_read_error, - - .timer_handler = nxt_controller_conn_read_timeout, - .timer_value = nxt_controller_conn_timeout_value, - .timer_data = 60 * 1000, - .timer_autoreset = 1, -}; - - -static void -nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data) -{ - size_t read; - nxt_buf_t *b; - nxt_conn_t *c; - nxt_controller_request_t *r; - - c = obj; - r = data; - b = c->read; - - read = nxt_buf_mem_used_size(&b->mem); - - nxt_debug(task, "controller conn body read: %uz of %uz", - read, r->length); - - if (read >= r->length) { - nxt_controller_process_request(task, r); - return; - } - - nxt_conn_read(task->thread->engine, c); -} - - -static const nxt_event_conn_state_t nxt_controller_conn_write_state - nxt_aligned(64) = -{ - .ready_handler = nxt_controller_conn_write, - .error_handler = nxt_controller_conn_write_error, - - .timer_handler = nxt_controller_conn_write_timeout, - .timer_value = nxt_controller_conn_timeout_value, - .timer_data = 60 * 1000, - .timer_autoreset = 1, -}; - - -static void -nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *b; - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "controller conn write"); - - b = c->write; - - if (b->mem.pos != b->mem.free) { - nxt_conn_write(task->thread->engine, c); - return; - } - - nxt_debug(task, "controller conn write complete"); - - nxt_controller_conn_close(task, c, data); -} - - -static void -nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "controller conn write error"); - - nxt_controller_conn_close(task, c, data); -} - - -static void -nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - - timer = obj; - - c = nxt_write_timer_conn(timer); - c->socket.timedout = 1; - c->socket.closed = 1; - - nxt_debug(task, "controller conn write timeout"); - - nxt_controller_conn_close(task, c, data); -} - - -static const nxt_event_conn_state_t nxt_controller_conn_close_state - nxt_aligned(64) = -{ - .ready_handler = nxt_controller_conn_free, -}; - - -static void -nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "controller conn close"); - - nxt_queue_remove(&c->link); - - c->write_state = &nxt_controller_conn_close_state; - - nxt_conn_close(task->thread->engine, c); -} - - -static void -nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "controller conn free"); - - nxt_sockaddr_cache_free(task->thread->engine, c); - - nxt_conn_free(task, c); -} - - -static nxt_int_t -nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field, - uintptr_t data) -{ - off_t length; - nxt_controller_request_t *r; - - r = ctx; - - length = nxt_off_t_parse(field->value, field->value_length); - - if (nxt_fast_path(length >= 0)) { - - if (nxt_slow_path(length > NXT_SIZE_T_MAX)) { - nxt_log_error(NXT_LOG_ERR, &r->conn->log, - "Content-Length is too big"); - return NXT_ERROR; - } - - r->length = length; - return NXT_OK; - } - - nxt_log_error(NXT_LOG_ERR, &r->conn->log, "Content-Length is invalid"); - - return NXT_ERROR; -} - - -static void -nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) -{ - uint32_t i, count; - nxt_str_t path; - nxt_conn_t *c; - nxt_conf_value_t *value; - nxt_controller_response_t resp; -#if (NXT_TLS) - nxt_conf_value_t *certs; -#endif -#if (NXT_HAVE_NJS) - nxt_conf_value_t *scripts; -#endif - -#if (NXT_TLS) - static nxt_str_t certificates = nxt_string("certificates"); -#endif - -#if (NXT_HAVE_NJS) - static nxt_str_t scripts_str = nxt_string("js_modules"); -#endif - - static nxt_str_t config = nxt_string("config"); - static nxt_str_t status = nxt_string("status"); - - c = req->conn; - path = req->parser.path; - - if (path.length > 1 && path.start[path.length - 1] == '/') { - path.length--; - } - - if (nxt_str_start(&path, "/config", 7) - && (path.length == 7 || path.start[7] == '/')) - { - if (path.length == 7) { - path.length = 1; - - } else { - path.length -= 7; - path.start += 7; - } - - nxt_controller_process_config(task, req, &path); - return; - } - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - if (nxt_str_start(&path, "/status", 7) - && (path.length == 7 || path.start[7] == '/')) - { - if (!nxt_str_eq(&req->parser.method, "GET", 3)) { - goto invalid_method; - } - - if (nxt_controller_status == NULL) { - nxt_controller_process_status(task, req); - return; - } - - if (path.length == 7) { - path.length = 1; - - } else { - path.length -= 7; - path.start += 7; - } - - nxt_controller_status_response(task, req, &path); - return; - } - -#if (NXT_TLS) - - if (nxt_str_start(&path, "/certificates", 13) - && (path.length == 13 || path.start[13] == '/')) - { - if (path.length == 13) { - path.length = 1; - - } else { - path.length -= 13; - path.start += 13; - } - - nxt_controller_process_cert(task, req, &path); - return; - } - -#endif - -#if (NXT_HAVE_NJS) - - if (nxt_str_start(&path, "/js_modules", 11) - && (path.length == 11 || path.start[11] == '/')) - { - if (path.length == 11) { - path.length = 1; - - } else { - path.length -= 11; - path.start += 11; - } - - nxt_controller_process_script(task, req, &path); - return; - } - -#endif - - if (nxt_str_start(&path, "/control/", 9)) { - path.length -= 9; - path.start += 9; - - nxt_controller_process_control(task, req, &path); - return; - } - - if (path.length == 1 && path.start[0] == '/') { - - if (!nxt_str_eq(&req->parser.method, "GET", 3)) { - goto invalid_method; - } - - if (nxt_controller_status == NULL) { - nxt_controller_process_status(task, req); - return; - } - - count = 2; -#if (NXT_TLS) - count++; -#endif -#if (NXT_HAVE_NJS) - count++; -#endif - - value = nxt_conf_create_object(c->mem_pool, count); - if (nxt_slow_path(value == NULL)) { - goto alloc_fail; - } - - i = 0; - -#if (NXT_TLS) - certs = nxt_cert_info_get_all(c->mem_pool); - if (nxt_slow_path(certs == NULL)) { - goto alloc_fail; - } - - nxt_conf_set_member(value, &certificates, certs, i++); -#endif - -#if (NXT_HAVE_NJS) - scripts = nxt_script_info_get_all(c->mem_pool); - if (nxt_slow_path(scripts == NULL)) { - goto alloc_fail; - } - - nxt_conf_set_member(value, &scripts_str, scripts, i++); -#endif - - nxt_conf_set_member(value, &config, nxt_controller_conf.root, i++); - nxt_conf_set_member(value, &status, nxt_controller_status, i); - - resp.status = 200; - resp.conf = value; - - nxt_controller_response(task, req, &resp); - return; - } - - resp.status = 404; - resp.title = (u_char *) "Value doesn't exist."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -invalid_method: - - resp.status = 405; - resp.title = (u_char *) "Invalid method."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -alloc_fail: - - resp.status = 500; - resp.title = (u_char *) "Memory allocation failed."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; -} - - -static void -nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req, - nxt_str_t *path) -{ - nxt_mp_t *mp; - nxt_int_t rc; - nxt_conn_t *c; - nxt_bool_t post; - nxt_buf_mem_t *mbuf; - nxt_conf_op_t *ops; - nxt_conf_value_t *value; - nxt_conf_validation_t vldt; - nxt_conf_json_error_t error; - nxt_controller_response_t resp; - - static const nxt_str_t empty_obj = nxt_string("{}"); - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - c = req->conn; - - if (nxt_str_eq(&req->parser.method, "GET", 3)) { - - value = nxt_conf_get_path(nxt_controller_conf.root, path); - - if (value == NULL) { - goto not_found; - } - - resp.status = 200; - resp.conf = value; - - nxt_controller_response(task, req, &resp); - return; - } - - if (nxt_str_eq(&req->parser.method, "POST", 4)) { - if (path->length == 1) { - goto not_allowed; - } - - post = 1; - - } else { - post = 0; - } - - if (post || nxt_str_eq(&req->parser.method, "PUT", 3)) { - - if (nxt_controller_check_postpone_request(task)) { - nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); - return; - } - - mp = nxt_mp_create(1024, 128, 256, 32); - - if (nxt_slow_path(mp == NULL)) { - goto alloc_fail; - } - - mbuf = &c->read->mem; - - nxt_memzero(&error, sizeof(nxt_conf_json_error_t)); - - /* Skip UTF-8 BOM. */ - if (nxt_buf_mem_used_size(mbuf) >= 3 - && memcmp(mbuf->pos, "\xEF\xBB\xBF", 3) == 0) - { - mbuf->pos += 3; - } - - value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error); - - if (value == NULL) { - nxt_mp_destroy(mp); - - if (error.pos == NULL) { - goto alloc_fail; - } - - resp.status = 400; - resp.title = (u_char *) "Invalid JSON."; - resp.detail.length = nxt_strlen(error.detail); - resp.detail.start = error.detail; - resp.offset = error.pos - mbuf->pos; - - nxt_conf_json_position(mbuf->pos, error.pos, - &resp.line, &resp.column); - - nxt_controller_response(task, req, &resp); - return; - } - - if (path->length != 1) { - rc = nxt_conf_op_compile(c->mem_pool, &ops, - nxt_controller_conf.root, - path, value, post); - - if (rc != NXT_CONF_OP_OK) { - nxt_mp_destroy(mp); - - switch (rc) { - case NXT_CONF_OP_NOT_FOUND: - goto not_found; - - case NXT_CONF_OP_NOT_ALLOWED: - goto not_allowed; - } - - /* rc == NXT_CONF_OP_ERROR */ - goto alloc_fail; - } - - value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); - - if (nxt_slow_path(value == NULL)) { - nxt_mp_destroy(mp); - goto alloc_fail; - } - } - - nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); - - vldt.conf = value; - vldt.pool = c->mem_pool; - vldt.conf_pool = mp; - vldt.ver = NXT_VERNUM; - - rc = nxt_conf_validate(&vldt); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_mp_destroy(mp); - - if (rc == NXT_DECLINED) { - resp.detail = vldt.error; - goto invalid_conf; - } - - /* rc == NXT_ERROR */ - goto alloc_fail; - } - - rc = nxt_controller_conf_send(task, mp, value, - nxt_controller_conf_handler, req); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_mp_destroy(mp); - - /* rc == NXT_ERROR */ - goto alloc_fail; - } - - req->conf.root = value; - req->conf.pool = mp; - - nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); - - return; - } - - if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { - - if (nxt_controller_check_postpone_request(task)) { - nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); - return; - } - - if (path->length == 1) { - mp = nxt_mp_create(1024, 128, 256, 32); - - if (nxt_slow_path(mp == NULL)) { - goto alloc_fail; - } - - value = nxt_conf_json_parse_str(mp, &empty_obj); - - } else { - rc = nxt_conf_op_compile(c->mem_pool, &ops, - nxt_controller_conf.root, - path, NULL, 0); - - if (rc != NXT_OK) { - if (rc == NXT_CONF_OP_NOT_FOUND) { - goto not_found; - } - - /* rc == NXT_CONF_OP_ERROR */ - goto alloc_fail; - } - - mp = nxt_mp_create(1024, 128, 256, 32); - - if (nxt_slow_path(mp == NULL)) { - goto alloc_fail; - } - - value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); - } - - if (nxt_slow_path(value == NULL)) { - nxt_mp_destroy(mp); - goto alloc_fail; - } - - nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); - - vldt.conf = value; - vldt.pool = c->mem_pool; - vldt.conf_pool = mp; - vldt.ver = NXT_VERNUM; - - rc = nxt_conf_validate(&vldt); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_mp_destroy(mp); - - if (rc == NXT_DECLINED) { - resp.detail = vldt.error; - goto invalid_conf; - } - - /* rc == NXT_ERROR */ - goto alloc_fail; - } - - rc = nxt_controller_conf_send(task, mp, value, - nxt_controller_conf_handler, req); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_mp_destroy(mp); - - /* rc == NXT_ERROR */ - goto alloc_fail; - } - - req->conf.root = value; - req->conf.pool = mp; - - nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); - - return; - } - -not_allowed: - - resp.status = 405; - resp.title = (u_char *) "Method isn't allowed."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -not_found: - - resp.status = 404; - resp.title = (u_char *) "Value doesn't exist."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -invalid_conf: - - resp.status = 400; - resp.title = (u_char *) "Invalid configuration."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -alloc_fail: - - resp.status = 500; - resp.title = (u_char *) "Memory allocation failed."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); -} - - -static nxt_bool_t -nxt_controller_check_postpone_request(nxt_task_t *task) -{ - nxt_port_t *router_port; - nxt_runtime_t *rt; - - if (!nxt_queue_is_empty(&nxt_controller_waiting_requests) - || nxt_controller_waiting_init_conf - || !nxt_controller_router_ready) - { - return 1; - } - - rt = task->thread->runtime; - - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - return (router_port == NULL); -} - - -static void -nxt_controller_process_status(nxt_task_t *task, nxt_controller_request_t *req) -{ - uint32_t stream; - nxt_int_t rc; - nxt_port_t *router_port, *controller_port; - nxt_runtime_t *rt; - nxt_controller_response_t resp; - - if (nxt_controller_check_postpone_request(task)) { - nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); - return; - } - - rt = task->thread->runtime; - - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - nxt_assert(router_port != NULL); - nxt_assert(nxt_controller_router_ready); - - controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; - - stream = nxt_port_rpc_register_handler(task, controller_port, - nxt_controller_status_handler, - nxt_controller_status_handler, - router_port->pid, req); - if (nxt_slow_path(stream == 0)) { - goto fail; - } - - rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_STATUS, - -1, stream, controller_port->id, NULL); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_port_rpc_cancel(task, controller_port, stream); - - goto fail; - } - - nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); - return; - -fail: - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - resp.status = 500; - resp.title = (u_char *) "Failed to get status."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; -} - - -static void -nxt_controller_status_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_conf_value_t *status; - nxt_controller_request_t *req; - nxt_controller_response_t resp; - - nxt_debug(task, "controller status handler"); - - req = data; - - if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) { - status = nxt_status_get((nxt_status_report_t *) msg->buf->mem.pos, - req->conn->mem_pool); - } else { - status = NULL; - } - - if (status == NULL) { - nxt_queue_remove(&req->link); - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - resp.status = 500; - resp.title = (u_char *) "Failed to get status."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - } - - nxt_controller_status = status; - - nxt_controller_flush_requests(task); - - nxt_controller_status = NULL; -} - - -static void -nxt_controller_status_response(nxt_task_t *task, nxt_controller_request_t *req, - nxt_str_t *path) -{ - nxt_conf_value_t *status; - nxt_controller_response_t resp; - - status = nxt_conf_get_path(nxt_controller_status, path); - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - if (status == NULL) { - resp.status = 404; - resp.title = (u_char *) "Invalid path."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - } - - resp.status = 200; - resp.conf = status; - - nxt_controller_response(task, req, &resp); -} - - -#if (NXT_TLS) - -static void -nxt_controller_process_cert(nxt_task_t *task, - nxt_controller_request_t *req, nxt_str_t *path) -{ - u_char *p; - nxt_str_t name; - nxt_int_t ret; - nxt_conn_t *c; - nxt_cert_t *cert; - nxt_conf_value_t *value; - nxt_controller_response_t resp; - - name.length = path->length - 1; - name.start = path->start + 1; - - p = memchr(name.start, '/', name.length); - - if (p != NULL) { - name.length = p - name.start; - - path->length -= p - path->start; - path->start = p; - - } else { - path = NULL; - } - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - c = req->conn; - - if (nxt_str_eq(&req->parser.method, "GET", 3)) { - - if (name.length != 0) { - value = nxt_cert_info_get(&name); - if (value == NULL) { - goto cert_not_found; - } - - if (path != NULL) { - value = nxt_conf_get_path(value, path); - if (value == NULL) { - goto not_found; - } - } - - } else { - value = nxt_cert_info_get_all(c->mem_pool); - if (value == NULL) { - goto alloc_fail; - } - } - - resp.status = 200; - resp.conf = value; - - nxt_controller_response(task, req, &resp); - return; - } - - if (name.length == 0 || path != NULL) { - goto invalid_name; - } - - if (nxt_str_eq(&req->parser.method, "PUT", 3)) { - value = nxt_cert_info_get(&name); - if (value != NULL) { - goto exists_cert; - } - - cert = nxt_cert_mem(task, &c->read->mem); - if (cert == NULL) { - goto invalid_cert; - } - - ret = nxt_cert_info_save(&name, cert); - - nxt_cert_destroy(cert); - - if (nxt_slow_path(ret != NXT_OK)) { - goto alloc_fail; - } - - nxt_cert_store_get(task, &name, c->mem_pool, - nxt_controller_process_cert_save, req); - return; - } - - if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { - - if (nxt_controller_cert_in_use(&name)) { - goto cert_in_use; - } - - if (nxt_cert_info_delete(&name) != NXT_OK) { - goto cert_not_found; - } - - nxt_cert_store_delete(task, &name, c->mem_pool); - - resp.status = 200; - resp.title = (u_char *) "Certificate deleted."; - - nxt_controller_response(task, req, &resp); - return; - } - - resp.status = 405; - resp.title = (u_char *) "Invalid method."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -invalid_name: - - resp.status = 400; - resp.title = (u_char *) "Invalid certificate name."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -invalid_cert: - - resp.status = 400; - resp.title = (u_char *) "Invalid certificate."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -exists_cert: - - resp.status = 400; - resp.title = (u_char *) "Certificate already exists."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -cert_in_use: - - resp.status = 400; - resp.title = (u_char *) "Certificate is used in the configuration."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -cert_not_found: - - resp.status = 404; - resp.title = (u_char *) "Certificate doesn't exist."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -not_found: - - resp.status = 404; - resp.title = (u_char *) "Invalid path."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -alloc_fail: - - resp.status = 500; - resp.title = (u_char *) "Memory allocation failed."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; -} - - -static void -nxt_controller_process_cert_save(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_conn_t *c; - nxt_buf_mem_t *mbuf; - nxt_controller_request_t *req; - nxt_controller_response_t resp; - - req = data; - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { - resp.status = 500; - resp.title = (u_char *) "Failed to store certificate."; - - nxt_controller_response(task, req, &resp); - return; - } - - c = req->conn; - - mbuf = &c->read->mem; - - nxt_fd_write(msg->fd[0], mbuf->pos, nxt_buf_mem_used_size(mbuf)); - - nxt_fd_close(msg->fd[0]); - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - resp.status = 200; - resp.title = (u_char *) "Certificate chain uploaded."; - - nxt_controller_response(task, req, &resp); -} - - -static nxt_bool_t -nxt_controller_cert_in_use(nxt_str_t *name) -{ - uint32_t next; - nxt_str_t str; - nxt_conf_value_t *listeners, *listener, *value; - - static nxt_str_t listeners_path = nxt_string("/listeners"); - static nxt_str_t certificate_path = nxt_string("/tls/certificate"); - - listeners = nxt_conf_get_path(nxt_controller_conf.root, &listeners_path); - - if (listeners != NULL) { - next = 0; - - for ( ;; ) { - listener = nxt_conf_next_object_member(listeners, &str, &next); - if (listener == NULL) { - break; - } - - value = nxt_conf_get_path(listener, &certificate_path); - if (value == NULL) { - continue; - } - - nxt_conf_get_string(value, &str); - - if (nxt_strstr_eq(&str, name)) { - return 1; - } - } - } - - return 0; -} - -#endif - - -#if (NXT_HAVE_NJS) - -static void -nxt_controller_process_script(nxt_task_t *task, - nxt_controller_request_t *req, nxt_str_t *path) -{ - u_char *p; - nxt_int_t ret; - nxt_str_t name; - nxt_conn_t *c; - nxt_script_t *script; - nxt_buf_mem_t *bm; - nxt_conf_value_t *value; - nxt_controller_response_t resp; - u_char error[NXT_MAX_ERROR_STR]; - - name.length = path->length - 1; - name.start = path->start + 1; - - p = memchr(name.start, '/', name.length); - - if (p != NULL) { - name.length = p - name.start; - - path->length -= p - path->start; - path->start = p; - - } else { - path = NULL; - } - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - c = req->conn; - - if (nxt_str_eq(&req->parser.method, "GET", 3)) { - - if (name.length != 0) { - value = nxt_script_info_get(&name); - if (value == NULL) { - goto script_not_found; - } - - if (path != NULL) { - value = nxt_conf_get_path(value, path); - if (value == NULL) { - goto not_found; - } - } - - } else { - value = nxt_script_info_get_all(c->mem_pool); - if (value == NULL) { - goto alloc_fail; - } - } - - resp.status = 200; - resp.conf = value; - - nxt_controller_response(task, req, &resp); - return; - } - - if (name.length == 0 || path != NULL) { - goto invalid_name; - } - - if (nxt_str_eq(&req->parser.method, "PUT", 3)) { - value = nxt_script_info_get(&name); - if (value != NULL) { - goto exists_script; - } - - bm = &c->read->mem; - - script = nxt_script_new(task, &name, bm->pos, - nxt_buf_mem_used_size(bm), error); - if (script == NULL) { - goto invalid_script; - } - - ret = nxt_script_info_save(&name, script); - - nxt_script_destroy(script); - - if (nxt_slow_path(ret != NXT_OK)) { - goto alloc_fail; - } - - nxt_script_store_get(task, &name, c->mem_pool, - nxt_controller_process_script_save, req); - return; - } - - if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { - - if (nxt_controller_script_in_use(&name)) { - goto script_in_use; - } - - if (nxt_script_info_delete(&name) != NXT_OK) { - goto script_not_found; - } - - nxt_script_store_delete(task, &name, c->mem_pool); - - resp.status = 200; - resp.title = (u_char *) "JS module deleted."; - - nxt_controller_response(task, req, &resp); - return; - } - - resp.status = 405; - resp.title = (u_char *) "Invalid method."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -invalid_name: - - resp.status = 400; - resp.title = (u_char *) "Invalid JS module name."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -invalid_script: - - resp.status = 400; - resp.title = (u_char *) "Invalid JS module."; - resp.offset = -1; - - resp.detail.start = error; - resp.detail.length = nxt_strlen(error); - - nxt_controller_response(task, req, &resp); - return; - -exists_script: - - resp.status = 400; - resp.title = (u_char *) "JS module already exists."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -script_in_use: - - resp.status = 400; - resp.title = (u_char *) "JS module is used in the configuration."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -script_not_found: - - resp.status = 404; - resp.title = (u_char *) "JS module doesn't exist."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -not_found: - - resp.status = 404; - resp.title = (u_char *) "Invalid path."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -alloc_fail: - - resp.status = 500; - resp.title = (u_char *) "Memory allocation failed."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); -} - - -static void -nxt_controller_process_script_save(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_conn_t *c; - nxt_buf_mem_t *mbuf; - nxt_controller_request_t *req; - nxt_controller_response_t resp; - - req = data; - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { - resp.status = 500; - resp.title = (u_char *) "Failed to store script."; - - nxt_controller_response(task, req, &resp); - return; - } - - c = req->conn; - - mbuf = &c->read->mem; - - nxt_fd_write(msg->fd[0], mbuf->pos, nxt_buf_mem_used_size(mbuf)); - - nxt_fd_close(msg->fd[0]); - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - resp.status = 200; - resp.title = (u_char *) "JS module uploaded."; - - nxt_controller_response(task, req, &resp); -} - - -static nxt_bool_t -nxt_controller_script_in_use(nxt_str_t *name) -{ - uint32_t i, n; - nxt_str_t str; - nxt_conf_value_t *js_module, *element; - - static nxt_str_t js_module_path = nxt_string("/settings/js_module"); - - js_module = nxt_conf_get_path(nxt_controller_conf.root, - &js_module_path); - - if (js_module != NULL) { - - if (nxt_conf_type(js_module) == NXT_CONF_ARRAY) { - n = nxt_conf_array_elements_count(js_module); - - for (i = 0; i < n; i++) { - element = nxt_conf_get_array_element(js_module, i); - - nxt_conf_get_string(element, &str); - - if (nxt_strstr_eq(&str, name)) { - return 1; - } - } - - } else { - /* NXT_CONF_STRING */ - - nxt_conf_get_string(js_module, &str); - - if (nxt_strstr_eq(&str, name)) { - return 1; - } - } - } - - return 0; -} - - -static void -nxt_controller_script_cleanup(nxt_task_t *task, void *obj, void *data) -{ - pid_t main_pid; - nxt_array_t *scripts; - nxt_runtime_t *rt; - - scripts = obj; - rt = data; - - main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid; - - if (nxt_pid == main_pid && scripts != NULL) { - nxt_script_store_release(scripts); - } -} - -#endif - - -static void -nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_controller_request_t *req; - nxt_controller_response_t resp; - - req = data; - - nxt_debug(task, "controller conf ready: %*s", - nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos); - - nxt_queue_remove(&req->link); - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) { - nxt_mp_destroy(nxt_controller_conf.pool); - - nxt_controller_conf = req->conf; - - nxt_controller_conf_store(task, req->conf.root); - - resp.status = 200; - resp.title = (u_char *) "Reconfiguration done."; - - } else { - nxt_mp_destroy(req->conf.pool); - - resp.status = 500; - resp.title = (u_char *) "Failed to apply new configuration."; - resp.offset = -1; - } - - nxt_controller_response(task, req, &resp); - - nxt_controller_flush_requests(task); -} - - -static void -nxt_controller_process_control(nxt_task_t *task, - nxt_controller_request_t *req, nxt_str_t *path) -{ - uint32_t stream; - nxt_buf_t *b; - nxt_int_t rc; - nxt_port_t *router_port, *controller_port; - nxt_runtime_t *rt; - nxt_conf_value_t *value; - nxt_controller_response_t resp; - - static nxt_str_t applications = nxt_string("applications"); - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - if (!nxt_str_eq(&req->parser.method, "GET", 3)) { - goto not_allowed; - } - - if (!nxt_str_start(path, "applications/", 13) - || memcmp(path->start + path->length - 8, "/restart", 8) != 0) - { - goto not_found; - } - - path->start += 13; - path->length -= 13 + 8; - - if (nxt_controller_check_postpone_request(task)) { - nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); - return; - } - - value = nxt_controller_conf.root; - if (value == NULL) { - goto not_found; - } - - value = nxt_conf_get_object_member(value, &applications, NULL); - if (value == NULL) { - goto not_found; - } - - value = nxt_conf_get_object_member(value, path, NULL); - if (value == NULL) { - goto not_found; - } - - b = nxt_buf_mem_alloc(req->conn->mem_pool, path->length, 0); - if (nxt_slow_path(b == NULL)) { - goto alloc_fail; - } - - b->mem.free = nxt_cpymem(b->mem.pos, path->start, path->length); - - rt = task->thread->runtime; - - controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - stream = nxt_port_rpc_register_handler(task, controller_port, - nxt_controller_app_restart_handler, - nxt_controller_app_restart_handler, - router_port->pid, req); - if (nxt_slow_path(stream == 0)) { - goto alloc_fail; - } - - rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_APP_RESTART, - -1, stream, 0, b); - if (nxt_slow_path(rc != NXT_OK)) { - nxt_port_rpc_cancel(task, controller_port, stream); - - goto fail; - } - - nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); - - return; - -not_allowed: - - resp.status = 405; - resp.title = (u_char *) "Method isn't allowed."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -not_found: - - resp.status = 404; - resp.title = (u_char *) "Value doesn't exist."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -alloc_fail: - - resp.status = 500; - resp.title = (u_char *) "Memory allocation failed."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); - return; - -fail: - - resp.status = 500; - resp.title = (u_char *) "Send restart failed."; - resp.offset = -1; - - nxt_controller_response(task, req, &resp); -} - - -static void -nxt_controller_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_controller_request_t *req; - nxt_controller_response_t resp; - - req = data; - - nxt_debug(task, "controller app restart handler"); - - nxt_queue_remove(&req->link); - - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - - if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) { - resp.status = 200; - resp.title = (u_char *) "Ok"; - - } else { - resp.status = 500; - resp.title = (u_char *) "Failed to restart app."; - resp.offset = -1; - } - - nxt_controller_response(task, req, &resp); - - nxt_controller_flush_requests(task); -} - - -static void -nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf) -{ - void *mem; - u_char *end; - size_t size; - nxt_fd_t fd; - nxt_buf_t *b; - nxt_port_t *main_port; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - - size = nxt_conf_json_length(conf, NULL); - - fd = nxt_shm_open(task, size); - if (nxt_slow_path(fd == -1)) { - return; - } - - mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (nxt_slow_path(mem == MAP_FAILED)) { - goto fail; - } - - end = nxt_conf_json_print(mem, conf, NULL); - - nxt_mem_munmap(mem, size); - - size = end - (u_char *) mem; - - b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, sizeof(size_t), 0); - if (nxt_slow_path(b == NULL)) { - goto fail; - } - - b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t)); - - (void) nxt_port_socket_write(task, main_port, - NXT_PORT_MSG_CONF_STORE | NXT_PORT_MSG_CLOSE_FD, - fd, 0, -1, b); - - return; - -fail: - - nxt_fd_close(fd); -} - - -static void -nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req, - nxt_controller_response_t *resp) -{ - size_t size; - nxt_str_t status_line, str; - nxt_buf_t *b, *body; - nxt_conn_t *c; - nxt_uint_t n; - nxt_conf_value_t *value, *location; - nxt_conf_json_pretty_t pretty; - - static nxt_str_t success_str = nxt_string("success"); - static nxt_str_t error_str = nxt_string("error"); - static nxt_str_t detail_str = nxt_string("detail"); - static nxt_str_t location_str = nxt_string("location"); - static nxt_str_t offset_str = nxt_string("offset"); - static nxt_str_t line_str = nxt_string("line"); - static nxt_str_t column_str = nxt_string("column"); - - static nxt_time_string_t date_cache = { - (nxt_atomic_uint_t) -1, - nxt_controller_date, - "%s, %02d %s %4d %02d:%02d:%02d GMT", - nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"), - NXT_THREAD_TIME_GMT, - NXT_THREAD_TIME_SEC, - }; - - switch (resp->status) { - - case 200: - nxt_str_set(&status_line, "200 OK"); - break; - - case 400: - nxt_str_set(&status_line, "400 Bad Request"); - break; - - case 404: - nxt_str_set(&status_line, "404 Not Found"); - break; - - case 405: - nxt_str_set(&status_line, "405 Method Not Allowed"); - break; - - default: - nxt_str_set(&status_line, "500 Internal Server Error"); - break; - } - - c = req->conn; - value = resp->conf; - - if (value == NULL) { - n = 1 - + (resp->detail.length != 0) - + (resp->status >= 400 && resp->offset != -1); - - value = nxt_conf_create_object(c->mem_pool, n); - - if (nxt_slow_path(value == NULL)) { - nxt_controller_conn_close(task, c, req); - return; - } - - str.length = nxt_strlen(resp->title); - str.start = resp->title; - - if (resp->status < 400) { - nxt_conf_set_member_string(value, &success_str, &str, 0); - - } else { - nxt_conf_set_member_string(value, &error_str, &str, 0); - } - - n = 0; - - if (resp->detail.length != 0) { - n++; - - nxt_conf_set_member_string(value, &detail_str, &resp->detail, n); - } - - if (resp->status >= 400 && resp->offset != -1) { - n++; - - location = nxt_conf_create_object(c->mem_pool, - resp->line != 0 ? 3 : 1); - - nxt_conf_set_member(value, &location_str, location, n); - - nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0); - - if (resp->line != 0) { - nxt_conf_set_member_integer(location, &line_str, - resp->line, 1); - - nxt_conf_set_member_integer(location, &column_str, - resp->column, 2); - } - } - } - - nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); - - size = nxt_conf_json_length(value, &pretty) + 2; - - body = nxt_buf_mem_alloc(c->mem_pool, size, 0); - if (nxt_slow_path(body == NULL)) { - nxt_controller_conn_close(task, c, req); - return; - } - - nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); - - body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty); - - body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2); - - size = nxt_length("HTTP/1.1 " "\r\n") + status_line.length - + nxt_length("Server: " NXT_SERVER "\r\n") - + nxt_length("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n") - + nxt_length("Content-Type: application/json\r\n") - + nxt_length("Content-Length: " "\r\n") + NXT_SIZE_T_LEN - + nxt_length("Connection: close\r\n") - + nxt_length("\r\n"); - - b = nxt_buf_mem_alloc(c->mem_pool, size, 0); - if (nxt_slow_path(b == NULL)) { - nxt_controller_conn_close(task, c, req); - return; - } - - b->next = body; - - nxt_str_set(&str, "HTTP/1.1 "); - - b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); - b->mem.free = nxt_cpymem(b->mem.free, status_line.start, - status_line.length); - - nxt_str_set(&str, "\r\n" - "Server: " NXT_SERVER "\r\n" - "Date: "); - - b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); - - b->mem.free = nxt_thread_time_string(task->thread, &date_cache, - b->mem.free); - - nxt_str_set(&str, "\r\n" - "Content-Type: application/json\r\n" - "Content-Length: "); - - b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); - - b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz", - nxt_buf_mem_used_size(&body->mem)); - - nxt_str_set(&str, "\r\n" - "Connection: close\r\n" - "\r\n"); - - b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); - - c->write = b; - c->write_state = &nxt_controller_conn_write_state; - - nxt_conn_write(task->thread->engine, c); -} - - -static u_char * -nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, - size_t size, const char *format) -{ - static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", - "Sat" }; - - static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - return nxt_sprintf(buf, buf + size, format, - week[tm->tm_wday], tm->tm_mday, - month[tm->tm_mon], tm->tm_year + 1900, - tm->tm_hour, tm->tm_min, tm->tm_sec); -} diff --git a/src/nxt_credential.c b/src/nxt_credential.c deleted file mode 100644 index 1c9fa9a7..00000000 --- a/src/nxt_credential.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static nxt_int_t nxt_credential_groups_get(nxt_task_t *task, nxt_mp_t *mp, - nxt_credential_t *uc); - - -nxt_int_t -nxt_credential_get(nxt_task_t *task, nxt_mp_t *mp, nxt_credential_t *uc, - const char *group) -{ - struct group *grp; - struct passwd *pwd; - - nxt_errno = 0; - - pwd = getpwnam(uc->user); - - if (nxt_slow_path(pwd == NULL)) { - - if (nxt_errno == 0) { - nxt_alert(task, "getpwnam(\"%s\") failed, user \"%s\" not found", - uc->user, uc->user); - } else { - nxt_alert(task, "getpwnam(\"%s\") failed %E", uc->user, nxt_errno); - } - - return NXT_ERROR; - } - - uc->uid = pwd->pw_uid; - uc->base_gid = pwd->pw_gid; - - if (group != NULL && group[0] != '\0') { - nxt_errno = 0; - - grp = getgrnam(group); - - if (nxt_slow_path(grp == NULL)) { - - if (nxt_errno == 0) { - nxt_alert(task, - "getgrnam(\"%s\") failed, group \"%s\" not found", - group, group); - } else { - nxt_alert(task, "getgrnam(\"%s\") failed %E", group, nxt_errno); - } - - return NXT_ERROR; - } - - uc->base_gid = grp->gr_gid; - } - - nxt_debug(task, "about to get \"%s\" groups (uid:%d, base gid:%d)", - uc->user, uc->uid, uc->base_gid); - - if (nxt_credential_groups_get(task, mp, uc) != NXT_OK) { - return NXT_ERROR; - } - -#if (NXT_DEBUG) - { - u_char *p, *end; - nxt_uint_t i; - u_char msg[NXT_MAX_ERROR_STR]; - - p = msg; - end = msg + NXT_MAX_ERROR_STR; - - for (i = 0; i < uc->ngroups; i++) { - p = nxt_sprintf(p, end, "%d,", uc->gids[i]); - } - - if (uc->ngroups > 0) { - p--; - } - - nxt_debug(task, "user \"%s\" has gids:%*s", uc->user, p - msg, msg); - } -#endif - - return NXT_OK; -} - - -#if (NXT_HAVE_GETGROUPLIST && !NXT_MACOSX) - -#define NXT_NGROUPS nxt_min(256, NGROUPS_MAX) - - -static nxt_int_t -nxt_credential_groups_get(nxt_task_t *task, nxt_mp_t *mp, - nxt_credential_t *uc) -{ - int ngroups; - gid_t groups[NXT_NGROUPS]; - - ngroups = NXT_NGROUPS; - - if (getgrouplist(uc->user, uc->base_gid, groups, &ngroups) < 0) { - if (nxt_slow_path(ngroups <= NXT_NGROUPS)) { - nxt_alert(task, "getgrouplist(\"%s\", %d, ...) failed %E", uc->user, - uc->base_gid, nxt_errno); - - return NXT_ERROR; - } - } - - if (ngroups > NXT_NGROUPS) { - if (ngroups > NGROUPS_MAX) { - ngroups = NGROUPS_MAX; - } - - uc->ngroups = ngroups; - - uc->gids = nxt_mp_alloc(mp, ngroups * sizeof(gid_t)); - if (nxt_slow_path(uc->gids == NULL)) { - return NXT_ERROR; - } - - if (nxt_slow_path(getgrouplist(uc->user, uc->base_gid, uc->gids, - &ngroups) < 0)) { - - nxt_alert(task, "getgrouplist(\"%s\", %d) failed %E", uc->user, - uc->base_gid, nxt_errno); - - return NXT_ERROR; - } - - return NXT_OK; - } - - uc->ngroups = ngroups; - - uc->gids = nxt_mp_alloc(mp, ngroups * sizeof(gid_t)); - if (nxt_slow_path(uc->gids == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy(uc->gids, groups, ngroups * sizeof(gid_t)); - - return NXT_OK; -} - - -#else - -/* - * For operating systems that lack getgrouplist(3) or it's buggy (MacOS), - * nxt_credential_groups_get() stores an array of groups IDs which should be - * set by the setgroups() function for a given user. The initgroups() - * may block a just forked worker process for some time if LDAP or NDIS+ - * is used, so nxt_credential_groups_get() allows to get worker user groups in - * main process. In a nutshell the initgroups() calls getgrouplist() - * followed by setgroups(). However older Solaris lacks the getgrouplist(). - * Besides getgrouplist() does not allow to query the exact number of - * groups in some platforms, while NGROUPS_MAX can be quite large (e.g. - * 65536 on Linux). - * So nxt_credential_groups_get() emulates getgrouplist(): at first the - * function saves the super-user groups IDs, then calls initgroups() and saves - * the specified user groups IDs, and then restores the super-user groups IDs. - * This works at least on Linux, FreeBSD, and Solaris, but does not work - * on MacOSX, getgroups(2): - * - * To provide compatibility with applications that use getgroups() in - * environments where users may be in more than {NGROUPS_MAX} groups, - * a variant of getgroups(), obtained when compiling with either the - * macros _DARWIN_UNLIMITED_GETGROUPS or _DARWIN_C_SOURCE defined, can - * be used that is not limited to {NGROUPS_MAX} groups. However, this - * variant only returns the user's default group access list and not - * the group list modified by a call to setgroups(2). - * - * For such cases initgroups() is used in worker process as fallback. - */ - -static nxt_int_t -nxt_credential_groups_get(nxt_task_t *task, nxt_mp_t *mp, nxt_credential_t *uc) -{ - int nsaved, ngroups; - nxt_int_t ret; - nxt_gid_t *saved; - - nsaved = getgroups(0, NULL); - - if (nxt_slow_path(nsaved == -1)) { - nxt_alert(task, "getgroups(0, NULL) failed %E", nxt_errno); - return NXT_ERROR; - } - - nxt_debug(task, "getgroups(0, NULL): %d", nsaved); - - if (nsaved > NGROUPS_MAX) { - /* MacOSX case. */ - - uc->gids = NULL; - uc->ngroups = 0; - - return NXT_OK; - } - - saved = nxt_mp_alloc(mp, nsaved * sizeof(nxt_gid_t)); - - if (nxt_slow_path(saved == NULL)) { - return NXT_ERROR; - } - - ret = NXT_ERROR; - - nsaved = getgroups(nsaved, saved); - - if (nxt_slow_path(nsaved == -1)) { - nxt_alert(task, "getgroups(%d) failed %E", nsaved, nxt_errno); - goto free; - } - - nxt_debug(task, "getgroups(): %d", nsaved); - - if (initgroups(uc->user, uc->base_gid) != 0) { - if (nxt_errno == NXT_EPERM) { - nxt_log(task, NXT_LOG_NOTICE, - "initgroups(%s, %d) failed %E, ignored", - uc->user, uc->base_gid, nxt_errno); - - ret = NXT_OK; - - goto free; - - } else { - nxt_alert(task, "initgroups(%s, %d) failed %E", - uc->user, uc->base_gid, nxt_errno); - goto restore; - } - } - - ngroups = getgroups(0, NULL); - - if (nxt_slow_path(ngroups == -1)) { - nxt_alert(task, "getgroups(0, NULL) failed %E", nxt_errno); - goto restore; - } - - nxt_debug(task, "getgroups(0, NULL): %d", ngroups); - - uc->gids = nxt_mp_alloc(mp, ngroups * sizeof(nxt_gid_t)); - - if (nxt_slow_path(uc->gids == NULL)) { - goto restore; - } - - ngroups = getgroups(ngroups, uc->gids); - - if (nxt_slow_path(ngroups == -1)) { - nxt_alert(task, "getgroups(%d) failed %E", ngroups, nxt_errno); - goto restore; - } - - uc->ngroups = ngroups; - - ret = NXT_OK; - -restore: - - if (nxt_slow_path(setgroups(nsaved, saved) != 0)) { - nxt_alert(task, "setgroups(%d) failed %E", nsaved, nxt_errno); - ret = NXT_ERROR; - } - -free: - - nxt_mp_free(mp, saved); - - return ret; -} - - -#endif - - -nxt_int_t -nxt_credential_setuid(nxt_task_t *task, nxt_credential_t *uc) -{ - nxt_debug(task, "user cred set: \"%s\" uid:%d", uc->user, uc->uid); - - if (setuid(uc->uid) != 0) { - -#if (NXT_HAVE_LINUX_NS) - if (nxt_errno == EINVAL) { - nxt_log(task, NXT_LOG_ERR, "The uid %d (user \"%s\") isn't " - "valid in the application namespace.", uc->uid, uc->user); - return NXT_ERROR; - } -#endif - - nxt_alert(task, "setuid(%d) failed %E", uc->uid, nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; -} - - -nxt_int_t -nxt_credential_setgids(nxt_task_t *task, nxt_credential_t *uc) -{ - nxt_runtime_t *rt; - - nxt_debug(task, "user cred set gids: base gid:%d, ngroups: %d", - uc->base_gid, uc->ngroups); - - rt = task->thread->runtime; - - if (setgid(uc->base_gid) != 0) { - -#if (NXT_HAVE_LINUX_NS) - if (nxt_errno == EINVAL) { - nxt_log(task, NXT_LOG_ERR, "The gid %d isn't valid in the " - "application namespace.", uc->base_gid); - return NXT_ERROR; - } -#endif - - nxt_alert(task, "setgid(%d) failed %E", uc->base_gid, nxt_errno); - return NXT_ERROR; - } - - if (!rt->capabilities.setid) { - return NXT_OK; - } - - if (nxt_slow_path(uc->ngroups > 0 - && setgroups(uc->ngroups, uc->gids) != 0)) { - -#if (NXT_HAVE_LINUX_NS) - if (nxt_errno == EINVAL) { - nxt_log(task, NXT_LOG_ERR, "The user \"%s\" (uid: %d) has " - "supplementary group ids not valid in the application " - "namespace.", uc->user, uc->uid); - return NXT_ERROR; - } -#endif - - nxt_alert(task, "setgroups(%i) failed %E", uc->ngroups, nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; -} diff --git a/src/nxt_credential.h b/src/nxt_credential.h deleted file mode 100644 index 243eba83..00000000 --- a/src/nxt_credential.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_CREDENTIAL_H_INCLUDED_ -#define _NXT_CREDENTIAL_H_INCLUDED_ - - -typedef uid_t nxt_uid_t; -typedef gid_t nxt_gid_t; - -typedef struct { - const char *user; - nxt_uid_t uid; - nxt_gid_t base_gid; - nxt_uint_t ngroups; - nxt_gid_t *gids; -} nxt_credential_t; - - -NXT_EXPORT nxt_int_t nxt_credential_get(nxt_task_t *task, nxt_mp_t *mp, - nxt_credential_t *uc, const char *group); -NXT_EXPORT nxt_int_t nxt_credential_setuid(nxt_task_t *task, - nxt_credential_t *uc); -NXT_EXPORT nxt_int_t nxt_credential_setgids(nxt_task_t *task, - nxt_credential_t *uc); - - -#endif /* _NXT_CREDENTIAL_H_INCLUDED_ */ diff --git a/src/nxt_cyassl.c b/src/nxt_cyassl.c deleted file mode 100644 index 91039e0c..00000000 --- a/src/nxt_cyassl.c +++ /dev/null @@ -1,621 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - * Copyright (C) Igor Sysoev - */ - -#include -#include -#include - - -typedef struct { - CYASSL *session; - - int ssl_error; - uint8_t times; /* 2 bits */ - - nxt_buf_mem_t buffer; -} nxt_cyassl_conn_t; - - -static nxt_int_t nxt_cyassl_server_init(nxt_ssltls_conf_t *conf); -static void nxt_cyassl_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf, - nxt_event_conn_t *c); -static void nxt_cyassl_session_cleanup(void *data); -static int nxt_cyassl_io_recv(CYASSL *ssl, char *buf, int size, void *data); -static int nxt_cyassl_io_send(CYASSL *ssl, char *buf, int size, void *data); -static void nxt_cyassl_conn_handshake(nxt_thread_t *thr, void *obj, void *data); -static void nxt_cyassl_conn_io_read(nxt_thread_t *thr, void *obj, void *data); -static void nxt_cyassl_conn_io_shutdown(nxt_thread_t *thr, void *obj, - void *data); -static ssize_t nxt_cyassl_conn_io_write_chunk(nxt_thread_t *thr, - nxt_event_conn_t *c, nxt_buf_t *b, size_t limit); -static ssize_t nxt_cyassl_conn_io_send(nxt_event_conn_t *c, void *buf, - size_t size); -static nxt_int_t nxt_cyassl_conn_test_error(nxt_thread_t *thr, - nxt_event_conn_t *c, int err, nxt_work_handler_t handler); -static void nxt_cdecl nxt_cyassl_conn_error(nxt_event_conn_t *c, nxt_err_t err, - const char *fmt, ...); -static nxt_uint_t nxt_cyassl_log_error_level(nxt_event_conn_t *c, nxt_err_t err, - int ssl_error); -static void nxt_cdecl nxt_cyassl_log_error(nxt_uint_t level, nxt_log_t *log, - int ret, const char *fmt, ...); -static u_char *nxt_cyassl_copy_error(int err, u_char *p, u_char *end); - - -const nxt_ssltls_lib_t nxt_cyassl_lib = { - nxt_cyassl_server_init, - NULL, -}; - - -static nxt_event_conn_io_t nxt_cyassl_event_conn_io = { - NULL, - NULL, - - nxt_cyassl_conn_io_read, - NULL, - NULL, - - nxt_event_conn_io_write, - nxt_cyassl_conn_io_write_chunk, - NULL, - NULL, - nxt_cyassl_conn_io_send, - - nxt_cyassl_conn_io_shutdown, -}; - - -static nxt_int_t -nxt_cyassl_start(void) -{ - int err; - nxt_thread_t *thr; - static nxt_bool_t started; - - if (nxt_fast_path(started)) { - return NXT_OK; - } - - started = 1; - - thr = nxt_thread(); - - /* TODO: CyaSSL_Cleanup() */ - - err = CyaSSL_Init(); - if (err != SSL_SUCCESS) { - nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err, - "CyaSSL_Init() failed"); - return NXT_ERROR; - } - - nxt_thread_log_error(NXT_LOG_INFO, "CyaSSL version: %s", - LIBCYASSL_VERSION_STRING); - - /* CyaSSL_SetLoggingCb */ - /* CyaSSL_SetAllocators */ - - return NXT_OK; -} - - -static nxt_int_t -nxt_cyassl_server_init(nxt_ssltls_conf_t *conf) -{ - int err; - char *certificate, *key; - CYASSL_CTX *ctx; - nxt_thread_t *thr; - - thr = nxt_thread(); - - if (nxt_slow_path(nxt_cyassl_start() != NXT_OK)) { - return NXT_ERROR; - } - - ctx = CyaSSL_CTX_new(CyaSSLv23_server_method()); - if (ctx == NULL) { - nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, 0, - "CyaSSL_CTX_new() failed"); - return NXT_ERROR; - } - - conf->ctx = ctx; - conf->conn_init = nxt_cyassl_conn_init; - - certificate = conf->certificate; - - err = CyaSSL_CTX_use_certificate_file(ctx, certificate, SSL_FILETYPE_PEM); - if (err != SSL_SUCCESS) { - nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err, - "CyaSSL_CTX_use_certificate_file(\"%s\") failed", - certificate); - goto fail; - } - - key = conf->certificate_key; - - err = CyaSSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM); - if (err != SSL_SUCCESS) { - nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err, - "CyaSSL_CTX_use_PrivateKey_file(\"%s\") failed", - key); - goto fail; - } - - if (conf->ciphers != NULL) { - err = CyaSSL_CTX_set_cipher_list(ctx, conf->ciphers); - if (err != SSL_SUCCESS) { - nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err, - "CyaSSL_CTX_set_cipher_list(\"%s\") failed", - conf->ciphers); - goto fail; - } - } - - /* TODO: ca_certificate */ - - CyaSSL_SetIORecv(ctx, nxt_cyassl_io_recv); - CyaSSL_SetIOSend(ctx, nxt_cyassl_io_send); - - return NXT_OK; - -fail: - - CyaSSL_CTX_free(ctx); - - return NXT_ERROR; -} - - -static void -nxt_cyassl_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf, - nxt_event_conn_t *c) -{ - CYASSL *s; - CYASSL_CTX *ctx; - nxt_cyassl_conn_t *ssltls; - nxt_mem_pool_cleanup_t *mpcl; - - nxt_log_debug(c->socket.log, "cyassl conn init"); - - ssltls = nxt_mp_zget(c->mem_pool, sizeof(nxt_cyassl_conn_t)); - if (ssltls == NULL) { - goto fail; - } - - c->u.ssltls = ssltls; - nxt_buf_mem_set_size(&ssltls->buffer, conf->buffer_size); - - mpcl = nxt_mem_pool_cleanup(c->mem_pool, 0); - if (mpcl == NULL) { - goto fail; - } - - ctx = conf->ctx; - - s = CyaSSL_new(ctx); - if (s == NULL) { - nxt_cyassl_log_error(NXT_LOG_ALERT, c->socket.log, 0, - "CyaSSL_new() failed"); - goto fail; - } - - ssltls->session = s; - mpcl->handler = nxt_cyassl_session_cleanup; - mpcl->data = ssltls; - - CyaSSL_SetIOReadCtx(s, c); - CyaSSL_SetIOWriteCtx(s, c); - - c->io = &nxt_cyassl_event_conn_io; - c->sendfile = NXT_CONN_SENDFILE_OFF; - - nxt_cyassl_conn_handshake(thr, c, c->socket.data); - return; - -fail: - - nxt_event_conn_io_handle(thr, c->read_work_queue, - c->read_state->error_handler, c, c->socket.data); -} - - -static void -nxt_cyassl_session_cleanup(void *data) -{ - nxt_cyassl_conn_t *ssltls; - - ssltls = data; - - nxt_thread_log_debug("cyassl session cleanup"); - - nxt_free(ssltls->buffer.start); - - CyaSSL_free(ssltls->session); -} - - -static int -nxt_cyassl_io_recv(CYASSL *ssl, char *buf, int size, void *data) -{ - ssize_t n; - nxt_thread_t *thr; - nxt_event_conn_t *c; - - c = data; - thr = nxt_thread(); - - n = thr->engine->event->io->recv(c, (u_char *) buf, size, 0); - - if (n > 0) { - return n; - } - - if (n == 0) { - return CYASSL_CBIO_ERR_CONN_CLOSE; - } - - if (n == NXT_AGAIN) { - return CYASSL_CBIO_ERR_WANT_READ; - } - - return CYASSL_CBIO_ERR_GENERAL; -} - - -static int -nxt_cyassl_io_send(CYASSL *ssl, char *buf, int size, void *data) -{ - ssize_t n; - nxt_thread_t *thr; - nxt_event_conn_t *c; - - c = data; - thr = nxt_thread(); - - n = thr->engine->event->io->send(c, (u_char *) buf, size); - - if (n > 0) { - return n; - } - - if (n == NXT_AGAIN) { - return CYASSL_CBIO_ERR_WANT_WRITE; - } - - return CYASSL_CBIO_ERR_GENERAL; -} - - -static void -nxt_cyassl_conn_handshake(nxt_thread_t *thr, void *obj, void *data) -{ - int ret; - nxt_int_t n; - nxt_err_t err; - nxt_event_conn_t *c; - nxt_cyassl_conn_t *ssltls; - - c = obj; - ssltls = c->u.ssltls; - - nxt_log_debug(thr->log, "cyassl conn handshake: %d", ssltls->times); - - /* "ssltls->times == 1" is suitable to run CyaSSL_negotiate() in job. */ - - ret = CyaSSL_negotiate(ssltls->session); - - err = (ret != 0) ? nxt_socket_errno : 0; - - nxt_thread_time_debug_update(thr); - - nxt_log_debug(thr->log, "CyaSSL_negotiate(%d): %d", c->socket.fd, ret); - - if (ret == 0) { - nxt_cyassl_conn_io_read(thr, c, data); - return; - } - - n = nxt_cyassl_conn_test_error(thr, c, ret, nxt_cyassl_conn_handshake); - - if (n == NXT_ERROR) { - nxt_cyassl_conn_error(c, err, "CyaSSL_negotiate(%d) failed", - c->socket.fd); - - nxt_event_conn_io_handle(thr, c->read_work_queue, - c->read_state->error_handler, c, data); - - } else if (ssltls->ssl_error == SSL_ERROR_WANT_READ && ssltls->times < 2) { - ssltls->times++; - } -} - - -static void -nxt_cyassl_conn_io_read(nxt_thread_t *thr, void *obj, void *data) -{ - int ret; - nxt_buf_t *b; - nxt_err_t err; - nxt_int_t n; - nxt_event_conn_t *c; - nxt_cyassl_conn_t *ssltls; - nxt_work_handler_t handler; - - c = obj; - - nxt_log_debug(thr->log, "cyassl conn read"); - - handler = c->read_state->ready_handler; - b = c->read; - - /* b == NULL is used to test descriptor readiness. */ - - if (b != NULL) { - ssltls = c->u.ssltls; - - ret = CyaSSL_read(ssltls->session, b->mem.free, - b->mem.end - b->mem.free); - - err = (ret <= 0) ? nxt_socket_errno : 0; - - nxt_log_debug(thr->log, "CyaSSL_read(%d, %p, %uz): %d", - c->socket.fd, b->mem.free, b->mem.end - b->mem.free, ret); - - if (ret > 0) { - /* c->socket.read_ready is kept. */ - b->mem.free += ret; - handler = c->read_state->ready_handler; - - } else { - n = nxt_cyassl_conn_test_error(thr, c, ret, - nxt_cyassl_conn_io_read); - - if (nxt_fast_path(n != NXT_ERROR)) { - return; - } - - nxt_cyassl_conn_error(c, err, "CyaSSL_read(%d, %p, %uz) failed", - c->socket.fd, b->mem.free, - b->mem.end - b->mem.free); - - handler = c->read_state->error_handler; - } - } - - nxt_event_conn_io_handle(thr, c->read_work_queue, handler, c, data); -} - - -static ssize_t -nxt_cyassl_conn_io_write_chunk(nxt_thread_t *thr, nxt_event_conn_t *c, - nxt_buf_t *b, size_t limit) -{ - nxt_cyassl_conn_t *ssltls; - - nxt_log_debug(thr->log, "cyassl conn write chunk"); - - ssltls = c->u.ssltls; - - return nxt_sendbuf_copy_coalesce(c, &ssltls->buffer, b, limit); -} - - -static ssize_t -nxt_cyassl_conn_io_send(nxt_event_conn_t *c, void *buf, size_t size) -{ - int ret; - nxt_err_t err; - nxt_int_t n; - nxt_cyassl_conn_t *ssltls; - - nxt_log_debug(c->socket.log, "cyassl send"); - - ssltls = c->u.ssltls; - - ret = CyaSSL_write(ssltls->session, buf, size); - - if (ret <= 0) { - err = nxt_socket_errno; - c->socket.error = err; - - } else { - err = 0; - } - - nxt_log_debug(c->socket.log, "CyaSSL_write(%d, %p, %uz): %d", - c->socket.fd, buf, size, ret); - - if (ret > 0) { - return ret; - } - - n = nxt_cyassl_conn_test_error(nxt_thread(), c, ret, - nxt_event_conn_io_write); - - if (nxt_slow_path(n == NXT_ERROR)) { - nxt_cyassl_conn_error(c, err, "CyaSSL_write(%d, %p, %uz) failed", - c->socket.fd, buf, size); - } - - return n; -} - - -static void -nxt_cyassl_conn_io_shutdown(nxt_thread_t *thr, void *obj, void *data) -{ - int ret; - nxt_event_conn_t *c; - nxt_cyassl_conn_t *ssltls; - - c = obj; - - nxt_log_debug(thr->log, "cyassl conn shutdown"); - - ssltls = c->u.ssltls; - - ret = CyaSSL_shutdown(ssltls->session); - - nxt_log_debug(thr->log, "CyaSSL_shutdown(%d): %d", c->socket.fd, ret); - - if (nxt_slow_path(ret != SSL_SUCCESS)) { - nxt_cyassl_conn_error(c, 0, "CyaSSL_shutdown(%d) failed", c->socket.fd); - } - - nxt_event_conn_io_handle(thr, c->write_work_queue, - c->write_state->close_handler, c, data); -} - - -static nxt_int_t -nxt_cyassl_conn_test_error(nxt_thread_t *thr, nxt_event_conn_t *c, int ret, - nxt_work_handler_t handler) -{ - nxt_work_queue_t *wq; - nxt_cyassl_conn_t *ssltls; - - ssltls = c->u.ssltls; - ssltls->ssl_error = CyaSSL_get_error(ssltls->session, ret); - - nxt_log_debug(thr->log, "CyaSSL_get_error(): %d", ssltls->ssl_error); - - switch (ssltls->ssl_error) { - - case SSL_ERROR_WANT_READ: - nxt_event_fd_block_write(thr->engine, &c->socket); - - c->socket.read_ready = 0; - c->socket.read_handler = handler; - - if (nxt_event_fd_is_disabled(c->socket.read)) { - nxt_event_fd_enable_read(thr->engine, &c->socket); - } - - return NXT_AGAIN; - - case SSL_ERROR_WANT_WRITE: - nxt_event_fd_block_read(thr->engine, &c->socket); - - c->socket.write_ready = 0; - c->socket.write_handler = handler; - - if (nxt_event_fd_is_disabled(c->socket.write)) { - nxt_event_fd_enable_write(thr->engine, &c->socket); - } - - return NXT_AGAIN; - - case SSL_ERROR_ZERO_RETURN: - /* A "close notify" alert */ - - if (c->read_state != NULL) { - wq = c->read_work_queue; - handler = c->read_state->close_handler; - - } else { - wq = c->write_work_queue; - handler = c->write_state->close_handler; - } - - nxt_event_conn_io_handle(thr, wq, handler, c, c->socket.data); - - return 0; - - default: - return NXT_ERROR; - } -} - - -static void nxt_cdecl -nxt_cyassl_conn_error(nxt_event_conn_t *c, nxt_err_t err, const char *fmt, ...) -{ - u_char *p, *end; - va_list args; - nxt_uint_t level; - nxt_cyassl_conn_t *ssltls; - u_char msg[NXT_MAX_ERROR_STR]; - - ssltls = c->u.ssltls; - - level = nxt_cyassl_log_error_level(c, err, ssltls->ssl_error); - - if (nxt_log_level_enough(c->socket.log, level)) { - - end = msg + sizeof(msg); - - va_start(args, fmt); - p = nxt_vsprintf(msg, end, fmt, args); - va_end(args); - - if (err != 0) { - p = nxt_sprintf(p, end, " %E", err); - } - - p = nxt_cyassl_copy_error(ssltls->ssl_error, p, end); - - nxt_log_error(level, c->socket.log, "%*s", p - msg, msg); - } -} - - -static nxt_uint_t -nxt_cyassl_log_error_level(nxt_event_conn_t *c, nxt_err_t err, int ssl_error) -{ - switch (ssl_error) { - - case SOCKET_ERROR_E: /* -208 */ - case MATCH_SUITE_ERROR: /* -261 */ - break; - - default: - return NXT_LOG_ALERT; - } - - return NXT_LOG_INFO; -} - - -static void nxt_cdecl -nxt_cyassl_log_error(nxt_uint_t level, nxt_log_t *log, int err, - const char *fmt, ...) -{ - u_char *p, *end; - va_list args; - u_char msg[NXT_MAX_ERROR_STR]; - - if (nxt_log_level_enough(log, level)) { - - end = msg + sizeof(msg); - - va_start(args, fmt); - p = nxt_vsprintf(msg, end, fmt, args); - va_end(args); - - p = nxt_cyassl_copy_error(err, p, end); - - nxt_log_error(level, log, "%*s", p - msg, msg); - } -} - - -static u_char * -nxt_cyassl_copy_error(int err, u_char *p, u_char *end) -{ - p = nxt_sprintf(p, end, " (SSL:%d ", err); - - CyaSSL_ERR_error_string_n(err, (char *) p, end - p); - - p += nxt_strlen(p); - - if (p < end) { - *p++ = ')'; - } - - return p; -} diff --git a/src/nxt_devpoll_engine.c b/src/nxt_devpoll_engine.c deleted file mode 100644 index 71ab11a3..00000000 --- a/src/nxt_devpoll_engine.c +++ /dev/null @@ -1,661 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * "/dev/poll" has been introduced in Solaris 7 (11/99), HP-UX 11.22 (named - * "eventport pseudo driver" internally, not to be confused with Solaris 10 - * event ports), IRIX 6.5.15, and Tru64 UNIX 5.1A. - * - * Although "/dev/poll" descriptor is a file descriptor, nevertheless - * it cannot be added to another poll set, Solaris poll(7d): - * - * The /dev/poll driver does not yet support polling. Polling on a - * /dev/poll file descriptor will result in POLLERR being returned - * in the revents field of pollfd structure. - */ - - -#define NXT_DEVPOLL_ADD 0 -#define NXT_DEVPOLL_UPDATE 1 -#define NXT_DEVPOLL_CHANGE 2 -#define NXT_DEVPOLL_DELETE 3 - - -static nxt_int_t nxt_devpoll_create(nxt_event_engine_t *engine, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_devpoll_free(nxt_event_engine_t *engine); -static void nxt_devpoll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static void nxt_devpoll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static nxt_bool_t nxt_devpoll_close(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_devpoll_enable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_devpoll_enable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_devpoll_disable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_devpoll_disable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_devpoll_block_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_devpoll_block_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_devpoll_oneshot_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_devpoll_oneshot_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_devpoll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, - nxt_uint_t op, nxt_uint_t events); -static nxt_int_t nxt_devpoll_commit_changes(nxt_event_engine_t *engine); -static void nxt_devpoll_change_error(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_devpoll_remove(nxt_event_engine_t *engine, nxt_fd_t fd); -static nxt_int_t nxt_devpoll_write(nxt_event_engine_t *engine, - struct pollfd *pfd, size_t n); -static void nxt_devpoll_poll(nxt_event_engine_t *engine, - nxt_msec_t timeout); - - -const nxt_event_interface_t nxt_devpoll_engine = { - "devpoll", - nxt_devpoll_create, - nxt_devpoll_free, - nxt_devpoll_enable, - nxt_devpoll_disable, - nxt_devpoll_disable, - nxt_devpoll_close, - nxt_devpoll_enable_read, - nxt_devpoll_enable_write, - nxt_devpoll_disable_read, - nxt_devpoll_disable_write, - nxt_devpoll_block_read, - nxt_devpoll_block_write, - nxt_devpoll_oneshot_read, - nxt_devpoll_oneshot_write, - nxt_devpoll_enable_read, - NULL, - NULL, - NULL, - NULL, - nxt_devpoll_poll, - - &nxt_unix_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static nxt_int_t -nxt_devpoll_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - void *changes; - - engine->u.devpoll.fd = -1; - engine->u.devpoll.mchanges = mchanges; - engine->u.devpoll.mevents = mevents; - - changes = nxt_malloc(sizeof(nxt_devpoll_change_t) * mchanges); - if (changes == NULL) { - goto fail; - } - - engine->u.devpoll.changes = changes; - - /* - * NXT_DEVPOLL_CHANGE requires two struct pollfd's: - * for POLLREMOVE and subsequent POLLIN or POLLOUT. - */ - changes = nxt_malloc(2 * sizeof(struct pollfd) * mchanges); - if (changes == NULL) { - goto fail; - } - - engine->u.devpoll.write_changes = changes; - - engine->u.devpoll.events = nxt_malloc(sizeof(struct pollfd) * mevents); - if (engine->u.devpoll.events == NULL) { - goto fail; - } - - engine->u.devpoll.fd = open("/dev/poll", O_RDWR); - - if (engine->u.devpoll.fd == -1) { - nxt_alert(&engine->task, "open(\"/dev/poll\") failed %E", nxt_errno); - goto fail; - } - - nxt_debug(&engine->task, "open(\"/dev/poll\"): %d", engine->u.devpoll.fd); - - return NXT_OK; - -fail: - - nxt_devpoll_free(engine); - - return NXT_ERROR; -} - - -static void -nxt_devpoll_free(nxt_event_engine_t *engine) -{ - nxt_fd_t fd; - - fd = engine->u.devpoll.fd; - - nxt_debug(&engine->task, "devpoll %d free", fd); - - if (fd != -1 && close(fd) != 0) { - nxt_alert(&engine->task, "devpoll close(%d) failed %E", fd, nxt_errno); - } - - nxt_free(engine->u.devpoll.events); - nxt_free(engine->u.devpoll.write_changes); - nxt_free(engine->u.devpoll.changes); - nxt_fd_event_hash_destroy(&engine->u.devpoll.fd_hash); - - nxt_memzero(&engine->u.devpoll, sizeof(nxt_devpoll_engine_t)); -} - - -static void -nxt_devpoll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_ACTIVE; - ev->write = NXT_EVENT_ACTIVE; - - nxt_devpoll_change(engine, ev, NXT_DEVPOLL_ADD, POLLIN | POLLOUT); -} - - -static void -nxt_devpoll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_devpoll_change(engine, ev, NXT_DEVPOLL_DELETE, POLLREMOVE); - } -} - - -/* - * Solaris does not automatically remove a closed file descriptor from - * a "/dev/poll" set: ioctl(DP_ISPOLLED) for the descriptor returns 1, - * significative of active descriptor. POLLREMOVE can remove already - * closed file descriptor, so the removal can be batched, Solaris poll(7d): - * - * When using the "/dev/poll" driver, you should remove a closed file - * descriptor from a monitored poll set. Failure to do so may result - * in a POLLNVAL revents being returned for the closed file descriptor. - * When a file descriptor is closed but not removed from the monitored - * set, and is reused in subsequent open of a different device, you - * will be polling the device associated with the reused file descriptor. - * In a multithreaded application, careful coordination among threads - * doing close and DP_POLL ioctl is recommended for consistent results. - * - * Besides Solaris and HP-UX allow to add invalid descriptors to an - * "/dev/poll" set, although the descriptors are not marked as polled, - * that is, ioctl(DP_ISPOLLED) returns 0. - * - * HP-UX poll(7): - * - * When a polled file descriptor is closed, it is automatically - * deregistered. - */ - -static nxt_bool_t -nxt_devpoll_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_devpoll_disable(engine, ev); - - return ev->changing; -} - - -/* - * Solaris poll(7d): - * - * The fd field specifies the file descriptor being polled. The events - * field indicates the interested poll events on the file descriptor. - * If a pollfd array contains multiple pollfd entries with the same fd field, - * the "events" field in each pollfd entry is OR'ed. A special POLLREMOVE - * event in the events field of the pollfd structure removes the fd from - * the monitored set. The revents field is not used. - */ - -static void -nxt_devpoll_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - if (ev->read != NXT_EVENT_BLOCKED) { - - events = POLLIN; - - if (ev->write == NXT_EVENT_INACTIVE) { - op = NXT_DEVPOLL_ADD; - - } else if (ev->write == NXT_EVENT_BLOCKED) { - ev->write = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_CHANGE; - - } else { - op = NXT_DEVPOLL_UPDATE; - events = POLLIN | POLLOUT; - } - - nxt_devpoll_change(engine, ev, op, events); - } - - ev->read = NXT_EVENT_ACTIVE; -} - - -static void -nxt_devpoll_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - if (ev->write != NXT_EVENT_BLOCKED) { - - events = POLLOUT; - - if (ev->read == NXT_EVENT_INACTIVE) { - op = NXT_DEVPOLL_ADD; - - } else if (ev->read == NXT_EVENT_BLOCKED) { - ev->read = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_CHANGE; - - } else { - op = NXT_DEVPOLL_UPDATE; - events = POLLIN | POLLOUT; - } - - nxt_devpoll_change(engine, ev, op, events); - } - - ev->write = NXT_EVENT_ACTIVE; -} - - -static void -nxt_devpoll_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write <= NXT_EVENT_BLOCKED) { - ev->write = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_DELETE; - events = POLLREMOVE; - - } else { - op = NXT_DEVPOLL_CHANGE; - events = POLLOUT; - } - - nxt_devpoll_change(engine, ev, op, events); -} - - -static void -nxt_devpoll_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read <= NXT_EVENT_BLOCKED) { - ev->read = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_DELETE; - events = POLLREMOVE; - - } else { - op = NXT_DEVPOLL_CHANGE; - events = POLLIN; - } - - nxt_devpoll_change(engine, ev, op, events); -} - - -static void -nxt_devpoll_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_devpoll_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_devpoll_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_devpoll_enable_read(engine, ev); - - ev->read = NXT_EVENT_ONESHOT; -} - - -static void -nxt_devpoll_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_devpoll_enable_write(engine, ev); - - ev->write = NXT_EVENT_ONESHOT; -} - - -static void -nxt_devpoll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, - nxt_uint_t op, nxt_uint_t events) -{ - nxt_devpoll_change_t *change; - - nxt_debug(ev->task, "devpoll %d change fd:%d op:%ui ev:%04Xi", - engine->u.devpoll.fd, ev->fd, op, events); - - if (engine->u.devpoll.nchanges >= engine->u.devpoll.mchanges) { - (void) nxt_devpoll_commit_changes(engine); - } - - ev->changing = 1; - - change = &engine->u.devpoll.changes[engine->u.devpoll.nchanges++]; - change->op = op; - change->events = events; - change->event = ev; -} - - -static nxt_int_t -nxt_devpoll_commit_changes(nxt_event_engine_t *engine) -{ - size_t n; - nxt_int_t ret, retval; - struct pollfd *pfd, *write_changes; - nxt_fd_event_t *ev; - nxt_devpoll_change_t *change, *end; - - nxt_debug(&engine->task, "devpoll %d changes:%ui", - engine->u.devpoll.fd, engine->u.devpoll.nchanges); - - retval = NXT_OK; - n = 0; - write_changes = engine->u.devpoll.write_changes; - change = engine->u.devpoll.changes; - end = change + engine->u.devpoll.nchanges; - - do { - ev = change->event; - - nxt_debug(&engine->task, "devpoll fd:%d op:%d ev:%04Xd", - ev->fd, change->op, change->events); - - if (change->op == NXT_DEVPOLL_CHANGE) { - pfd = &write_changes[n++]; - pfd->fd = ev->fd; - pfd->events = POLLREMOVE; - pfd->revents = 0; - } - - pfd = &write_changes[n++]; - pfd->fd = ev->fd; - pfd->events = change->events; - pfd->revents = 0; - - ev->changing = 0; - - change++; - - } while (change < end); - - change = engine->u.devpoll.changes; - end = change + engine->u.devpoll.nchanges; - - ret = nxt_devpoll_write(engine, write_changes, n); - - if (nxt_slow_path(ret != NXT_OK)) { - - do { - nxt_devpoll_change_error(engine, change->event); - change++; - } while (change < end); - - engine->u.devpoll.nchanges = 0; - - return NXT_ERROR; - } - - do { - ev = change->event; - - if (change->op == NXT_DEVPOLL_ADD) { - ret = nxt_fd_event_hash_add(&engine->u.devpoll.fd_hash, ev->fd, ev); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_devpoll_change_error(engine, ev); - retval = NXT_ERROR; - } - - } else if (change->op == NXT_DEVPOLL_DELETE) { - nxt_fd_event_hash_delete(&engine->task, &engine->u.devpoll.fd_hash, - ev->fd, 0); - } - - /* Nothing tp do for NXT_DEVPOLL_UPDATE and NXT_DEVPOLL_CHANGE. */ - - change++; - - } while (change < end); - - engine->u.devpoll.nchanges = 0; - - return retval; -} - - -static void -nxt_devpoll_change_error(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler, - ev->task, ev, ev->data); - - nxt_fd_event_hash_delete(ev->task, &engine->u.devpoll.fd_hash, ev->fd, 1); - - nxt_devpoll_remove(engine, ev->fd); -} - - -static void -nxt_devpoll_remove(nxt_event_engine_t *engine, nxt_fd_t fd) -{ - int n; - struct pollfd pfd; - - pfd.fd = fd; - pfd.events = 0; - pfd.revents = 0; - - n = ioctl(engine->u.devpoll.fd, DP_ISPOLLED, &pfd); - - nxt_debug(&engine->task, "ioctl(%d, DP_ISPOLLED, %d): %d", - engine->u.devpoll.fd, fd, n); - - if (n == 0) { - /* The file descriptor is not in the set. */ - return; - } - - if (n == -1) { - nxt_alert(&engine->task, "ioctl(%d, DP_ISPOLLED, %d) failed %E", - engine->u.devpoll.fd, fd, nxt_errno); - /* Fall through. */ - } - - /* n == 1: the file descriptor is in the set. */ - - nxt_debug(&engine->task, "devpoll %d remove fd:%d", - engine->u.devpoll.fd, fd); - - pfd.fd = fd; - pfd.events = POLLREMOVE; - pfd.revents = 0; - - nxt_devpoll_write(engine, &pfd, 1); -} - - -static nxt_int_t -nxt_devpoll_write(nxt_event_engine_t *engine, struct pollfd *pfd, size_t n) -{ - int fd; - - fd = engine->u.devpoll.fd; - - nxt_debug(&engine->task, "devpoll write(%d) changes:%uz", fd, n); - - n *= sizeof(struct pollfd); - - if (nxt_slow_path(write(fd, pfd, n) == (ssize_t) n)) { - return NXT_OK; - } - - nxt_alert(&engine->task, "devpoll write(%d) failed %E", fd, nxt_errno); - - return NXT_ERROR; -} - - -static void -nxt_devpoll_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) -{ - int nevents; - nxt_fd_t fd; - nxt_int_t i; - nxt_err_t err; - nxt_uint_t events, level; - struct dvpoll dvp; - struct pollfd *pfd; - nxt_fd_event_t *ev; - - if (engine->u.devpoll.nchanges != 0) { - if (nxt_devpoll_commit_changes(engine) != NXT_OK) { - /* Error handlers have been enqueued on failure. */ - timeout = 0; - } - } - - nxt_debug(&engine->task, "ioctl(%d, DP_POLL) timeout:%M", - engine->u.devpoll.fd, timeout); - - dvp.dp_fds = engine->u.devpoll.events; - dvp.dp_nfds = engine->u.devpoll.mevents; - dvp.dp_timeout = timeout; - - nevents = ioctl(engine->u.devpoll.fd, DP_POLL, &dvp); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(engine->task.thread); - - nxt_debug(&engine->task, "ioctl(%d, DP_POLL): %d", - engine->u.devpoll.fd, nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - - nxt_log(&engine->task, level, "ioctl(%d, DP_POLL) failed %E", - engine->u.devpoll.fd, err); - - return; - } - - for (i = 0; i < nevents; i++) { - - pfd = &engine->u.devpoll.events[i]; - fd = pfd->fd; - events = pfd->revents; - - ev = nxt_fd_event_hash_get(&engine->task, &engine->u.devpoll.fd_hash, - fd); - - if (nxt_slow_path(ev == NULL)) { - nxt_alert(&engine->task, - "ioctl(%d, DP_POLL) returned invalid " - "fd:%d ev:%04Xd rev:%04uXi", - engine->u.devpoll.fd, fd, pfd->events, events); - - nxt_devpoll_remove(engine, fd); - continue; - } - - nxt_debug(ev->task, "devpoll: fd:%d ev:%04uXi rd:%d wr:%d", - fd, events, ev->read, ev->write); - - if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { - nxt_alert(ev->task, - "ioctl(%d, DP_POLL) error fd:%d ev:%04Xd rev:%04uXi", - engine->u.devpoll.fd, fd, pfd->events, events); - - nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler, - ev->task, ev, ev->data); - continue; - } - - if (events & POLLIN) { - ev->read_ready = 1; - - if (ev->read != NXT_EVENT_BLOCKED) { - nxt_work_queue_add(ev->read_work_queue, ev->read_handler, - ev->task, ev, ev->data); - } - - if (ev->read == NXT_EVENT_BLOCKED - || ev->read == NXT_EVENT_ONESHOT) - { - nxt_devpoll_disable_read(engine, ev); - } - } - - if (events & POLLOUT) { - ev->write_ready = 1; - - if (ev->write != NXT_EVENT_BLOCKED) { - nxt_work_queue_add(ev->write_work_queue, ev->write_handler, - ev->task, ev, ev->data); - } - - if (ev->write == NXT_EVENT_BLOCKED - || ev->write == NXT_EVENT_ONESHOT) - { - nxt_devpoll_disable_write(engine, ev); - } - } - } -} diff --git a/src/nxt_djb_hash.c b/src/nxt_djb_hash.c deleted file mode 100644 index cd315869..00000000 --- a/src/nxt_djb_hash.c +++ /dev/null @@ -1,45 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -uint32_t -nxt_djb_hash(const void *data, size_t len) -{ - uint32_t hash; - const u_char *p; - - p = data; - hash = NXT_DJB_HASH_INIT; - - while (len != 0) { - hash = nxt_djb_hash_add(hash, *p++); - len--; - } - - return hash; -} - - -uint32_t -nxt_djb_hash_lowcase(const void *data, size_t len) -{ - u_char c; - uint32_t hash; - const u_char *p; - - p = data; - hash = NXT_DJB_HASH_INIT; - - while (len != 0) { - c = *p++; - hash = nxt_djb_hash_add(hash, nxt_lowcase(c)); - len--; - } - - return hash; -} diff --git a/src/nxt_djb_hash.h b/src/nxt_djb_hash.h deleted file mode 100644 index 43395e6a..00000000 --- a/src/nxt_djb_hash.h +++ /dev/null @@ -1,25 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_DJB_HASH_H_INCLUDED_ -#define _NXT_DJB_HASH_H_INCLUDED_ - - -/* A fast and simple hash function by Daniel J. Bernstein. */ - - -NXT_EXPORT uint32_t nxt_djb_hash(const void *data, size_t len); -NXT_EXPORT uint32_t nxt_djb_hash_lowcase(const void *data, size_t len); - - -#define NXT_DJB_HASH_INIT 5381 - - -#define nxt_djb_hash_add(hash, val) \ - ((uint32_t) ((((hash) << 5) + (hash)) ^ (uint32_t) (val))) - - -#endif /* _NXT_DJB_HASH_H_INCLUDED_ */ diff --git a/src/nxt_dyld.c b/src/nxt_dyld.c deleted file mode 100644 index 63e6be14..00000000 --- a/src/nxt_dyld.c +++ /dev/null @@ -1,86 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_int_t -nxt_dyld_load(nxt_dyld_t *dyld) -{ - const char *err; - - dyld->handle = dlopen(dyld->name, RTLD_NOW | RTLD_GLOBAL); - - if (dyld->handle != NULL) { - nxt_thread_log_debug("dlopen(\"%s\")", dyld->name); - return NXT_OK; - } - - err = dlerror(); - if (err == NULL) { - err = "(null)"; - } - - nxt_thread_log_alert("dlopen(\"%s\") failed: %s", dyld->name, err); - - return NXT_ERROR; -} - - -void * -nxt_dyld_symbol(nxt_dyld_t *dyld, const char *symbol) -{ - void *handle, *s; - const char *name; - const char *err; - - if (dyld == NXT_DYLD_ANY) { - handle = RTLD_DEFAULT; - name = "RTLD_DEFAULT"; - - } else { - handle = dyld->handle; - name = dyld->name; - } - - s = dlsym(handle, symbol); - - if (s != NULL) { - nxt_thread_log_debug("dlsym(\"%s\", \"%s\")", name, symbol); - return s; - } - - err = dlerror(); - if (err == NULL) { - err = "(null)"; - } - - nxt_thread_log_alert("dlsym(\"%s\", \"%s\") failed: %s", name, symbol, err); - - return s; -} - - -nxt_int_t -nxt_dyld_unload(nxt_dyld_t *dyld) -{ - const char *err; - - if (dlclose(dyld->handle) == 0) { - nxt_thread_log_debug("dlclose(\"%s\")", dyld->name); - return NXT_OK; - } - - err = dlerror(); - - if (err == NULL) { - err = "(null)"; - } - - nxt_thread_log_alert("dlclose(\"%s\") failed: %s", dyld->name, err); - - return NXT_ERROR; -} diff --git a/src/nxt_dyld.h b/src/nxt_dyld.h deleted file mode 100644 index 65ce1874..00000000 --- a/src/nxt_dyld.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_DYLD_H_INCLUDED_ -#define _NXT_UNIX_DYLD_H_INCLUDED_ - - -typedef struct { - void *handle; - char *name; -} nxt_dyld_t; - - -#define NXT_DYLD_ANY RTLD_DEFAULT - - -#define nxt_dyld_is_valid(dyld) \ - ((dyld)->handle != NULL) - - -NXT_EXPORT nxt_int_t nxt_dyld_load(nxt_dyld_t *dyld); -NXT_EXPORT void *nxt_dyld_symbol(nxt_dyld_t *dyld, const char *symbol); -NXT_EXPORT nxt_int_t nxt_dyld_unload(nxt_dyld_t *dyld); - - -#endif /* _NXT_UNIX_DYLD_H_INCLUDED_ */ diff --git a/src/nxt_epoll_engine.c b/src/nxt_epoll_engine.c deleted file mode 100644 index d53df1bc..00000000 --- a/src/nxt_epoll_engine.c +++ /dev/null @@ -1,1174 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * The first epoll version has been introduced in Linux 2.5.44. The - * interface was changed several times since then and the final version - * of epoll_create(), epoll_ctl(), epoll_wait(), and EPOLLET mode has - * been introduced in Linux 2.6.0 and is supported since glibc 2.3.2. - * - * EPOLLET mode did not work reliable in early implementaions and in - * Linux 2.4 backport. - * - * EPOLLONESHOT Linux 2.6.2, glibc 2.3. - * EPOLLRDHUP Linux 2.6.17, glibc 2.8. - * epoll_pwait() Linux 2.6.19, glibc 2.6. - * signalfd() Linux 2.6.22, glibc 2.7. - * eventfd() Linux 2.6.22, glibc 2.7. - * timerfd_create() Linux 2.6.25, glibc 2.8. - * epoll_create1() Linux 2.6.27, glibc 2.9. - * signalfd4() Linux 2.6.27, glibc 2.9. - * eventfd2() Linux 2.6.27, glibc 2.9. - * accept4() Linux 2.6.28, glibc 2.10. - * eventfd2(EFD_SEMAPHORE) Linux 2.6.30, glibc 2.10. - * EPOLLEXCLUSIVE Linux 4.5, glibc 2.24. - */ - - -#if (NXT_HAVE_EPOLL_EDGE) -static nxt_int_t nxt_epoll_edge_create(nxt_event_engine_t *engine, - nxt_uint_t mchanges, nxt_uint_t mevents); -#endif -static nxt_int_t nxt_epoll_level_create(nxt_event_engine_t *engine, - nxt_uint_t mchanges, nxt_uint_t mevents); -static nxt_int_t nxt_epoll_create(nxt_event_engine_t *engine, - nxt_uint_t mchanges, nxt_uint_t mevents, nxt_conn_io_t *io, uint32_t mode); -static void nxt_epoll_test_accept4(nxt_event_engine_t *engine, - nxt_conn_io_t *io); -static void nxt_epoll_free(nxt_event_engine_t *engine); -static void nxt_epoll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static void nxt_epoll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static void nxt_epoll_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static nxt_bool_t nxt_epoll_close(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_epoll_enable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_epoll_enable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_epoll_disable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_epoll_disable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_epoll_block_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_epoll_block_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_epoll_oneshot_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_epoll_oneshot_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_epoll_enable_accept(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_epoll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, - int op, uint32_t events); -static void nxt_epoll_commit_changes(nxt_event_engine_t *engine); -static void nxt_epoll_error_handler(nxt_task_t *task, void *obj, void *data); -#if (NXT_HAVE_SIGNALFD) -static nxt_int_t nxt_epoll_add_signal(nxt_event_engine_t *engine); -static void nxt_epoll_signalfd_handler(nxt_task_t *task, void *obj, void *data); -#endif -#if (NXT_HAVE_EVENTFD) -static nxt_int_t nxt_epoll_enable_post(nxt_event_engine_t *engine, - nxt_work_handler_t handler); -static void nxt_epoll_eventfd_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_epoll_signal(nxt_event_engine_t *engine, nxt_uint_t signo); -#endif -static void nxt_epoll_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); - -#if (NXT_HAVE_ACCEPT4) -static void nxt_epoll_conn_io_accept4(nxt_task_t *task, void *obj, - void *data); -#endif - - -#if (NXT_HAVE_EPOLL_EDGE) - -static void nxt_epoll_edge_conn_io_connect(nxt_task_t *task, void *obj, - void *data); -static void nxt_epoll_edge_conn_connected(nxt_task_t *task, void *obj, - void *data); -static ssize_t nxt_epoll_edge_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); - - -static nxt_conn_io_t nxt_epoll_edge_conn_io = { - .connect = nxt_epoll_edge_conn_io_connect, - .accept = nxt_conn_io_accept, - - .read = nxt_conn_io_read, - .recvbuf = nxt_epoll_edge_conn_io_recvbuf, - .recv = nxt_conn_io_recv, - - .write = nxt_conn_io_write, - .sendbuf = nxt_conn_io_sendbuf, - -#if (NXT_HAVE_LINUX_SENDFILE) - .old_sendbuf = nxt_linux_event_conn_io_sendfile, -#else - .old_sendbuf = nxt_event_conn_io_sendbuf, -#endif - - .writev = nxt_event_conn_io_writev, - .send = nxt_event_conn_io_send, -}; - - -const nxt_event_interface_t nxt_epoll_edge_engine = { - "epoll_edge", - nxt_epoll_edge_create, - nxt_epoll_free, - nxt_epoll_enable, - nxt_epoll_disable, - nxt_epoll_delete, - nxt_epoll_close, - nxt_epoll_enable_read, - nxt_epoll_enable_write, - nxt_epoll_disable_read, - nxt_epoll_disable_write, - nxt_epoll_block_read, - nxt_epoll_block_write, - nxt_epoll_oneshot_read, - nxt_epoll_oneshot_write, - nxt_epoll_enable_accept, - NULL, - NULL, -#if (NXT_HAVE_EVENTFD) - nxt_epoll_enable_post, - nxt_epoll_signal, -#else - NULL, - NULL, -#endif - nxt_epoll_poll, - - &nxt_epoll_edge_conn_io, - -#if (NXT_HAVE_INOTIFY) - NXT_FILE_EVENTS, -#else - NXT_NO_FILE_EVENTS, -#endif - -#if (NXT_HAVE_SIGNALFD) - NXT_SIGNAL_EVENTS, -#else - NXT_NO_SIGNAL_EVENTS, -#endif -}; - -#endif - - -const nxt_event_interface_t nxt_epoll_level_engine = { - "epoll_level", - nxt_epoll_level_create, - nxt_epoll_free, - nxt_epoll_enable, - nxt_epoll_disable, - nxt_epoll_delete, - nxt_epoll_close, - nxt_epoll_enable_read, - nxt_epoll_enable_write, - nxt_epoll_disable_read, - nxt_epoll_disable_write, - nxt_epoll_block_read, - nxt_epoll_block_write, - nxt_epoll_oneshot_read, - nxt_epoll_oneshot_write, - nxt_epoll_enable_accept, - NULL, - NULL, -#if (NXT_HAVE_EVENTFD) - nxt_epoll_enable_post, - nxt_epoll_signal, -#else - NULL, - NULL, -#endif - nxt_epoll_poll, - - &nxt_unix_conn_io, - -#if (NXT_HAVE_INOTIFY) - NXT_FILE_EVENTS, -#else - NXT_NO_FILE_EVENTS, -#endif - -#if (NXT_HAVE_SIGNALFD) - NXT_SIGNAL_EVENTS, -#else - NXT_NO_SIGNAL_EVENTS, -#endif -}; - - -#if (NXT_HAVE_EPOLL_EDGE) - -static nxt_int_t -nxt_epoll_edge_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - return nxt_epoll_create(engine, mchanges, mevents, &nxt_epoll_edge_conn_io, - EPOLLET | EPOLLRDHUP); -} - -#endif - - -static nxt_int_t -nxt_epoll_level_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - return nxt_epoll_create(engine, mchanges, mevents, - &nxt_unix_conn_io, 0); -} - - -static nxt_int_t -nxt_epoll_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, - nxt_uint_t mevents, nxt_conn_io_t *io, uint32_t mode) -{ - engine->u.epoll.fd = -1; - engine->u.epoll.mode = mode; - engine->u.epoll.mchanges = mchanges; - engine->u.epoll.mevents = mevents; -#if (NXT_HAVE_SIGNALFD) - engine->u.epoll.signalfd.fd = -1; -#endif - - engine->u.epoll.changes = nxt_malloc(sizeof(nxt_epoll_change_t) * mchanges); - if (engine->u.epoll.changes == NULL) { - goto fail; - } - - engine->u.epoll.events = nxt_malloc(sizeof(struct epoll_event) * mevents); - if (engine->u.epoll.events == NULL) { - goto fail; - } - - engine->u.epoll.fd = epoll_create(1); - if (engine->u.epoll.fd == -1) { - nxt_alert(&engine->task, "epoll_create() failed %E", nxt_errno); - goto fail; - } - - nxt_debug(&engine->task, "epoll_create(): %d", engine->u.epoll.fd); - - if (engine->signals != NULL) { - -#if (NXT_HAVE_SIGNALFD) - - if (nxt_epoll_add_signal(engine) != NXT_OK) { - goto fail; - } - -#endif - - nxt_epoll_test_accept4(engine, io); - } - - return NXT_OK; - -fail: - - nxt_epoll_free(engine); - - return NXT_ERROR; -} - - -static void -nxt_epoll_test_accept4(nxt_event_engine_t *engine, nxt_conn_io_t *io) -{ - static nxt_work_handler_t handler; - - if (handler == NULL) { - - handler = io->accept; - -#if (NXT_HAVE_ACCEPT4) - - (void) accept4(-1, NULL, NULL, SOCK_NONBLOCK); - - if (nxt_errno != NXT_ENOSYS) { - handler = nxt_epoll_conn_io_accept4; - - } else { - nxt_log(&engine->task, NXT_LOG_INFO, "accept4() failed %E", - NXT_ENOSYS); - } - -#endif - } - - io->accept = handler; -} - - -static void -nxt_epoll_free(nxt_event_engine_t *engine) -{ - int fd; - - nxt_debug(&engine->task, "epoll %d free", engine->u.epoll.fd); - -#if (NXT_HAVE_SIGNALFD) - - fd = engine->u.epoll.signalfd.fd; - - if (fd != -1 && close(fd) != 0) { - nxt_alert(&engine->task, "signalfd close(%d) failed %E", fd, nxt_errno); - } - -#endif - -#if (NXT_HAVE_EVENTFD) - - fd = engine->u.epoll.eventfd.fd; - - if (fd != -1 && close(fd) != 0) { - nxt_alert(&engine->task, "eventfd close(%d) failed %E", fd, nxt_errno); - } - -#endif - - fd = engine->u.epoll.fd; - - if (fd != -1 && close(fd) != 0) { - nxt_alert(&engine->task, "epoll close(%d) failed %E", fd, nxt_errno); - } - - nxt_free(engine->u.epoll.events); - nxt_free(engine->u.epoll.changes); - - nxt_memzero(&engine->u.epoll, sizeof(nxt_epoll_engine_t)); -} - - -static void -nxt_epoll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_ACTIVE; - ev->write = NXT_EVENT_ACTIVE; - - nxt_epoll_change(engine, ev, EPOLL_CTL_ADD, - EPOLLIN | EPOLLOUT | engine->u.epoll.mode); -} - - -static void -nxt_epoll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read > NXT_EVENT_DISABLED || ev->write > NXT_EVENT_DISABLED) { - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_epoll_change(engine, ev, EPOLL_CTL_DEL, 0); - } -} - - -static void -nxt_epoll_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_epoll_change(engine, ev, EPOLL_CTL_DEL, 0); - } -} - - -/* - * Although calling close() on a file descriptor will remove any epoll - * events that reference the descriptor, in this case the close() acquires - * the kernel global "epmutex" while epoll_ctl(EPOLL_CTL_DEL) does not - * acquire the "epmutex" since Linux 3.13 if the file descriptor presents - * only in one epoll set. Thus removing events explicitly before closing - * eliminates possible lock contention. - */ - -static nxt_bool_t -nxt_epoll_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_epoll_delete(engine, ev); - - return ev->changing; -} - - -static void -nxt_epoll_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - int op; - uint32_t events; - - if (ev->read != NXT_EVENT_BLOCKED) { - - op = EPOLL_CTL_MOD; - events = EPOLLIN | engine->u.epoll.mode; - - if (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) { - op = EPOLL_CTL_ADD; - - } else if (ev->write >= NXT_EVENT_BLOCKED) { - events |= EPOLLOUT; - } - - nxt_epoll_change(engine, ev, op, events); - } - - ev->read = NXT_EVENT_ACTIVE; -} - - -static void -nxt_epoll_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - int op; - uint32_t events; - - if (ev->write != NXT_EVENT_BLOCKED) { - - op = EPOLL_CTL_MOD; - events = EPOLLOUT | engine->u.epoll.mode; - - if (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) { - op = EPOLL_CTL_ADD; - - } else if (ev->read >= NXT_EVENT_BLOCKED) { - events |= EPOLLIN; - } - - nxt_epoll_change(engine, ev, op, events); - } - - ev->write = NXT_EVENT_ACTIVE; -} - - -static void -nxt_epoll_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - int op; - uint32_t events; - - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write <= NXT_EVENT_DISABLED) { - ev->write = NXT_EVENT_INACTIVE; - op = EPOLL_CTL_DEL; - events = 0; - - } else { - op = EPOLL_CTL_MOD; - events = EPOLLOUT | engine->u.epoll.mode; - } - - nxt_epoll_change(engine, ev, op, events); -} - - -static void -nxt_epoll_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - int op; - uint32_t events; - - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read <= NXT_EVENT_DISABLED) { - ev->read = NXT_EVENT_INACTIVE; - op = EPOLL_CTL_DEL; - events = 0; - - } else { - op = EPOLL_CTL_MOD; - events = EPOLLIN | engine->u.epoll.mode; - } - - nxt_epoll_change(engine, ev, op, events); -} - - -static void -nxt_epoll_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_epoll_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_BLOCKED; - } -} - - -/* - * NXT_EVENT_DISABLED state is used to track whether EPOLLONESHOT - * event should be added or modified, epoll_ctl(2): - * - * EPOLLONESHOT (since Linux 2.6.2) - * Sets the one-shot behavior for the associated file descriptor. - * This means that after an event is pulled out with epoll_wait(2) - * the associated file descriptor is internally disabled and no - * other events will be reported by the epoll interface. The user - * must call epoll_ctl() with EPOLL_CTL_MOD to rearm the file - * descriptor with a new event mask. - */ - -static void -nxt_epoll_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - int op; - - op = (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) ? - EPOLL_CTL_ADD : EPOLL_CTL_MOD; - - ev->read = NXT_EVENT_ONESHOT; - ev->write = NXT_EVENT_INACTIVE; - - nxt_epoll_change(engine, ev, op, EPOLLIN | EPOLLONESHOT); -} - - -static void -nxt_epoll_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - int op; - - op = (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) ? - EPOLL_CTL_ADD : EPOLL_CTL_MOD; - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_ONESHOT; - - nxt_epoll_change(engine, ev, op, EPOLLOUT | EPOLLONESHOT); -} - - -static void -nxt_epoll_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - uint32_t events; - - ev->read = NXT_EVENT_ACTIVE; - - events = EPOLLIN; - -#ifdef EPOLLEXCLUSIVE - events |= EPOLLEXCLUSIVE; -#endif - - nxt_epoll_change(engine, ev, EPOLL_CTL_ADD, events); -} - - -/* - * epoll changes are batched to improve instruction and data cache - * locality of several epoll_ctl() calls followed by epoll_wait() call. - */ - -static void -nxt_epoll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, int op, - uint32_t events) -{ - nxt_epoll_change_t *change; - - nxt_debug(ev->task, "epoll %d set event: fd:%d op:%d ev:%XD", - engine->u.epoll.fd, ev->fd, op, events); - - if (engine->u.epoll.nchanges >= engine->u.epoll.mchanges) { - nxt_epoll_commit_changes(engine); - } - - ev->changing = 1; - - change = &engine->u.epoll.changes[engine->u.epoll.nchanges++]; - change->op = op; - change->event.events = events; - change->event.data.ptr = ev; -} - - -static void -nxt_epoll_commit_changes(nxt_event_engine_t *engine) -{ - int ret; - nxt_fd_event_t *ev; - nxt_epoll_change_t *change, *end; - - nxt_debug(&engine->task, "epoll %d changes:%ui", - engine->u.epoll.fd, engine->u.epoll.nchanges); - - change = engine->u.epoll.changes; - end = change + engine->u.epoll.nchanges; - - do { - ev = change->event.data.ptr; - ev->changing = 0; - - nxt_debug(ev->task, "epoll_ctl(%d): fd:%d op:%d ev:%XD", - engine->u.epoll.fd, ev->fd, change->op, - change->event.events); - - ret = epoll_ctl(engine->u.epoll.fd, change->op, ev->fd, &change->event); - - if (nxt_slow_path(ret != 0)) { - nxt_alert(ev->task, "epoll_ctl(%d, %d, %d) failed %E", - engine->u.epoll.fd, change->op, ev->fd, nxt_errno); - - nxt_work_queue_add(&engine->fast_work_queue, - nxt_epoll_error_handler, ev->task, ev, ev->data); - - engine->u.epoll.error = 1; - } - - change++; - - } while (change < end); - - engine->u.epoll.nchanges = 0; -} - - -static void -nxt_epoll_error_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_fd_event_t *ev; - - ev = obj; - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - ev->error_handler(ev->task, ev, data); -} - - -#if (NXT_HAVE_SIGNALFD) - -static nxt_int_t -nxt_epoll_add_signal(nxt_event_engine_t *engine) -{ - int fd; - struct epoll_event ee; - - if (sigprocmask(SIG_BLOCK, &engine->signals->sigmask, NULL) != 0) { - nxt_alert(&engine->task, "sigprocmask(SIG_BLOCK) failed %E", nxt_errno); - return NXT_ERROR; - } - - /* - * Glibc signalfd() wrapper always has the flags argument. Glibc 2.7 - * and 2.8 signalfd() wrappers call the original signalfd() syscall - * without the flags argument. Glibc 2.9+ signalfd() wrapper at first - * tries to call signalfd4() syscall and if it fails then calls the - * original signalfd() syscall. For this reason the non-blocking mode - * is set separately. - */ - - fd = signalfd(-1, &engine->signals->sigmask, 0); - - if (fd == -1) { - nxt_alert(&engine->task, "signalfd(%d) failed %E", - engine->u.epoll.signalfd.fd, nxt_errno); - return NXT_ERROR; - } - - engine->u.epoll.signalfd.fd = fd; - - if (nxt_fd_nonblocking(&engine->task, fd) != NXT_OK) { - return NXT_ERROR; - } - - nxt_debug(&engine->task, "signalfd(): %d", fd); - - engine->u.epoll.signalfd.data = engine->signals->handler; - engine->u.epoll.signalfd.read_work_queue = &engine->fast_work_queue; - engine->u.epoll.signalfd.read_handler = nxt_epoll_signalfd_handler; - engine->u.epoll.signalfd.log = engine->task.log; - engine->u.epoll.signalfd.task = &engine->task; - - ee.events = EPOLLIN; - ee.data.ptr = &engine->u.epoll.signalfd; - - if (epoll_ctl(engine->u.epoll.fd, EPOLL_CTL_ADD, fd, &ee) != 0) { - nxt_alert(&engine->task, "epoll_ctl(%d, %d, %d) failed %E", - engine->u.epoll.fd, EPOLL_CTL_ADD, fd, nxt_errno); - - return NXT_ERROR; - } - - return NXT_OK; -} - - -static void -nxt_epoll_signalfd_handler(nxt_task_t *task, void *obj, void *data) -{ - int n; - nxt_fd_event_t *ev; - nxt_work_handler_t handler; - struct signalfd_siginfo sfd; - - ev = obj; - handler = data; - - nxt_debug(task, "signalfd handler"); - - n = read(ev->fd, &sfd, sizeof(struct signalfd_siginfo)); - - nxt_debug(task, "read signalfd(%d): %d", ev->fd, n); - - if (n != sizeof(struct signalfd_siginfo)) { - nxt_alert(task, "read signalfd(%d) failed %E", ev->fd, nxt_errno); - return; - } - - nxt_debug(task, "signalfd(%d) signo:%d", ev->fd, sfd.ssi_signo); - - handler(task, (void *) (uintptr_t) sfd.ssi_signo, NULL); -} - -#endif - - -#if (NXT_HAVE_EVENTFD) - -static nxt_int_t -nxt_epoll_enable_post(nxt_event_engine_t *engine, nxt_work_handler_t handler) -{ - int ret; - struct epoll_event ee; - - engine->u.epoll.post_handler = handler; - - /* - * Glibc eventfd() wrapper always has the flags argument. Glibc 2.7 - * and 2.8 eventfd() wrappers call the original eventfd() syscall - * without the flags argument. Glibc 2.9+ eventfd() wrapper at first - * tries to call eventfd2() syscall and if it fails then calls the - * original eventfd() syscall. For this reason the non-blocking mode - * is set separately. - */ - - engine->u.epoll.eventfd.fd = eventfd(0, 0); - - if (engine->u.epoll.eventfd.fd == -1) { - nxt_alert(&engine->task, "eventfd() failed %E", nxt_errno); - return NXT_ERROR; - } - - ret = nxt_fd_nonblocking(&engine->task, engine->u.epoll.eventfd.fd); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - nxt_debug(&engine->task, "eventfd(): %d", engine->u.epoll.eventfd.fd); - - engine->u.epoll.eventfd.read_work_queue = &engine->fast_work_queue; - engine->u.epoll.eventfd.read_handler = nxt_epoll_eventfd_handler; - engine->u.epoll.eventfd.data = engine; - engine->u.epoll.eventfd.log = engine->task.log; - engine->u.epoll.eventfd.task = &engine->task; - - ee.events = EPOLLIN | EPOLLET; - ee.data.ptr = &engine->u.epoll.eventfd; - - ret = epoll_ctl(engine->u.epoll.fd, EPOLL_CTL_ADD, - engine->u.epoll.eventfd.fd, &ee); - - if (nxt_fast_path(ret == 0)) { - return NXT_OK; - } - - nxt_alert(&engine->task, "epoll_ctl(%d, %d, %d) failed %E", - engine->u.epoll.fd, EPOLL_CTL_ADD, engine->u.epoll.eventfd.fd, - nxt_errno); - - return NXT_ERROR; -} - - -static void -nxt_epoll_eventfd_handler(nxt_task_t *task, void *obj, void *data) -{ - int n; - uint64_t events; - nxt_event_engine_t *engine; - - engine = data; - - nxt_debug(task, "eventfd handler, times:%ui", engine->u.epoll.neventfd); - - /* - * The maximum value after write() to a eventfd() descriptor will - * block or return EAGAIN is 0xFFFFFFFFFFFFFFFE, so the descriptor - * can be read once per many notifications, for example, once per - * 2^32-2 noticifcations. Since the eventfd() file descriptor is - * always registered in EPOLLET mode, epoll returns event about - * only the latest write() to the descriptor. - */ - - if (engine->u.epoll.neventfd++ >= 0xFFFFFFFE) { - engine->u.epoll.neventfd = 0; - - n = read(engine->u.epoll.eventfd.fd, &events, sizeof(uint64_t)); - - nxt_debug(task, "read(%d): %d events:%uL", - engine->u.epoll.eventfd.fd, n, events); - - if (n != sizeof(uint64_t)) { - nxt_alert(task, "read eventfd(%d) failed %E", - engine->u.epoll.eventfd.fd, nxt_errno); - } - } - - engine->u.epoll.post_handler(task, NULL, NULL); -} - - -static void -nxt_epoll_signal(nxt_event_engine_t *engine, nxt_uint_t signo) -{ - size_t ret; - uint64_t event; - - /* - * eventfd() presents along with signalfd(), so the function - * is used only to post events and the signo argument is ignored. - */ - - event = 1; - - ret = write(engine->u.epoll.eventfd.fd, &event, sizeof(uint64_t)); - - if (nxt_slow_path(ret != sizeof(uint64_t))) { - nxt_alert(&engine->task, "write(%d) to eventfd failed %E", - engine->u.epoll.eventfd.fd, nxt_errno); - } -} - -#endif - - -static void -nxt_epoll_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) -{ - int nevents; - uint32_t events; - nxt_int_t i; - nxt_err_t err; - nxt_bool_t error; - nxt_uint_t level; - nxt_fd_event_t *ev; - struct epoll_event *event; - - if (engine->u.epoll.nchanges != 0) { - nxt_epoll_commit_changes(engine); - } - - if (engine->u.epoll.error) { - engine->u.epoll.error = 0; - /* Error handlers have been enqueued on failure. */ - timeout = 0; - } - - nxt_debug(&engine->task, "epoll_wait(%d) timeout:%M", - engine->u.epoll.fd, timeout); - - nevents = epoll_wait(engine->u.epoll.fd, engine->u.epoll.events, - engine->u.epoll.mevents, timeout); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(engine->task.thread); - - nxt_debug(&engine->task, "epoll_wait(%d): %d", engine->u.epoll.fd, nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - - nxt_log(&engine->task, level, "epoll_wait(%d) failed %E", - engine->u.epoll.fd, err); - - return; - } - - for (i = 0; i < nevents; i++) { - - event = &engine->u.epoll.events[i]; - events = event->events; - ev = event->data.ptr; - - nxt_debug(ev->task, "epoll: fd:%d ev:%04XD d:%p rd:%d wr:%d", - ev->fd, events, ev, ev->read, ev->write); - - /* - * On error epoll may set EPOLLERR and EPOLLHUP only without EPOLLIN - * or EPOLLOUT, so the "error" variable enqueues only error handler. - */ - error = ((events & (EPOLLERR | EPOLLHUP)) != 0); - ev->epoll_error = error; - - if (error - && ev->read <= NXT_EVENT_BLOCKED - && ev->write <= NXT_EVENT_BLOCKED) - { - error = 0; - } - -#if (NXT_HAVE_EPOLL_EDGE) - - ev->epoll_eof = ((events & EPOLLRDHUP) != 0); - -#endif - - if ((events & EPOLLIN) != 0) { - ev->read_ready = 1; - - if (ev->read != NXT_EVENT_BLOCKED) { - - if (ev->read == NXT_EVENT_ONESHOT) { - ev->read = NXT_EVENT_DISABLED; - } - - nxt_work_queue_add(ev->read_work_queue, ev->read_handler, - ev->task, ev, ev->data); - - error = 0; - - } else if (engine->u.epoll.mode == 0) { - /* Level-triggered mode. */ - nxt_epoll_disable_read(engine, ev); - } - } - - if ((events & EPOLLOUT) != 0) { - ev->write_ready = 1; - - if (ev->write != NXT_EVENT_BLOCKED) { - - if (ev->write == NXT_EVENT_ONESHOT) { - ev->write = NXT_EVENT_DISABLED; - } - - nxt_work_queue_add(ev->write_work_queue, ev->write_handler, - ev->task, ev, ev->data); - - error = 0; - - } else if (engine->u.epoll.mode == 0) { - /* Level-triggered mode. */ - nxt_epoll_disable_write(engine, ev); - } - } - - if (!error) { - continue; - } - - ev->read_ready = 1; - ev->write_ready = 1; - - if (ev->read == NXT_EVENT_BLOCKED && ev->write == NXT_EVENT_BLOCKED) { - - if (engine->u.epoll.mode == 0) { - /* Level-triggered mode. */ - nxt_epoll_disable(engine, ev); - } - - continue; - } - - nxt_work_queue_add(&engine->fast_work_queue, nxt_epoll_error_handler, - ev->task, ev, ev->data); - } -} - - -#if (NXT_HAVE_ACCEPT4) - -static void -nxt_epoll_conn_io_accept4(nxt_task_t *task, void *obj, void *data) -{ - socklen_t socklen; - nxt_conn_t *c; - nxt_socket_t s; - struct sockaddr *sa; - nxt_listen_event_t *lev; - - lev = obj; - c = lev->next; - - lev->ready--; - lev->socket.read_ready = (lev->ready != 0); - - sa = &c->remote->u.sockaddr; - socklen = c->remote->socklen; - /* - * The returned socklen is ignored here, - * see comment in nxt_conn_io_accept(). - */ - s = accept4(lev->socket.fd, sa, &socklen, SOCK_NONBLOCK); - - if (s != -1) { - c->socket.fd = s; - - nxt_debug(task, "accept4(%d): %d", lev->socket.fd, s); - - nxt_conn_accept(task, lev, c); - return; - } - - nxt_conn_accept_error(task, lev, "accept4", nxt_errno); -} - -#endif - - -#if (NXT_HAVE_EPOLL_EDGE) - -/* - * nxt_epoll_edge_event_conn_io_connect() eliminates the getsockopt() - * syscall to test pending connect() error. Although this special - * interface can work in both edge-triggered and level-triggered - * modes it is enabled only for the former mode because this mode is - * available in all modern Linux distributions. For the latter mode - * it is required to create additional nxt_epoll_level_event_conn_io - * with single non-generic connect() interface. - */ - -static void -nxt_epoll_edge_conn_io_connect(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_event_engine_t *engine; - nxt_work_handler_t handler; - const nxt_event_conn_state_t *state; - - c = obj; - - state = c->write_state; - - switch (nxt_socket_connect(task, c->socket.fd, c->remote)) { - - case NXT_OK: - c->socket.write_ready = 1; - handler = state->ready_handler; - break; - - case NXT_AGAIN: - c->socket.write_handler = nxt_epoll_edge_conn_connected; - c->socket.error_handler = nxt_conn_connect_error; - - engine = task->thread->engine; - nxt_conn_timer(engine, c, state, &c->write_timer); - - nxt_epoll_enable(engine, &c->socket); - c->socket.read = NXT_EVENT_BLOCKED; - return; - -#if 0 - case NXT_AGAIN: - nxt_conn_timer(engine, c, state, &c->write_timer); - - /* Fall through. */ - - case NXT_OK: - /* - * Mark both read and write directions as ready and try to perform - * I/O operations before receiving readiness notifications. - * On unconnected socket Linux send() and recv() return EAGAIN - * instead of ENOTCONN. - */ - c->socket.read_ready = 1; - c->socket.write_ready = 1; - /* - * Enabling both read and write notifications on a getting - * connected socket eliminates one epoll_ctl() syscall. - */ - c->socket.write_handler = nxt_epoll_edge_event_conn_connected; - c->socket.error_handler = state->error_handler; - - nxt_epoll_enable(engine, &c->socket); - c->socket.read = NXT_EVENT_BLOCKED; - - handler = state->ready_handler; - break; -#endif - - case NXT_ERROR: - handler = state->error_handler; - break; - - default: /* NXT_DECLINED: connection refused. */ - handler = state->close_handler; - break; - } - - nxt_work_queue_add(c->write_work_queue, handler, task, c, data); -} - - -static void -nxt_epoll_edge_conn_connected(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "epoll event conn connected fd:%d", c->socket.fd); - - if (!c->socket.epoll_error) { - c->socket.write = NXT_EVENT_BLOCKED; - - if (c->write_state->timer_autoreset) { - nxt_timer_disable(task->thread->engine, &c->write_timer); - } - - nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler, - task, c, data); - return; - } - - nxt_conn_connect_test(task, c, data); -} - - -/* - * nxt_epoll_edge_conn_io_recvbuf() is just wrapper around - * standard nxt_conn_io_recvbuf() to enforce to read a pending EOF - * in edge-triggered mode. - */ - -static ssize_t -nxt_epoll_edge_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b) -{ - ssize_t n; - - n = nxt_conn_io_recvbuf(c, b); - - if (n > 0 && c->socket.epoll_eof) { - c->socket.read_ready = 1; - } - - return n; -} - -#endif diff --git a/src/nxt_errno.c b/src/nxt_errno.c deleted file mode 100644 index 47479a82..00000000 --- a/src/nxt_errno.c +++ /dev/null @@ -1,152 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * The strerror() messages are copied because: - * - * 1) strerror() and strerror_r() functions are not Async-Signal-Safe, - * therefore, they can not be used in signal handlers; - * - * 2) a direct sys_errlist[] array may be used instead of these functions, - * but Linux linker warns about this usage: - * - * warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead - * warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead - * - * causing false bug reports. - */ - -static u_char *nxt_bootstrap_strerror(nxt_err_t err, u_char *errstr, - size_t size); -static u_char *nxt_runtime_strerror(nxt_err_t err, u_char *errstr, size_t size); - - -nxt_strerror_t nxt_strerror = nxt_bootstrap_strerror; -static nxt_str_t *nxt_sys_errlist; -static nxt_uint_t nxt_sys_nerr; - - -nxt_int_t -nxt_strerror_start(void) -{ - char *msg; - u_char *p; - size_t size, length, n; - nxt_uint_t err, invalid; - - /* The last entry. */ - size = nxt_length("Unknown error"); - - /* - * Linux has holes for error codes 41 and 58, so the loop - * stops only after 100 invalid codes in succession. - */ - - for (invalid = 0; invalid < 100 && nxt_sys_nerr < 65536; nxt_sys_nerr++) { - - nxt_set_errno(0); - msg = strerror((int) nxt_sys_nerr); - - /* - * strerror() behaviour on passing invalid error code depends - * on OS and version: - * Linux returns "Unknown error NN"; - * FreeBSD, NetBSD and OpenBSD return "Unknown error: NN" - * and set errno to EINVAL; - * Solaris 10 returns "Unknown error" and sets errno to EINVAL; - * Solaris 9 returns "Unknown error"; - * Solaris 2 returns NULL; - * MacOSX returns "Unknown error: NN"; - * AIX returns "Error NNN occurred."; - * HP-UX returns "Unknown error" for invalid codes lesser than 250 - * or empty string for larger codes. - */ - - if (msg == NULL) { - invalid++; - continue; - } - - length = nxt_strlen(msg); - size += length; - - if (length == 0 /* HP-UX empty strings. */ - || nxt_errno == NXT_EINVAL - || memcmp(msg, "Unknown error", 13) == 0) - { - invalid++; - continue; - } - -#if (NXT_AIX) - - if (memcmp(msg, "Error ", 6) == 0 - && memcmp(msg + length - 10, " occurred.", 9) == 0) - { - invalid++; - continue; - } - -#endif - } - - nxt_sys_nerr -= invalid; - - nxt_main_log_debug("sys_nerr: %d", nxt_sys_nerr); - - n = (nxt_sys_nerr + 1) * sizeof(nxt_str_t); - - nxt_sys_errlist = nxt_malloc(n + size); - if (nxt_sys_errlist == NULL) { - return NXT_ERROR; - } - - p = nxt_pointer_to(nxt_sys_errlist, n); - - for (err = 0; err < nxt_sys_nerr; err++) { - msg = strerror((int) err); - length = nxt_strlen(msg); - - nxt_sys_errlist[err].length = length; - nxt_sys_errlist[err].start = p; - - p = nxt_cpymem(p, msg, length); - } - - nxt_sys_errlist[err].length = 13; - nxt_sys_errlist[err].start = p; - nxt_memcpy(p, "Unknown error", 13); - - nxt_strerror = nxt_runtime_strerror; - - return NXT_OK; -} - - -static u_char * -nxt_bootstrap_strerror(nxt_err_t err, u_char *errstr, size_t size) -{ - return nxt_cpystrn(errstr, (u_char *) strerror(err), size); -} - - -static u_char * -nxt_runtime_strerror(nxt_err_t err, u_char *errstr, size_t size) -{ - nxt_str_t *msg; - nxt_uint_t n; - - n = nxt_min((nxt_uint_t) err, nxt_sys_nerr); - - msg = &nxt_sys_errlist[n]; - - size = nxt_min(size, msg->length); - - return nxt_cpymem(errstr, msg->start, size); -} diff --git a/src/nxt_errno.h b/src/nxt_errno.h deleted file mode 100644 index f19d50ba..00000000 --- a/src/nxt_errno.h +++ /dev/null @@ -1,88 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_ERRNO_H_INCLUDED_ -#define _NXT_UNIX_ERRNO_H_INCLUDED_ - - -typedef int nxt_err_t; - - -#define NXT_EPERM EPERM -#define NXT_ENOENT ENOENT -#define NXT_ENOPATH ENOENT -#define NXT_ESRCH ESRCH -#define NXT_EINTR EINTR -#define NXT_ENXIO ENXIO -#define NXT_ECHILD ECHILD -#define NXT_ENOMEM ENOMEM -#define NXT_EACCES EACCES -#define NXT_EBUSY EBUSY -#define NXT_EEXIST EEXIST -#define NXT_ELOOP ELOOP -#define NXT_EXDEV EXDEV -#define NXT_ENOTDIR ENOTDIR -#define NXT_EISDIR EISDIR -#define NXT_EINVAL EINVAL -#define NXT_ENOSPC ENOSPC -#define NXT_EPIPE EPIPE -#define NXT_EINPROGRESS EINPROGRESS -#define NXT_EOPNOTSUPP EOPNOTSUPP -#define NXT_EADDRINUSE EADDRINUSE -#define NXT_ECONNABORTED ECONNABORTED -#define NXT_ECONNRESET ECONNRESET -#define NXT_ENOTCONN ENOTCONN -#define NXT_ETIMEDOUT ETIMEDOUT -#define NXT_ECONNREFUSED ECONNREFUSED -#define NXT_ENAMETOOLONG ENAMETOOLONG -#define NXT_ENETDOWN ENETDOWN -#define NXT_ENETUNREACH ENETUNREACH -#define NXT_EHOSTDOWN EHOSTDOWN -#define NXT_EHOSTUNREACH EHOSTUNREACH -#define NXT_ENOSYS ENOSYS -#define NXT_ECANCELED ECANCELED -#define NXT_EILSEQ EILSEQ -#define NXT_ETIME ETIME -#define NXT_ENOMOREFILES 0 -#define NXT_ENOBUFS ENOBUFS -#define NXT_ERANGE ERANGE - -#if (NXT_HPUX) -/* HP-UX uses EWOULDBLOCK instead of EAGAIN. */ -#define NXT_EAGAIN EWOULDBLOCK -#else -#define NXT_EAGAIN EAGAIN -#endif - - -#define NXT_OK 0 -#define NXT_ERROR (-1) -#define NXT_AGAIN (-2) -#define NXT_DECLINED (-3) -#define NXT_DONE (-4) - - -#define nxt_errno \ - errno - -#define nxt_socket_errno \ - errno - -#define nxt_set_errno(err) \ - errno = err - -#define nxt_set_socket_errno(err) \ - errno = err - - -nxt_int_t nxt_strerror_start(void); - - -typedef u_char *(*nxt_strerror_t)(nxt_err_t err, u_char *errstr, size_t size); -extern nxt_strerror_t nxt_strerror; - - -#endif /* _NXT_UNIX_ERRNO_H_INCLUDED_ */ diff --git a/src/nxt_event_conn_job_sendfile.c b/src/nxt_event_conn_job_sendfile.c deleted file mode 100644 index 0f6f9353..00000000 --- a/src/nxt_event_conn_job_sendfile.c +++ /dev/null @@ -1,259 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -typedef struct { - nxt_job_t job; - nxt_buf_t *out; - size_t sent; - size_t limit; - nxt_work_handler_t ready_handler; -} nxt_job_sendfile_t; - - -static void nxt_event_conn_job_sendfile_start(nxt_task_t *task, void *obj, - void *data); -static void nxt_event_conn_job_sendfile_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_event_conn_job_sendfile_return(nxt_task_t *task, void *obj, - void *data); -static nxt_buf_t *nxt_event_conn_job_sendfile_completion(nxt_task_t *task, - nxt_conn_t *c, nxt_buf_t *b); - - -void -nxt_event_conn_job_sendfile(nxt_task_t *task, nxt_conn_t *c) -{ - nxt_fd_event_disable(task->thread->engine, &c->socket); - - /* A work item data is not used in nxt_event_conn_job_sendfile_start(). */ - nxt_event_conn_job_sendfile_start(task, c, NULL); -} - - -static void -nxt_event_conn_job_sendfile_start(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_iobuf_t b; - nxt_job_sendfile_t *jbs; - nxt_sendbuf_coalesce_t sb; - - c = obj; - - nxt_debug(task, "event conn sendfile fd:%d", c->socket.fd); - - jbs = nxt_job_create(c->mem_pool, sizeof(nxt_job_sendfile_t)); - - if (nxt_slow_path(jbs == NULL)) { - c->write_state->error_handler(task, c, NULL); - return; - } - - c->socket.write_handler = nxt_event_conn_job_sendfile_start; - c->socket.error_handler = c->write_state->error_handler; - - jbs->job.data = c; - nxt_job_set_name(&jbs->job, "job sendfile"); - - jbs->limit = nxt_event_conn_write_limit(c); - - if (jbs->limit != 0) { - - sb.buf = c->write; - sb.iobuf = &b; - sb.nmax = 1; - sb.sync = 0; - sb.size = 0; - sb.limit = jbs->limit; - - if (nxt_sendbuf_mem_coalesce(c->socket.task, &sb) != 0 || !sb.sync) { - - jbs->job.thread_pool = c->u.thread_pool; - jbs->job.log = c->socket.log; - jbs->out = c->write; - c->write = NULL; - jbs->ready_handler = nxt_event_conn_job_sendfile_return; - - c->block_read = 1; - c->block_write = 1; - - nxt_job_start(task, &jbs->job, nxt_event_conn_job_sendfile_handler); - return; - } - } - - nxt_event_conn_job_sendfile_return(task, jbs, c); -} - - -static void -nxt_event_conn_job_sendfile_handler(nxt_task_t *task, void *obj, void *data) -{ - ssize_t ret; - nxt_buf_t *b; - nxt_bool_t first; - nxt_conn_t *c; - nxt_job_sendfile_t *jbs; - - jbs = obj; - c = data; - - nxt_debug(task, "event conn job sendfile fd:%d", c->socket.fd); - - first = c->socket.write_ready; - b = jbs->out; - - do { - ret = c->io->old_sendbuf(c, b, jbs->limit); - - if (ret == NXT_AGAIN) { - break; - } - - if (nxt_slow_path(ret == NXT_ERROR)) { - goto done; - } - - jbs->sent += ret; - jbs->limit -= ret; - - b = nxt_sendbuf_update(b, ret); - - if (b == NULL) { - goto done; - } - - if (jbs->limit == 0) { - - if (c->rate == NULL) { - jbs->limit = c->max_chunk; - goto fast; - } - - goto done; - } - - } while (c->socket.write_ready); - - if (first && task->thread->thread_pool->work_queue.head != NULL) { - goto fast; - } - -done: - - nxt_job_return(task, &jbs->job, jbs->ready_handler); - return; - -fast: - - nxt_work_set(&jbs->job.work, nxt_event_conn_job_sendfile_handler, - jbs->job.task, jbs, c); - - nxt_thread_pool_post(task->thread->thread_pool, &jbs->job.work); -} - - -static void -nxt_event_conn_job_sendfile_return(nxt_task_t *task, void *obj, void *data) -{ - size_t sent; - nxt_buf_t *b; - nxt_bool_t done; - nxt_conn_t *c; - nxt_job_sendfile_t *jbs; - - jbs = obj; - c = data; - - c->block_read = 0; - c->block_write = 0; - - sent = jbs->sent; - c->sent += sent; - - nxt_debug(task, "event conn sendfile sent:%z", sent); - - b = jbs->out; - - /* The job must be destroyed before connection error handler. */ - nxt_job_destroy(task, jbs); - - if (0 /* STUB: c->write_state->process_buffers */) { - b = nxt_event_conn_job_sendfile_completion(task, c, b); - - done = (b == NULL); - - /* Add data which might be added after sendfile job has started. */ - nxt_buf_chain_add(&b, c->write); - c->write = b; - - if (done) { - /* All data has been sent. */ - - if (b != NULL) { - /* But new data has been added. */ - nxt_event_conn_job_sendfile_start(task, c, NULL); - } - - return; - } - } - - if (sent != 0 && c->write_state->timer_autoreset) { - nxt_timer_disable(task->thread->engine, &c->write_timer); - } - - if (c->socket.error == 0 - && !nxt_event_conn_write_delayed(task->thread->engine, c, sent)) - { - nxt_conn_timer(task->thread->engine, c, c->write_state, - &c->write_timer); - - nxt_fd_event_oneshot_write(task->thread->engine, &c->socket); - } - - if (sent != 0) { - nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler, - task, c, c->socket.data); - /* - * Fall through if first operations were - * successful but the last one failed. - */ - } - - if (nxt_slow_path(c->socket.error != 0)) { - nxt_work_queue_add(c->write_work_queue, c->write_state->error_handler, - task, c, c->socket.data); - } -} - - -static nxt_buf_t * -nxt_event_conn_job_sendfile_completion(nxt_task_t *task, nxt_conn_t *c, - nxt_buf_t *b) -{ - while (b != NULL) { - - nxt_prefetch(b->next); - - if (nxt_buf_is_mem(b) && b->mem.pos != b->mem.free) { - break; - - } else if (nxt_buf_is_file(b) && b->file_pos != b->file_end) { - break; - } - - nxt_work_queue_add(c->write_work_queue, - b->completion_handler, task, b, b->parent); - - b = b->next; - } - - return b; -} diff --git a/src/nxt_event_engine.c b/src/nxt_event_engine.c deleted file mode 100644 index 78c79bb1..00000000 --- a/src/nxt_event_engine.c +++ /dev/null @@ -1,759 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -typedef struct nxt_mem_cache_block_s nxt_mem_cache_block_t; - -struct nxt_mem_cache_block_s { - nxt_mem_cache_block_t *next; -}; - - -typedef struct { - nxt_mem_cache_block_t *free; - uint32_t size; - uint32_t count; -} nxt_mem_cache_t; - - -static nxt_int_t nxt_event_engine_post_init(nxt_event_engine_t *engine); -static nxt_int_t nxt_event_engine_signal_pipe_create( - nxt_event_engine_t *engine); -static void nxt_event_engine_signal_pipe_close(nxt_task_t *task, void *obj, - void *data); -static void nxt_event_engine_signal_pipe(nxt_task_t *task, void *obj, - void *data); -static void nxt_event_engine_post_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_event_engine_signal_pipe_error(nxt_task_t *task, void *obj, - void *data); -static void nxt_event_engine_signal_handler(nxt_task_t *task, void *obj, - void *data); -static nxt_work_handler_t nxt_event_engine_queue_pop(nxt_event_engine_t *engine, - nxt_task_t **task, void **obj, void **data); - - -nxt_event_engine_t * -nxt_event_engine_create(nxt_task_t *task, - const nxt_event_interface_t *interface, const nxt_sig_event_t *signals, - nxt_uint_t flags, nxt_uint_t batch) -{ - nxt_uint_t events; - nxt_thread_t *thread; - nxt_event_engine_t *engine; - - engine = nxt_zalloc(sizeof(nxt_event_engine_t)); - if (engine == NULL) { - return NULL; - } - - nxt_debug(task, "create engine %p", engine); - - thread = task->thread; - - engine->task.thread = thread; - engine->task.log = thread->log; - engine->task.ident = nxt_task_next_ident(); - - engine->batch = batch; - -#if 0 - if (flags & NXT_ENGINE_FIBERS) { - engine->fibers = nxt_fiber_main_create(engine); - if (engine->fibers == NULL) { - goto fibers_fail; - } - } -#endif - - engine->current_work_queue = &engine->fast_work_queue; - - nxt_work_queue_cache_create(&engine->work_queue_cache, 0); - - engine->fast_work_queue.cache = &engine->work_queue_cache; - engine->accept_work_queue.cache = &engine->work_queue_cache; - engine->read_work_queue.cache = &engine->work_queue_cache; - engine->socket_work_queue.cache = &engine->work_queue_cache; - engine->connect_work_queue.cache = &engine->work_queue_cache; - engine->write_work_queue.cache = &engine->work_queue_cache; - engine->shutdown_work_queue.cache = &engine->work_queue_cache; - engine->close_work_queue.cache = &engine->work_queue_cache; - - nxt_work_queue_name(&engine->fast_work_queue, "fast"); - nxt_work_queue_name(&engine->accept_work_queue, "accept"); - nxt_work_queue_name(&engine->read_work_queue, "read"); - nxt_work_queue_name(&engine->socket_work_queue, "socket"); - nxt_work_queue_name(&engine->connect_work_queue, "connect"); - nxt_work_queue_name(&engine->write_work_queue, "write"); - nxt_work_queue_name(&engine->shutdown_work_queue, "shutdown"); - nxt_work_queue_name(&engine->close_work_queue, "close"); - - if (signals != NULL) { - engine->signals = nxt_event_engine_signals(signals); - if (engine->signals == NULL) { - goto signals_fail; - } - - engine->signals->handler = nxt_event_engine_signal_handler; - - if (!interface->signal_support) { - if (nxt_event_engine_signals_start(engine) != NXT_OK) { - goto signals_fail; - } - } - } - - /* - * Number of event set and timers changes should be at least twice - * more than number of events to avoid premature flushes of the changes. - * Fourfold is for sure. - */ - events = (batch != 0) ? batch : 32; - - if (interface->create(engine, 4 * events, events) != NXT_OK) { - goto event_set_fail; - } - - engine->event = *interface; - - if (nxt_event_engine_post_init(engine) != NXT_OK) { - goto post_fail; - } - - if (nxt_timers_init(&engine->timers, 4 * events) != NXT_OK) { - goto timers_fail; - } - - thread = task->thread; - - nxt_thread_time_update(thread); - engine->timers.now = nxt_thread_monotonic_time(thread) / 1000000; - - engine->max_connections = 0xFFFFFFFF; - - nxt_queue_init(&engine->joints); - nxt_queue_init(&engine->listen_connections); - nxt_queue_init(&engine->idle_connections); - - return engine; - -timers_fail: -post_fail: - - interface->free(engine); - -event_set_fail: -signals_fail: - - nxt_free(engine->signals); - nxt_work_queue_cache_destroy(&engine->work_queue_cache); - nxt_free(engine->fibers); - -#if 0 -fibers_fail: -#endif - - nxt_free(engine); - - return NULL; -} - - -static nxt_int_t -nxt_event_engine_post_init(nxt_event_engine_t *engine) -{ - if (engine->event.enable_post != NULL) { - return engine->event.enable_post(engine, nxt_event_engine_post_handler); - } - - if (nxt_event_engine_signal_pipe_create(engine) != NXT_OK) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_event_engine_signal_pipe_create(nxt_event_engine_t *engine) -{ - nxt_event_engine_pipe_t *pipe; - - pipe = nxt_zalloc(sizeof(nxt_event_engine_pipe_t)); - if (pipe == NULL) { - return NXT_ERROR; - } - - engine->pipe = pipe; - - /* - * An event engine pipe is in blocking mode for writer - * and in non-blocking node for reader. - */ - - if (nxt_pipe_create(&engine->task, pipe->fds, 1, 0) != NXT_OK) { - nxt_free(pipe); - return NXT_ERROR; - } - - pipe->event.fd = pipe->fds[0]; - pipe->event.task = &engine->task; - pipe->event.read_work_queue = &engine->fast_work_queue; - pipe->event.read_handler = nxt_event_engine_signal_pipe; - pipe->event.write_work_queue = &engine->fast_work_queue; - pipe->event.error_handler = nxt_event_engine_signal_pipe_error; - pipe->event.log = engine->task.log; - - nxt_fd_event_enable_read(engine, &pipe->event); - - return NXT_OK; -} - - -static void -nxt_event_engine_signal_pipe_free(nxt_event_engine_t *engine) -{ - nxt_event_engine_pipe_t *pipe; - - pipe = engine->pipe; - - if (pipe != NULL) { - - if (pipe->event.read_work_queue != NULL) { - nxt_fd_event_close(engine, &pipe->event); - nxt_pipe_close(pipe->event.task, pipe->fds); - } - - nxt_free(pipe); - } -} - - -static void -nxt_event_engine_signal_pipe_close(nxt_task_t *task, void *obj, void *data) -{ - nxt_event_engine_pipe_t *pipe; - - pipe = obj; - - nxt_pipe_close(pipe->event.task, pipe->fds); - nxt_free(pipe); -} - - -void -nxt_event_engine_post(nxt_event_engine_t *engine, nxt_work_t *work) -{ - nxt_debug(&engine->task, "event engine post"); - -#if (NXT_DEBUG) - if (nxt_slow_path(work->next != NULL)) { - nxt_debug(&engine->task, "event engine post multiple works"); - } -#endif - - nxt_locked_work_queue_add(&engine->locked_work_queue, work); - - nxt_event_engine_signal(engine, 0); -} - - -void -nxt_event_engine_signal(nxt_event_engine_t *engine, nxt_uint_t signo) -{ - u_char buf; - - nxt_debug(&engine->task, "event engine signal:%ui", signo); - - /* - * A signal number may be sent in a signal context, so the signal - * information cannot be passed via a locked work queue. - */ - - if (engine->event.signal != NULL) { - engine->event.signal(engine, signo); - return; - } - - buf = (u_char) signo; - (void) nxt_fd_write(engine->pipe->fds[1], &buf, 1); -} - - -static void -nxt_event_engine_signal_pipe(nxt_task_t *task, void *obj, void *data) -{ - int i, n; - u_char signo; - nxt_bool_t post; - nxt_fd_event_t *ev; - u_char buf[128]; - - ev = obj; - - nxt_debug(task, "engine signal pipe"); - - post = 0; - - do { - n = nxt_fd_read(ev->fd, buf, sizeof(buf)); - - for (i = 0; i < n; i++) { - signo = buf[i]; - - nxt_debug(task, "engine pipe signo:%d", signo); - - if (signo == 0) { - /* A post should be processed only once. */ - post = 1; - - } else { - nxt_event_engine_signal_handler(task, - (void *) (uintptr_t) signo, NULL); - } - } - - } while (n == sizeof(buf)); - - if (post) { - nxt_event_engine_post_handler(task, NULL, NULL); - } -} - - -static void -nxt_event_engine_post_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_thread_t *thread; - nxt_event_engine_t *engine; - - thread = task->thread; - engine = thread->engine; - - nxt_locked_work_queue_move(thread, &engine->locked_work_queue, - &engine->fast_work_queue); -} - - -static void -nxt_event_engine_signal_pipe_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_event_engine_t *engine; - nxt_event_engine_pipe_t *pipe; - - engine = task->thread->engine; - pipe = engine->pipe; - - nxt_alert(task, "engine pipe(%FD:%FD) event error", - pipe->fds[0], pipe->fds[1]); - - nxt_fd_event_close(engine, &pipe->event); - nxt_pipe_close(pipe->event.task, pipe->fds); -} - - -static void -nxt_event_engine_signal_handler(nxt_task_t *task, void *obj, void *data) -{ - uintptr_t signo; - const nxt_sig_event_t *sigev; - - signo = (uintptr_t) obj; - - for (sigev = task->thread->engine->signals->sigev; - sigev->signo != 0; - sigev++) - { - if (signo == (nxt_uint_t) sigev->signo) { - sigev->handler(task, (void *) signo, (void *) sigev->name); - return; - } - } - - nxt_alert(task, "signal %ui handler not found", (nxt_uint_t) signo); -} - - -nxt_int_t -nxt_event_engine_change(nxt_event_engine_t *engine, - const nxt_event_interface_t *interface, nxt_uint_t batch) -{ - nxt_uint_t events; - - engine->batch = batch; - - if (!engine->event.signal_support && interface->signal_support) { - /* - * Block signal processing if the current event - * facility does not support signal processing. - */ - nxt_event_engine_signals_stop(engine); - - /* - * Add to engine fast work queue the signal events possibly - * received before the blocking signal processing. - */ - nxt_event_engine_signal_pipe(&engine->task, &engine->pipe->event, NULL); - } - - if (engine->pipe != NULL && interface->enable_post != NULL) { - /* - * An engine pipe must be closed after all signal events - * added above to engine fast work queue will be processed. - */ - nxt_work_queue_add(&engine->fast_work_queue, - nxt_event_engine_signal_pipe_close, - &engine->task, engine->pipe, NULL); - - engine->pipe = NULL; - } - - engine->event.free(engine); - - events = (batch != 0) ? batch : 32; - - if (interface->create(engine, 4 * events, events) != NXT_OK) { - return NXT_ERROR; - } - - engine->event = *interface; - - if (nxt_event_engine_post_init(engine) != NXT_OK) { - return NXT_ERROR; - } - - if (engine->signals != NULL) { - - if (!engine->event.signal_support) { - return nxt_event_engine_signals_start(engine); - } - - /* - * Reset the PID flag to start the signal thread if - * some future event facility will not support signals. - */ - engine->signals->process = 0; - } - - return NXT_OK; -} - - -void -nxt_event_engine_free(nxt_event_engine_t *engine) -{ - nxt_thread_log_debug("free engine %p", engine); - - nxt_event_engine_signal_pipe_free(engine); - nxt_free(engine->signals); - - nxt_work_queue_cache_destroy(&engine->work_queue_cache); - - engine->event.free(engine); - - /* TODO: free timers */ - - nxt_free(engine); -} - - -static nxt_work_handler_t -nxt_event_engine_queue_pop(nxt_event_engine_t *engine, nxt_task_t **task, - void **obj, void **data) -{ - nxt_work_queue_t *wq, *last; - - wq = engine->current_work_queue; - last = wq; - - if (wq->head == NULL) { - wq = &engine->fast_work_queue; - - if (wq->head == NULL) { - - do { - engine->current_work_queue++; - wq = engine->current_work_queue; - - if (wq > &engine->close_work_queue) { - wq = &engine->fast_work_queue; - engine->current_work_queue = wq; - } - - if (wq->head != NULL) { - goto found; - } - - } while (wq != last); - - engine->current_work_queue = &engine->fast_work_queue; - - return NULL; - } - } - -found: - - nxt_debug(&engine->task, "work queue: %s", wq->name); - - return nxt_work_queue_pop(wq, task, obj, data); -} - - -void -nxt_event_engine_start(nxt_event_engine_t *engine) -{ - void *obj, *data; - nxt_task_t *task; - nxt_msec_t timeout, now; - nxt_thread_t *thr; - nxt_work_handler_t handler; - - thr = nxt_thread(); - - if (engine->fibers) { - /* - * _setjmp() cannot be wrapped in a function since return from - * the function clobbers stack used by future _setjmp() returns. - */ - _setjmp(engine->fibers->fiber.jmp); - - /* A return point from fibers. */ - } - - thr->log = engine->task.log; - - for ( ;; ) { - - for ( ;; ) { - handler = nxt_event_engine_queue_pop(engine, &task, &obj, &data); - - if (handler == NULL) { - break; - } - - thr->task = task; - - handler(task, obj, data); - } - - /* Attach some event engine work queues in preferred order. */ - - timeout = nxt_timer_find(engine); - - engine->event.poll(engine, timeout); - - now = nxt_thread_monotonic_time(thr) / 1000000; - - nxt_timer_expire(engine, now); - } -} - - -void * -nxt_event_engine_mem_alloc(nxt_event_engine_t *engine, uint8_t *hint, - size_t size) -{ - uint32_t n; - nxt_uint_t items; - nxt_array_t *mem_cache; - nxt_mem_cache_t *cache; - nxt_mem_cache_block_t *block; - - mem_cache = engine->mem_cache; - n = *hint; - - if (n == NXT_EVENT_ENGINE_NO_MEM_HINT) { - - if (mem_cache == NULL) { - /* IPv4 nxt_sockaddr_t and HTTP/1 and HTTP/2 buffers. */ - items = 3; -#if (NXT_INET6) - items++; -#endif -#if (NXT_HAVE_UNIX_DOMAIN) - items++; -#endif - - mem_cache = nxt_array_create(engine->mem_pool, items, - sizeof(nxt_mem_cache_t)); - if (nxt_slow_path(mem_cache == NULL)) { - return mem_cache; - } - - engine->mem_cache = mem_cache; - } - - cache = mem_cache->elts; - for (n = 0; n < mem_cache->nelts; n++) { - if (cache[n].size == size) { - goto found; - } - } - - cache = nxt_array_add(mem_cache); - if (nxt_slow_path(cache == NULL)) { - return cache; - } - - cache->free = NULL; - cache->size = size; - cache->count = 0; - - found: - - if (n < NXT_EVENT_ENGINE_NO_MEM_HINT) { - *hint = (uint8_t) n; - } - } - - cache = mem_cache->elts; - cache = cache + n; - - block = cache->free; - - if (block != NULL) { - cache->free = block->next; - cache->count--; - return block; - } - - return nxt_mp_alloc(engine->mem_pool, size); -} - - -void -nxt_event_engine_mem_free(nxt_event_engine_t *engine, uint8_t hint, void *p, - size_t size) -{ - uint32_t n; - nxt_array_t *mem_cache; - nxt_mem_cache_t *cache; - nxt_mem_cache_block_t *block; - - block = p; - mem_cache = engine->mem_cache; - cache = mem_cache->elts; - - n = hint; - - if (nxt_slow_path(n == NXT_EVENT_ENGINE_NO_MEM_HINT)) { - - if (size != 0) { - for (n = 0; n < mem_cache->nelts; n++) { - if (cache[n].size == size) { - goto found; - } - } - - nxt_alert(&engine->task, - "event engine mem free(%p, %z) not found", p, size); - } - - goto done; - } - -found: - - cache = cache + n; - - if (cache->count < 16) { - cache->count++; - block->next = cache->free; - cache->free = block; - - return; - } - -done: - - nxt_mp_free(engine->mem_pool, p); -} - - -void * -nxt_event_engine_buf_mem_alloc(nxt_event_engine_t *engine, size_t size) -{ - nxt_buf_t *b; - uint8_t hint; - - hint = NXT_EVENT_ENGINE_NO_MEM_HINT; - - b = nxt_event_engine_mem_alloc(engine, &hint, NXT_BUF_MEM_SIZE + size); - if (nxt_slow_path(b == NULL)) { - return NULL; - } - - nxt_memzero(b, NXT_BUF_MEM_SIZE); - - b->cache_hint = hint; - b->data = engine; - b->completion_handler = nxt_event_engine_buf_mem_completion; - - if (size != 0) { - b->mem.start = nxt_pointer_to(b, NXT_BUF_MEM_SIZE); - b->mem.pos = b->mem.start; - b->mem.free = b->mem.start; - b->mem.end = b->mem.start + size; - } - - return b; -} - - -void -nxt_event_engine_buf_mem_free(nxt_event_engine_t *engine, nxt_buf_t *b) -{ - size_t size; - - size = NXT_BUF_MEM_SIZE + nxt_buf_mem_size(&b->mem); - - nxt_event_engine_mem_free(engine, b->cache_hint, b, size); -} - - -void -nxt_event_engine_buf_mem_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *b, *next, *parent; - nxt_event_engine_t *engine; - - b = obj; - - nxt_debug(task, "buf completion: %p %p", b, b->mem.start); - - engine = b->data; - - do { - next = b->next; - parent = b->parent; - - nxt_event_engine_buf_mem_free(engine, b); - - nxt_buf_parent_completion(task, parent); - - b = next; - } while (b != NULL); -} - - -#if (NXT_DEBUG) - -void nxt_event_engine_thread_adopt(nxt_event_engine_t *engine) -{ - nxt_work_queue_thread_adopt(&engine->fast_work_queue); - nxt_work_queue_thread_adopt(&engine->accept_work_queue); - nxt_work_queue_thread_adopt(&engine->read_work_queue); - nxt_work_queue_thread_adopt(&engine->socket_work_queue); - nxt_work_queue_thread_adopt(&engine->connect_work_queue); - nxt_work_queue_thread_adopt(&engine->write_work_queue); - nxt_work_queue_thread_adopt(&engine->shutdown_work_queue); - nxt_work_queue_thread_adopt(&engine->close_work_queue); -} - -#endif diff --git a/src/nxt_event_engine.h b/src/nxt_event_engine.h deleted file mode 100644 index 291ea749..00000000 --- a/src/nxt_event_engine.h +++ /dev/null @@ -1,542 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_EVENT_ENGINE_H_INCLUDED_ -#define _NXT_EVENT_ENGINE_H_INCLUDED_ - -/* - * An event interface is kernel interface such as kqueue, epoll, etc. - * intended to get event notifications about file descriptor state, - * signals, etc. - */ - -#define NXT_FILE_EVENTS 1 -#define NXT_NO_FILE_EVENTS 0 - -#define NXT_SIGNAL_EVENTS 1 -#define NXT_NO_SIGNAL_EVENTS 0 - - -typedef struct { - - /* The canonical event set name. */ - const char *name; - - /* - * Create an event set. The mchanges argument is a maximum number of - * changes to send to the kernel. The mevents argument is a maximum - * number of events to retrieve from the kernel at once, if underlying - * event facility supports batch operations. - */ - nxt_int_t (*create)(nxt_event_engine_t *engine, - nxt_uint_t mchanges, nxt_uint_t mevents); - - /* Close and free an event set. */ - void (*free)(nxt_event_engine_t *engine); - - /* - * Add a file descriptor to an event set and enable the most - * effective read and write event notification method provided - * by underlying event facility. - */ - void (*enable)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* Disable file descriptor event notifications. */ - void (*disable)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* - * Delete a file descriptor from an event set. A possible usage - * is a moving of the file descriptor from one event set to another. - */ - void (*delete)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* - * Delete a file descriptor from an event set before closing the - * file descriptor. The most event facilities such as Linux epoll, - * BSD kqueue, Solaris event ports, AIX pollset, and HP-UX /dev/poll - * delete a file descriptor automatically on the file descriptor close. - * Some facilities such as Solaris /dev/poll require to delete a file - * descriptor explicitly. - */ - nxt_bool_t (*close)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* - * Add a file descriptor to an event set and enable the most effective - * read event notification method provided by underlying event facility. - */ - void (*enable_read)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* - * Add a file descriptor to an event set and enable the most effective - * write event notification method provided by underlying event facility. - */ - void (*enable_write)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* Disable file descriptor read event notifications. */ - void (*disable_read)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* Disable file descriptor write event notifications. */ - void (*disable_write)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* Block file descriptor read event notifications. */ - void (*block_read)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* Block file descriptor write event notifications. */ - void (*block_write)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* - * Add a file descriptor to an event set and enable an oneshot - * read event notification method. - */ - void (*oneshot_read)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* - * Add a file descriptor to an event set and enable an oneshot - * write event notification method. - */ - void (*oneshot_write)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* - * Add a listening socket descriptor to an event set and enable - * a level-triggered read event notification method. - */ - void (*enable_accept)(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); - - /* - * Add a file to an event set and enable a file change notification - * events. - */ - void (*enable_file)(nxt_event_engine_t *engine, - nxt_file_event_t *ev); - - /* - * Delete a file from an event set before closing the file descriptor. - */ - void (*close_file)(nxt_event_engine_t *engine, - nxt_file_event_t *ev); - - /* - * Enable post event notifications and set a post handler to handle - * the zero signal. - */ - nxt_int_t (*enable_post)(nxt_event_engine_t *engine, - nxt_work_handler_t handler); - - /* - * Signal an event set. If a signal number is non-zero then - * a signal handler added to the event set is called. This is - * a way to route Unix signals to an event engine if underlying - * event facility does not support signal events. - * - * If a signal number is zero, then the post_handler of the event - * set is called. This has no relation to Unix signals but is - * a way to wake up the event set to process works posted to - * the event engine locked work queue. - */ - void (*signal)(nxt_event_engine_t *engine, - nxt_uint_t signo); - - /* Poll an event set for new event notifications. */ - void (*poll)(nxt_event_engine_t *engine, - nxt_msec_t timeout); - - /* I/O operations suitable to underlying event facility. */ - nxt_conn_io_t *io; - - /* True if an event facility supports file change event notifications. */ - uint8_t file_support; /* 1 bit */ - - /* True if an event facility supports signal event notifications. */ - uint8_t signal_support; /* 1 bit */ -} nxt_event_interface_t; - - -#if (NXT_HAVE_KQUEUE) - -typedef struct { - int fd; - int nchanges; - int mchanges; - int mevents; - nxt_pid_t pid; - - nxt_work_handler_t post_handler; - - struct kevent *changes; - struct kevent *events; -} nxt_kqueue_engine_t; - -extern const nxt_event_interface_t nxt_kqueue_engine; - -#endif - - -#if (NXT_HAVE_EPOLL) - -typedef struct { - int op; - struct epoll_event event; -} nxt_epoll_change_t; - - -typedef struct { - int fd; - uint32_t mode; - nxt_uint_t nchanges; - nxt_uint_t mchanges; - int mevents; - - uint8_t error; /* 1 bit */ - - nxt_epoll_change_t *changes; - struct epoll_event *events; - -#if (NXT_HAVE_EVENTFD) - nxt_work_handler_t post_handler; - nxt_fd_event_t eventfd; - uint32_t neventfd; -#endif - -#if (NXT_HAVE_SIGNALFD) - nxt_fd_event_t signalfd; -#endif -} nxt_epoll_engine_t; - - -extern const nxt_event_interface_t nxt_epoll_edge_engine; -extern const nxt_event_interface_t nxt_epoll_level_engine; - -#endif - - -#if (NXT_HAVE_EVENTPORT) - -typedef struct { - int events; - nxt_fd_event_t *event; -} nxt_eventport_change_t; - - -typedef struct { - int fd; - nxt_uint_t nchanges; - nxt_uint_t mchanges; - u_int mevents; - - nxt_eventport_change_t *changes; - port_event_t *events; - - nxt_work_handler_t post_handler; - nxt_work_handler_t signal_handler; -} nxt_eventport_engine_t; - -extern const nxt_event_interface_t nxt_eventport_engine; - -#endif - - -#if (NXT_HAVE_DEVPOLL) - -typedef struct { - uint8_t op; - short events; - nxt_fd_event_t *event; -} nxt_devpoll_change_t; - - -typedef struct { - int fd; - int nchanges; - int mchanges; - int mevents; - - nxt_devpoll_change_t *changes; - struct pollfd *write_changes; - struct pollfd *events; - nxt_lvlhsh_t fd_hash; -} nxt_devpoll_engine_t; - -extern const nxt_event_interface_t nxt_devpoll_engine; - -#endif - - -#if (NXT_HAVE_POLLSET) - -typedef struct { - uint8_t op; - uint8_t cmd; - short events; - nxt_fd_event_t *event; -} nxt_pollset_change_t; - - -typedef struct { - pollset_t ps; - int nchanges; - int mchanges; - int mevents; - - nxt_pollset_change_t *changes; - struct poll_ctl *write_changes; - struct pollfd *events; - nxt_lvlhsh_t fd_hash; -} nxt_pollset_engine_t; - -extern const nxt_event_interface_t nxt_pollset_engine; - -#endif - - -typedef struct { - uint8_t op; - short events; - nxt_fd_event_t *event; -} nxt_poll_change_t; - - -typedef struct { - nxt_uint_t max_nfds; - nxt_uint_t nfds; - - nxt_uint_t nchanges; - nxt_uint_t mchanges; - - nxt_poll_change_t *changes; - struct pollfd *set; - - nxt_lvlhsh_t fd_hash; -} nxt_poll_engine_t; - -extern const nxt_event_interface_t nxt_poll_engine; - - -typedef struct { - int nfds; - uint32_t update_nfds; /* 1 bit */ - - nxt_fd_event_t **events; - - fd_set main_read_fd_set; - fd_set main_write_fd_set; - fd_set work_read_fd_set; - fd_set work_write_fd_set; -} nxt_select_engine_t; - -extern const nxt_event_interface_t nxt_select_engine; - - -nxt_int_t nxt_fd_event_hash_add(nxt_lvlhsh_t *lvlhsh, nxt_fd_t fd, - nxt_fd_event_t *ev); -void *nxt_fd_event_hash_get(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, - nxt_fd_t fd); -void nxt_fd_event_hash_delete(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, - nxt_fd_t fd, nxt_bool_t ignore); -void nxt_fd_event_hash_destroy(nxt_lvlhsh_t *lvlhsh); - - -#define nxt_fd_event_disable(engine, ev) \ - (engine)->event.disable(engine, ev) - - -#define nxt_fd_event_delete(engine, ev) \ - (engine)->event.delete(engine, ev) - - -#define nxt_fd_event_close(engine, ev) \ - (engine)->event.close(engine, ev) - - -#define nxt_fd_event_enable_read(engine, ev) \ - (engine)->event.enable_read(engine, ev) - - -#define nxt_fd_event_enable_write(engine, ev) \ - (engine)->event.enable_write(engine, ev) - - -#define nxt_fd_event_disable_read(engine, ev) \ - (engine)->event.disable_read(engine, ev) - - -#define nxt_fd_event_disable_write(engine, ev) \ - (engine)->event.disable_write(engine, ev) - - -#define nxt_fd_event_block_read(engine, ev) \ - do { \ - if (nxt_fd_event_is_active((ev)->read)) { \ - (engine)->event.block_read(engine, ev); \ - } \ - } while (0) - - -#define nxt_fd_event_block_write(engine, ev) \ - do { \ - if (nxt_fd_event_is_active((ev)->write)) { \ - (engine)->event.block_write(engine, ev); \ - } \ - } while (0) - - -#define nxt_fd_event_oneshot_read(engine, ev) \ - (engine)->event.oneshot_read(engine, ev) - - -#define nxt_fd_event_oneshot_write(engine, ev) \ - (engine)->event.oneshot_write(engine, ev) - - -#define nxt_fd_event_enable_accept(engine, ev) \ - (engine)->event.enable_accept(engine, ev) - - -#define NXT_ENGINE_FIBERS 1 - - -typedef struct { - nxt_fd_t fds[2]; - nxt_fd_event_t event; -} nxt_event_engine_pipe_t; - - -struct nxt_event_engine_s { - nxt_task_t task; - - union { - nxt_poll_engine_t poll; - nxt_select_engine_t select; - -#if (NXT_HAVE_KQUEUE) - nxt_kqueue_engine_t kqueue; -#endif -#if (NXT_HAVE_EPOLL) - nxt_epoll_engine_t epoll; -#endif -#if (NXT_HAVE_EVENTPORT) - nxt_eventport_engine_t eventport; -#endif -#if (NXT_HAVE_DEVPOLL) - nxt_devpoll_engine_t devpoll; -#endif -#if (NXT_HAVE_POLLSET) - nxt_pollset_engine_t pollset; -#endif - } u; - - nxt_timers_t timers; - - nxt_work_queue_cache_t work_queue_cache; - nxt_work_queue_t *current_work_queue; - nxt_work_queue_t fast_work_queue; - nxt_work_queue_t accept_work_queue; - nxt_work_queue_t read_work_queue; - nxt_work_queue_t socket_work_queue; - nxt_work_queue_t connect_work_queue; - nxt_work_queue_t write_work_queue; - nxt_work_queue_t shutdown_work_queue; - nxt_work_queue_t close_work_queue; - - nxt_locked_work_queue_t locked_work_queue; - - nxt_event_interface_t event; - - /* - * A pipe to pass event signals to the engine, if the engine's - * underlying event facility does not support user events. - */ - nxt_event_engine_pipe_t *pipe; - - nxt_event_signals_t *signals; - - nxt_fiber_main_t *fibers; - - /* The engine ID, the main engine has ID 0. */ - uint32_t id; - - uint8_t shutdown; /* 1 bit */ - - uint32_t batch; - uint32_t connections; - uint32_t max_connections; - - nxt_port_t *port; - nxt_mp_t *mem_pool; - nxt_queue_t joints; - nxt_queue_t listen_connections; - nxt_queue_t idle_connections; - nxt_array_t *mem_cache; - - nxt_atomic_uint_t accepted_conns_cnt; - nxt_atomic_uint_t idle_conns_cnt; - nxt_atomic_uint_t closed_conns_cnt; - nxt_atomic_uint_t requests_cnt; - - nxt_queue_link_t link; - // STUB: router link - nxt_queue_link_t link0; -}; - - -NXT_EXPORT nxt_event_engine_t *nxt_event_engine_create(nxt_task_t *task, - const nxt_event_interface_t *interface, const nxt_sig_event_t *signals, - nxt_uint_t flags, nxt_uint_t batch); -NXT_EXPORT nxt_int_t nxt_event_engine_change(nxt_event_engine_t *engine, - const nxt_event_interface_t *interface, nxt_uint_t batch); -NXT_EXPORT void nxt_event_engine_free(nxt_event_engine_t *engine); -NXT_EXPORT void nxt_event_engine_start(nxt_event_engine_t *engine); - -NXT_EXPORT void nxt_event_engine_post(nxt_event_engine_t *engine, - nxt_work_t *work); -NXT_EXPORT void nxt_event_engine_signal(nxt_event_engine_t *engine, - nxt_uint_t signo); - -#define NXT_EVENT_ENGINE_NO_MEM_HINT 255 - -void *nxt_event_engine_mem_alloc(nxt_event_engine_t *engine, uint8_t *hint, - size_t size); -void nxt_event_engine_mem_free(nxt_event_engine_t *engine, uint8_t hint, - void *p, size_t size); -void *nxt_event_engine_buf_mem_alloc(nxt_event_engine_t *engine, size_t size); -void nxt_event_engine_buf_mem_free(nxt_event_engine_t *engine, nxt_buf_t *b); -void nxt_event_engine_buf_mem_completion(nxt_task_t *task, void *obj, - void *data); - - -nxt_inline nxt_event_engine_t * -nxt_thread_event_engine(void) -{ - nxt_thread_t *thr; - - thr = nxt_thread(); - return thr->engine; -} - -#if (NXT_DEBUG) - -NXT_EXPORT void nxt_event_engine_thread_adopt(nxt_event_engine_t *engine); - -#else - -#define nxt_event_engine_thread_adopt(_engine) - -#endif - - -#endif /* _NXT_EVENT_ENGINE_H_INCLUDED_ */ diff --git a/src/nxt_eventport_engine.c b/src/nxt_eventport_engine.c deleted file mode 100644 index 7ac7f44d..00000000 --- a/src/nxt_eventport_engine.c +++ /dev/null @@ -1,613 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * The event ports have been introduced in Solaris 10. - * The PORT_SOURCE_MQ and PORT_SOURCE_FILE sources have - * been added in OpenSolaris. - */ - - -static nxt_int_t nxt_eventport_create(nxt_event_engine_t *engine, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_eventport_free(nxt_event_engine_t *engine); -static void nxt_eventport_enable(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_eventport_disable(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static nxt_bool_t nxt_eventport_close(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_eventport_enable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_eventport_enable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_eventport_enable_event(nxt_event_engine_t *engine, - nxt_fd_event_t *ev, nxt_uint_t events); -static void nxt_eventport_disable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_eventport_disable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_eventport_disable_event(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static nxt_int_t nxt_eventport_commit_changes(nxt_event_engine_t *engine); -static void nxt_eventport_error_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_eventport_block_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_eventport_block_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_eventport_oneshot_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_eventport_oneshot_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_eventport_enable_accept(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static nxt_int_t nxt_eventport_enable_post(nxt_event_engine_t *engine, - nxt_work_handler_t handler); -static void nxt_eventport_signal(nxt_event_engine_t *engine, nxt_uint_t signo); -static void nxt_eventport_poll(nxt_event_engine_t *engine, - nxt_msec_t timeout); - - -const nxt_event_interface_t nxt_eventport_engine = { - "eventport", - nxt_eventport_create, - nxt_eventport_free, - nxt_eventport_enable, - nxt_eventport_disable, - nxt_eventport_disable, - nxt_eventport_close, - nxt_eventport_enable_read, - nxt_eventport_enable_write, - nxt_eventport_disable_read, - nxt_eventport_disable_write, - nxt_eventport_block_read, - nxt_eventport_block_write, - nxt_eventport_oneshot_read, - nxt_eventport_oneshot_write, - nxt_eventport_enable_accept, - NULL, - NULL, - nxt_eventport_enable_post, - nxt_eventport_signal, - nxt_eventport_poll, - - &nxt_unix_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static nxt_int_t -nxt_eventport_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - nxt_eventport_change_t *changes; - - engine->u.eventport.fd = -1; - engine->u.eventport.mchanges = mchanges; - engine->u.eventport.mevents = mevents; - - changes = nxt_malloc(sizeof(nxt_eventport_change_t) * mchanges); - if (changes == NULL) { - goto fail; - } - - engine->u.eventport.changes = changes; - - engine->u.eventport.events = nxt_malloc(sizeof(port_event_t) * mevents); - if (engine->u.eventport.events == NULL) { - goto fail; - } - - engine->u.eventport.fd = port_create(); - if (engine->u.eventport.fd == -1) { - nxt_alert(&engine->task, "port_create() failed %E", nxt_errno); - goto fail; - } - - nxt_debug(&engine->task, "port_create(): %d", engine->u.eventport.fd); - - if (engine->signals != NULL) { - engine->u.eventport.signal_handler = engine->signals->handler; - } - - return NXT_OK; - -fail: - - nxt_eventport_free(engine); - - return NXT_ERROR; -} - - -static void -nxt_eventport_free(nxt_event_engine_t *engine) -{ - int port; - - port = engine->u.eventport.fd; - - nxt_debug(&engine->task, "eventport %d free", port); - - if (port != -1 && close(port) != 0) { - nxt_alert(&engine->task, "eventport close(%d) failed %E", - port, nxt_errno); - } - - nxt_free(engine->u.eventport.events); - - nxt_memzero(&engine->u.eventport, sizeof(nxt_eventport_engine_t)); -} - - -static void -nxt_eventport_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_ACTIVE; - ev->write = NXT_EVENT_ACTIVE; - - nxt_eventport_enable_event(engine, ev, POLLIN | POLLOUT); -} - - -static void -nxt_eventport_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_eventport_disable_event(engine, ev); - } -} - - -/* - * port_dissociate(3): - * - * The association is removed if the owner of the association closes the port. - */ - -static nxt_bool_t -nxt_eventport_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - return ev->changing; -} - - -static void -nxt_eventport_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t events; - - if (ev->read != NXT_EVENT_BLOCKED) { - events = (ev->write == NXT_EVENT_INACTIVE) ? POLLIN - : (POLLIN | POLLOUT); - nxt_eventport_enable_event(engine, ev, events); - } - - ev->read = NXT_EVENT_ACTIVE; -} - - -static void -nxt_eventport_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t events; - - if (ev->write != NXT_EVENT_BLOCKED) { - events = (ev->read == NXT_EVENT_INACTIVE) ? POLLOUT - : (POLLIN | POLLOUT); - nxt_eventport_enable_event(engine, ev, events); - } - - ev->write = NXT_EVENT_ACTIVE; -} - - -/* - * eventport changes are batched to improve instruction and data - * cache locality of several port_associate() and port_dissociate() - * calls followed by port_getn() call. - */ - -static void -nxt_eventport_enable_event(nxt_event_engine_t *engine, nxt_fd_event_t *ev, - nxt_uint_t events) -{ - nxt_eventport_change_t *change; - - nxt_debug(ev->task, "port %d set event: fd:%d ev:%04XD u:%p", - engine->u.eventport.fd, ev->fd, events, ev); - - if (engine->u.eventport.nchanges >= engine->u.eventport.mchanges) { - (void) nxt_eventport_commit_changes(engine); - } - - ev->changing = 1; - - change = &engine->u.eventport.changes[engine->u.eventport.nchanges++]; - change->events = events; - change->event = ev; -} - - -static void -nxt_eventport_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write == NXT_EVENT_INACTIVE) { - nxt_eventport_disable_event(engine, ev); - - } else { - nxt_eventport_enable_event(engine, ev, POLLOUT); - } -} - - -static void -nxt_eventport_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read == NXT_EVENT_INACTIVE) { - nxt_eventport_disable_event(engine, ev); - - } else { - nxt_eventport_enable_event(engine, ev, POLLIN); - } -} - - -static void -nxt_eventport_disable_event(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_eventport_change_t *change; - - nxt_debug(ev->task, "port %d disable event : fd:%d", - engine->u.eventport.fd, ev->fd); - - if (engine->u.eventport.nchanges >= engine->u.eventport.mchanges) { - (void) nxt_eventport_commit_changes(engine); - } - - ev->changing = 1; - - change = &engine->u.eventport.changes[engine->u.eventport.nchanges++]; - change->events = 0; - change->event = ev; -} - - -static nxt_int_t -nxt_eventport_commit_changes(nxt_event_engine_t *engine) -{ - int ret, port; - nxt_int_t retval; - nxt_fd_event_t *ev; - nxt_eventport_change_t *change, *end; - - port = engine->u.eventport.fd; - - nxt_debug(&engine->task, "eventport %d changes:%ui", - port, engine->u.eventport.nchanges); - - retval = NXT_OK; - change = engine->u.eventport.changes; - end = change + engine->u.eventport.nchanges; - - do { - ev = change->event; - ev->changing = 0; - - if (change->events != 0) { - nxt_debug(ev->task, "port_associate(%d): fd:%d ev:%04XD u:%p", - port, ev->fd, change->events, ev); - - ret = port_associate(port, PORT_SOURCE_FD, - ev->fd, change->events, ev); - - if (nxt_fast_path(ret == 0)) { - goto next; - } - - nxt_alert(ev->task, "port_associate(%d, %d, %d, %04XD) failed %E", - port, PORT_SOURCE_FD, ev->fd, change->events, nxt_errno); - - } else { - nxt_debug(ev->task, "port_dissociate(%d): fd:%d", port, ev->fd); - - ret = port_dissociate(port, PORT_SOURCE_FD, ev->fd); - - if (nxt_fast_path(ret == 0)) { - goto next; - } - - nxt_alert(ev->task, "port_dissociate(%d, %d, %d) failed %E", - port, PORT_SOURCE_FD, ev->fd, nxt_errno); - } - - nxt_work_queue_add(&engine->fast_work_queue, - nxt_eventport_error_handler, - ev->task, ev, ev->data); - - retval = NXT_ERROR; - - next: - - change++; - - } while (change < end); - - engine->u.eventport.nchanges = 0; - - return retval; -} - - -static void -nxt_eventport_error_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_fd_event_t *ev; - - ev = obj; - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - ev->error_handler(task, ev, data); -} - - -static void -nxt_eventport_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_eventport_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_eventport_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read == NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_ACTIVE; - - nxt_eventport_enable_event(engine, ev, POLLIN); - } -} - - -static void -nxt_eventport_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->write == NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_ACTIVE; - - nxt_eventport_enable_event(engine, ev, POLLOUT); - } -} - - -static void -nxt_eventport_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_LEVEL; - - nxt_eventport_enable_event(engine, ev, POLLIN); -} - - -static nxt_int_t -nxt_eventport_enable_post(nxt_event_engine_t *engine, - nxt_work_handler_t handler) -{ - engine->u.eventport.post_handler = handler; - - return NXT_OK; -} - - -static void -nxt_eventport_signal(nxt_event_engine_t *engine, nxt_uint_t signo) -{ - int port; - - port = engine->u.eventport.fd; - - nxt_debug(&engine->task, "port_send(%d, %ui)", port, signo); - - if (port_send(port, signo, NULL) != 0) { - nxt_alert(&engine->task, "port_send(%d) failed %E", port, nxt_errno); - } -} - - -static void -nxt_eventport_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) -{ - int n, events, signo; - uint_t nevents; - nxt_err_t err; - nxt_uint_t i, level; - timespec_t ts, *tp; - port_event_t *event; - nxt_fd_event_t *ev; - nxt_work_handler_t handler; - - if (engine->u.eventport.nchanges != 0) { - if (nxt_eventport_commit_changes(engine) != NXT_OK) { - /* Error handlers have been enqueued on failure. */ - timeout = 0; - } - } - - if (timeout == NXT_INFINITE_MSEC) { - tp = NULL; - - } else { - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (timeout % 1000) * 1000000; - tp = &ts; - } - - nxt_debug(&engine->task, "port_getn(%d) timeout: %M", - engine->u.eventport.fd, timeout); - - /* - * A trap for possible error when Solaris does not update nevents - * if ETIME or EINTR is returned. This issue will be logged as - * "unexpected port_getn() event". - * - * The details are in OpenSolaris mailing list thread "port_getn() - * and timeouts - is this a bug or an undocumented feature?" - */ - event = &engine->u.eventport.events[0]; - event->portev_events = -1; /* invalid port events */ - event->portev_source = -1; /* invalid port source */ - event->portev_object = -1; - event->portev_user = (void *) -1; - - nevents = 1; - n = port_getn(engine->u.eventport.fd, engine->u.eventport.events, - engine->u.eventport.mevents, &nevents, tp); - - /* - * 32-bit port_getn() on Solaris 10 x86 returns large negative - * values instead of 0 when returning immediately. - */ - err = (n < 0) ? nxt_errno : 0; - - nxt_thread_time_update(engine->task.thread); - - if (n == -1) { - if (err == NXT_ETIME || err == NXT_EINTR) { - if (nevents != 0) { - nxt_alert(&engine->task, "port_getn(%d) failed %E, events:%ud", - engine->u.eventport.fd, err, nevents); - } - } - - if (err != NXT_ETIME) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - - nxt_log(&engine->task, level, "port_getn(%d) failed %E", - engine->u.eventport.fd, err); - - if (err != NXT_EINTR) { - return; - } - } - } - - nxt_debug(&engine->task, "port_getn(%d) events: %d", - engine->u.eventport.fd, nevents); - - for (i = 0; i < nevents; i++) { - event = &engine->u.eventport.events[i]; - - switch (event->portev_source) { - - case PORT_SOURCE_FD: - ev = event->portev_user; - events = event->portev_events; - - nxt_debug(ev->task, "eventport: fd:%d ev:%04Xd u:%p rd:%d wr:%d", - event->portev_object, events, ev, ev->read, ev->write); - - if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { - nxt_alert(ev->task, "port_getn(%d) error fd:%d events:%04Xud", - engine->u.eventport.fd, ev->fd, events); - - nxt_work_queue_add(&engine->fast_work_queue, - nxt_eventport_error_handler, - ev->task, ev, ev->data); - continue; - } - - if (events & POLLIN) { - ev->read_ready = 1; - - if (ev->read != NXT_EVENT_BLOCKED) { - nxt_work_queue_add(ev->read_work_queue, ev->read_handler, - ev->task, ev, ev->data); - - } - - if (ev->read != NXT_EVENT_LEVEL) { - ev->read = NXT_EVENT_INACTIVE; - } - } - - if (events & POLLOUT) { - ev->write_ready = 1; - - if (ev->write != NXT_EVENT_BLOCKED) { - nxt_work_queue_add(ev->write_work_queue, ev->write_handler, - ev->task, ev, ev->data); - } - - ev->write = NXT_EVENT_INACTIVE; - } - - /* - * Reactivate counterpart direction, because the - * eventport is oneshot notification facility. - */ - events = (ev->read == NXT_EVENT_INACTIVE) ? 0 : POLLIN; - events |= (ev->write == NXT_EVENT_INACTIVE) ? 0 : POLLOUT; - - if (events != 0) { - nxt_eventport_enable_event(engine, ev, events); - } - - break; - - case PORT_SOURCE_USER: - nxt_debug(&engine->task, "eventport: user ev:%d u:%p", - event->portev_events, event->portev_user); - - signo = event->portev_events; - - handler = (signo == 0) ? engine->u.eventport.post_handler - : engine->u.eventport.signal_handler; - - nxt_work_queue_add(&engine->fast_work_queue, handler, - &engine->task, (void *) (uintptr_t) signo, NULL); - - break; - - default: - nxt_alert(&engine->task, - "unexpected port_getn(%d) event: " - "ev:%d src:%d obj:%p u:%p", - engine->u.eventport.fd, event->portev_events, - event->portev_source, event->portev_object, - event->portev_user); - } - } -} diff --git a/src/nxt_external.c b/src/nxt_external.c deleted file mode 100644 index c724b9bd..00000000 --- a/src/nxt_external.c +++ /dev/null @@ -1,208 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -static nxt_int_t nxt_external_start(nxt_task_t *task, nxt_process_data_t *data); - - -nxt_app_module_t nxt_external_module = { - 0, - NULL, - nxt_string("external"), - "*", - NULL, - 0, - NULL, - nxt_external_start, -}; - - -extern char **environ; - - -nxt_inline nxt_int_t -nxt_external_fd_no_cloexec(nxt_task_t *task, nxt_socket_t fd) -{ - int res, flags; - - if (fd == -1) { - return NXT_OK; - } - - flags = fcntl(fd, F_GETFD); - - if (nxt_slow_path(flags == -1)) { - nxt_alert(task, "fcntl(%d, F_GETFD) failed %E", fd, nxt_errno); - return NXT_ERROR; - } - - flags &= ~FD_CLOEXEC; - - res = fcntl(fd, F_SETFD, flags); - - if (nxt_slow_path(res == -1)) { - nxt_alert(task, "fcntl(%d, F_SETFD) failed %E", fd, nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_external_start(nxt_task_t *task, nxt_process_data_t *data) -{ - char **argv; - u_char buf[256]; - u_char *p, *end; - uint32_t index; - size_t size; - nxt_str_t str; - nxt_int_t rc; - nxt_uint_t i, argc; - nxt_port_t *my_port, *proto_port, *router_port; - nxt_runtime_t *rt; - nxt_conf_value_t *value; - nxt_common_app_conf_t *conf; - nxt_external_app_conf_t *c; - - rt = task->thread->runtime; - conf = data->app; - - proto_port = rt->port_by_type[NXT_PROCESS_PROTOTYPE]; - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - my_port = nxt_runtime_port_find(rt, nxt_pid, 0); - - if (nxt_slow_path(proto_port == NULL || my_port == NULL - || router_port == NULL)) - { - return NXT_ERROR; - } - - rc = nxt_external_fd_no_cloexec(task, proto_port->pair[1]); - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - rc = nxt_external_fd_no_cloexec(task, router_port->pair[1]); - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - rc = nxt_external_fd_no_cloexec(task, my_port->pair[0]); - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - rc = nxt_external_fd_no_cloexec(task, my_port->pair[1]); - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - rc = nxt_external_fd_no_cloexec(task, conf->shared_port_fd); - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - rc = nxt_external_fd_no_cloexec(task, conf->shared_queue_fd); - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - - end = buf + sizeof(buf); - - p = nxt_sprintf(buf, end, - "%s;%uD;" - "%PI,%ud,%d;" - "%PI,%ud,%d;" - "%PI,%ud,%d,%d;" - "%d,%d;" - "%d,%z,%uD,%Z", - NXT_VERSION, my_port->process->stream, - proto_port->pid, proto_port->id, proto_port->pair[1], - router_port->pid, router_port->id, router_port->pair[1], - my_port->pid, my_port->id, my_port->pair[0], - my_port->pair[1], - conf->shared_port_fd, conf->shared_queue_fd, - 2, conf->shm_limit, conf->request_limit); - - if (nxt_slow_path(p == end)) { - nxt_alert(task, "internal error: buffer too small for NXT_UNIT_INIT"); - - return NXT_ERROR; - } - - nxt_debug(task, "update "NXT_UNIT_INIT_ENV"=%s", buf); - - rc = setenv(NXT_UNIT_INIT_ENV, (char *) buf, 1); - if (nxt_slow_path(rc == -1)) { - nxt_alert(task, "setenv("NXT_UNIT_INIT_ENV", %s) failed %E", buf, - nxt_errno); - - return NXT_ERROR; - } - - c = &conf->u.external; - - argc = 2; - size = 0; - - if (c->arguments != NULL) { - - for (index = 0; /* void */ ; index++) { - value = nxt_conf_get_array_element(c->arguments, index); - if (value == NULL) { - break; - } - - nxt_conf_get_string(value, &str); - - size += str.length + 1; - argc++; - } - } - - argv = nxt_malloc(argc * sizeof(argv[0]) + size); - if (nxt_slow_path(argv == NULL)) { - nxt_alert(task, "failed to allocate arguments"); - return NXT_ERROR; - } - - argv[0] = c->executable; - i = 1; - - if (c->arguments != NULL) { - p = (u_char *) &argv[argc]; - - for (index = 0; /* void */ ; index++) { - value = nxt_conf_get_array_element(c->arguments, index); - if (value == NULL) { - break; - } - - argv[i++] = (char *) p; - - nxt_conf_get_string(value, &str); - - p = nxt_cpymem(p, str.start, str.length); - *p++ = '\0'; - } - } - - argv[i] = NULL; - - (void) execve(c->executable, argv, environ); - - nxt_alert(task, "execve(%s) failed %E", c->executable, nxt_errno); - - nxt_free(argv); - - return NXT_ERROR; -} diff --git a/src/nxt_fd_event.c b/src/nxt_fd_event.c deleted file mode 100644 index dffe1026..00000000 --- a/src/nxt_fd_event.c +++ /dev/null @@ -1,112 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static nxt_int_t nxt_fd_event_hash_test(nxt_lvlhsh_query_t *lhq, void *data); -static void nxt_fd_event_hash_error(nxt_task_t *task, nxt_fd_t fd); - - -static const nxt_lvlhsh_proto_t nxt_event_set_fd_hash_proto nxt_aligned(64) = -{ - NXT_LVLHSH_LARGE_MEMALIGN, - nxt_fd_event_hash_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -/* nxt_murmur_hash2() is unique for 4 bytes. */ - -static nxt_int_t -nxt_fd_event_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - return NXT_OK; -} - - -nxt_int_t -nxt_fd_event_hash_add(nxt_lvlhsh_t *lvlhsh, nxt_fd_t fd, nxt_fd_event_t *ev) -{ - nxt_int_t ret; - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); - lhq.replace = 0; - lhq.value = ev; - lhq.proto = &nxt_event_set_fd_hash_proto; - - ret = nxt_lvlhsh_insert(lvlhsh, &lhq); - - if (nxt_fast_path(ret == NXT_OK)) { - return NXT_OK; - } - - nxt_alert(ev->task, "fd event %d is already in hash", ev->fd); - - return NXT_ERROR; -} - - -void * -nxt_fd_event_hash_get(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, nxt_fd_t fd) -{ - nxt_int_t ret; - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); - lhq.proto = &nxt_event_set_fd_hash_proto; - - ret = nxt_lvlhsh_find(lvlhsh, &lhq); - - if (nxt_fast_path(ret == NXT_OK)) { - return lhq.value; - } - - nxt_fd_event_hash_error(task, fd); - - return NULL; -} - - -void -nxt_fd_event_hash_delete(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, nxt_fd_t fd, - nxt_bool_t ignore) -{ - nxt_int_t ret; - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); - lhq.proto = &nxt_event_set_fd_hash_proto; - - ret = nxt_lvlhsh_delete(lvlhsh, &lhq); - - if (nxt_slow_path(ret != NXT_OK)) { - if (!ignore) { - nxt_fd_event_hash_error(task, fd); - } - } -} - - -void -nxt_fd_event_hash_destroy(nxt_lvlhsh_t *lvlhsh) -{ - nxt_fd_event_t *ev; - - do { - ev = nxt_lvlhsh_retrieve(lvlhsh, &nxt_event_set_fd_hash_proto, NULL); - - } while (ev != NULL); -} - - -static void -nxt_fd_event_hash_error(nxt_task_t *task, nxt_fd_t fd) -{ - nxt_alert(task, "fd event %d not found in hash", fd); -} diff --git a/src/nxt_fd_event.h b/src/nxt_fd_event.h deleted file mode 100644 index 3a8d9460..00000000 --- a/src/nxt_fd_event.h +++ /dev/null @@ -1,118 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_FD_EVENT_H_INCLUDED_ -#define _NXT_FD_EVENT_H_INCLUDED_ - - -typedef enum { - /* A completely inactive event. */ - NXT_EVENT_INACTIVE = 0, - - /* - * An event presents in the kernel but disabled after oneshot. - * Used by epoll. - */ - NXT_EVENT_DISABLED, - - /* - * An event is active in the kernel but blocked by application. - * Used by kqueue, epoll, eventport, devpoll, and pollset. - */ - NXT_EVENT_BLOCKED, - - /* - * An active oneshot event. - * Used by epoll, devpoll, pollset, poll, and select. - */ - NXT_EVENT_ONESHOT, - - /* An active level-triggered event. Used by eventport. */ - NXT_EVENT_LEVEL, - - /* - * An active default event. The event type depends on interface: - * edge-triggered for kqueue, and modern epoll; - * level-triggered for old epoll, devpoll, pollset, poll, and select; - * oneshot for kqueue and eventport. - */ - NXT_EVENT_DEFAULT, - NXT_EVENT_ACTIVE = NXT_EVENT_DEFAULT, -} nxt_fd_event_state_t; - - -#define nxt_fd_event_is_disabled(state) \ - ((state) < NXT_EVENT_ONESHOT) - - -#define nxt_fd_event_is_active(state) \ - ((state) >= NXT_EVENT_ONESHOT) - - -struct nxt_fd_event_s { - void *data; - - /* Both are int's. */ - nxt_socket_t fd; - nxt_err_t error; - - /* The flags should also be prefetched by nxt_work_queue_pop(). */ - -#if (NXT_64BIT) - nxt_fd_event_state_t read:8; /* 3 bits. */ - nxt_fd_event_state_t write:8; /* 3 bits. */ - uint8_t read_ready; - uint8_t write_ready; - uint8_t changing; - uint8_t closed; - uint8_t timedout; - uint8_t shutdown:1; -#if (NXT_HAVE_EPOLL) - uint8_t epoll_eof:1; - uint8_t epoll_error:1; -#endif -#if (NXT_HAVE_KQUEUE) - uint8_t kq_eof:1; -#endif - -#else /* NXT_32BIT */ - nxt_fd_event_state_t read:3; - nxt_fd_event_state_t write:3; - uint8_t read_ready:1; - uint8_t write_ready:1; - uint8_t changing:1; - uint8_t closed:1; - uint8_t timedout:1; - uint8_t shutdown:1; -#if (NXT_HAVE_EPOLL) - uint8_t epoll_eof:1; - uint8_t epoll_error:1; -#endif -#if (NXT_HAVE_KQUEUE) - uint8_t kq_eof:1; -#endif -#endif /* NXT_64BIT */ - -#if (NXT_HAVE_KQUEUE) - /* nxt_err_t is int. */ - nxt_err_t kq_errno; - /* struct kevent.data is intptr_t, however int32_t is enough. */ - int32_t kq_available; -#endif - - nxt_task_t *task; - - nxt_work_queue_t *read_work_queue; - nxt_work_handler_t read_handler; - nxt_work_queue_t *write_work_queue; - nxt_work_handler_t write_handler; - nxt_work_handler_t error_handler; - - nxt_log_t *log; -}; - - -#endif /* _NXT_FD_EVENT_H_INCLUDED_ */ diff --git a/src/nxt_fiber.c b/src/nxt_fiber.c deleted file mode 100644 index d6cac893..00000000 --- a/src/nxt_fiber.c +++ /dev/null @@ -1,465 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static char *nxt_fiber_create_stack(nxt_task_t *task, nxt_fiber_t *fib); -static void nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent); -static void nxt_fiber_switch_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_fiber_switch(nxt_task_t *task, nxt_fiber_t *fib); -static void nxt_fiber_timer_handler(nxt_task_t *task, void *obj, void *data); - - -#define nxt_fiber_enqueue(thr, task, fib) \ - nxt_work_queue_add(&(thr)->engine->fast_work_queue, \ - nxt_fiber_switch_handler, task, fib, NULL) - - -nxt_fiber_main_t * -nxt_fiber_main_create(nxt_event_engine_t *engine) -{ - nxt_fiber_main_t *fm; - - fm = nxt_zalloc(sizeof(nxt_fiber_main_t)); - if (nxt_slow_path(fm == NULL)) { - return NULL; - } - - fm->engine = engine; - fm->stack_size = 512 * 1024 - nxt_pagesize; - fm->idle = NULL; - - return fm; -} - - -nxt_int_t -nxt_fiber_create(nxt_fiber_start_t start, void *data, size_t stack) -{ - int ret; - jmp_buf parent; - nxt_fid_t fid; - nxt_fiber_t *fib; - nxt_thread_t *thr; - nxt_fiber_main_t *fm; - - thr = nxt_thread(); - fm = thr->engine->fibers; - - fid = ++fm->fid; - - if (fid == 0) { - fid = ++fm->fid; - } - - fib = fm->idle; - - if (fib != NULL) { - fm->idle = fib->next; - fib->fid = fid; - fib->start = start; - fib->data = data; - fib->main = fm; - - fib->task.thread = thr; - fib->task.log = thr->log; - fib->task.ident = nxt_task_next_ident(); - - nxt_debug(&fib->task, "fiber create cached: %PF", fib->fid); - - nxt_fiber_enqueue(thr, &fm->engine->task, fib); - - return NXT_OK; - } - - nxt_log_debug(thr->log, "fiber create"); - - fib = nxt_malloc(sizeof(nxt_fiber_t)); - if (nxt_slow_path(fib == NULL)) { - return NXT_ERROR; - } - - fib->fid = fid; - fib->start = start; - fib->data = data; - fib->stack_size = fm->stack_size; - fib->main = fm; - - fib->task.thread = thr; - fib->task.log = thr->log; - fib->task.ident = nxt_task_next_ident(); - - fib->stack = nxt_fiber_create_stack(&fib->task, fib); - - if (nxt_fast_path(fib->stack != NULL)) { - - if (_setjmp(parent) != 0) { - nxt_log_debug(thr->log, "fiber create: %PF", fib->fid); - return NXT_OK; - } - - nxt_fiber_switch_stack(fib, &parent); - /* It does not return if the switch was successful. */ - } - - ret = munmap(fib->stack - nxt_pagesize, fib->stack_size + nxt_pagesize); - - if (nxt_slow_path(ret != 0)) { - nxt_log_alert(thr->log, "munmap() failed %E", nxt_errno); - } - - nxt_free(fib); - - return NXT_ERROR; -} - - -#if (NXT_LINUX) - -static char * -nxt_fiber_create_stack(nxt_task_t *task, nxt_fiber_t *fib) -{ - char *s; - size_t size; - - size = fib->stack_size + nxt_pagesize; - - s = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN, -1, 0); - - if (nxt_slow_path(s == MAP_FAILED)) { - nxt_alert(task, "fiber stack " - "mmap(%uz, MAP_PRIVATE|MAP_ANON|MAP_GROWSDOWN) failed %E", - size, nxt_errno); - - return NULL; - } - - if (nxt_slow_path(mprotect(s, nxt_pagesize, PROT_NONE) != 0)) { - nxt_alert(task, "fiber stack mprotect(%uz, PROT_NONE) failed %E", - size, nxt_errno); - - return NULL; - } - - s += nxt_pagesize; - - nxt_debug(task, "fiber stack mmap: %p", s); - - return s; -} - -#else /* Generic version. */ - -static char * -nxt_fiber_create_stack(nxt_task_t *task, nxt_fiber_t *fib) -{ - char *s; - size_t size; - - size = fib->stack_size + nxt_pagesize; - - s = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); - - if (nxt_slow_path(s == MAP_FAILED)) { - nxt_alert(task, "fiber stack mmap(%uz, MAP_PRIVATE|MAP_ANON) failed %E", - size, nxt_errno); - - return NULL; - } - - if (nxt_slow_path(mprotect(s, nxt_pagesize, PROT_NONE) != 0)) { - nxt_alert(task, "fiber stack mprotect(%uz, PROT_NONE) failed %E", - size, nxt_errno); - - return NULL; - } - - s += nxt_pagesize; - - nxt_debug(task, "fiber stack mmap: %p", s); - - return s; -} - -#endif - - -#if (NXT_LINUX && NXT_64BIT) - -/* - * Linux 64-bit ucontext version. 64-bit glibc makecontext() passes - * pointers as signed int's. The bug has been fixed in glibc 2.8. - */ - -static void nxt_fiber_trampoline(uint32_t fh, uint32_t fl, uint32_t ph, - uint32_t pl); - - -static void -nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent) -{ - ucontext_t uc; - - nxt_debug(&fib->task, "fiber switch to stack: %p", fib->stack); - - if (nxt_slow_path(getcontext(&uc) != 0)) { - nxt_alert(&fib->task, "getcontext() failed"); - return; - } - - uc.uc_link = NULL; - uc.uc_stack.ss_sp = fib->stack; - uc.uc_stack.ss_size = fib->stack_size; - - makecontext(&uc, (void (*)(void)) nxt_fiber_trampoline, 4, - (uint32_t) ((uintptr_t) fib >> 32), - (uint32_t) ((uintptr_t) fib & 0xFFFFFFFF), - (uint32_t) ((uintptr_t) parent >> 32), - (uint32_t) ((uintptr_t) parent & 0xFFFFFFFF)); - - setcontext(&uc); - - nxt_alert(&fib->task, "setcontext() failed"); -} - - -static void -nxt_fiber_trampoline(uint32_t fh, uint32_t fl, uint32_t ph, uint32_t pl) -{ - jmp_buf *parent; - nxt_task_t *task; - nxt_fiber_t *fib; - - fib = (nxt_fiber_t *) (((uintptr_t) fh << 32) + fl); - parent = (jmp_buf *) (((uintptr_t) ph << 32) + pl); - - task = &fib->task; - - if (_setjmp(fib->jmp) == 0) { - nxt_debug(task, "fiber return to parent stack"); - - nxt_fiber_enqueue(task->thread, task, fib); - - _longjmp(*parent, 1); - - nxt_unreachable(); - } - - nxt_debug(task, "fiber start"); - - fib->start(fib->data); - - nxt_fiber_exit(task, &fib->main->fiber, NULL); - - nxt_unreachable(); -} - -#elif (NXT_HAVE_UCONTEXT) - -/* Generic ucontext version. */ - -static void nxt_fiber_trampoline(nxt_fiber_t *fib, jmp_buf *parent); - - -static void -nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent) -{ - ucontext_t uc; - - nxt_debug(&fib->task, "fiber switch to stack: %p", fib->stack); - - if (nxt_slow_path(getcontext(&uc) != 0)) { - nxt_alert(&fib->task, "getcontext() failed"); - return; - } - - uc.uc_link = NULL; - uc.uc_stack.ss_sp = fib->stack; - uc.uc_stack.ss_size = fib->stack_size; - - makecontext(&uc, (void (*)(void)) nxt_fiber_trampoline, 2, fib, parent); - - setcontext(&uc); - -#if !(NXT_SOLARIS) - /* Solaris declares setcontext() as __NORETURN. */ - - nxt_alert(&fib->task, "setcontext() failed"); -#endif -} - - -static void -nxt_fiber_trampoline(nxt_fiber_t *fib, jmp_buf *parent) -{ - nxt_task_t *task; - - task = &fib->task; - - if (_setjmp(fib->jmp) == 0) { - nxt_debug(task, "fiber return to parent stack"); - - nxt_fiber_enqueue(task->thread, task, fib); - - _longjmp(*parent, 1); - - nxt_unreachable(); - } - - nxt_debug(task, "fiber start"); - - fib->start(fib->data); - - nxt_fiber_exit(task, &fib->main->fiber, NULL); - - nxt_unreachable(); -} - -#else - -#error No ucontext(3) interface. - -#endif - - -static void -nxt_fiber_switch_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_fiber_t *fib; - - fib = obj; - - nxt_fiber_switch(task, fib); - nxt_unreachable(); -} - - -static void -nxt_fiber_switch(nxt_task_t *task, nxt_fiber_t *fib) -{ - nxt_debug(task, "fiber switch: %PF", fib->fid); - - task->thread->fiber = fib; - - _longjmp(fib->jmp, 1); - - nxt_unreachable(); -} - - -nxt_fiber_t * -nxt_fiber_self(nxt_thread_t *thr) -{ - return (nxt_fast_path(thr != NULL)) ? thr->fiber : NULL; -} - - -void -nxt_fiber_yield(nxt_task_t *task) -{ - nxt_fiber_t *fib; - - fib = task->thread->fiber; - - if (_setjmp(fib->jmp) == 0) { - - nxt_debug(task, "fiber yield"); - - nxt_fiber_enqueue(task->thread, &fib->main->engine->task, fib); - - nxt_fiber_switch(task, &fib->main->fiber); - - nxt_unreachable(); - } - - nxt_debug(task, "fiber yield return"); -} - - -void -nxt_fiber_sleep(nxt_task_t *task, nxt_msec_t timeout) -{ - nxt_fiber_t *fib; - - fib = task->thread->fiber; - - fib->timer.work_queue = &task->thread->engine->fast_work_queue; - fib->timer.handler = nxt_fiber_timer_handler; - fib->timer.log = &nxt_main_log; - - task = &fib->task; - - nxt_timer_add(task->thread->engine, &fib->timer, timeout); - - if (_setjmp(fib->jmp) == 0) { - - nxt_debug(task, "fiber sleep: %T", timeout); - - nxt_fiber_switch(task, &fib->main->fiber); - - nxt_unreachable(); - } - - nxt_debug(task, "fiber sleep return"); -} - - -static void -nxt_fiber_timer_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_fiber_t *fib; - nxt_timer_t *ev; - - ev = obj; - - nxt_debug(task, "fiber timer handler"); - - fib = nxt_timer_data(ev, nxt_fiber_t, timer); - - nxt_fiber_switch(task, fib); - - nxt_unreachable(); -} - - -void -nxt_fiber_wait(nxt_task_t *task) -{ - nxt_fiber_t *fib; - - fib = task->thread->fiber; - - if (_setjmp(fib->jmp) == 0) { - nxt_debug(task, "fiber wait"); - - nxt_fiber_switch(task, &fib->main->fiber); - - nxt_unreachable(); - } - - nxt_debug(task, "fiber wait return"); -} - - -void -nxt_fiber_exit(nxt_task_t *task, nxt_fiber_t *next, void *data) -{ - nxt_fiber_t *fib; - - fib = task->thread->fiber; - - nxt_debug(task, "fiber exit"); - - /* TODO: limit idle fibers. */ - fib->next = fib->main->idle; - fib->main->idle = fib; - - nxt_fiber_switch(task, next); - - nxt_unreachable(); -} diff --git a/src/nxt_fiber.h b/src/nxt_fiber.h deleted file mode 100644 index 7f1beace..00000000 --- a/src/nxt_fiber.h +++ /dev/null @@ -1,57 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_FIBER_H_INCLUDED_ -#define _NXT_FIBER_H_INCLUDED_ - - -typedef struct nxt_fiber_main_s nxt_fiber_main_t; -typedef void (*nxt_fiber_start_t)(void *data); - - -typedef uint32_t nxt_fid_t; -#define nxt_fiber_id(f) (f)->fid; - - -typedef struct nxt_fiber_s nxt_fiber_t; - -struct nxt_fiber_s { - jmp_buf jmp; - nxt_fid_t fid; - nxt_fiber_start_t start; - void *data; - char *stack; - size_t stack_size; - nxt_err_t err; - - nxt_task_t task; - - nxt_fiber_main_t *main; - nxt_fiber_t *next; - - nxt_timer_t timer; -}; - - -struct nxt_fiber_main_s { - nxt_fiber_t fiber; - nxt_fiber_t *idle; - nxt_event_engine_t *engine; - size_t stack_size; - nxt_fid_t fid; -}; - - -nxt_fiber_main_t *nxt_fiber_main_create(nxt_event_engine_t *engine); -nxt_int_t nxt_fiber_create(nxt_fiber_start_t start, void *data, size_t stack); -void nxt_fiber_yield(nxt_task_t *task); -void nxt_fiber_sleep(nxt_task_t *task, nxt_msec_t timeout); -void nxt_fiber_wait(nxt_task_t *task); -void nxt_fiber_exit(nxt_task_t *task, nxt_fiber_t *next, void *data); -NXT_EXPORT nxt_fiber_t *nxt_fiber_self(nxt_thread_t *thr); - - -#endif /* _NXT_FIBER_H_INCLUDED_ */ diff --git a/src/nxt_file.c b/src/nxt_file.c deleted file mode 100644 index 4047d9d7..00000000 --- a/src/nxt_file.c +++ /dev/null @@ -1,777 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_int_t -nxt_file_open(nxt_task_t *task, nxt_file_t *file, nxt_uint_t mode, - nxt_uint_t create, nxt_file_access_t access) -{ -#ifdef __CYGWIN__ - mode |= O_BINARY; -#endif - - /* O_NONBLOCK is to prevent blocking on FIFOs, special devices, etc. */ - mode |= (O_NONBLOCK | create); - - file->fd = open((char *) file->name, mode, access); - - file->error = (file->fd == -1) ? nxt_errno : 0; - -#if (NXT_DEBUG) - nxt_thread_time_update(task->thread); -#endif - - nxt_debug(task, "open(\"%FN\", 0x%uXi, 0x%uXi): %FD err:%d", - file->name, mode, access, file->fd, file->error); - - if (file->fd != -1) { - return NXT_OK; - } - - if (file->log_level != 0) { - nxt_log(task, file->log_level, "open(\"%FN\") failed %E", - file->name, file->error); - } - - return NXT_ERROR; -} - - -#if (NXT_HAVE_OPENAT2) - -nxt_int_t -nxt_file_openat2(nxt_task_t *task, nxt_file_t *file, nxt_uint_t mode, - nxt_uint_t create, nxt_file_access_t access, nxt_fd_t dfd, - nxt_uint_t resolve) -{ - struct open_how how; - - nxt_memzero(&how, sizeof(how)); - - /* O_NONBLOCK is to prevent blocking on FIFOs, special devices, etc. */ - mode |= (O_NONBLOCK | create); - - how.flags = mode; - how.mode = access; - how.resolve = resolve; - - file->fd = syscall(SYS_openat2, dfd, file->name, &how, sizeof(how)); - - file->error = (file->fd == -1) ? nxt_errno : 0; - -#if (NXT_DEBUG) - nxt_thread_time_update(task->thread); -#endif - - nxt_debug(task, "openat2(%FD, \"%FN\"): %FD err:%d", dfd, file->name, - file->fd, file->error); - - if (file->fd != -1) { - return NXT_OK; - } - - if (file->log_level != 0) { - nxt_log(task, file->log_level, "openat2(%FD, \"%FN\") failed %E", dfd, - file->name, file->error); - } - - return NXT_ERROR; -} - -#endif - - -void -nxt_file_close(nxt_task_t *task, nxt_file_t *file) -{ - nxt_debug(task, "close(%FD)", file->fd); - - if (close(file->fd) != 0) { - nxt_alert(task, "close(%FD, \"%FN\") failed %E", - file->fd, file->name, nxt_errno); - } -} - - -ssize_t -nxt_file_write(nxt_file_t *file, const u_char *buf, size_t size, - nxt_off_t offset) -{ - ssize_t n; - - nxt_thread_debug(thr); - - n = pwrite(file->fd, buf, size, offset); - - file->error = (n < 0) ? nxt_errno : 0; - - nxt_thread_time_debug_update(thr); - - nxt_log_debug(thr->log, "pwrite(%FD, %p, %uz, %O): %z", - file->fd, buf, size, offset, n); - - if (nxt_fast_path(n >= 0)) { - return n; - } - - nxt_thread_log_alert("pwrite(%FD, \"%FN\", %p, %uz, %O) failed %E", - file->fd, file->name, buf, size, - offset, file->error); - - return NXT_ERROR; -} - - -ssize_t -nxt_file_read(nxt_file_t *file, u_char *buf, size_t size, nxt_off_t offset) -{ - ssize_t n; - - nxt_thread_debug(thr); - - n = pread(file->fd, buf, size, offset); - - file->error = (n <= 0) ? nxt_errno : 0; - - nxt_thread_time_debug_update(thr); - - nxt_log_debug(thr->log, "pread(%FD, %p, %uz, %O): %z", - file->fd, buf, size, offset, n); - - if (nxt_fast_path(n >= 0)) { - return n; - } - - nxt_thread_log_alert("pread(%FD, \"%FN\", %p, %uz, %O) failed %E", - file->fd, file->name, buf, size, - offset, file->error); - - return NXT_ERROR; -} - - -#if (NXT_HAVE_READAHEAD) - -/* FreeBSD 8.0 fcntl(F_READAHEAD, size) enables read ahead up to the size. */ - -void -nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size) -{ - int ret; - u_char buf; - - ret = fcntl(file->fd, F_READAHEAD, (int) size); - - nxt_thread_log_debug("fcntl(%FD, F_READAHEAD, %uz): %d", - file->fd, size, ret); - - if (nxt_fast_path(ret != -1)) { - (void) nxt_file_read(file, &buf, 1, offset); - return; - } - - nxt_thread_log_alert("fcntl(%FD, \"%FN\", F_READAHEAD, %uz) failed %E", - file->fd, file->name, size, nxt_errno); -} - -#elif (NXT_HAVE_POSIX_FADVISE) - -/* - * POSIX_FADV_SEQUENTIAL - * Linux doubles the default readahead window size of a backing device - * which is usually 128K. - * - * FreeBSD does nothing. - * - * POSIX_FADV_WILLNEED - * Linux preloads synchronously up to 2M of specified file region in - * the kernel page cache. Linux-specific readahead(2) syscall does - * the same. Both operations are blocking despite posix_fadvise(2) - * claims the opposite. - * - * FreeBSD does nothing. - */ - -void -nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size) -{ - nxt_err_t err; - - err = posix_fadvise(file->fd, offset, size, POSIX_FADV_WILLNEED); - - nxt_thread_log_debug("posix_fadvise(%FD, \"%FN\", %O, %uz, %d): %d", - file->fd, file->name, offset, size, - POSIX_FADV_WILLNEED, err); - - if (nxt_fast_path(err == 0)) { - return; - } - - nxt_thread_log_alert("posix_fadvise(%FD, \"%FN\", %O, %uz, %d) failed %E", - file->fd, file->name, offset, size, - POSIX_FADV_WILLNEED, err); -} - -#elif (NXT_HAVE_RDAHEAD) - -/* MacOSX fcntl(F_RDAHEAD). */ - -void -nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size) -{ - int ret; - u_char buf; - - ret = fcntl(file->fd, F_RDAHEAD, 1); - - nxt_thread_log_debug("fcntl(%FD, F_RDAHEAD, 1): %d", file->fd, ret); - - if (nxt_fast_path(ret != -1)) { - (void) nxt_file_read(file, &buf, 1, offset); - return; - } - - nxt_thread_log_alert("fcntl(%FD, \"%FN\", F_RDAHEAD, 1) failed %E", - file->fd, file->name, nxt_errno); -} - -#else - -void -nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size) -{ - u_char buf; - - (void) nxt_file_read(file, &buf, 1, offset); -} - -#endif - - -nxt_int_t -nxt_file_info(nxt_file_t *file, nxt_file_info_t *fi) -{ - int n; - - if (file->fd == NXT_FILE_INVALID) { - n = stat((char *) file->name, fi); - - file->error = (n != 0) ? nxt_errno : 0; - - nxt_thread_log_debug("stat(\"%FN)\": %d", file->name, n); - - if (n == 0) { - return NXT_OK; - } - - if (file->log_level != 0) { - nxt_thread_log_error(file->log_level, "stat(\"%FN\") failed %E", - file->name, file->error); - } - - return NXT_ERROR; - - } else { - n = fstat(file->fd, fi); - - file->error = (n != 0) ? nxt_errno : 0; - - nxt_thread_log_debug("fstat(%FD): %d", file->fd, n); - - if (n == 0) { - return NXT_OK; - } - - /* Use NXT_LOG_ALERT because fstat() error on open file is strange. */ - - nxt_thread_log_alert("fstat(%FD, \"%FN\") failed %E", - file->fd, file->name, file->error); - - return NXT_ERROR; - } -} - - -nxt_int_t -nxt_file_delete(nxt_file_name_t *name) -{ - nxt_thread_log_debug("unlink(\"%FN\")", name); - - if (nxt_fast_path(unlink((char *) name) == 0)) { - return NXT_OK; - } - - nxt_thread_log_alert("unlink(\"%FN\") failed %E", name, nxt_errno); - - return NXT_ERROR; -} - - -nxt_int_t -nxt_file_set_access(nxt_file_name_t *name, nxt_file_access_t access) -{ - if (nxt_fast_path(chmod((char *) name, access) == 0)) { - return NXT_OK; - } - - nxt_thread_log_alert("chmod(\"%FN\") failed %E", name, nxt_errno); - - return NXT_ERROR; -} - - -nxt_int_t -nxt_file_chown(nxt_file_name_t *name, const char *owner, const char *group) -{ - int err; - char *buf; - long bufsize; - gid_t gid = ~0; - uid_t uid = ~0; - - if (owner == NULL && group == NULL) { - return NXT_OK; - } - - if (owner != NULL) { - struct passwd pwd, *result; - - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize == -1) { - bufsize = 32768; - } - - buf = nxt_malloc(bufsize); - if (buf == NULL) { - return NXT_ERROR; - } - - err = getpwnam_r(owner, &pwd, buf, bufsize, &result); - if (result == NULL) { - nxt_thread_log_alert("getpwnam_r(\"%s\", ...) failed %E %s", - owner, nxt_errno, - err == 0 ? "(User not found)" : ""); - goto out_err_free; - } - - uid = pwd.pw_uid; - - nxt_free(buf); - } - - if (group != NULL) { - struct group grp, *result; - - bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); - if (bufsize == -1) { - bufsize = 32768; - } - - buf = nxt_malloc(bufsize); - if (buf == NULL) { - return NXT_ERROR; - } - - err = getgrnam_r(group, &grp, buf, bufsize, &result); - if (result == NULL) { - nxt_thread_log_alert("getgrnam_r(\"%s\", ...) failed %E %s", - group, nxt_errno, - err == 0 ? "(Group not found)" : ""); - goto out_err_free; - } - - gid = grp.gr_gid; - - nxt_free(buf); - } - - if (nxt_fast_path(chown((const char *) name, uid, gid) == 0)) { - return NXT_OK; - } - - nxt_thread_log_alert("chown(\"%FN\", %l, %l) failed %E", name, - owner != NULL ? (long) uid : -1, - group != NULL ? (long) gid : -1, nxt_errno); - - return NXT_ERROR; - -out_err_free: - nxt_free(buf); - - return NXT_ERROR; -} - - -nxt_int_t -nxt_file_rename(nxt_file_name_t *old_name, nxt_file_name_t *new_name) -{ - int ret; - - nxt_thread_log_debug("rename(\"%FN\", \"%FN\")", old_name, new_name); - - ret = rename((char *) old_name, (char *) new_name); - if (nxt_fast_path(ret == 0)) { - return NXT_OK; - } - - nxt_thread_log_alert("rename(\"%FN\", \"%FN\") failed %E", - old_name, new_name, nxt_errno); - - return NXT_ERROR; -} - - -/* - * ioctl(FIONBIO) sets a non-blocking mode using one syscall, - * thereas fcntl(F_SETFL, O_NONBLOCK) needs to learn the current state - * using fcntl(F_GETFL). - * - * ioctl() and fcntl() are syscalls at least in Linux 2.2, FreeBSD 2.x, - * and Solaris 7. - * - * Linux 2.4 uses BKL for ioctl() and fcntl(F_SETFL). - * Linux 2.6 does not use BKL. - */ - -#if (NXT_HAVE_FIONBIO) - -nxt_int_t -nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd) -{ - int nb; - - nb = 1; - - if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) { - return NXT_OK; - } - - nxt_alert(task, "ioctl(%d, FIONBIO) failed %E", fd, nxt_errno); - - return NXT_ERROR; - -} - - -nxt_int_t -nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd) -{ - int nb; - - nb = 0; - - if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) { - return NXT_OK; - } - - nxt_alert(task, "ioctl(%d, !FIONBIO) failed %E", fd, nxt_errno); - - return NXT_ERROR; -} - -#else /* !(NXT_HAVE_FIONBIO) */ - -nxt_int_t -nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd) -{ - int flags; - - flags = fcntl(fd, F_GETFL); - - if (nxt_slow_path(flags == -1)) { - nxt_alert(task, "fcntl(%d, F_GETFL) failed %E", fd, nxt_errno); - return NXT_ERROR; - } - - flags |= O_NONBLOCK; - - if (nxt_slow_path(fcntl(fd, F_SETFL, flags) == -1)) { - nxt_alert(task, "fcntl(%d, F_SETFL, O_NONBLOCK) failed %E", - fd, nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; -} - - -nxt_int_t -nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd) -{ - int flags; - - flags = fcntl(fd, F_GETFL); - - if (nxt_slow_path(flags == -1)) { - nxt_alert(task, "fcntl(%d, F_GETFL) failed %E", fd, nxt_errno); - return NXT_ERROR; - } - - flags &= O_NONBLOCK; - - if (nxt_slow_path(fcntl(fd, F_SETFL, flags) == -1)) { - nxt_alert(task, "fcntl(%d, F_SETFL, !O_NONBLOCK) failed %E", - fd, nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; -} - -#endif /* NXT_HAVE_FIONBIO */ - - -ssize_t -nxt_fd_write(nxt_fd_t fd, u_char *buf, size_t size) -{ - ssize_t n; - nxt_err_t err; - - n = write(fd, buf, size); - - err = (n == -1) ? nxt_errno : 0; - - nxt_thread_log_debug("write(%FD, %p, %uz): %z", fd, buf, size, n); - - if (nxt_slow_path(n <= 0)) { - nxt_thread_log_alert("write(%FD) failed %E", fd, err); - } - - return n; -} - - -ssize_t -nxt_fd_read(nxt_fd_t fd, u_char *buf, size_t size) -{ - ssize_t n; - nxt_err_t err; - - n = read(fd, buf, size); - - err = (n == -1) ? nxt_errno : 0; - - nxt_thread_log_debug("read(%FD, %p, %uz): %z", fd, buf, size, n); - - if (nxt_slow_path(n <= 0)) { - - if (err == NXT_EAGAIN) { - return 0; - } - - nxt_thread_log_alert("read(%FD) failed %E", fd, err); - } - - return n; -} - - -void -nxt_fd_close(nxt_fd_t fd) -{ - nxt_thread_log_debug("close(%FD)", fd); - - if (nxt_slow_path(close(fd) != 0)) { - nxt_thread_log_alert("close(%FD) failed %E", fd, nxt_errno); - } -} - - -FILE * -nxt_file_fopen(nxt_task_t *task, const char *pathname, const char *mode) -{ - int err; - FILE *fp; - -#if (NXT_DEBUG) - nxt_thread_time_update(task->thread); -#endif - - fp = fopen(pathname, mode); - err = (fp == NULL) ? nxt_errno : 0; - - nxt_debug(task, "fopen(\"%s\", \"%s\"): fp:%p err:%d", pathname, mode, fp, - err); - - if (nxt_fast_path(fp != NULL)) { - return fp; - } - - nxt_alert(task, "fopen(\"%s\") failed %E", pathname, err); - - return NULL; -} - - -void -nxt_file_fclose(nxt_task_t *task, FILE *fp) -{ - nxt_debug(task, "fclose(%p)", fp); - - if (nxt_slow_path(fclose(fp) == -1)) { - nxt_alert(task, "fclose() failed %E", nxt_errno); - } -} - - -/* - * nxt_file_redirect() redirects the file to the fd descriptor. - * Then the fd descriptor is closed. - */ - -nxt_int_t -nxt_file_redirect(nxt_file_t *file, nxt_fd_t fd) -{ - nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", fd, file->fd, file->name); - - if (dup2(fd, file->fd) == -1) { - nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E", - fd, file->fd, file->name, nxt_errno); - return NXT_ERROR; - } - - if (close(fd) != 0) { - nxt_thread_log_alert("close(%FD, \"%FN\") failed %E", - fd, file->name, nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; -} - - -/* nxt_file_stdout() redirects the stdout descriptor to the file. */ - -nxt_int_t -nxt_file_stdout(nxt_file_t *file) -{ - nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", - file->fd, STDOUT_FILENO, file->name); - - if (dup2(file->fd, STDOUT_FILENO) != -1) { - return NXT_OK; - } - - nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E", - file->fd, STDOUT_FILENO, file->name, nxt_errno); - - return NXT_ERROR; -} - - -/* nxt_file_stderr() redirects the stderr descriptor to the file. */ - -nxt_int_t -nxt_file_stderr(nxt_file_t *file) -{ - nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", - file->fd, STDERR_FILENO, file->name); - - if (dup2(file->fd, STDERR_FILENO) != -1) { - return NXT_OK; - } - - nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E", - file->fd, STDERR_FILENO, file->name, nxt_errno); - - return NXT_ERROR; -} - - -nxt_int_t -nxt_stderr_start(void) -{ - int flags, fd; - - flags = fcntl(nxt_stderr, F_GETFL); - - if (flags != -1) { - /* - * If the stderr output of a multithreaded application is - * redirected to a file: - * Linux, Solaris and MacOSX do not write atomically to the output; - * MacOSX besides adds zeroes to the output. - * O_APPEND fixes this. - */ - (void) fcntl(nxt_stderr, F_SETFL, flags | O_APPEND); - - } else { - /* - * The stderr descriptor is closed before application start. - * Reserve the stderr descriptor for future use. Errors are - * ignored because anyway they could be written nowhere. - */ - fd = open("/dev/null", O_WRONLY | O_APPEND); - - if (fd != -1) { - (void) dup2(fd, nxt_stderr); - - if (fd != nxt_stderr) { - (void) close(fd); - } - } - } - - return flags; -} - - -nxt_int_t -nxt_pipe_create(nxt_task_t *task, nxt_fd_t *pp, nxt_bool_t nbread, - nxt_bool_t nbwrite) -{ - if (pipe(pp) != 0) { - nxt_alert(task, "pipe() failed %E", nxt_errno); - - return NXT_ERROR; - } - - nxt_debug(task, "pipe(): %FD:%FD", pp[0], pp[1]); - - if (nbread) { - if (nxt_fd_nonblocking(task, pp[0]) != NXT_OK) { - return NXT_ERROR; - } - } - - if (nbwrite) { - if (nxt_fd_nonblocking(task, pp[1]) != NXT_OK) { - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -void -nxt_pipe_close(nxt_task_t *task, nxt_fd_t *pp) -{ - nxt_debug(task, "pipe close(%FD:%FD)", pp[0], pp[1]); - - if (close(pp[0]) != 0) { - nxt_alert(task, "pipe close(%FD) failed %E", pp[0], nxt_errno); - } - - if (close(pp[1]) != 0) { - nxt_alert(task, "pipe close(%FD) failed %E", pp[1], nxt_errno); - } -} - - -size_t -nxt_dir_current(char *buf, size_t len) -{ - if (nxt_fast_path(getcwd(buf, len) != NULL)) { - return nxt_strlen(buf); - } - - nxt_thread_log_alert("getcwd(%uz) failed %E", len, nxt_errno); - - return 0; -} diff --git a/src/nxt_file.h b/src/nxt_file.h deleted file mode 100644 index 0c03a5f9..00000000 --- a/src/nxt_file.h +++ /dev/null @@ -1,219 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_FILE_H_INCLUDED_ -#define _NXT_UNIX_FILE_H_INCLUDED_ - - -typedef int nxt_fd_t; - -#define NXT_FILE_INVALID -1 - -typedef nxt_uint_t nxt_file_access_t; -typedef struct stat nxt_file_info_t; - - -#define NXT_FILE_SYSTEM_NAME_UTF8 1 - -typedef u_char nxt_file_name_t; - - -typedef struct { - size_t len; - nxt_file_name_t *start; -} nxt_file_name_str_t; - - -#define nxt_file_name_str_set(file_name, mem_pool, name) \ - ((file_name) = (nxt_file_name_t *) (name), NXT_OK) - - -#define nxt_file_name_alloc(mem_pool, len) \ - nxt_mp_nget(mem_pool, len) - - -#define nxt_file_name_copy(dst, src, len) \ - nxt_cpymem(dst, src, len) - - -#define nxt_file_name_add(dst, src, len) \ - nxt_cpymem(dst, src, len) - - -#if (NXT_HAVE_CASELESS_FILESYSTEM) - -/* MacOSX, Cygwin. */ - -#define nxt_file_name_eq(fn1, fn2) \ - (nxt_strcasecmp(fn1, fn2) == 0) - -#else - -#define nxt_file_name_eq(fn1, fn2) \ - (nxt_strcmp(fn1, fn2) == 0) - -#endif - - -#define nxt_file_name_is_absolute(name) \ - (name[0] == '/') - - -#define NXT_MAX_PATH_LEN MAXPATHLEN - - -typedef enum { - NXT_FILE_UNKNOWN = 0, - NXT_FILE_REGULAR, - NXT_FILE_DIRECTORY, -} nxt_file_type_t; - - -typedef struct { - nxt_file_name_t *name; - - /* Both are int's. */ - nxt_fd_t fd; - nxt_err_t error; - -#define NXT_FILE_ACCESSED_LONG_AGO 0xFFFF - /* - * Number of seconds ago the file content was last - * read. The maximum value is about 18 hours. - */ - uint16_t accessed; - - uint8_t type; /* nxt_file_type_t */ - - /* - * Log open() file error with given log level if it is non zero. - * Note that zero log level is NXT_LOG_ALERT. - */ - uint8_t log_level; - - nxt_time_t mtime; - nxt_off_t size; -} nxt_file_t; - - -NXT_EXPORT nxt_int_t nxt_file_open(nxt_task_t *task, nxt_file_t *file, - nxt_uint_t mode, nxt_uint_t create, nxt_file_access_t access); - -#if (NXT_HAVE_OPENAT2) -NXT_EXPORT nxt_int_t nxt_file_openat2(nxt_task_t *task, nxt_file_t *file, - nxt_uint_t mode, nxt_uint_t create, nxt_file_access_t access, nxt_fd_t dfd, - nxt_uint_t resolve); -#endif - - -/* The file open access modes. */ -#define NXT_FILE_RDONLY O_RDONLY -#define NXT_FILE_WRONLY O_WRONLY -#define NXT_FILE_RDWR O_RDWR -#define NXT_FILE_APPEND (O_WRONLY | O_APPEND) - -#if (NXT_HAVE_OPENAT2) - -#if defined(O_DIRECTORY) -#define NXT_FILE_DIRECTORY O_DIRECTORY -#else -#define NXT_FILE_DIRECTORY 0 -#endif - -#if defined(O_SEARCH) -#define NXT_FILE_SEARCH (O_SEARCH|NXT_FILE_DIRECTORY) - -#elif defined(O_EXEC) -#define NXT_FILE_SEARCH (O_EXEC|NXT_FILE_DIRECTORY) - -#else -/* - * O_PATH is used in combination with O_RDONLY. The last one is ignored - * if O_PATH is used, but it allows Unit to not fail when it was built on - * modern system (i.e. glibc 2.14+) and run with a kernel older than 2.6.39. - * Then O_PATH is unknown to the kernel and ignored, while O_RDONLY is used. - */ -#define NXT_FILE_SEARCH (O_PATH|O_RDONLY|NXT_FILE_DIRECTORY) -#endif - -#endif /* NXT_HAVE_OPENAT2 */ - -/* The file creation modes. */ -#define NXT_FILE_CREATE_OR_OPEN O_CREAT -#define NXT_FILE_OPEN 0 -#define NXT_FILE_TRUNCATE (O_CREAT | O_TRUNC) - -/* The file access rights. */ -#define NXT_FILE_DEFAULT_ACCESS 0644 -#define NXT_FILE_OWNER_ACCESS 0600 - - -NXT_EXPORT void nxt_file_close(nxt_task_t *task, nxt_file_t *file); -NXT_EXPORT ssize_t nxt_file_write(nxt_file_t *file, const u_char *buf, - size_t size, nxt_off_t offset); -NXT_EXPORT ssize_t nxt_file_read(nxt_file_t *file, u_char *buf, size_t size, - nxt_off_t offset); -NXT_EXPORT void nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, - size_t size); -NXT_EXPORT nxt_int_t nxt_file_info(nxt_file_t *file, nxt_file_info_t *fi); - - -#define nxt_is_dir(fi) \ - (S_ISDIR((fi)->st_mode)) - -#define nxt_is_file(fi) \ - (S_ISREG((fi)->st_mode)) - -#define nxt_file_size(fi) \ - (fi)->st_size - -#define nxt_file_mtime(fi) \ - (fi)->st_mtime - - -NXT_EXPORT nxt_int_t nxt_file_delete(nxt_file_name_t *name); -NXT_EXPORT nxt_int_t nxt_file_set_access(nxt_file_name_t *name, - nxt_file_access_t access); -NXT_EXPORT nxt_int_t nxt_file_chown(nxt_file_name_t *name, const char *owner, - const char *group); -NXT_EXPORT nxt_int_t nxt_file_rename(nxt_file_name_t *old_name, - nxt_file_name_t *new_name); - -NXT_EXPORT nxt_int_t nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd); -NXT_EXPORT nxt_int_t nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd); -NXT_EXPORT ssize_t nxt_fd_write(nxt_fd_t fd, u_char *buf, size_t size); -NXT_EXPORT ssize_t nxt_fd_read(nxt_fd_t fd, u_char *buf, size_t size); -NXT_EXPORT void nxt_fd_close(nxt_fd_t fd); - -NXT_EXPORT FILE *nxt_file_fopen(nxt_task_t *task, const char *pathname, - const char *mode); -NXT_EXPORT void nxt_file_fclose(nxt_task_t *task, FILE *fp); - -NXT_EXPORT nxt_int_t nxt_file_redirect(nxt_file_t *file, nxt_fd_t fd); -NXT_EXPORT nxt_int_t nxt_file_stdout(nxt_file_t *file); -NXT_EXPORT nxt_int_t nxt_file_stderr(nxt_file_t *file); -NXT_EXPORT nxt_int_t nxt_stderr_start(void); - - -#define nxt_stdout STDOUT_FILENO -#define nxt_stderr STDERR_FILENO - - -#define nxt_write_console(fd, buf, size) \ - write(fd, buf, size) - -#define nxt_write_syslog(priority, message) \ - syslog(priority, "%s", message) - - -NXT_EXPORT nxt_int_t nxt_pipe_create(nxt_task_t *task, nxt_fd_t *pp, - nxt_bool_t nbread, nxt_bool_t nbwrite); -NXT_EXPORT void nxt_pipe_close(nxt_task_t *task, nxt_fd_t *pp); - -NXT_EXPORT size_t nxt_dir_current(char *buf, size_t len); - - -#endif /* _NXT_UNIX_FILE_H_INCLUDED_ */ diff --git a/src/nxt_file_event.h b/src/nxt_file_event.h deleted file mode 100644 index d4255ce9..00000000 --- a/src/nxt_file_event.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_FILE_EVENT_H_INCLUDED_ -#define _NXT_FILE_EVENT_H_INCLUDED_ - - -typedef struct { - void *data; - nxt_file_t *file; - nxt_work_handler_t handler; - nxt_task_t *task; -} nxt_file_event_t; - - -#endif /* _NXT_FILE_EVENT_H_INCLUDED_ */ diff --git a/src/nxt_file_name.c b/src/nxt_file_name.c deleted file mode 100644 index 935479ea..00000000 --- a/src/nxt_file_name.c +++ /dev/null @@ -1,201 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * Supported formats: - * %s null-terminated string - * %*s length and string - * %FN nxt_file_name_t * - * %V nxt_str_t * - * %Z '\0', this null is not counted in file name lenght. - */ - -nxt_int_t -nxt_file_name_create(nxt_mp_t *mp, nxt_file_name_str_t *file_name, - const char *format, ...) -{ - u_char ch, *p; - size_t length; - va_list args; - nxt_str_t *v; - nxt_bool_t zero; - const char *fmt; - nxt_file_name_t *dst, *fn; - - va_start(args, format); - fmt = format; - zero = 0; - length = 0; - - for ( ;; ) { - ch = *fmt++; - - if (ch != '%') { - - if (ch != '\0') { - length++; - continue; - } - - break; - } - - ch = *fmt++; - - switch (ch) { - - case 'V': - v = va_arg(args, nxt_str_t *); - - if (nxt_fast_path(v != NULL)) { - length += v->length; - } - - continue; - - case 's': - p = va_arg(args, u_char *); - - if (nxt_fast_path(p != NULL)) { - while (*p != '\0') { - p++; - length++; - } - } - - continue; - - case '*': - length += va_arg(args, u_int); - fmt++; - - continue; - - case 'F': - ch = *fmt++; - - if (nxt_fast_path(ch == 'N')) { - fn = va_arg(args, nxt_file_name_t *); - - if (nxt_fast_path(fn != NULL)) { - while (*fn != '\0') { - fn++; - length += sizeof(nxt_file_name_t); - } - } - } - - continue; - - case 'Z': - zero = 1; - length++; - continue; - - default: - continue; - } - } - - va_end(args); - - if (length == 0) { - return NXT_ERROR; - } - - file_name->len = length - zero; - - fn = nxt_file_name_alloc(mp, length); - if (nxt_slow_path(fn == NULL)) { - return NXT_ERROR; - } - - file_name->start = fn; - dst = fn; - - va_start(args, format); - fmt = format; - - for ( ;; ) { - ch = *fmt++; - - if (ch != '%') { - - if (ch != '\0') { - *dst++ = (nxt_file_name_t) ch; - continue; - } - - break; - } - - ch = *fmt++; - - switch (ch) { - - case 'V': - v = va_arg(args, nxt_str_t *); - - if (nxt_fast_path(v != NULL)) { - dst = nxt_file_name_add(dst, v->start, v->length); - } - - continue; - - case 's': - p = va_arg(args, u_char *); - - if (nxt_fast_path(p != NULL)) { - while (*p != '\0') { - *dst++ = (nxt_file_name_t) (*p++); - } - } - - continue; - - case '*': - length += va_arg(args, u_int); - - ch = *fmt++; - - if (nxt_fast_path(ch == 's')) { - p = va_arg(args, u_char *); - dst = nxt_file_name_add(dst, p, length); - } - - continue; - - case 'F': - ch = *fmt++; - - if (nxt_fast_path(ch == 'N')) { - fn = va_arg(args, nxt_file_name_t *); - - if (nxt_fast_path(fn != NULL)) { - while (*fn != '\0') { - *dst++ = *fn++; - } - } - } - - continue; - - case 'Z': - *dst++ = '\0'; - continue; - - default: - continue; - } - } - - va_end(args); - - return NXT_OK; -} diff --git a/src/nxt_file_name.h b/src/nxt_file_name.h deleted file mode 100644 index f8e7a3ba..00000000 --- a/src/nxt_file_name.h +++ /dev/null @@ -1,15 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_FILE_NAME_H_INCLUDED_ -#define _NXT_FILE_NAME_H_INCLUDED_ - - -NXT_EXPORT nxt_int_t nxt_file_name_create(nxt_mp_t *mp, - nxt_file_name_str_t *fn, const char *format, ...); - - -#endif /* _NXT_FILE_NAME_H_INCLUDED_ */ diff --git a/src/nxt_freebsd_sendfile.c b/src/nxt_freebsd_sendfile.c deleted file mode 100644 index a9535c10..00000000 --- a/src/nxt_freebsd_sendfile.c +++ /dev/null @@ -1,143 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * sendfile() has been introduced in FreeBSD 3.1, - * however, early implementation had various bugs. - * This code supports FreeBSD 5.0 implementation. - */ - -#ifdef NXT_TEST_BUILD_FREEBSD_SENDFILE - -ssize_t nxt_freebsd_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, - size_t limit); - -static int nxt_sys_sendfile(int fd, int s, off_t offset, size_t nbytes, - struct sf_hdtr *hdtr, off_t *sbytes, int flags) -{ - return -1; -} - -#else -#define nxt_sys_sendfile sendfile -#endif - - -ssize_t -nxt_freebsd_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, - size_t limit) -{ - size_t file_size; - ssize_t n; - nxt_buf_t *fb; - nxt_err_t err; - nxt_off_t sent; - nxt_uint_t nhd, ntr; - struct iovec hd[NXT_IOBUF_MAX], tr[NXT_IOBUF_MAX]; - struct sf_hdtr hdtr, *ht; - nxt_sendbuf_coalesce_t sb; - - sb.buf = b; - sb.iobuf = hd; - sb.nmax = NXT_IOBUF_MAX; - sb.sync = 0; - sb.size = 0; - sb.limit = limit; - - nhd = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); - - if (nhd == 0 && sb.sync) { - return 0; - } - - if (sb.buf == NULL || !nxt_buf_is_file(sb.buf)) { - return nxt_event_conn_io_writev(c, hd, nhd); - } - - fb = sb.buf; - - file_size = nxt_sendbuf_file_coalesce(&sb); - - if (file_size == 0) { - return nxt_event_conn_io_writev(c, hd, nhd); - } - - sb.iobuf = tr; - - ntr = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); - - /* - * Disposal of surplus kernel operations - * if there are no headers or trailers. - */ - - ht = NULL; - nxt_memzero(&hdtr, sizeof(struct sf_hdtr)); - - if (nhd != 0) { - ht = &hdtr; - hdtr.headers = hd; - hdtr.hdr_cnt = nhd; - } - - if (ntr != 0) { - ht = &hdtr; - hdtr.trailers = tr; - hdtr.trl_cnt = ntr; - } - - nxt_debug(c->socket.task, "sendfile(%FD, %d, @%O, %uz) hd:%ui tr:%ui", - fb->file->fd, c->socket.fd, fb->file_pos, file_size, - nhd, ntr); - - sent = 0; - n = nxt_sys_sendfile(fb->file->fd, c->socket.fd, fb->file_pos, - file_size, ht, &sent, 0); - - err = (n == -1) ? nxt_errno : 0; - - nxt_debug(c->socket.task, "sendfile(): %d sent:%O", n, sent); - - if (n == -1) { - switch (err) { - - case NXT_EAGAIN: - c->socket.write_ready = 0; - break; - - case NXT_EINTR: - break; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "sendfile(%FD, %d, %O, %uz) failed %E \"%FN\" hd:%ui tr:%ui", - fb->file->fd, c->socket.fd, fb->file_pos, file_size, err, - fb->file->name, nhd, ntr); - - return NXT_ERROR; - } - - nxt_debug(c->socket.task, "sendfile() %E", err); - - return sent; - - } else if (sent == 0) { - nxt_log(c->socket.task, NXT_LOG_ERR, - "file \"%FN\" was truncated while sendfile()", fb->file->name); - - return NXT_ERROR; - } - - if (sent < (nxt_off_t) sb.size) { - c->socket.write_ready = 0; - } - - return sent; -} diff --git a/src/nxt_fs.c b/src/nxt_fs.c deleted file mode 100644 index e10c5bcb..00000000 --- a/src/nxt_fs.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) NGINX, Inc. - */ - -#include - - -static nxt_int_t nxt_fs_mkdir(const u_char *dir, mode_t mode); - - -nxt_int_t -nxt_fs_mkdir_all(const u_char *dir, mode_t mode) -{ - char *start, *end, *dst; - size_t dirlen; - char path[PATH_MAX]; - - dirlen = nxt_strlen(dir); - - nxt_assert(dirlen < PATH_MAX && dirlen > 1 && dir[0] == '/'); - - dst = path; - start = (char *) dir; - - while (*start != '\0') { - if (*start == '/') { - *dst++ = *start++; - } - - end = strchr(start, '/'); - if (end == NULL) { - end = ((char *)dir + dirlen); - } - - dst = nxt_cpymem(dst, start, end - start); - *dst = '\0'; - - if (nxt_slow_path(nxt_fs_mkdir((u_char *) path, mode) != NXT_OK - && nxt_errno != EEXIST)) - { - return NXT_ERROR; - } - - start = end; - } - - return NXT_OK; -} - - -nxt_int_t -nxt_fs_mkdir_parent(const u_char *path, mode_t mode) -{ - char *ptr, *dir; - nxt_int_t ret; - - dir = nxt_strdup(path); - if (nxt_slow_path(dir == NULL)) { - return NXT_ERROR; - } - - ret = NXT_OK; - - ptr = strrchr(dir, '/'); - if (nxt_fast_path(ptr != NULL)) { - *ptr = '\0'; - ret = nxt_fs_mkdir((const u_char *) dir, mode); - } - - nxt_free(dir); - - return ret; -} - - -static nxt_int_t -nxt_fs_mkdir(const u_char *dir, mode_t mode) -{ - if (nxt_fast_path(mkdir((const char *) dir, mode) == 0)) { - return NXT_OK; - } - - return NXT_ERROR; -} diff --git a/src/nxt_fs.h b/src/nxt_fs.h deleted file mode 100644 index c8868d80..00000000 --- a/src/nxt_fs.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_FS_H_INCLUDED_ -#define _NXT_FS_H_INCLUDED_ - - -nxt_int_t nxt_fs_mkdir_parent(const u_char *path, mode_t mode); -nxt_int_t nxt_fs_mkdir_all(const u_char *dir, mode_t mode); - - -#endif /* _NXT_FS_H_INCLUDED_ */ diff --git a/src/nxt_fs_mount.c b/src/nxt_fs_mount.c deleted file mode 100644 index d9b384e4..00000000 --- a/src/nxt_fs_mount.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) NGINX, Inc. - */ - -#include - -#if (NXT_HAVE_FREEBSD_NMOUNT) -#include -#include -#endif - - -#if (NXT_HAVE_LINUX_MOUNT) - -nxt_int_t -nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt) -{ - int rc; - const char *fsname; - unsigned long flags; - - flags = 0; - - switch (mnt->type) { - case NXT_FS_BIND: - if (nxt_slow_path(mnt->flags != 0)) { - nxt_log(task, NXT_LOG_WARN, - "bind mount ignores additional flags"); - } - - fsname = "bind"; - flags = MS_BIND | MS_REC; - break; - - case NXT_FS_PROC: - fsname = "proc"; - goto getflags; - - case NXT_FS_TMP: - fsname = "tmpfs"; - goto getflags; - - default: - fsname = (const char *) mnt->name; - - getflags: - - if (mnt->flags & NXT_FS_FLAGS_NODEV) { - flags |= MS_NODEV; - } - - if (mnt->flags & NXT_FS_FLAGS_NOEXEC) { - flags |= MS_NOEXEC; - } - - if (mnt->flags & NXT_FS_FLAGS_NOSUID) { - flags |= MS_NOSUID; - } - - if (!(mnt->flags & NXT_FS_FLAGS_NOTIME)) { - flags |= MS_RELATIME; - } - } - - rc = mount((const char *) mnt->src, (const char *) mnt->dst, fsname, flags, - mnt->data); - - if (nxt_slow_path(rc < 0)) { - nxt_alert(task, "mount(\"%s\", \"%s\", \"%s\", %ul, \"%s\") %E", - mnt->src, mnt->dst, fsname, flags, mnt->data, nxt_errno); - - return NXT_ERROR; - } - - return NXT_OK; -} - -#elif (NXT_HAVE_FREEBSD_NMOUNT) - -nxt_int_t -nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt) -{ - int flags; - u_char *data, *p, *end; - size_t iovlen; - nxt_int_t ret; - const char *fsname; - struct iovec iov[128]; - char errmsg[256]; - - if (nxt_slow_path((mnt->flags & NXT_FS_FLAGS_NODEV) && !mnt->builtin)) { - nxt_alert(task, "nmount(2) doesn't support \"nodev\" option"); - - return NXT_ERROR; - } - - flags = 0; - - switch (mnt->type) { - case NXT_FS_BIND: - fsname = "nullfs"; - break; - - case NXT_FS_PROC: - fsname = "procfs"; - goto getflags; - - case NXT_FS_TMP: - fsname = "tmpfs"; - goto getflags; - - default: - fsname = (const char *) mnt->name; - - getflags: - - if (mnt->flags & NXT_FS_FLAGS_NOEXEC) { - flags |= MNT_NOEXEC; - } - - if (mnt->flags & NXT_FS_FLAGS_NOSUID) { - flags |= MNT_NOSUID; - } - - if (mnt->flags & NXT_FS_FLAGS_NOTIME) { - flags |= MNT_NOATIME; - } - - if (mnt->flags & NXT_FS_FLAGS_RDONLY) { - flags |= MNT_RDONLY; - } - } - - iov[0].iov_base = (void *) "fstype"; - iov[0].iov_len = 7; - iov[1].iov_base = (void *) fsname; - iov[1].iov_len = nxt_strlen(fsname) + 1; - iov[2].iov_base = (void *) "fspath"; - iov[2].iov_len = 7; - iov[3].iov_base = (void *) mnt->dst; - iov[3].iov_len = nxt_strlen(mnt->dst) + 1; - iov[4].iov_base = (void *) "target"; - iov[4].iov_len = 7; - iov[5].iov_base = (void *) mnt->src; - iov[5].iov_len = nxt_strlen(mnt->src) + 1; - iov[6].iov_base = (void *) "errmsg"; - iov[6].iov_len = 7; - iov[7].iov_base = (void *) errmsg; - iov[7].iov_len = sizeof(errmsg); - - iovlen = 8; - - data = NULL; - - if (mnt->data != NULL) { - data = (u_char *) nxt_strdup(mnt->data); - if (nxt_slow_path(data == NULL)) { - return NXT_ERROR; - } - - end = data - 1; - - do { - p = end + 1; - end = nxt_strchr(p, '='); - if (end == NULL) { - break; - } - - *end = '\0'; - - iov[iovlen].iov_base = (void *) p; - iov[iovlen].iov_len = (end - p) + 1; - - iovlen++; - - p = end + 1; - - end = nxt_strchr(p, ','); - if (end != NULL) { - *end = '\0'; - } - - iov[iovlen].iov_base = (void *) p; - iov[iovlen].iov_len = nxt_strlen(p) + 1; - - iovlen++; - - } while (end != NULL && nxt_nitems(iov) > (iovlen + 2)); - } - - ret = NXT_OK; - - if (nxt_slow_path(nmount(iov, iovlen, flags) < 0)) { - nxt_alert(task, "nmount(%p, %d, 0) %s", iov, iovlen, errmsg); - ret = NXT_ERROR; - } - - if (data != NULL) { - free(data); - } - - return ret; -} - -#endif - - -#if (NXT_HAVE_LINUX_UMOUNT2) - -void -nxt_fs_unmount(const u_char *path) -{ - if (nxt_slow_path(umount2((const char *) path, MNT_DETACH) < 0)) { - nxt_thread_log_error(NXT_LOG_WARN, "umount2(%s, MNT_DETACH) %E", - path, nxt_errno); - } -} - -#elif (NXT_HAVE_UNMOUNT) - -void -nxt_fs_unmount(const u_char *path) -{ - if (nxt_slow_path(unmount((const char *) path, MNT_FORCE) < 0)) { - nxt_thread_log_error(NXT_LOG_WARN, "unmount(%s) %E", path, nxt_errno); - } -} - -#endif diff --git a/src/nxt_fs_mount.h b/src/nxt_fs_mount.h deleted file mode 100644 index e0fe6eb2..00000000 --- a/src/nxt_fs_mount.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_FS_MOUNT_H_INCLUDED_ -#define _NXT_FS_MOUNT_H_INCLUDED_ - - -typedef enum nxt_fs_type_s nxt_fs_type_t; -typedef enum nxt_fs_flags_s nxt_fs_flags_t; -typedef struct nxt_fs_mount_s nxt_fs_mount_t; - - -enum nxt_fs_type_s { - NXT_FS_UNKNOWN = 0, - NXT_FS_BIND, - NXT_FS_TMP, - NXT_FS_PROC, - NXT_FS_LAST, -}; - - -enum nxt_fs_flags_s { - NXT_FS_FLAGS_NOSUID = 1 << 0, - NXT_FS_FLAGS_NOEXEC = 1 << 1, - NXT_FS_FLAGS_NOTIME = 1 << 2, - NXT_FS_FLAGS_NODEV = 1 << 3, - NXT_FS_FLAGS_RDONLY = 1 << 4, -}; - - -struct nxt_fs_mount_s { - u_char *src; - u_char *dst; - nxt_fs_type_t type; - u_char *name; - nxt_fs_flags_t flags; - u_char *data; - nxt_uint_t builtin; /* 1-bit */ - nxt_uint_t deps; /* 1-bit */ -}; - - -nxt_int_t nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt); -void nxt_fs_unmount(const u_char *path); - - -#endif /* _NXT_FS_MOUNT_H_INCLUDED_ */ diff --git a/src/nxt_gmtime.c b/src/nxt_gmtime.c deleted file mode 100644 index 9c3fa190..00000000 --- a/src/nxt_gmtime.c +++ /dev/null @@ -1,79 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* The function is valid for positive nxt_time_t only. */ - -void -nxt_gmtime(nxt_time_t s, struct tm *tm) -{ - nxt_int_t yday; - nxt_uint_t daytime, mday, mon, year, days, leap; - - days = (nxt_uint_t) (s / 86400); - daytime = (nxt_uint_t) (s % 86400); - - /* January 1, 1970 was Thursday. */ - tm->tm_wday = (4 + days) % 7; - - /* The algorithm based on Gauss' formula. */ - - /* Days since March 1, 1 BCE. */ - days = days - (31 + 28) + 719527; - - /* - * The "days" should be adjusted by 1 only, however some March 1st's - * go to previous year, so "days" are adjusted by 2. This also shifts - * the last February days to the next year, but this is catched by - * negative "yday". - */ - year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1); - - yday = days - (365 * year + year / 4 - year / 100 + year / 400); - - leap = (year % 4 == 0) && (year % 100 || (year % 400 == 0)); - - if (yday < 0) { - yday = 365 + leap + yday; - year--; - } - - /* - * An empirical formula that maps "yday" to month. - * There are at least 10 variants, some of them are: - * mon = (yday + 31) * 15 / 459 - * mon = (yday + 31) * 17 / 520 - * mon = (yday + 31) * 20 / 612 - */ - - mon = (yday + 31) * 10 / 306; - - /* The Gauss' formula that evaluates days before month. */ - - mday = yday - (367 * mon / 12 - 30) + 1; - - if (yday >= 306) { - year++; - mon -= 11; - yday -= 306; - - } else { - mon++; - yday += 31 + 28 + leap; - } - - tm->tm_mday = mday; - tm->tm_mon = mon; - tm->tm_year = year - 1900; - tm->tm_yday = yday; - - tm->tm_hour = daytime / 3600; - daytime %= 3600; - tm->tm_min = daytime / 60; - tm->tm_sec = daytime % 60; -} diff --git a/src/nxt_gnutls.c b/src/nxt_gnutls.c deleted file mode 100644 index aab4699c..00000000 --- a/src/nxt_gnutls.c +++ /dev/null @@ -1,742 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -typedef struct { - gnutls_session_t session; - - uint8_t times; /* 2 bits */ - uint8_t no_shutdown; /* 1 bit */ - - nxt_buf_mem_t buffer; -} nxt_gnutls_conn_t; - - -typedef struct { - gnutls_priority_t ciphers; - gnutls_certificate_credentials_t certificate; -} nxt_gnutls_ctx_t; - - - -#if (NXT_HAVE_GNUTLS_SET_TIME) -time_t nxt_gnutls_time(time_t *tp); -#endif -static nxt_int_t nxt_gnutls_server_init(nxt_ssltls_conf_t *conf); -static nxt_int_t nxt_gnutls_set_ciphers(nxt_ssltls_conf_t *conf); - -static void nxt_gnutls_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf, - nxt_event_conn_t *c); -static void nxt_gnutls_session_cleanup(void *data); -static ssize_t nxt_gnutls_pull(gnutls_transport_ptr_t data, void *buf, - size_t size); -static ssize_t nxt_gnutls_push(gnutls_transport_ptr_t data, const void *buf, - size_t size); -#if (NXT_HAVE_GNUTLS_VEC_PUSH) -static ssize_t nxt_gnutls_vec_push(gnutls_transport_ptr_t data, - const giovec_t *iov, int iovcnt); -#endif -static void nxt_gnutls_conn_handshake(nxt_thread_t *thr, void *obj, void *data); -static void nxt_gnutls_conn_io_read(nxt_thread_t *thr, void *obj, void *data); -static ssize_t nxt_gnutls_conn_io_write_chunk(nxt_thread_t *thr, - nxt_event_conn_t *c, nxt_buf_t *b, size_t limit); -static ssize_t nxt_gnutls_conn_io_send(nxt_event_conn_t *c, void *buf, - size_t size); -static void nxt_gnutls_conn_io_shutdown(nxt_thread_t *thr, void *obj, - void *data); -static nxt_int_t nxt_gnutls_conn_test_error(nxt_thread_t *thr, - nxt_event_conn_t *c, ssize_t err, nxt_work_handler_t handler); -static void nxt_cdecl nxt_gnutls_conn_log_error(nxt_event_conn_t *c, - ssize_t err, const char *fmt, ...); -static nxt_uint_t nxt_gnutls_log_error_level(nxt_event_conn_t *c, ssize_t err); -static void nxt_cdecl nxt_gnutls_log_error(nxt_uint_t level, nxt_log_t *log, - int err, const char *fmt, ...); - - -const nxt_ssltls_lib_t nxt_gnutls_lib = { - nxt_gnutls_server_init, - NULL, -}; - - -static nxt_event_conn_io_t nxt_gnutls_event_conn_io = { - NULL, - NULL, - - nxt_gnutls_conn_io_read, - NULL, - NULL, - - nxt_event_conn_io_write, - nxt_gnutls_conn_io_write_chunk, - NULL, - NULL, - nxt_gnutls_conn_io_send, - - nxt_gnutls_conn_io_shutdown, -}; - - -static nxt_int_t -nxt_gnutls_start(void) -{ - int ret; - static nxt_bool_t started; - - if (nxt_fast_path(started)) { - return NXT_OK; - } - - started = 1; - - /* TODO: gnutls_global_deinit */ - - ret = gnutls_global_init(); - if (ret != GNUTLS_E_SUCCESS) { - nxt_gnutls_log_error(NXT_LOG_ALERT, nxt_thread_log(), ret, - "gnutls_global_init() failed"); - return NXT_ERROR; - } - - nxt_thread_log_error(NXT_LOG_INFO, "GnuTLS version: %s", - gnutls_check_version(NULL)); - -#if (NXT_HAVE_GNUTLS_SET_TIME) - gnutls_global_set_time_function(nxt_gnutls_time); -#endif - - return NXT_OK; -} - - -#if (NXT_HAVE_GNUTLS_SET_TIME) - -/* GnuTLS 2.12.0 */ - -time_t -nxt_gnutls_time(time_t *tp) -{ - time_t t; - nxt_thread_t *thr; - - thr = nxt_thread(); - nxt_log_debug(thr->log, "gnutls time"); - - t = (time_t) nxt_thread_time(thr); - - if (tp != NULL) { - *tp = t; - } - - return t; -} - -#endif - - -static nxt_int_t -nxt_gnutls_server_init(nxt_ssltls_conf_t *conf) -{ - int ret; - char *certificate, *key, *ca_certificate; - nxt_thread_t *thr; - nxt_gnutls_ctx_t *ctx; - - if (nxt_slow_path(nxt_gnutls_start() != NXT_OK)) { - return NXT_ERROR; - } - - /* TODO: mem_pool, cleanup: gnutls_certificate_free_credentials, - gnutls_priority_deinit */ - - ctx = nxt_zalloc(sizeof(nxt_gnutls_ctx_t)); - if (ctx == NULL) { - return NXT_ERROR; - } - - conf->ctx = ctx; - conf->conn_init = nxt_gnutls_conn_init; - - thr = nxt_thread(); - - ret = gnutls_certificate_allocate_credentials(&ctx->certificate); - if (ret != GNUTLS_E_SUCCESS) { - nxt_gnutls_log_error(NXT_LOG_ALERT, thr->log, ret, - "gnutls_certificate_allocate_credentials() failed"); - return NXT_ERROR; - } - - certificate = conf->certificate; - key = conf->certificate_key; - - ret = gnutls_certificate_set_x509_key_file(ctx->certificate, certificate, - key, GNUTLS_X509_FMT_PEM); - if (ret != GNUTLS_E_SUCCESS) { - nxt_gnutls_log_error(NXT_LOG_ALERT, thr->log, ret, - "gnutls_certificate_set_x509_key_file(\"%s\", \"%s\") failed", - certificate, key); - goto certificate_fail; - } - - if (nxt_gnutls_set_ciphers(conf) != NXT_OK) { - goto ciphers_fail; - } - - if (conf->ca_certificate != NULL) { - ca_certificate = conf->ca_certificate; - - ret = gnutls_certificate_set_x509_trust_file(ctx->certificate, - ca_certificate, - GNUTLS_X509_FMT_PEM); - if (ret < 0) { - nxt_gnutls_log_error(NXT_LOG_ALERT, thr->log, ret, - "gnutls_certificate_set_x509_trust_file(\"%s\") failed", - ca_certificate); - goto ca_certificate_fail; - } - } - - return NXT_OK; - -ca_certificate_fail: - - gnutls_priority_deinit(ctx->ciphers); - -ciphers_fail: - -certificate_fail: - - gnutls_certificate_free_credentials(ctx->certificate); - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_gnutls_set_ciphers(nxt_ssltls_conf_t *conf) -{ - int ret; - const char *ciphers; - const char *err; - nxt_gnutls_ctx_t *ctx; - - ciphers = (conf->ciphers != NULL) ? conf->ciphers : "NORMAL:!COMP-DEFLATE"; - ctx = conf->ctx; - - ret = gnutls_priority_init(&ctx->ciphers, ciphers, &err); - - switch (ret) { - - case GNUTLS_E_SUCCESS: - return NXT_OK; - - case GNUTLS_E_INVALID_REQUEST: - nxt_gnutls_log_error(NXT_LOG_ALERT, nxt_thread_log(), ret, - "gnutls_priority_init(\"%s\") failed at \"%s\"", - ciphers, err); - return NXT_ERROR; - - default: - nxt_gnutls_log_error(NXT_LOG_ALERT, nxt_thread_log(), ret, - "gnutls_priority_init() failed"); - return NXT_ERROR; - } -} - - -static void -nxt_gnutls_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf, - nxt_event_conn_t *c) -{ - int ret; - gnutls_session_t sess; - nxt_gnutls_ctx_t *ctx; - nxt_gnutls_conn_t *ssltls; - nxt_mem_pool_cleanup_t *mpcl; - - nxt_log_debug(c->socket.log, "gnutls conn init"); - - ssltls = nxt_mp_zget(c->mem_pool, sizeof(nxt_gnutls_conn_t)); - if (ssltls == NULL) { - goto fail; - } - - c->u.ssltls = ssltls; - nxt_buf_mem_set_size(&ssltls->buffer, conf->buffer_size); - - mpcl = nxt_mem_pool_cleanup(c->mem_pool, 0); - if (mpcl == NULL) { - goto fail; - } - - ret = gnutls_init(&ssltls->session, GNUTLS_SERVER); - if (ret != GNUTLS_E_SUCCESS) { - nxt_gnutls_log_error(NXT_LOG_ALERT, c->socket.log, ret, - "gnutls_init() failed"); - goto fail; - } - - sess = ssltls->session; - mpcl->handler = nxt_gnutls_session_cleanup; - mpcl->data = ssltls; - - ctx = conf->ctx; - - ret = gnutls_priority_set(sess, ctx->ciphers); - if (ret != GNUTLS_E_SUCCESS) { - nxt_gnutls_log_error(NXT_LOG_ALERT, c->socket.log, ret, - "gnutls_priority_set() failed"); - goto fail; - } - - /* - * Disable TLS random padding of records in CBC ciphers, - * which may be up to 255 bytes. - */ - gnutls_record_disable_padding(sess); - - ret = gnutls_credentials_set(sess, GNUTLS_CRD_CERTIFICATE, - ctx->certificate); - if (ret != GNUTLS_E_SUCCESS) { - nxt_gnutls_log_error(NXT_LOG_ALERT, c->socket.log, ret, - "gnutls_credentials_set() failed"); - goto fail; - } - - if (conf->ca_certificate != NULL) { - gnutls_certificate_server_set_request(sess, GNUTLS_CERT_REQUEST); - } - - gnutls_transport_set_ptr(sess, (gnutls_transport_ptr_t) c); - gnutls_transport_set_pull_function(sess, nxt_gnutls_pull); - gnutls_transport_set_push_function(sess, nxt_gnutls_push); -#if (NXT_HAVE_GNUTLS_VEC_PUSH) - gnutls_transport_set_vec_push_function(sess, nxt_gnutls_vec_push); -#endif - - c->io = &nxt_gnutls_event_conn_io; - c->sendfile = NXT_CONN_SENDFILE_OFF; - - nxt_gnutls_conn_handshake(thr, c, c->socket.data); - return; - -fail: - - nxt_event_conn_io_handle(thr, c->read_work_queue, - c->read_state->error_handler, c, c->socket.data); -} - - -static void -nxt_gnutls_session_cleanup(void *data) -{ - nxt_gnutls_conn_t *ssltls; - - ssltls = data; - - nxt_thread_log_debug("gnutls session cleanup"); - - nxt_free(ssltls->buffer.start); - - gnutls_deinit(ssltls->session); -} - - -static ssize_t -nxt_gnutls_pull(gnutls_transport_ptr_t data, void *buf, size_t size) -{ - ssize_t n; - nxt_thread_t *thr; - nxt_event_conn_t *c; - - c = data; - thr = nxt_thread(); - - n = thr->engine->event->io->recv(c, buf, size, 0); - - if (n == NXT_AGAIN) { - nxt_set_errno(NXT_EAGAIN); - return -1; - } - - return n; -} - - -static ssize_t -nxt_gnutls_push(gnutls_transport_ptr_t data, const void *buf, size_t size) -{ - ssize_t n; - nxt_thread_t *thr; - nxt_event_conn_t *c; - - c = data; - thr = nxt_thread(); - - n = thr->engine->event->io->send(c, (u_char *) buf, size); - - if (n == NXT_AGAIN) { - nxt_set_errno(NXT_EAGAIN); - return -1; - } - - return n; -} - - -#if (NXT_HAVE_GNUTLS_VEC_PUSH) - -/* GnuTLS 2.12.0 */ - -static ssize_t -nxt_gnutls_vec_push(gnutls_transport_ptr_t data, const giovec_t *iov, - int iovcnt) -{ - ssize_t n; - nxt_thread_t *thr; - nxt_event_conn_t *c; - - c = data; - thr = nxt_thread(); - - /* - * This code assumes that giovec_t is the same as "struct iovec" - * and nxt_iobuf_t. It is not true for Windows. - */ - n = thr->engine->event->io->writev(c, (nxt_iobuf_t *) iov, iovcnt); - - if (n == NXT_AGAIN) { - nxt_set_errno(NXT_EAGAIN); - return -1; - } - - return n; -} - -#endif - - -static void -nxt_gnutls_conn_handshake(nxt_thread_t *thr, void *obj, void *data) -{ - int err; - nxt_int_t ret; - nxt_event_conn_t *c; - nxt_gnutls_conn_t *ssltls; - - c = obj; - ssltls = c->u.ssltls; - - nxt_log_debug(thr->log, "gnutls conn handshake: %d", ssltls->times); - - /* "ssltls->times == 1" is suitable to run gnutls_handshake() in job. */ - - err = gnutls_handshake(ssltls->session); - - nxt_thread_time_debug_update(thr); - - nxt_log_debug(thr->log, "gnutls_handshake(): %d", err); - - if (err == GNUTLS_E_SUCCESS) { - nxt_gnutls_conn_io_read(thr, c, data); - return; - } - - ret = nxt_gnutls_conn_test_error(thr, c, err, nxt_gnutls_conn_handshake); - - if (ret == NXT_ERROR) { - nxt_gnutls_conn_log_error(c, err, "gnutls_handshake() failed"); - - nxt_event_conn_io_handle(thr, c->read_work_queue, - c->read_state->error_handler, c, data); - - } else if (err == GNUTLS_E_AGAIN - && ssltls->times < 2 - && gnutls_record_get_direction(ssltls->session) == 0) - { - ssltls->times++; - } -} - - -static void -nxt_gnutls_conn_io_read(nxt_thread_t *thr, void *obj, void *data) -{ - ssize_t n; - nxt_buf_t *b; - nxt_int_t ret; - nxt_event_conn_t *c; - nxt_gnutls_conn_t *ssltls; - nxt_work_handler_t handler; - - c = obj; - - nxt_log_debug(thr->log, "gnutls conn read"); - - handler = c->read_state->ready_handler; - b = c->read; - - /* b == NULL is used to test descriptor readiness. */ - - if (b != NULL) { - ssltls = c->u.ssltls; - - n = gnutls_record_recv(ssltls->session, b->mem.free, - b->mem.end - b->mem.free); - - nxt_log_debug(thr->log, "gnutls_record_recv(%d, %p, %uz): %z", - c->socket.fd, b->mem.free, b->mem.end - b->mem.free, n); - - if (n > 0) { - /* c->socket.read_ready is kept. */ - b->mem.free += n; - handler = c->read_state->ready_handler; - - } else if (n == 0) { - handler = c->read_state->close_handler; - - } else { - ret = nxt_gnutls_conn_test_error(thr, c, n, - nxt_gnutls_conn_io_read); - - if (nxt_fast_path(ret != NXT_ERROR)) { - return; - } - - nxt_gnutls_conn_log_error(c, n, - "gnutls_record_recv(%d, %p, %uz): failed", - c->socket.fd, b->mem.free, - b->mem.end - b->mem.free); - - handler = c->read_state->error_handler; - } - } - - nxt_event_conn_io_handle(thr, c->read_work_queue, handler, c, data); -} - - -static ssize_t -nxt_gnutls_conn_io_write_chunk(nxt_thread_t *thr, nxt_event_conn_t *c, - nxt_buf_t *b, size_t limit) -{ - nxt_gnutls_conn_t *ssltls; - - nxt_log_debug(thr->log, "gnutls conn write chunk"); - - ssltls = c->u.ssltls; - - return nxt_sendbuf_copy_coalesce(c, &ssltls->buffer, b, limit); -} - - -static ssize_t -nxt_gnutls_conn_io_send(nxt_event_conn_t *c, void *buf, size_t size) -{ - ssize_t n; - nxt_int_t ret; - nxt_gnutls_conn_t *ssltls; - - ssltls = c->u.ssltls; - - n = gnutls_record_send(ssltls->session, buf, size); - - nxt_log_debug(c->socket.log, "gnutls_record_send(%d, %p, %uz): %z", - c->socket.fd, buf, size, n); - - if (n > 0) { - return n; - } - - ret = nxt_gnutls_conn_test_error(nxt_thread(), c, n, - nxt_event_conn_io_write); - - if (nxt_slow_path(ret == NXT_ERROR)) { - nxt_gnutls_conn_log_error(c, n, - "gnutls_record_send(%d, %p, %uz): failed", - c->socket.fd, buf, size); - } - - return ret; -} - - -static void -nxt_gnutls_conn_io_shutdown(nxt_thread_t *thr, void *obj, void *data) -{ - int err; - nxt_int_t ret; - nxt_event_conn_t *c; - nxt_gnutls_conn_t *ssltls; - nxt_work_handler_t handler; - gnutls_close_request_t how; - - c = obj; - ssltls = c->u.ssltls; - - if (ssltls->session == NULL || ssltls->no_shutdown) { - handler = c->write_state->close_handler; - goto done; - } - - nxt_log_debug(c->socket.log, "gnutls conn shutdown"); - - if (c->socket.timedout || c->socket.error != 0) { - how = GNUTLS_SHUT_WR; - - } else if (c->socket.closed) { - how = GNUTLS_SHUT_RDWR; - - } else { - how = GNUTLS_SHUT_RDWR; - } - - err = gnutls_bye(ssltls->session, how); - - nxt_log_debug(c->socket.log, "gnutls_bye(%d, %d): %d", - c->socket.fd, how, err); - - if (err == GNUTLS_E_SUCCESS) { - handler = c->write_state->close_handler; - - } else { - ret = nxt_gnutls_conn_test_error(thr, c, err, - nxt_gnutls_conn_io_shutdown); - - if (ret != NXT_ERROR) { /* ret == NXT_AGAIN */ - c->socket.error_handler = c->read_state->error_handler; - nxt_event_timer_add(thr->engine, &c->read_timer, 5000); - return; - } - - nxt_gnutls_conn_log_error(c, err, "gnutls_bye(%d) failed", - c->socket.fd); - - handler = c->write_state->error_handler; - } - -done: - - nxt_event_conn_io_handle(thr, c->write_work_queue, handler, c, data); -} - - -static nxt_int_t -nxt_gnutls_conn_test_error(nxt_thread_t *thr, nxt_event_conn_t *c, ssize_t err, - nxt_work_handler_t handler) -{ - int ret; - nxt_gnutls_conn_t *ssltls; - - switch (err) { - - case GNUTLS_E_REHANDSHAKE: - case GNUTLS_E_AGAIN: - ssltls = c->u.ssltls; - ret = gnutls_record_get_direction(ssltls->session); - - nxt_log_debug(thr->log, "gnutls_record_get_direction(): %d", ret); - - if (ret == 0) { - /* A read direction. */ - - nxt_event_fd_block_write(thr->engine, &c->socket); - - c->socket.read_ready = 0; - c->socket.read_handler = handler; - - if (nxt_event_fd_is_disabled(c->socket.read)) { - nxt_event_fd_enable_read(thr->engine, &c->socket); - } - - } else { - /* A write direction. */ - - nxt_event_fd_block_read(thr->engine, &c->socket); - - c->socket.write_ready = 0; - c->socket.write_handler = handler; - - if (nxt_event_fd_is_disabled(c->socket.write)) { - nxt_event_fd_enable_write(thr->engine, &c->socket); - } - } - - return NXT_AGAIN; - - default: - c->socket.error = 1000; /* Nonexistent errno code. */ - return NXT_ERROR; - } -} - - -static void -nxt_gnutls_conn_log_error(nxt_event_conn_t *c, ssize_t err, - const char *fmt, ...) -{ - va_list args; - nxt_uint_t level; - u_char *p, msg[NXT_MAX_ERROR_STR]; - - level = nxt_gnutls_log_error_level(c, err); - - if (nxt_log_level_enough(c->socket.log, level)) { - - va_start(args, fmt); - p = nxt_vsprintf(msg, msg + sizeof(msg), fmt, args); - va_end(args); - - nxt_log_error(level, c->socket.log, "%*s (%d: %s)", - p - msg, msg, err, gnutls_strerror(err)); - } -} - - -static nxt_uint_t -nxt_gnutls_log_error_level(nxt_event_conn_t *c, ssize_t err) -{ - nxt_gnutls_conn_t *ssltls; - - switch (err) { - - case GNUTLS_E_UNKNOWN_CIPHER_SUITE: /* -21 */ - - /* Disable gnutls_bye(), because it returns GNUTLS_E_INTERNAL_ERROR. */ - ssltls = c->u.ssltls; - ssltls->no_shutdown = 1; - - /* Fall through. */ - - case GNUTLS_E_UNEXPECTED_PACKET_LENGTH: /* -9 */ - c->socket.error = 1000; /* Nonexistent errno code. */ - break; - - default: - return NXT_LOG_ALERT; - } - - return NXT_LOG_INFO; -} - - -static void -nxt_gnutls_log_error(nxt_uint_t level, nxt_log_t *log, int err, - const char *fmt, ...) -{ - va_list args; - u_char *p, msg[NXT_MAX_ERROR_STR]; - - va_start(args, fmt); - p = nxt_vsprintf(msg, msg + sizeof(msg), fmt, args); - va_end(args); - - nxt_log_error(level, log, "%*s (%d: %s)", - p - msg, msg, err, gnutls_strerror(err)); -} diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c deleted file mode 100644 index 1dfe4b6e..00000000 --- a/src/nxt_h1proto.c +++ /dev/null @@ -1,2887 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include -#include - - -/* - * nxt_http_conn_ and nxt_h1p_conn_ prefixes are used for connection handlers. - * nxt_h1p_idle_ prefix is used for idle connection handlers. - * nxt_h1p_request_ prefix is used for HTTP/1 protocol request methods. - */ - -#if (NXT_TLS) -static ssize_t nxt_http_idle_io_read_handler(nxt_task_t *task, nxt_conn_t *c); -static void nxt_http_conn_test(nxt_task_t *task, void *obj, void *data); -#endif -static ssize_t nxt_h1p_idle_io_read_handler(nxt_task_t *task, nxt_conn_t *c); -static void nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_request_header_parse(nxt_task_t *task, void *obj, - void *data); -static nxt_int_t nxt_h1p_header_process(nxt_task_t *task, nxt_h1proto_t *h1p, - nxt_http_request_t *r); -static nxt_int_t nxt_h1p_header_buffer_test(nxt_task_t *task, - nxt_h1proto_t *h1p, nxt_conn_t *c, nxt_socket_conf_t *skcf); -static nxt_int_t nxt_h1p_connection(void *ctx, nxt_http_field_t *field, - uintptr_t data); -static nxt_int_t nxt_h1p_upgrade(void *ctx, nxt_http_field_t *field, - uintptr_t data); -static nxt_int_t nxt_h1p_websocket_key(void *ctx, nxt_http_field_t *field, - uintptr_t data); -static nxt_int_t nxt_h1p_websocket_version(void *ctx, nxt_http_field_t *field, - uintptr_t data); -static nxt_int_t nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, - uintptr_t data); -static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r); -static void nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj, - void *data); -static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r); -static void nxt_h1p_request_header_send(nxt_task_t *task, - nxt_http_request_t *r, nxt_work_handler_t body_handler, void *data); -static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *out); -static nxt_buf_t *nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *out); -static nxt_off_t nxt_h1p_request_body_bytes_sent(nxt_task_t *task, - nxt_http_proto_t proto); -static void nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *last); -static void nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, - void *data); -static void nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, - void *data); -nxt_inline void nxt_h1p_request_error(nxt_task_t *task, nxt_h1proto_t *h1p, - nxt_http_request_t *r); -static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto, - nxt_socket_conf_joint_t *joint); -static void nxt_h1p_conn_sent(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data); -static nxt_msec_t nxt_h1p_conn_timer_value(nxt_conn_t *c, uintptr_t data); -static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, - nxt_conn_t *c); -static void nxt_h1p_idle_close(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_idle_timeout(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_idle_response(nxt_task_t *task, nxt_conn_t *c); -static void nxt_h1p_idle_response_sent(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_idle_response_error(nxt_task_t *task, void *obj, - void *data); -static void nxt_h1p_idle_response_timeout(nxt_task_t *task, void *obj, - void *data); -static nxt_msec_t nxt_h1p_idle_response_timer_value(nxt_conn_t *c, - uintptr_t data); -static void nxt_h1p_shutdown(nxt_task_t *task, nxt_conn_t *c); -static void nxt_h1p_closing(nxt_task_t *task, nxt_conn_t *c); -static void nxt_h1p_conn_ws_shutdown(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_closing(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data); - -static void nxt_h1p_peer_connect(nxt_task_t *task, nxt_http_peer_t *peer); -static void nxt_h1p_peer_connected(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_peer_refused(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_peer_header_send(nxt_task_t *task, nxt_http_peer_t *peer); -static void nxt_h1p_peer_header_sent(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_peer_header_read(nxt_task_t *task, nxt_http_peer_t *peer); -static ssize_t nxt_h1p_peer_io_read_handler(nxt_task_t *task, nxt_conn_t *c); -static void nxt_h1p_peer_header_read_done(nxt_task_t *task, void *obj, - void *data); -static nxt_int_t nxt_h1p_peer_header_parse(nxt_http_peer_t *peer, - nxt_buf_mem_t *bm); -static void nxt_h1p_peer_read(nxt_task_t *task, nxt_http_peer_t *peer); -static void nxt_h1p_peer_read_done(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_peer_body_process(nxt_task_t *task, nxt_http_peer_t *peer, nxt_buf_t *out); -static void nxt_h1p_peer_closed(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_peer_error(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_peer_send_timeout(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_peer_read_timeout(nxt_task_t *task, void *obj, void *data); -static nxt_msec_t nxt_h1p_peer_timer_value(nxt_conn_t *c, uintptr_t data); -static void nxt_h1p_peer_close(nxt_task_t *task, nxt_http_peer_t *peer); -static void nxt_h1p_peer_free(nxt_task_t *task, void *obj, void *data); -static nxt_int_t nxt_h1p_peer_transfer_encoding(void *ctx, - nxt_http_field_t *field, uintptr_t data); - -#if (NXT_TLS) -static const nxt_conn_state_t nxt_http_idle_state; -static const nxt_conn_state_t nxt_h1p_shutdown_state; -#endif -static const nxt_conn_state_t nxt_h1p_idle_state; -static const nxt_conn_state_t nxt_h1p_header_parse_state; -static const nxt_conn_state_t nxt_h1p_read_body_state; -static const nxt_conn_state_t nxt_h1p_request_send_state; -static const nxt_conn_state_t nxt_h1p_timeout_response_state; -static const nxt_conn_state_t nxt_h1p_keepalive_state; -static const nxt_conn_state_t nxt_h1p_close_state; -static const nxt_conn_state_t nxt_h1p_peer_connect_state; -static const nxt_conn_state_t nxt_h1p_peer_header_send_state; -static const nxt_conn_state_t nxt_h1p_peer_header_body_send_state; -static const nxt_conn_state_t nxt_h1p_peer_header_read_state; -static const nxt_conn_state_t nxt_h1p_peer_header_read_timer_state; -static const nxt_conn_state_t nxt_h1p_peer_read_state; -static const nxt_conn_state_t nxt_h1p_peer_close_state; - - -const nxt_http_proto_table_t nxt_http_proto[3] = { - /* NXT_HTTP_PROTO_H1 */ - { - .body_read = nxt_h1p_request_body_read, - .local_addr = nxt_h1p_request_local_addr, - .header_send = nxt_h1p_request_header_send, - .send = nxt_h1p_request_send, - .body_bytes_sent = nxt_h1p_request_body_bytes_sent, - .discard = nxt_h1p_request_discard, - .close = nxt_h1p_request_close, - - .peer_connect = nxt_h1p_peer_connect, - .peer_header_send = nxt_h1p_peer_header_send, - .peer_header_read = nxt_h1p_peer_header_read, - .peer_read = nxt_h1p_peer_read, - .peer_close = nxt_h1p_peer_close, - - .ws_frame_start = nxt_h1p_websocket_frame_start, - }, - /* NXT_HTTP_PROTO_H2 */ - /* NXT_HTTP_PROTO_DEVNULL */ -}; - - -static nxt_lvlhsh_t nxt_h1p_fields_hash; - -static nxt_http_field_proc_t nxt_h1p_fields[] = { - { nxt_string("Connection"), &nxt_h1p_connection, 0 }, - { nxt_string("Upgrade"), &nxt_h1p_upgrade, 0 }, - { nxt_string("Sec-WebSocket-Key"), &nxt_h1p_websocket_key, 0 }, - { nxt_string("Sec-WebSocket-Version"), - &nxt_h1p_websocket_version, 0 }, - { nxt_string("Transfer-Encoding"), &nxt_h1p_transfer_encoding, 0 }, - - { nxt_string("Host"), &nxt_http_request_host, 0 }, - { nxt_string("Cookie"), &nxt_http_request_field, - offsetof(nxt_http_request_t, cookie) }, - { nxt_string("Referer"), &nxt_http_request_field, - offsetof(nxt_http_request_t, referer) }, - { nxt_string("User-Agent"), &nxt_http_request_field, - offsetof(nxt_http_request_t, user_agent) }, - { nxt_string("Content-Type"), &nxt_http_request_field, - offsetof(nxt_http_request_t, content_type) }, - { nxt_string("Content-Length"), &nxt_http_request_content_length, 0 }, - { nxt_string("Authorization"), &nxt_http_request_field, - offsetof(nxt_http_request_t, authorization) }, -}; - - -static nxt_lvlhsh_t nxt_h1p_peer_fields_hash; - -static nxt_http_field_proc_t nxt_h1p_peer_fields[] = { - { nxt_string("Connection"), &nxt_http_proxy_skip, 0 }, - { nxt_string("Transfer-Encoding"), &nxt_h1p_peer_transfer_encoding, 0 }, - { nxt_string("Server"), &nxt_http_proxy_skip, 0 }, - { nxt_string("Date"), &nxt_http_proxy_date, 0 }, - { nxt_string("Content-Length"), &nxt_http_proxy_content_length, 0 }, -}; - - -nxt_int_t -nxt_h1p_init(nxt_task_t *task) -{ - nxt_int_t ret; - - ret = nxt_http_fields_hash(&nxt_h1p_fields_hash, - nxt_h1p_fields, nxt_nitems(nxt_h1p_fields)); - - if (nxt_fast_path(ret == NXT_OK)) { - ret = nxt_http_fields_hash(&nxt_h1p_peer_fields_hash, - nxt_h1p_peer_fields, - nxt_nitems(nxt_h1p_peer_fields)); - } - - return ret; -} - - -void -nxt_http_conn_init(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_socket_conf_t *skcf; - nxt_event_engine_t *engine; - nxt_listen_event_t *lev; - nxt_socket_conf_joint_t *joint; - - c = obj; - lev = data; - - nxt_debug(task, "http conn init"); - - joint = lev->socket.data; - skcf = joint->socket_conf; - c->local = skcf->sockaddr; - - engine = task->thread->engine; - c->read_work_queue = &engine->fast_work_queue; - c->write_work_queue = &engine->fast_work_queue; - - c->read_state = &nxt_h1p_idle_state; - -#if (NXT_TLS) - if (skcf->tls != NULL) { - c->read_state = &nxt_http_idle_state; - } -#endif - - nxt_conn_read(engine, c); -} - - -#if (NXT_TLS) - -static const nxt_conn_state_t nxt_http_idle_state - nxt_aligned(64) = -{ - .ready_handler = nxt_http_conn_test, - .close_handler = nxt_h1p_conn_close, - .error_handler = nxt_h1p_conn_error, - - .io_read_handler = nxt_http_idle_io_read_handler, - - .timer_handler = nxt_h1p_idle_timeout, - .timer_value = nxt_h1p_conn_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), -}; - - -static ssize_t -nxt_http_idle_io_read_handler(nxt_task_t *task, nxt_conn_t *c) -{ - size_t size; - ssize_t n; - nxt_buf_t *b; - nxt_socket_conf_joint_t *joint; - - joint = c->listen->socket.data; - - if (nxt_slow_path(joint == NULL)) { - /* - * Listening socket had been closed while - * connection was in keep-alive state. - */ - c->read_state = &nxt_h1p_idle_close_state; - return 0; - } - - size = joint->socket_conf->header_buffer_size; - - b = nxt_event_engine_buf_mem_alloc(task->thread->engine, size); - if (nxt_slow_path(b == NULL)) { - c->socket.error = NXT_ENOMEM; - return NXT_ERROR; - } - - /* - * 1 byte is enough to distinguish between SSLv3/TLS and plain HTTP. - * 11 bytes are enough to log supported SSLv3/TLS version. - * 16 bytes are just for more optimized kernel copy-out operation. - */ - n = c->io->recv(c, b->mem.pos, 16, MSG_PEEK); - - if (n > 0) { - c->read = b; - - } else { - c->read = NULL; - nxt_event_engine_buf_mem_free(task->thread->engine, b); - } - - return n; -} - - -static void -nxt_http_conn_test(nxt_task_t *task, void *obj, void *data) -{ - u_char *p; - nxt_buf_t *b; - nxt_conn_t *c; - nxt_tls_conf_t *tls; - nxt_event_engine_t *engine; - nxt_socket_conf_joint_t *joint; - - c = obj; - - nxt_debug(task, "h1p conn https test"); - - engine = task->thread->engine; - b = c->read; - p = b->mem.pos; - - c->read_state = &nxt_h1p_idle_state; - - if (p[0] != 0x16) { - b->mem.free = b->mem.pos; - - nxt_conn_read(engine, c); - return; - } - - /* SSLv3/TLS ClientHello message. */ - -#if (NXT_DEBUG) - if (nxt_buf_mem_used_size(&b->mem) >= 11) { - u_char major, minor; - const char *protocol; - - major = p[9]; - minor = p[10]; - - if (major == 3) { - if (minor == 0) { - protocol = "SSLv"; - - } else { - protocol = "TLSv"; - major -= 2; - minor -= 1; - } - - nxt_debug(task, "SSL/TLS: %s%ud.%ud", protocol, major, minor); - } - } -#endif - - c->read = NULL; - nxt_event_engine_buf_mem_free(engine, b); - - joint = c->listen->socket.data; - - if (nxt_slow_path(joint == NULL)) { - /* - * Listening socket had been closed while - * connection was in keep-alive state. - */ - nxt_h1p_closing(task, c); - return; - } - - tls = joint->socket_conf->tls; - - tls->conn_init(task, tls, c); -} - -#endif - - -static const nxt_conn_state_t nxt_h1p_idle_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_conn_proto_init, - .close_handler = nxt_h1p_conn_close, - .error_handler = nxt_h1p_conn_error, - - .io_read_handler = nxt_h1p_idle_io_read_handler, - - .timer_handler = nxt_h1p_idle_timeout, - .timer_value = nxt_h1p_conn_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), - .timer_autoreset = 1, -}; - - -static ssize_t -nxt_h1p_idle_io_read_handler(nxt_task_t *task, nxt_conn_t *c) -{ - size_t size; - ssize_t n; - nxt_buf_t *b; - nxt_socket_conf_joint_t *joint; - - joint = c->listen->socket.data; - - if (nxt_slow_path(joint == NULL)) { - /* - * Listening socket had been closed while - * connection was in keep-alive state. - */ - c->read_state = &nxt_h1p_idle_close_state; - return 0; - } - - b = c->read; - - if (b == NULL) { - size = joint->socket_conf->header_buffer_size; - - b = nxt_event_engine_buf_mem_alloc(task->thread->engine, size); - if (nxt_slow_path(b == NULL)) { - c->socket.error = NXT_ENOMEM; - return NXT_ERROR; - } - } - - n = c->io->recvbuf(c, b); - - if (n > 0) { - c->read = b; - - } else { - c->read = NULL; - nxt_event_engine_buf_mem_free(task->thread->engine, b); - } - - return n; -} - - -static void -nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_h1proto_t *h1p; - - c = obj; - - nxt_debug(task, "h1p conn proto init"); - - h1p = nxt_mp_zget(c->mem_pool, sizeof(nxt_h1proto_t)); - if (nxt_slow_path(h1p == NULL)) { - nxt_h1p_closing(task, c); - return; - } - - c->socket.data = h1p; - h1p->conn = c; - - nxt_h1p_conn_request_init(task, c, h1p); -} - - -static void -nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data) -{ - nxt_int_t ret; - nxt_conn_t *c; - nxt_h1proto_t *h1p; - nxt_socket_conf_t *skcf; - nxt_http_request_t *r; - nxt_socket_conf_joint_t *joint; - - c = obj; - h1p = data; - - nxt_debug(task, "h1p conn request init"); - - nxt_conn_active(task->thread->engine, c); - - r = nxt_http_request_create(task); - - if (nxt_fast_path(r != NULL)) { - h1p->request = r; - r->proto.h1 = h1p; - - /* r->protocol = NXT_HTTP_PROTO_H1 is done by zeroing. */ - r->remote = c->remote; - -#if (NXT_TLS) - r->tls = (c->u.tls != NULL); -#endif - - r->task = c->task; - task = &r->task; - c->socket.task = task; - c->read_timer.task = task; - c->write_timer.task = task; - - ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool); - - if (nxt_fast_path(ret == NXT_OK)) { - joint = c->listen->socket.data; - joint->count++; - - r->conf = joint; - skcf = joint->socket_conf; - r->log_route = skcf->log_route; - - if (c->local == NULL) { - c->local = skcf->sockaddr; - } - - h1p->parser.discard_unsafe_fields = skcf->discard_unsafe_fields; - - nxt_h1p_conn_request_header_parse(task, c, h1p); - return; - } - - /* - * The request is very incomplete here, - * so "internal server error" useless here. - */ - nxt_mp_release(r->mem_pool); - } - - nxt_h1p_closing(task, c); -} - - -static const nxt_conn_state_t nxt_h1p_header_parse_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_conn_request_header_parse, - .close_handler = nxt_h1p_conn_request_error, - .error_handler = nxt_h1p_conn_request_error, - - .timer_handler = nxt_h1p_conn_request_timeout, - .timer_value = nxt_h1p_conn_request_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), -}; - - -static void -nxt_h1p_conn_request_header_parse(nxt_task_t *task, void *obj, void *data) -{ - nxt_int_t ret; - nxt_conn_t *c; - nxt_h1proto_t *h1p; - nxt_http_status_t status; - nxt_http_request_t *r; - - c = obj; - h1p = data; - - nxt_debug(task, "h1p conn header parse"); - - ret = nxt_http_parse_request(&h1p->parser, &c->read->mem); - - ret = nxt_expect(NXT_DONE, ret); - - if (ret != NXT_AGAIN) { - nxt_timer_disable(task->thread->engine, &c->read_timer); - } - - r = h1p->request; - - switch (ret) { - - case NXT_DONE: - /* - * By default the keepalive mode is disabled in HTTP/1.0 and - * enabled in HTTP/1.1. The mode can be overridden later by - * the "Connection" field processed in nxt_h1p_connection(). - */ - h1p->keepalive = (h1p->parser.version.s.minor != '0'); - - r->request_line.start = h1p->parser.method.start; - r->request_line.length = h1p->parser.request_line_end - - r->request_line.start; - - if (nxt_slow_path(r->log_route)) { - nxt_log(task, NXT_LOG_NOTICE, "http request line \"%V\"", - &r->request_line); - } - - ret = nxt_h1p_header_process(task, h1p, r); - - if (nxt_fast_path(ret == NXT_OK)) { - -#if (NXT_TLS) - if (c->u.tls == NULL && r->conf->socket_conf->tls != NULL) { - status = NXT_HTTP_TO_HTTPS; - goto error; - } -#endif - - r->state->ready_handler(task, r, NULL); - return; - } - - status = ret; - goto error; - - case NXT_AGAIN: - status = nxt_h1p_header_buffer_test(task, h1p, c, r->conf->socket_conf); - - if (nxt_fast_path(status == NXT_OK)) { - c->read_state = &nxt_h1p_header_parse_state; - - nxt_conn_read(task->thread->engine, c); - return; - } - - break; - - case NXT_HTTP_PARSE_INVALID: - status = NXT_HTTP_BAD_REQUEST; - break; - - case NXT_HTTP_PARSE_UNSUPPORTED_VERSION: - status = NXT_HTTP_VERSION_NOT_SUPPORTED; - break; - - case NXT_HTTP_PARSE_TOO_LARGE_FIELD: - status = NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE; - break; - - default: - case NXT_ERROR: - status = NXT_HTTP_INTERNAL_SERVER_ERROR; - break; - } - - (void) nxt_h1p_header_process(task, h1p, r); - -error: - - h1p->keepalive = 0; - - nxt_http_request_error(task, r, status); -} - - -static nxt_int_t -nxt_h1p_header_process(nxt_task_t *task, nxt_h1proto_t *h1p, - nxt_http_request_t *r) -{ - u_char *m; - nxt_int_t ret; - - r->target.start = h1p->parser.target_start; - r->target.length = h1p->parser.target_end - h1p->parser.target_start; - - if (h1p->parser.version.ui64 != 0) { - r->version.start = h1p->parser.version.str; - r->version.length = sizeof(h1p->parser.version.str); - } - - r->method = &h1p->parser.method; - r->path = &h1p->parser.path; - r->args = &h1p->parser.args; - - r->fields = h1p->parser.fields; - - ret = nxt_http_fields_process(r->fields, &nxt_h1p_fields_hash, r); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - if (h1p->connection_upgrade && h1p->upgrade_websocket) { - m = h1p->parser.method.start; - - if (nxt_slow_path(h1p->parser.method.length != 3 - || m[0] != 'G' - || m[1] != 'E' - || m[2] != 'T')) - { - nxt_log(task, NXT_LOG_INFO, "h1p upgrade: bad method"); - - return NXT_HTTP_BAD_REQUEST; - } - - if (nxt_slow_path(h1p->parser.version.s.minor != '1')) { - nxt_log(task, NXT_LOG_INFO, "h1p upgrade: bad protocol version"); - - return NXT_HTTP_BAD_REQUEST; - } - - if (nxt_slow_path(h1p->websocket_key == NULL)) { - nxt_log(task, NXT_LOG_INFO, - "h1p upgrade: bad or absent websocket key"); - - return NXT_HTTP_BAD_REQUEST; - } - - if (nxt_slow_path(h1p->websocket_version_ok == 0)) { - nxt_log(task, NXT_LOG_INFO, - "h1p upgrade: bad or absent websocket version"); - - return NXT_HTTP_UPGRADE_REQUIRED; - } - - r->websocket_handshake = 1; - } - - return ret; -} - - -static nxt_int_t -nxt_h1p_header_buffer_test(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c, - nxt_socket_conf_t *skcf) -{ - size_t size, used; - nxt_buf_t *in, *b; - - in = c->read; - - if (nxt_buf_mem_free_size(&in->mem) == 0) { - size = skcf->large_header_buffer_size; - used = nxt_buf_mem_used_size(&in->mem); - - if (size <= used || h1p->nbuffers >= skcf->large_header_buffers) { - return NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE; - } - - b = nxt_buf_mem_alloc(c->mem_pool, size, 0); - if (nxt_slow_path(b == NULL)) { - return NXT_HTTP_INTERNAL_SERVER_ERROR; - } - - b->mem.free = nxt_cpymem(b->mem.pos, in->mem.pos, used); - - in->next = h1p->buffers; - h1p->buffers = in; - h1p->nbuffers++; - - c->read = b; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data) -{ - nxt_http_request_t *r; - - r = ctx; - field->hopbyhop = 1; - - if (field->value_length == 5 - && nxt_memcasecmp(field->value, "close", 5) == 0) - { - r->proto.h1->keepalive = 0; - - } else if (field->value_length == 10 - && nxt_memcasecmp(field->value, "keep-alive", 10) == 0) - { - r->proto.h1->keepalive = 1; - - } else if (field->value_length == 7 - && nxt_memcasecmp(field->value, "upgrade", 7) == 0) - { - r->proto.h1->connection_upgrade = 1; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_h1p_upgrade(void *ctx, nxt_http_field_t *field, uintptr_t data) -{ - nxt_http_request_t *r; - - r = ctx; - - if (field->value_length == 9 - && nxt_memcasecmp(field->value, "websocket", 9) == 0) - { - r->proto.h1->upgrade_websocket = 1; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_h1p_websocket_key(void *ctx, nxt_http_field_t *field, uintptr_t data) -{ - nxt_http_request_t *r; - - r = ctx; - - if (field->value_length == 24) { - r->proto.h1->websocket_key = field; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_h1p_websocket_version(void *ctx, nxt_http_field_t *field, uintptr_t data) -{ - nxt_http_request_t *r; - - r = ctx; - - if (field->value_length == 2 - && field->value[0] == '1' && field->value[1] == '3') - { - r->proto.h1->websocket_version_ok = 1; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, uintptr_t data) -{ - nxt_http_te_t te; - nxt_http_request_t *r; - - r = ctx; - field->skip = 1; - field->hopbyhop = 1; - - if (field->value_length == 7 - && memcmp(field->value, "chunked", 7) == 0) - { - te = NXT_HTTP_TE_CHUNKED; - - } else { - te = NXT_HTTP_TE_UNSUPPORTED; - } - - r->proto.h1->transfer_encoding = te; - - return NXT_OK; -} - - -static void -nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r) -{ - size_t size, body_length, body_buffer_size, body_rest; - ssize_t res; - nxt_str_t *tmp_path, tmp_name; - nxt_buf_t *in, *b; - nxt_conn_t *c; - nxt_h1proto_t *h1p; - nxt_http_status_t status; - - static const nxt_str_t tmp_name_pattern = nxt_string("/req-XXXXXXXX"); - - h1p = r->proto.h1; - - nxt_debug(task, "h1p request body read %O te:%d", - r->content_length_n, h1p->transfer_encoding); - - switch (h1p->transfer_encoding) { - - case NXT_HTTP_TE_CHUNKED: - status = NXT_HTTP_LENGTH_REQUIRED; - goto error; - - case NXT_HTTP_TE_UNSUPPORTED: - status = NXT_HTTP_NOT_IMPLEMENTED; - goto error; - - default: - case NXT_HTTP_TE_NONE: - break; - } - - if (r->content_length_n == -1 || r->content_length_n == 0) { - goto ready; - } - - body_length = (size_t) r->content_length_n; - - body_buffer_size = nxt_min(r->conf->socket_conf->body_buffer_size, - body_length); - - if (body_length > body_buffer_size) { - tmp_path = &r->conf->socket_conf->body_temp_path; - - tmp_name.length = tmp_path->length + tmp_name_pattern.length; - - b = nxt_buf_file_alloc(r->mem_pool, - body_buffer_size + sizeof(nxt_file_t) - + tmp_name.length + 1, 0); - - } else { - /* This initialization required for CentOS 6, gcc 4.4.7. */ - tmp_path = NULL; - tmp_name.length = 0; - - b = nxt_buf_mem_alloc(r->mem_pool, body_buffer_size, 0); - } - - if (nxt_slow_path(b == NULL)) { - status = NXT_HTTP_INTERNAL_SERVER_ERROR; - goto error; - } - - r->body = b; - - if (body_length > body_buffer_size) { - tmp_name.start = nxt_pointer_to(b->mem.start, sizeof(nxt_file_t)); - - memcpy(tmp_name.start, tmp_path->start, tmp_path->length); - memcpy(tmp_name.start + tmp_path->length, tmp_name_pattern.start, - tmp_name_pattern.length); - tmp_name.start[tmp_name.length] = '\0'; - - b->file = (nxt_file_t *) b->mem.start; - nxt_memzero(b->file, sizeof(nxt_file_t)); - b->file->fd = -1; - b->file->size = body_length; - - b->mem.start += sizeof(nxt_file_t) + tmp_name.length + 1; - b->mem.pos = b->mem.start; - b->mem.free = b->mem.start; - - b->file->fd = mkstemp((char *) tmp_name.start); - if (nxt_slow_path(b->file->fd == -1)) { - nxt_alert(task, "mkstemp(%s) failed %E", tmp_name.start, nxt_errno); - - status = NXT_HTTP_INTERNAL_SERVER_ERROR; - goto error; - } - - nxt_debug(task, "create body tmp file \"%V\", %d", - &tmp_name, b->file->fd); - - unlink((char *) tmp_name.start); - } - - body_rest = body_length; - - in = h1p->conn->read; - - size = nxt_buf_mem_used_size(&in->mem); - - if (size != 0) { - size = nxt_min(size, body_length); - - if (nxt_buf_is_file(b)) { - res = nxt_fd_write(b->file->fd, in->mem.pos, size); - if (nxt_slow_path(res < (ssize_t) size)) { - status = NXT_HTTP_INTERNAL_SERVER_ERROR; - goto error; - } - - b->file_end += size; - - } else { - size = nxt_min(body_buffer_size, size); - b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size); - } - - in->mem.pos += size; - body_rest -= size; - } - - nxt_debug(task, "h1p body rest: %uz", body_rest); - - if (body_rest != 0) { - in->next = h1p->buffers; - h1p->buffers = in; - h1p->nbuffers++; - - c = h1p->conn; - c->read = b; - c->read_state = &nxt_h1p_read_body_state; - - nxt_conn_read(task->thread->engine, c); - return; - } - - if (nxt_buf_is_file(b)) { - b->mem.start = NULL; - b->mem.end = NULL; - b->mem.pos = NULL; - b->mem.free = NULL; - } - -ready: - - r->state->ready_handler(task, r, NULL); - - return; - -error: - - h1p->keepalive = 0; - - nxt_http_request_error(task, r, status); -} - - -static const nxt_conn_state_t nxt_h1p_read_body_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_conn_request_body_read, - .close_handler = nxt_h1p_conn_request_error, - .error_handler = nxt_h1p_conn_request_error, - - .timer_handler = nxt_h1p_conn_request_timeout, - .timer_value = nxt_h1p_conn_request_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout), - .timer_autoreset = 1, -}; - - -static void -nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj, void *data) -{ - size_t size, body_rest; - ssize_t res; - nxt_buf_t *b; - nxt_conn_t *c; - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - nxt_event_engine_t *engine; - - c = obj; - h1p = data; - - nxt_debug(task, "h1p conn request body read"); - - r = h1p->request; - - engine = task->thread->engine; - - b = c->read; - - if (nxt_buf_is_file(b)) { - body_rest = b->file->size - b->file_end; - - size = nxt_buf_mem_used_size(&b->mem); - size = nxt_min(size, body_rest); - - res = nxt_fd_write(b->file->fd, b->mem.pos, size); - if (nxt_slow_path(res < (ssize_t) size)) { - nxt_h1p_request_error(task, h1p, r); - return; - } - - b->file_end += size; - body_rest -= res; - - b->mem.pos += size; - - if (b->mem.pos == b->mem.free) { - if (body_rest >= (size_t) nxt_buf_mem_size(&b->mem)) { - b->mem.free = b->mem.start; - - } else { - /* This required to avoid reading next request. */ - b->mem.free = b->mem.end - body_rest; - } - - b->mem.pos = b->mem.free; - } - - } else { - body_rest = nxt_buf_mem_free_size(&c->read->mem); - } - - nxt_debug(task, "h1p body rest: %uz", body_rest); - - if (body_rest != 0) { - nxt_conn_read(engine, c); - - } else { - if (nxt_buf_is_file(b)) { - b->mem.start = NULL; - b->mem.end = NULL; - b->mem.pos = NULL; - b->mem.free = NULL; - } - - c->read = NULL; - - r->state->ready_handler(task, r, NULL); - } -} - - -static void -nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r) -{ - r->local = nxt_conn_local_addr(task, r->proto.h1->conn); -} - - -#define NXT_HTTP_LAST_INFORMATIONAL \ - (NXT_HTTP_CONTINUE + nxt_nitems(nxt_http_informational) - 1) - -static const nxt_str_t nxt_http_informational[] = { - nxt_string("HTTP/1.1 100 Continue\r\n"), - nxt_string("HTTP/1.1 101 Switching Protocols\r\n"), -}; - - -#define NXT_HTTP_LAST_SUCCESS \ - (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1) - -static const nxt_str_t nxt_http_success[] = { - nxt_string("HTTP/1.1 200 OK\r\n"), - nxt_string("HTTP/1.1 201 Created\r\n"), - nxt_string("HTTP/1.1 202 Accepted\r\n"), - nxt_string("HTTP/1.1 203 Non-Authoritative Information\r\n"), - nxt_string("HTTP/1.1 204 No Content\r\n"), - nxt_string("HTTP/1.1 205 Reset Content\r\n"), - nxt_string("HTTP/1.1 206 Partial Content\r\n"), -}; - - -#define NXT_HTTP_LAST_REDIRECTION \ - (NXT_HTTP_MULTIPLE_CHOICES + nxt_nitems(nxt_http_redirection) - 1) - -static const nxt_str_t nxt_http_redirection[] = { - nxt_string("HTTP/1.1 300 Multiple Choices\r\n"), - nxt_string("HTTP/1.1 301 Moved Permanently\r\n"), - nxt_string("HTTP/1.1 302 Found\r\n"), - nxt_string("HTTP/1.1 303 See Other\r\n"), - nxt_string("HTTP/1.1 304 Not Modified\r\n"), - nxt_string("HTTP/1.1 307 Temporary Redirect\r\n"), - nxt_string("HTTP/1.1 308 Permanent Redirect\r\n"), -}; - - -#define NXT_HTTP_LAST_CLIENT_ERROR \ - (NXT_HTTP_BAD_REQUEST + nxt_nitems(nxt_http_client_error) - 1) - -static const nxt_str_t nxt_http_client_error[] = { - nxt_string("HTTP/1.1 400 Bad Request\r\n"), - nxt_string("HTTP/1.1 401 Unauthorized\r\n"), - nxt_string("HTTP/1.1 402 Payment Required\r\n"), - nxt_string("HTTP/1.1 403 Forbidden\r\n"), - nxt_string("HTTP/1.1 404 Not Found\r\n"), - nxt_string("HTTP/1.1 405 Method Not Allowed\r\n"), - nxt_string("HTTP/1.1 406 Not Acceptable\r\n"), - nxt_string("HTTP/1.1 407 Proxy Authentication Required\r\n"), - nxt_string("HTTP/1.1 408 Request Timeout\r\n"), - nxt_string("HTTP/1.1 409 Conflict\r\n"), - nxt_string("HTTP/1.1 410 Gone\r\n"), - nxt_string("HTTP/1.1 411 Length Required\r\n"), - nxt_string("HTTP/1.1 412 Precondition Failed\r\n"), - nxt_string("HTTP/1.1 413 Payload Too Large\r\n"), - nxt_string("HTTP/1.1 414 URI Too Long\r\n"), - nxt_string("HTTP/1.1 415 Unsupported Media Type\r\n"), - nxt_string("HTTP/1.1 416 Range Not Satisfiable\r\n"), - nxt_string("HTTP/1.1 417 Expectation Failed\r\n"), - nxt_string("HTTP/1.1 418 I'm a teapot\r\n"), - nxt_string("HTTP/1.1 419 \r\n"), - nxt_string("HTTP/1.1 420 \r\n"), - nxt_string("HTTP/1.1 421 Misdirected Request\r\n"), - nxt_string("HTTP/1.1 422 Unprocessable Entity\r\n"), - nxt_string("HTTP/1.1 423 Locked\r\n"), - nxt_string("HTTP/1.1 424 Failed Dependency\r\n"), - nxt_string("HTTP/1.1 425 \r\n"), - nxt_string("HTTP/1.1 426 Upgrade Required\r\n"), - nxt_string("HTTP/1.1 427 \r\n"), - nxt_string("HTTP/1.1 428 \r\n"), - nxt_string("HTTP/1.1 429 \r\n"), - nxt_string("HTTP/1.1 430 \r\n"), - nxt_string("HTTP/1.1 431 Request Header Fields Too Large\r\n"), -}; - - -#define NXT_HTTP_LAST_NGINX_ERROR \ - (NXT_HTTP_TO_HTTPS + nxt_nitems(nxt_http_nginx_error) - 1) - -static const nxt_str_t nxt_http_nginx_error[] = { - nxt_string("HTTP/1.1 400 " - "The plain HTTP request was sent to HTTPS port\r\n"), -}; - - -#define NXT_HTTP_LAST_SERVER_ERROR \ - (NXT_HTTP_INTERNAL_SERVER_ERROR + nxt_nitems(nxt_http_server_error) - 1) - -static const nxt_str_t nxt_http_server_error[] = { - nxt_string("HTTP/1.1 500 Internal Server Error\r\n"), - nxt_string("HTTP/1.1 501 Not Implemented\r\n"), - nxt_string("HTTP/1.1 502 Bad Gateway\r\n"), - nxt_string("HTTP/1.1 503 Service Unavailable\r\n"), - nxt_string("HTTP/1.1 504 Gateway Timeout\r\n"), - nxt_string("HTTP/1.1 505 HTTP Version Not Supported\r\n"), -}; - - -#define UNKNOWN_STATUS_LENGTH nxt_length("HTTP/1.1 999 \r\n") - -static void -nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r, - nxt_work_handler_t body_handler, void *data) -{ - u_char *p; - size_t size; - nxt_buf_t *header; - nxt_str_t unknown_status; - nxt_int_t conn; - nxt_uint_t n; - nxt_bool_t http11; - nxt_conn_t *c; - nxt_h1proto_t *h1p; - const nxt_str_t *status; - nxt_http_field_t *field; - u_char buf[UNKNOWN_STATUS_LENGTH]; - - static const char chunked[] = "Transfer-Encoding: chunked\r\n"; - static const char websocket_version[] = "Sec-WebSocket-Version: 13\r\n"; - - static const nxt_str_t connection[3] = { - nxt_string("Connection: close\r\n"), - nxt_string("Connection: keep-alive\r\n"), - nxt_string("Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Accept: "), - }; - - nxt_debug(task, "h1p request header send"); - - r->header_sent = 1; - h1p = r->proto.h1; - n = r->status; - - if (n >= NXT_HTTP_CONTINUE && n <= NXT_HTTP_LAST_INFORMATIONAL) { - status = &nxt_http_informational[n - NXT_HTTP_CONTINUE]; - - } else if (n >= NXT_HTTP_OK && n <= NXT_HTTP_LAST_SUCCESS) { - status = &nxt_http_success[n - NXT_HTTP_OK]; - - } else if (n >= NXT_HTTP_MULTIPLE_CHOICES - && n <= NXT_HTTP_LAST_REDIRECTION) - { - status = &nxt_http_redirection[n - NXT_HTTP_MULTIPLE_CHOICES]; - - } else if (n >= NXT_HTTP_BAD_REQUEST && n <= NXT_HTTP_LAST_CLIENT_ERROR) { - status = &nxt_http_client_error[n - NXT_HTTP_BAD_REQUEST]; - - } else if (n >= NXT_HTTP_TO_HTTPS && n <= NXT_HTTP_LAST_NGINX_ERROR) { - status = &nxt_http_nginx_error[n - NXT_HTTP_TO_HTTPS]; - - } else if (n >= NXT_HTTP_INTERNAL_SERVER_ERROR - && n <= NXT_HTTP_LAST_SERVER_ERROR) - { - status = &nxt_http_server_error[n - NXT_HTTP_INTERNAL_SERVER_ERROR]; - - } else if (n <= NXT_HTTP_STATUS_MAX) { - (void) nxt_sprintf(buf, buf + UNKNOWN_STATUS_LENGTH, - "HTTP/1.1 %03d \r\n", n); - - unknown_status.length = UNKNOWN_STATUS_LENGTH; - unknown_status.start = buf; - status = &unknown_status; - - } else { - status = &nxt_http_server_error[0]; - } - - size = status->length; - /* Trailing CRLF at the end of header. */ - size += nxt_length("\r\n"); - - conn = -1; - - if (r->websocket_handshake && n == NXT_HTTP_SWITCHING_PROTOCOLS) { - h1p->websocket = 1; - h1p->keepalive = 0; - conn = 2; - size += NXT_WEBSOCKET_ACCEPT_SIZE + 2; - - } else { - http11 = nxt_h1p_is_http11(h1p); - - if (r->resp.content_length == NULL || r->resp.content_length->skip) { - - if (http11) { - if (n != NXT_HTTP_NOT_MODIFIED - && n != NXT_HTTP_NO_CONTENT - && body_handler != NULL - && !h1p->websocket) - { - h1p->chunked = 1; - size += nxt_length(chunked); - /* Trailing CRLF will be added by the first chunk header. */ - size -= nxt_length("\r\n"); - } - - } else { - h1p->keepalive = 0; - } - } - - if (http11 ^ h1p->keepalive) { - conn = h1p->keepalive; - } - } - - if (conn >= 0) { - size += connection[conn].length; - } - - nxt_list_each(field, r->resp.fields) { - - if (!field->skip) { - size += field->name_length + field->value_length; - size += nxt_length(": \r\n"); - } - - } nxt_list_loop; - - if (nxt_slow_path(n == NXT_HTTP_UPGRADE_REQUIRED)) { - size += nxt_length(websocket_version); - } - - header = nxt_http_buf_mem(task, r, size); - if (nxt_slow_path(header == NULL)) { - nxt_h1p_request_error(task, h1p, r); - return; - } - - p = nxt_cpymem(header->mem.free, status->start, status->length); - - nxt_list_each(field, r->resp.fields) { - - if (!field->skip) { - p = nxt_cpymem(p, field->name, field->name_length); - *p++ = ':'; *p++ = ' '; - p = nxt_cpymem(p, field->value, field->value_length); - *p++ = '\r'; *p++ = '\n'; - } - - } nxt_list_loop; - - if (conn >= 0) { - p = nxt_cpymem(p, connection[conn].start, connection[conn].length); - } - - if (h1p->websocket) { - nxt_websocket_accept(p, h1p->websocket_key->value); - p += NXT_WEBSOCKET_ACCEPT_SIZE; - - *p++ = '\r'; *p++ = '\n'; - } - - if (nxt_slow_path(n == NXT_HTTP_UPGRADE_REQUIRED)) { - p = nxt_cpymem(p, websocket_version, nxt_length(websocket_version)); - } - - if (h1p->chunked) { - p = nxt_cpymem(p, chunked, nxt_length(chunked)); - /* Trailing CRLF will be added by the first chunk header. */ - - } else { - *p++ = '\r'; *p++ = '\n'; - } - - header->mem.free = p; - - h1p->header_size = nxt_buf_mem_used_size(&header->mem); - - c = h1p->conn; - - c->write = header; - h1p->conn_write_tail = &header->next; - c->write_state = &nxt_h1p_request_send_state; - - if (body_handler != NULL) { - /* - * The body handler will run before c->io->write() handler, - * because the latter was inqueued by nxt_conn_write() - * in engine->write_work_queue. - */ - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - body_handler, task, r, data); - - } else { - header->next = nxt_http_buf_last(r); - } - - nxt_conn_write(task->thread->engine, c); - - if (h1p->websocket) { - nxt_h1p_websocket_first_frame_start(task, r, c->read); - } -} - - -void -nxt_h1p_complete_buffers(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_bool_t all) -{ - size_t size; - nxt_buf_t *b, *in, *next; - nxt_conn_t *c; - - nxt_debug(task, "h1p complete buffers"); - - b = h1p->buffers; - c = h1p->conn; - in = c->read; - - if (b != NULL) { - if (in == NULL) { - /* A request with large body. */ - in = b; - c->read = in; - - b = in->next; - in->next = NULL; - } - - while (b != NULL) { - next = b->next; - b->next = NULL; - - b->completion_handler(task, b, b->parent); - - b = next; - } - - h1p->buffers = NULL; - h1p->nbuffers = 0; - } - - if (in != NULL) { - size = nxt_buf_mem_used_size(&in->mem); - - if (size == 0 || all) { - in->completion_handler(task, in, in->parent); - - c->read = NULL; - } - } -} - - -static const nxt_conn_state_t nxt_h1p_request_send_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_conn_sent, - .error_handler = nxt_h1p_conn_request_error, - - .timer_handler = nxt_h1p_conn_request_send_timeout, - .timer_value = nxt_h1p_conn_request_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, send_timeout), - .timer_autoreset = 1, -}; - - -static void -nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) -{ - nxt_conn_t *c; - nxt_h1proto_t *h1p; - - nxt_debug(task, "h1p request send"); - - h1p = r->proto.h1; - c = h1p->conn; - - if (h1p->chunked) { - out = nxt_h1p_chunk_create(task, r, out); - if (nxt_slow_path(out == NULL)) { - nxt_h1p_request_error(task, h1p, r); - return; - } - } - - if (c->write == NULL) { - c->write = out; - c->write_state = &nxt_h1p_request_send_state; - - nxt_conn_write(task->thread->engine, c); - - } else { - *h1p->conn_write_tail = out; - } - - while (out->next != NULL) { - out = out->next; - } - - h1p->conn_write_tail = &out->next; -} - - -static nxt_buf_t * -nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) -{ - nxt_off_t size; - nxt_buf_t *b, **prev, *header, *tail; - - const size_t chunk_size = 2 * nxt_length("\r\n") + NXT_OFF_T_HEXLEN; - static const char tail_chunk[] = "\r\n0\r\n\r\n"; - - size = 0; - prev = &out; - - for (b = out; b != NULL; b = b->next) { - - if (nxt_buf_is_last(b)) { - tail = nxt_http_buf_mem(task, r, sizeof(tail_chunk)); - if (nxt_slow_path(tail == NULL)) { - return NULL; - } - - *prev = tail; - tail->next = b; - /* - * The tail_chunk size with trailing zero is 8 bytes, so - * memcpy may be inlined with just single 8 byte move operation. - */ - nxt_memcpy(tail->mem.free, tail_chunk, sizeof(tail_chunk)); - tail->mem.free += nxt_length(tail_chunk); - - break; - } - - size += nxt_buf_used_size(b); - prev = &b->next; - } - - if (size == 0) { - return out; - } - - header = nxt_http_buf_mem(task, r, chunk_size); - if (nxt_slow_path(header == NULL)) { - return NULL; - } - - header->next = out; - header->mem.free = nxt_sprintf(header->mem.free, header->mem.end, - "\r\n%xO\r\n", size); - return header; -} - - -static nxt_off_t -nxt_h1p_request_body_bytes_sent(nxt_task_t *task, nxt_http_proto_t proto) -{ - nxt_off_t sent; - nxt_h1proto_t *h1p; - - h1p = proto.h1; - - sent = h1p->conn->sent - h1p->header_size; - - return (sent > 0) ? sent : 0; -} - - -static void -nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *last) -{ - nxt_buf_t *b; - nxt_conn_t *c; - nxt_h1proto_t *h1p; - nxt_work_queue_t *wq; - - nxt_debug(task, "h1p request discard"); - - h1p = r->proto.h1; - h1p->keepalive = 0; - - c = h1p->conn; - b = c->write; - c->write = NULL; - - wq = &task->thread->engine->fast_work_queue; - - nxt_sendbuf_drain(task, wq, b); - nxt_sendbuf_drain(task, wq, last); -} - - -static void -nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - - h1p = data; - - nxt_debug(task, "h1p conn request error"); - - r = h1p->request; - - if (nxt_slow_path(r == NULL)) { - nxt_h1p_shutdown(task, h1p->conn); - return; - } - - if (r->fields == NULL) { - (void) nxt_h1p_header_process(task, h1p, r); - } - - if (r->status == 0) { - r->status = NXT_HTTP_BAD_REQUEST; - } - - nxt_h1p_request_error(task, h1p, r); -} - - -static void -nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - - timer = obj; - - nxt_debug(task, "h1p conn request timeout"); - - c = nxt_read_timer_conn(timer); - c->block_read = 1; - /* - * Disable SO_LINGER off during socket closing - * to send "408 Request Timeout" error response. - */ - c->socket.timedout = 0; - - h1p = c->socket.data; - h1p->keepalive = 0; - r = h1p->request; - - if (r->fields == NULL) { - (void) nxt_h1p_header_process(task, h1p, r); - } - - nxt_http_request_error(task, r, NXT_HTTP_REQUEST_TIMEOUT); -} - - -static void -nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - nxt_h1proto_t *h1p; - - timer = obj; - - nxt_debug(task, "h1p conn request send timeout"); - - c = nxt_write_timer_conn(timer); - c->block_write = 1; - h1p = c->socket.data; - - nxt_h1p_request_error(task, h1p, h1p->request); -} - - -nxt_msec_t -nxt_h1p_conn_request_timer_value(nxt_conn_t *c, uintptr_t data) -{ - nxt_h1proto_t *h1p; - - h1p = c->socket.data; - - return nxt_value_at(nxt_msec_t, h1p->request->conf->socket_conf, data); -} - - -nxt_inline void -nxt_h1p_request_error(nxt_task_t *task, nxt_h1proto_t *h1p, - nxt_http_request_t *r) -{ - h1p->keepalive = 0; - - r->state->error_handler(task, r, h1p); -} - - -static void -nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto, - nxt_socket_conf_joint_t *joint) -{ - nxt_conn_t *c; - nxt_h1proto_t *h1p; - - nxt_debug(task, "h1p request close"); - - h1p = proto.h1; - h1p->keepalive &= !h1p->request->inconsistent; - h1p->request = NULL; - - nxt_router_conf_release(task, joint); - - c = h1p->conn; - task = &c->task; - c->socket.task = task; - c->read_timer.task = task; - c->write_timer.task = task; - - if (h1p->keepalive) { - nxt_h1p_keepalive(task, h1p, c); - - } else { - nxt_h1p_shutdown(task, c); - } -} - - -static void -nxt_h1p_conn_sent(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_event_engine_t *engine; - - c = obj; - - nxt_debug(task, "h1p conn sent"); - - engine = task->thread->engine; - - c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write); - - if (c->write != NULL) { - nxt_conn_write(engine, c); - } -} - - -static void -nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "h1p conn close"); - - nxt_conn_active(task->thread->engine, c); - - nxt_h1p_shutdown(task, c); -} - - -static void -nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "h1p conn error"); - - nxt_conn_active(task->thread->engine, c); - - nxt_h1p_shutdown(task, c); -} - - -static nxt_msec_t -nxt_h1p_conn_timer_value(nxt_conn_t *c, uintptr_t data) -{ - nxt_socket_conf_joint_t *joint; - - joint = c->listen->socket.data; - - if (nxt_fast_path(joint != NULL)) { - return nxt_value_at(nxt_msec_t, joint->socket_conf, data); - } - - /* - * Listening socket had been closed while - * connection was in keep-alive state. - */ - return 1; -} - - -static void -nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c) -{ - size_t size; - nxt_buf_t *in; - nxt_event_engine_t *engine; - - nxt_debug(task, "h1p keepalive"); - - if (!c->tcp_nodelay) { - nxt_conn_tcp_nodelay_on(task, c); - } - - nxt_h1p_complete_buffers(task, h1p, 0); - - in = c->read; - - nxt_memzero(h1p, offsetof(nxt_h1proto_t, conn)); - - c->sent = 0; - - engine = task->thread->engine; - - nxt_conn_idle(engine, c); - - if (in == NULL) { - c->read_state = &nxt_h1p_keepalive_state; - - nxt_conn_read(engine, c); - - } else { - size = nxt_buf_mem_used_size(&in->mem); - - nxt_debug(task, "h1p pipelining"); - - nxt_memmove(in->mem.start, in->mem.pos, size); - - in->mem.pos = in->mem.start; - in->mem.free = in->mem.start + size; - - nxt_h1p_conn_request_init(task, c, c->socket.data); - } -} - - -static const nxt_conn_state_t nxt_h1p_keepalive_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_conn_request_init, - .close_handler = nxt_h1p_conn_close, - .error_handler = nxt_h1p_conn_error, - - .io_read_handler = nxt_h1p_idle_io_read_handler, - - .timer_handler = nxt_h1p_idle_timeout, - .timer_value = nxt_h1p_conn_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), - .timer_autoreset = 1, -}; - - -const nxt_conn_state_t nxt_h1p_idle_close_state - nxt_aligned(64) = -{ - .close_handler = nxt_h1p_idle_close, -}; - - -static void -nxt_h1p_idle_close(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "h1p idle close"); - - nxt_conn_active(task->thread->engine, c); - - nxt_h1p_idle_response(task, c); -} - - -static void -nxt_h1p_idle_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - - timer = obj; - - nxt_debug(task, "h1p idle timeout"); - - c = nxt_read_timer_conn(timer); - c->block_read = 1; - - nxt_conn_active(task->thread->engine, c); - - nxt_h1p_idle_response(task, c); -} - - -#define NXT_H1P_IDLE_TIMEOUT \ - "HTTP/1.1 408 Request Timeout\r\n" \ - "Server: " NXT_SERVER "\r\n" \ - "Connection: close\r\n" \ - "Content-Length: 0\r\n" \ - "Date: " - - -static void -nxt_h1p_idle_response(nxt_task_t *task, nxt_conn_t *c) -{ - u_char *p; - size_t size; - nxt_buf_t *out, *last; - - size = nxt_length(NXT_H1P_IDLE_TIMEOUT) - + nxt_http_date_cache.size - + nxt_length("\r\n\r\n"); - - out = nxt_buf_mem_alloc(c->mem_pool, size, 0); - if (nxt_slow_path(out == NULL)) { - goto fail; - } - - p = nxt_cpymem(out->mem.free, NXT_H1P_IDLE_TIMEOUT, - nxt_length(NXT_H1P_IDLE_TIMEOUT)); - - p = nxt_thread_time_string(task->thread, &nxt_http_date_cache, p); - - out->mem.free = nxt_cpymem(p, "\r\n\r\n", 4); - - last = nxt_mp_zget(c->mem_pool, NXT_BUF_SYNC_SIZE); - if (nxt_slow_path(last == NULL)) { - goto fail; - } - - out->next = last; - nxt_buf_set_sync(last); - nxt_buf_set_last(last); - - last->completion_handler = nxt_h1p_idle_response_sent; - last->parent = c; - - c->write = out; - c->write_state = &nxt_h1p_timeout_response_state; - - nxt_conn_write(task->thread->engine, c); - return; - -fail: - - nxt_h1p_shutdown(task, c); -} - - -static const nxt_conn_state_t nxt_h1p_timeout_response_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_conn_sent, - .error_handler = nxt_h1p_idle_response_error, - - .timer_handler = nxt_h1p_idle_response_timeout, - .timer_value = nxt_h1p_idle_response_timer_value, -}; - - -static void -nxt_h1p_idle_response_sent(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = data; - - nxt_debug(task, "h1p idle timeout response sent"); - - nxt_h1p_shutdown(task, c); -} - - -static void -nxt_h1p_idle_response_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "h1p response error"); - - nxt_h1p_shutdown(task, c); -} - - -static void -nxt_h1p_idle_response_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - - timer = obj; - - nxt_debug(task, "h1p idle timeout response timeout"); - - c = nxt_read_timer_conn(timer); - c->block_write = 1; - - nxt_h1p_shutdown(task, c); -} - - -static nxt_msec_t -nxt_h1p_idle_response_timer_value(nxt_conn_t *c, uintptr_t data) -{ - return 10 * 1000; -} - - -static void -nxt_h1p_shutdown(nxt_task_t *task, nxt_conn_t *c) -{ - nxt_timer_t *timer; - nxt_h1proto_t *h1p; - - nxt_debug(task, "h1p shutdown"); - - h1p = c->socket.data; - - if (h1p != NULL) { - nxt_h1p_complete_buffers(task, h1p, 1); - - if (nxt_slow_path(h1p->websocket_timer != NULL)) { - timer = &h1p->websocket_timer->timer; - - if (timer->handler != nxt_h1p_conn_ws_shutdown) { - timer->handler = nxt_h1p_conn_ws_shutdown; - nxt_timer_add(task->thread->engine, timer, 0); - - } else { - nxt_debug(task, "h1p already scheduled ws shutdown"); - } - - return; - } - } - - nxt_h1p_closing(task, c); -} - - -static void -nxt_h1p_conn_ws_shutdown(nxt_task_t *task, void *obj, void *data) -{ - nxt_timer_t *timer; - nxt_h1p_websocket_timer_t *ws_timer; - - nxt_debug(task, "h1p conn ws shutdown"); - - timer = obj; - ws_timer = nxt_timer_data(timer, nxt_h1p_websocket_timer_t, timer); - - nxt_h1p_closing(task, ws_timer->h1p->conn); -} - - -static void -nxt_h1p_closing(nxt_task_t *task, nxt_conn_t *c) -{ - nxt_debug(task, "h1p closing"); - - c->socket.data = NULL; - -#if (NXT_TLS) - - if (c->u.tls != NULL) { - c->write_state = &nxt_h1p_shutdown_state; - - c->io->shutdown(task, c, NULL); - return; - } - -#endif - - nxt_h1p_conn_closing(task, c, NULL); -} - - -#if (NXT_TLS) - -static const nxt_conn_state_t nxt_h1p_shutdown_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_conn_closing, - .close_handler = nxt_h1p_conn_closing, - .error_handler = nxt_h1p_conn_closing, -}; - -#endif - - -static void -nxt_h1p_conn_closing(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "h1p conn closing"); - - c->write_state = &nxt_h1p_close_state; - - nxt_conn_close(task->thread->engine, c); -} - - -static const nxt_conn_state_t nxt_h1p_close_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_conn_free, -}; - - -static void -nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_listen_event_t *lev; - nxt_event_engine_t *engine; - - c = obj; - - nxt_debug(task, "h1p conn free"); - - engine = task->thread->engine; - - nxt_sockaddr_cache_free(engine, c); - - lev = c->listen; - - nxt_conn_free(task, c); - - nxt_router_listen_event_release(&engine->task, lev, NULL); -} - - -static void -nxt_h1p_peer_connect(nxt_task_t *task, nxt_http_peer_t *peer) -{ - nxt_mp_t *mp; - nxt_int_t ret; - nxt_conn_t *c, *client; - nxt_h1proto_t *h1p; - nxt_fd_event_t *socket; - nxt_work_queue_t *wq; - nxt_http_request_t *r; - - nxt_debug(task, "h1p peer connect"); - - peer->status = NXT_HTTP_UNSET; - r = peer->request; - - mp = nxt_mp_create(1024, 128, 256, 32); - - if (nxt_slow_path(mp == NULL)) { - goto fail; - } - - h1p = nxt_mp_zalloc(mp, sizeof(nxt_h1proto_t)); - if (nxt_slow_path(h1p == NULL)) { - goto fail; - } - - ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - c = nxt_conn_create(mp, task); - if (nxt_slow_path(c == NULL)) { - goto fail; - } - - c->mem_pool = mp; - h1p->conn = c; - - peer->proto.h1 = h1p; - h1p->request = r; - - c->socket.data = peer; - c->remote = peer->server->sockaddr; - - c->socket.write_ready = 1; - c->write_state = &nxt_h1p_peer_connect_state; - - /* - * TODO: queues should be implemented via client proto interface. - */ - client = r->proto.h1->conn; - - socket = &client->socket; - wq = socket->read_work_queue; - c->read_work_queue = wq; - c->socket.read_work_queue = wq; - c->read_timer.work_queue = wq; - - wq = socket->write_work_queue; - c->write_work_queue = wq; - c->socket.write_work_queue = wq; - c->write_timer.work_queue = wq; - /* TODO END */ - - nxt_conn_connect(task->thread->engine, c); - - return; - -fail: - - peer->status = NXT_HTTP_INTERNAL_SERVER_ERROR; - - r->state->error_handler(task, r, peer); -} - - -static const nxt_conn_state_t nxt_h1p_peer_connect_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_peer_connected, - .close_handler = nxt_h1p_peer_refused, - .error_handler = nxt_h1p_peer_error, - - .timer_handler = nxt_h1p_peer_send_timeout, - .timer_value = nxt_h1p_peer_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, proxy_timeout), -}; - - -static void -nxt_h1p_peer_connected(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - peer = data; - - nxt_debug(task, "h1p peer connected"); - - r = peer->request; - r->state->ready_handler(task, r, peer); -} - - -static void -nxt_h1p_peer_refused(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - peer = data; - - nxt_debug(task, "h1p peer refused"); - - //peer->status = NXT_HTTP_SERVICE_UNAVAILABLE; - peer->status = NXT_HTTP_BAD_GATEWAY; - - r = peer->request; - r->state->error_handler(task, r, peer); -} - - -static void -nxt_h1p_peer_header_send(nxt_task_t *task, nxt_http_peer_t *peer) -{ - u_char *p; - size_t size; - nxt_buf_t *header, *body; - nxt_conn_t *c; - nxt_http_field_t *field; - nxt_http_request_t *r; - - nxt_debug(task, "h1p peer header send"); - - r = peer->request; - - size = r->method->length + sizeof(" ") + r->target.length - + sizeof(" HTTP/1.1\r\n") - + sizeof("Connection: close\r\n") - + sizeof("\r\n"); - - nxt_list_each(field, r->fields) { - - if (!field->hopbyhop) { - size += field->name_length + field->value_length; - size += nxt_length(": \r\n"); - } - - } nxt_list_loop; - - header = nxt_http_buf_mem(task, r, size); - if (nxt_slow_path(header == NULL)) { - r->state->error_handler(task, r, peer); - return; - } - - p = header->mem.free; - - p = nxt_cpymem(p, r->method->start, r->method->length); - *p++ = ' '; - p = nxt_cpymem(p, r->target.start, r->target.length); - p = nxt_cpymem(p, " HTTP/1.1\r\n", 11); - p = nxt_cpymem(p, "Connection: close\r\n", 19); - - nxt_list_each(field, r->fields) { - - if (!field->hopbyhop) { - p = nxt_cpymem(p, field->name, field->name_length); - *p++ = ':'; *p++ = ' '; - p = nxt_cpymem(p, field->value, field->value_length); - *p++ = '\r'; *p++ = '\n'; - } - - } nxt_list_loop; - - *p++ = '\r'; *p++ = '\n'; - header->mem.free = p; - size = p - header->mem.pos; - - c = peer->proto.h1->conn; - c->write = header; - c->write_state = &nxt_h1p_peer_header_send_state; - - if (r->body != NULL) { - if (nxt_buf_is_file(r->body)) { - body = nxt_buf_file_alloc(r->mem_pool, 0, 0); - - } else { - body = nxt_buf_mem_alloc(r->mem_pool, 0, 0); - } - - if (nxt_slow_path(body == NULL)) { - r->state->error_handler(task, r, peer); - return; - } - - header->next = body; - - if (nxt_buf_is_file(r->body)) { - body->file = r->body->file; - body->file_end = r->body->file_end; - - } else { - body->mem = r->body->mem; - } - - size += nxt_buf_used_size(body); - -// nxt_mp_retain(r->mem_pool); - } - - if (size > 16384) { - /* Use proxy_send_timeout instead of proxy_timeout. */ - c->write_state = &nxt_h1p_peer_header_body_send_state; - } - - nxt_conn_write(task->thread->engine, c); -} - - -static const nxt_conn_state_t nxt_h1p_peer_header_send_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_peer_header_sent, - .error_handler = nxt_h1p_peer_error, - - .timer_handler = nxt_h1p_peer_send_timeout, - .timer_value = nxt_h1p_peer_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, proxy_timeout), -}; - - -static const nxt_conn_state_t nxt_h1p_peer_header_body_send_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_peer_header_sent, - .error_handler = nxt_h1p_peer_error, - - .timer_handler = nxt_h1p_peer_send_timeout, - .timer_value = nxt_h1p_peer_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, proxy_send_timeout), - .timer_autoreset = 1, -}; - - -static void -nxt_h1p_peer_header_sent(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_http_peer_t *peer; - nxt_http_request_t *r; - nxt_event_engine_t *engine; - - c = obj; - peer = data; - - nxt_debug(task, "h1p peer header sent"); - - engine = task->thread->engine; - - c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write); - - if (c->write != NULL) { - nxt_conn_write(engine, c); - return; - } - - r = peer->request; - r->state->ready_handler(task, r, peer); -} - - -static void -nxt_h1p_peer_header_read(nxt_task_t *task, nxt_http_peer_t *peer) -{ - nxt_conn_t *c; - - nxt_debug(task, "h1p peer header read"); - - c = peer->proto.h1->conn; - - if (c->write_timer.enabled) { - c->read_state = &nxt_h1p_peer_header_read_state; - - } else { - c->read_state = &nxt_h1p_peer_header_read_timer_state; - } - - nxt_conn_read(task->thread->engine, c); -} - - -static const nxt_conn_state_t nxt_h1p_peer_header_read_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_peer_header_read_done, - .close_handler = nxt_h1p_peer_closed, - .error_handler = nxt_h1p_peer_error, - - .io_read_handler = nxt_h1p_peer_io_read_handler, -}; - - -static const nxt_conn_state_t nxt_h1p_peer_header_read_timer_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_peer_header_read_done, - .close_handler = nxt_h1p_peer_closed, - .error_handler = nxt_h1p_peer_error, - - .io_read_handler = nxt_h1p_peer_io_read_handler, - - .timer_handler = nxt_h1p_peer_read_timeout, - .timer_value = nxt_h1p_peer_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, proxy_timeout), -}; - - -static ssize_t -nxt_h1p_peer_io_read_handler(nxt_task_t *task, nxt_conn_t *c) -{ - size_t size; - ssize_t n; - nxt_buf_t *b; - nxt_http_peer_t *peer; - nxt_socket_conf_t *skcf; - nxt_http_request_t *r; - - peer = c->socket.data; - r = peer->request; - b = c->read; - - if (b == NULL) { - skcf = r->conf->socket_conf; - - size = (peer->header_received) ? skcf->proxy_buffer_size - : skcf->proxy_header_buffer_size; - - nxt_debug(task, "h1p peer io read: %z", size); - - b = nxt_http_proxy_buf_mem_alloc(task, r, size); - if (nxt_slow_path(b == NULL)) { - c->socket.error = NXT_ENOMEM; - return NXT_ERROR; - } - } - - n = c->io->recvbuf(c, b); - - if (n > 0) { - c->read = b; - - } else { - c->read = NULL; - nxt_http_proxy_buf_mem_free(task, r, b); - } - - return n; -} - - -static void -nxt_h1p_peer_header_read_done(nxt_task_t *task, void *obj, void *data) -{ - nxt_int_t ret; - nxt_buf_t *b; - nxt_conn_t *c; - nxt_h1proto_t *h1p; - nxt_http_peer_t *peer; - nxt_http_request_t *r; - nxt_event_engine_t *engine; - - c = obj; - peer = data; - - nxt_debug(task, "h1p peer header read done"); - - b = c->read; - - ret = nxt_h1p_peer_header_parse(peer, &b->mem); - - r = peer->request; - - ret = nxt_expect(NXT_DONE, ret); - - if (ret != NXT_AGAIN) { - engine = task->thread->engine; - nxt_timer_disable(engine, &c->write_timer); - nxt_timer_disable(engine, &c->read_timer); - } - - switch (ret) { - - case NXT_DONE: - peer->fields = peer->proto.h1->parser.fields; - - ret = nxt_http_fields_process(peer->fields, - &nxt_h1p_peer_fields_hash, r); - if (nxt_slow_path(ret != NXT_OK)) { - peer->status = NXT_HTTP_INTERNAL_SERVER_ERROR; - break; - } - - c->read = NULL; - - peer->header_received = 1; - - h1p = peer->proto.h1; - - if (h1p->chunked) { - if (r->resp.content_length != NULL) { - peer->status = NXT_HTTP_BAD_GATEWAY; - break; - } - - h1p->chunked_parse.mem_pool = c->mem_pool; - - } else if (r->resp.content_length_n > 0) { - h1p->remainder = r->resp.content_length_n; - } - - if (nxt_buf_mem_used_size(&b->mem) != 0) { - nxt_h1p_peer_body_process(task, peer, b); - return; - } - - r->state->ready_handler(task, r, peer); - return; - - case NXT_AGAIN: - if (nxt_buf_mem_free_size(&b->mem) != 0) { - nxt_conn_read(task->thread->engine, c); - return; - } - - /* Fall through. */ - - default: - case NXT_ERROR: - case NXT_HTTP_PARSE_INVALID: - case NXT_HTTP_PARSE_UNSUPPORTED_VERSION: - case NXT_HTTP_PARSE_TOO_LARGE_FIELD: - peer->status = NXT_HTTP_BAD_GATEWAY; - break; - } - - nxt_http_proxy_buf_mem_free(task, r, b); - - r->state->error_handler(task, r, peer); -} - - -static nxt_int_t -nxt_h1p_peer_header_parse(nxt_http_peer_t *peer, nxt_buf_mem_t *bm) -{ - u_char *p; - size_t length; - nxt_int_t status; - - if (peer->status < 0) { - length = nxt_buf_mem_used_size(bm); - - if (nxt_slow_path(length < 12)) { - return NXT_AGAIN; - } - - p = bm->pos; - - if (nxt_slow_path(memcmp(p, "HTTP/1.", 7) != 0 - || (p[7] != '0' && p[7] != '1'))) - { - return NXT_ERROR; - } - - status = nxt_int_parse(&p[9], 3); - - if (nxt_slow_path(status < 0)) { - return NXT_ERROR; - } - - p += 12; - length -= 12; - - p = memchr(p, '\n', length); - - if (nxt_slow_path(p == NULL)) { - return NXT_AGAIN; - } - - bm->pos = p + 1; - peer->status = status; - } - - return nxt_http_parse_fields(&peer->proto.h1->parser, bm); -} - - -static void -nxt_h1p_peer_read(nxt_task_t *task, nxt_http_peer_t *peer) -{ - nxt_conn_t *c; - - nxt_debug(task, "h1p peer read"); - - c = peer->proto.h1->conn; - c->read_state = &nxt_h1p_peer_read_state; - - nxt_conn_read(task->thread->engine, c); -} - - -static const nxt_conn_state_t nxt_h1p_peer_read_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_peer_read_done, - .close_handler = nxt_h1p_peer_closed, - .error_handler = nxt_h1p_peer_error, - - .io_read_handler = nxt_h1p_peer_io_read_handler, - - .timer_handler = nxt_h1p_peer_read_timeout, - .timer_value = nxt_h1p_peer_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, proxy_read_timeout), - .timer_autoreset = 1, -}; - - -static void -nxt_h1p_peer_read_done(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *out; - nxt_conn_t *c; - nxt_http_peer_t *peer; - - c = obj; - peer = data; - - nxt_debug(task, "h1p peer read done"); - - out = c->read; - c->read = NULL; - - nxt_h1p_peer_body_process(task, peer, out); -} - - -static void -nxt_h1p_peer_body_process(nxt_task_t *task, nxt_http_peer_t *peer, - nxt_buf_t *out) -{ - size_t length; - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - - h1p = peer->proto.h1; - - if (h1p->chunked) { - out = nxt_http_chunk_parse(task, &h1p->chunked_parse, out); - - if (h1p->chunked_parse.chunk_error || h1p->chunked_parse.error) { - peer->status = NXT_HTTP_BAD_GATEWAY; - r = peer->request; - r->state->error_handler(task, r, peer); - return; - } - - if (h1p->chunked_parse.last) { - nxt_buf_chain_add(&out, nxt_http_buf_last(peer->request)); - peer->closed = 1; - } - - } else if (h1p->remainder > 0) { - length = nxt_buf_chain_length(out); - h1p->remainder -= length; - } - - peer->body = out; - - r = peer->request; - r->state->ready_handler(task, r, peer); -} - - -static void -nxt_h1p_peer_closed(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - peer = data; - - nxt_debug(task, "h1p peer closed"); - - r = peer->request; - - if (peer->header_received) { - peer->body = nxt_http_buf_last(r); - peer->closed = 1; - r->inconsistent = (peer->proto.h1->remainder != 0); - - r->state->ready_handler(task, r, peer); - - } else { - peer->status = NXT_HTTP_BAD_GATEWAY; - - r->state->error_handler(task, r, peer); - } -} - - -static void -nxt_h1p_peer_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - peer = data; - - nxt_debug(task, "h1p peer error"); - - peer->status = NXT_HTTP_BAD_GATEWAY; - - r = peer->request; - r->state->error_handler(task, r, peer); -} - - -static void -nxt_h1p_peer_send_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - timer = obj; - - nxt_debug(task, "h1p peer send timeout"); - - c = nxt_write_timer_conn(timer); - c->block_write = 1; - c->block_read = 1; - - peer = c->socket.data; - peer->status = NXT_HTTP_GATEWAY_TIMEOUT; - - r = peer->request; - r->state->error_handler(task, r, peer); -} - - -static void -nxt_h1p_peer_read_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - timer = obj; - - nxt_debug(task, "h1p peer read timeout"); - - c = nxt_read_timer_conn(timer); - c->block_write = 1; - c->block_read = 1; - - peer = c->socket.data; - peer->status = NXT_HTTP_GATEWAY_TIMEOUT; - - r = peer->request; - r->state->error_handler(task, r, peer); -} - - -static nxt_msec_t -nxt_h1p_peer_timer_value(nxt_conn_t *c, uintptr_t data) -{ - nxt_http_peer_t *peer; - - peer = c->socket.data; - - return nxt_value_at(nxt_msec_t, peer->request->conf->socket_conf, data); -} - - -static void -nxt_h1p_peer_close(nxt_task_t *task, nxt_http_peer_t *peer) -{ - nxt_conn_t *c; - - nxt_debug(task, "h1p peer close"); - - peer->closed = 1; - - c = peer->proto.h1->conn; - task = &c->task; - c->socket.task = task; - c->read_timer.task = task; - c->write_timer.task = task; - - if (c->socket.fd != -1) { - c->write_state = &nxt_h1p_peer_close_state; - - nxt_conn_close(task->thread->engine, c); - - } else { - nxt_h1p_peer_free(task, c, NULL); - } -} - - -static const nxt_conn_state_t nxt_h1p_peer_close_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_peer_free, -}; - - -static void -nxt_h1p_peer_free(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "h1p peer free"); - - nxt_conn_free(task, c); -} - - -static nxt_int_t -nxt_h1p_peer_transfer_encoding(void *ctx, nxt_http_field_t *field, - uintptr_t data) -{ - nxt_http_request_t *r; - - r = ctx; - field->skip = 1; - - if (field->value_length == 7 - && memcmp(field->value, "chunked", 7) == 0) - { - r->peer->proto.h1->chunked = 1; - } - - return NXT_OK; -} diff --git a/src/nxt_h1proto.h b/src/nxt_h1proto.h deleted file mode 100644 index b324db8d..00000000 --- a/src/nxt_h1proto.h +++ /dev/null @@ -1,57 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_H1PROTO_H_INCLUDED_ -#define _NXT_H1PROTO_H_INCLUDED_ - - -#include -#include -#include -#include - - -typedef struct nxt_h1p_websocket_timer_s nxt_h1p_websocket_timer_t; - - -struct nxt_h1proto_s { - nxt_http_request_parse_t parser; - nxt_http_chunk_parse_t chunked_parse; - nxt_off_t remainder; - - uint8_t nbuffers; - uint8_t header_buffer_slot; - uint8_t large_buffer_slot; - uint8_t keepalive; /* 1 bit */ - uint8_t chunked; /* 1 bit */ - uint8_t websocket; /* 1 bit */ - uint8_t connection_upgrade; /* 1 bit */ - uint8_t upgrade_websocket; /* 1 bit */ - uint8_t websocket_version_ok; /* 1 bit */ - nxt_http_te_t transfer_encoding:8; /* 2 bits */ - - uint8_t websocket_cont_expected; /* 1 bit */ - uint8_t websocket_closed; /* 1 bit */ - - uint32_t header_size; - - nxt_http_field_t *websocket_key; - nxt_h1p_websocket_timer_t *websocket_timer; - - nxt_http_request_t *request; - nxt_buf_t *buffers; - - nxt_buf_t **conn_write_tail; - /* - * All fields before the conn field will - * be zeroed in a keep-alive connection. - */ - nxt_conn_t *conn; -}; - -#define nxt_h1p_is_http11(h1p) \ - ((h1p)->parser.version.s.minor != '0') - -#endif /* _NXT_H1PROTO_H_INCLUDED_ */ diff --git a/src/nxt_h1proto_websocket.c b/src/nxt_h1proto_websocket.c deleted file mode 100644 index 7be190f6..00000000 --- a/src/nxt_h1proto_websocket.c +++ /dev/null @@ -1,702 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include -#include - -typedef struct { - uint16_t code; - uint8_t args; - nxt_str_t desc; -} nxt_ws_error_t; - -static void nxt_h1p_conn_ws_keepalive(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_ws_frame_header_read(nxt_task_t *task, void *obj, - void *data); -static void nxt_h1p_conn_ws_keepalive_disable(nxt_task_t *task, - nxt_h1proto_t *h1p); -static void nxt_h1p_conn_ws_keepalive_enable(nxt_task_t *task, - nxt_h1proto_t *h1p); -static void nxt_h1p_conn_ws_frame_process(nxt_task_t *task, nxt_conn_t *c, - nxt_h1proto_t *h1p, nxt_websocket_header_t *wsh); -static void nxt_h1p_conn_ws_error(nxt_task_t *task, void *obj, void *data); -static ssize_t nxt_h1p_ws_io_read_handler(nxt_task_t *task, nxt_conn_t *c); -static void nxt_h1p_conn_ws_timeout(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_ws_frame_payload_read(nxt_task_t *task, void *obj, - void *data); -static void hxt_h1p_send_ws_error(nxt_task_t *task, nxt_http_request_t *r, - const nxt_ws_error_t *err, ...); -static void nxt_h1p_conn_ws_error_sent(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_ws_pong(nxt_task_t *task, void *obj, void *data); - -static const nxt_conn_state_t nxt_h1p_read_ws_frame_header_state; -static const nxt_conn_state_t nxt_h1p_read_ws_frame_payload_state; - -static const nxt_ws_error_t nxt_ws_err_out_of_memory = { - NXT_WEBSOCKET_CR_INTERNAL_SERVER_ERROR, - 0, nxt_string("Out of memory") }; -static const nxt_ws_error_t nxt_ws_err_too_big = { - NXT_WEBSOCKET_CR_MESSAGE_TOO_BIG, - 1, nxt_string("Message too big: %uL bytes") }; -static const nxt_ws_error_t nxt_ws_err_invalid_close_code = { - NXT_WEBSOCKET_CR_PROTOCOL_ERROR, - 1, nxt_string("Close code %ud is not valid") }; -static const nxt_ws_error_t nxt_ws_err_going_away = { - NXT_WEBSOCKET_CR_GOING_AWAY, - 0, nxt_string("Remote peer is going away") }; -static const nxt_ws_error_t nxt_ws_err_not_masked = { - NXT_WEBSOCKET_CR_PROTOCOL_ERROR, - 0, nxt_string("Not masked client frame") }; -static const nxt_ws_error_t nxt_ws_err_ctrl_fragmented = { - NXT_WEBSOCKET_CR_PROTOCOL_ERROR, - 0, nxt_string("Fragmented control frame") }; -static const nxt_ws_error_t nxt_ws_err_ctrl_too_big = { - NXT_WEBSOCKET_CR_PROTOCOL_ERROR, - 1, nxt_string("Control frame too big: %uL bytes") }; -static const nxt_ws_error_t nxt_ws_err_invalid_close_len = { - NXT_WEBSOCKET_CR_PROTOCOL_ERROR, - 0, nxt_string("Close frame payload length cannot be 1") }; -static const nxt_ws_error_t nxt_ws_err_invalid_opcode = { - NXT_WEBSOCKET_CR_PROTOCOL_ERROR, - 1, nxt_string("Unrecognized opcode %ud") }; -static const nxt_ws_error_t nxt_ws_err_cont_expected = { - NXT_WEBSOCKET_CR_PROTOCOL_ERROR, - 1, nxt_string("Continuation expected, but %ud opcode received") }; - -void -nxt_h1p_websocket_first_frame_start(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *ws_frame) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - nxt_h1proto_t *h1p; - nxt_websocket_conf_t *websocket_conf; - - nxt_debug(task, "h1p ws first frame start"); - - h1p = r->proto.h1; - c = h1p->conn; - - if (!c->tcp_nodelay) { - nxt_conn_tcp_nodelay_on(task, c); - } - - websocket_conf = &r->conf->socket_conf->websocket_conf; - - if (nxt_slow_path(websocket_conf->keepalive_interval != 0)) { - h1p->websocket_timer = nxt_mp_zget(c->mem_pool, - sizeof(nxt_h1p_websocket_timer_t)); - if (nxt_slow_path(h1p->websocket_timer == NULL)) { - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_out_of_memory); - return; - } - - h1p->websocket_timer->keepalive_interval = - websocket_conf->keepalive_interval; - h1p->websocket_timer->h1p = h1p; - - timer = &h1p->websocket_timer->timer; - timer->task = &c->task; - timer->work_queue = &task->thread->engine->fast_work_queue; - timer->log = &c->log; - timer->bias = NXT_TIMER_DEFAULT_BIAS; - timer->handler = nxt_h1p_conn_ws_keepalive; - } - - nxt_h1p_websocket_frame_start(task, r, ws_frame); -} - - -void -nxt_h1p_websocket_frame_start(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *ws_frame) -{ - size_t size; - nxt_buf_t *in; - nxt_conn_t *c; - nxt_h1proto_t *h1p; - - nxt_debug(task, "h1p ws frame start"); - - h1p = r->proto.h1; - - if (nxt_slow_path(h1p->websocket_closed)) { - return; - } - - c = h1p->conn; - c->read = ws_frame; - - nxt_h1p_complete_buffers(task, h1p, 0); - - in = c->read; - c->read_state = &nxt_h1p_read_ws_frame_header_state; - - if (in == NULL) { - nxt_conn_read(task->thread->engine, c); - nxt_h1p_conn_ws_keepalive_enable(task, h1p); - - } else { - size = nxt_buf_mem_used_size(&in->mem); - - nxt_debug(task, "h1p read client ws frame"); - - nxt_memmove(in->mem.start, in->mem.pos, size); - - in->mem.pos = in->mem.start; - in->mem.free = in->mem.start + size; - - nxt_h1p_conn_ws_frame_header_read(task, c, h1p); - } -} - - -static void -nxt_h1p_conn_ws_keepalive(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *out; - nxt_timer_t *timer; - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - nxt_websocket_header_t *wsh; - nxt_h1p_websocket_timer_t *ws_timer; - - nxt_debug(task, "h1p conn ws keepalive"); - - timer = obj; - ws_timer = nxt_timer_data(timer, nxt_h1p_websocket_timer_t, timer); - h1p = ws_timer->h1p; - - r = h1p->request; - if (nxt_slow_path(r == NULL)) { - return; - } - - out = nxt_http_buf_mem(task, r, 2); - if (nxt_slow_path(out == NULL)) { - nxt_http_request_error_handler(task, r, r->proto.any); - return; - } - - out->mem.start[0] = 0; - out->mem.start[1] = 0; - - wsh = (nxt_websocket_header_t *) out->mem.start; - out->mem.free = nxt_websocket_frame_init(wsh, 0); - - wsh->fin = 1; - wsh->opcode = NXT_WEBSOCKET_OP_PING; - - nxt_http_request_send(task, r, out); -} - - -static const nxt_conn_state_t nxt_h1p_read_ws_frame_header_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_conn_ws_frame_header_read, - .close_handler = nxt_h1p_conn_ws_error, - .error_handler = nxt_h1p_conn_ws_error, - - .io_read_handler = nxt_h1p_ws_io_read_handler, - - .timer_handler = nxt_h1p_conn_ws_timeout, - .timer_value = nxt_h1p_conn_request_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, websocket_conf.read_timeout), - .timer_autoreset = 1, -}; - - -static void -nxt_h1p_conn_ws_frame_header_read(nxt_task_t *task, void *obj, void *data) -{ - size_t size, hsize, frame_size, max_frame_size; - uint64_t payload_len; - nxt_conn_t *c; - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - nxt_event_engine_t *engine; - nxt_websocket_header_t *wsh; - - c = obj; - h1p = data; - - nxt_h1p_conn_ws_keepalive_disable(task, h1p); - - size = nxt_buf_mem_used_size(&c->read->mem); - - engine = task->thread->engine; - - if (size < 2) { - nxt_debug(task, "h1p conn ws frame header read %z", size); - - nxt_conn_read(engine, c); - nxt_h1p_conn_ws_keepalive_enable(task, h1p); - - return; - } - - wsh = (nxt_websocket_header_t *) c->read->mem.pos; - - hsize = nxt_websocket_frame_header_size(wsh); - - if (size < hsize) { - nxt_debug(task, "h1p conn ws frame header read %z < %z", size, hsize); - - nxt_conn_read(engine, c); - nxt_h1p_conn_ws_keepalive_enable(task, h1p); - - return; - } - - r = h1p->request; - if (nxt_slow_path(r == NULL)) { - return; - } - - r->ws_frame = c->read; - - if (nxt_slow_path(wsh->mask == 0)) { - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_not_masked); - return; - } - - if ((wsh->opcode & NXT_WEBSOCKET_OP_CTRL) != 0) { - if (nxt_slow_path(wsh->fin == 0)) { - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_ctrl_fragmented); - return; - } - - if (nxt_slow_path(wsh->opcode != NXT_WEBSOCKET_OP_PING - && wsh->opcode != NXT_WEBSOCKET_OP_PONG - && wsh->opcode != NXT_WEBSOCKET_OP_CLOSE)) - { - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_invalid_opcode, - wsh->opcode); - return; - } - - if (nxt_slow_path(wsh->payload_len > 125)) { - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_ctrl_too_big, - nxt_websocket_frame_payload_len(wsh)); - return; - } - - if (nxt_slow_path(wsh->opcode == NXT_WEBSOCKET_OP_CLOSE - && wsh->payload_len == 1)) - { - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_invalid_close_len); - return; - } - - } else { - if (h1p->websocket_cont_expected) { - if (nxt_slow_path(wsh->opcode != NXT_WEBSOCKET_OP_CONT)) { - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_cont_expected, - wsh->opcode); - return; - } - - } else { - if (nxt_slow_path(wsh->opcode != NXT_WEBSOCKET_OP_BINARY - && wsh->opcode != NXT_WEBSOCKET_OP_TEXT)) - { - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_invalid_opcode, - wsh->opcode); - return; - } - } - - h1p->websocket_cont_expected = !wsh->fin; - } - - max_frame_size = r->conf->socket_conf->websocket_conf.max_frame_size; - - payload_len = nxt_websocket_frame_payload_len(wsh); - - if (nxt_slow_path(hsize > max_frame_size - || payload_len > (max_frame_size - hsize))) - { - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_too_big, payload_len); - return; - } - - c->read_state = &nxt_h1p_read_ws_frame_payload_state; - - frame_size = payload_len + hsize; - - nxt_debug(task, "h1p conn ws frame header read: %z, %z", size, frame_size); - - if (frame_size <= size) { - nxt_h1p_conn_ws_frame_process(task, c, h1p, wsh); - - return; - } - - if (frame_size < (size_t) nxt_buf_mem_size(&c->read->mem)) { - c->read->mem.end = c->read->mem.start + frame_size; - - } else { - nxt_buf_t *b = nxt_buf_mem_alloc(c->mem_pool, frame_size - size, 0); - - c->read->next = b; - c->read = b; - } - - nxt_conn_read(engine, c); - nxt_h1p_conn_ws_keepalive_enable(task, h1p); -} - - -static void -nxt_h1p_conn_ws_keepalive_disable(nxt_task_t *task, nxt_h1proto_t *h1p) -{ - nxt_timer_t *timer; - - if (h1p->websocket_timer == NULL) { - return; - } - - timer = &h1p->websocket_timer->timer; - - if (nxt_slow_path(timer->handler != nxt_h1p_conn_ws_keepalive)) { - nxt_debug(task, "h1p ws keepalive disable: scheduled ws shutdown"); - return; - } - - nxt_timer_disable(task->thread->engine, timer); -} - - -static void -nxt_h1p_conn_ws_keepalive_enable(nxt_task_t *task, nxt_h1proto_t *h1p) -{ - nxt_timer_t *timer; - - if (h1p->websocket_timer == NULL) { - return; - } - - timer = &h1p->websocket_timer->timer; - - if (nxt_slow_path(timer->handler != nxt_h1p_conn_ws_keepalive)) { - nxt_debug(task, "h1p ws keepalive enable: scheduled ws shutdown"); - return; - } - - nxt_timer_add(task->thread->engine, timer, - h1p->websocket_timer->keepalive_interval); -} - - -static void -nxt_h1p_conn_ws_frame_process(nxt_task_t *task, nxt_conn_t *c, - nxt_h1proto_t *h1p, nxt_websocket_header_t *wsh) -{ - size_t hsize; - uint8_t *p, *mask; - uint16_t code; - nxt_http_request_t *r; - - r = h1p->request; - - c->read = NULL; - - if (nxt_slow_path(wsh->opcode == NXT_WEBSOCKET_OP_PING)) { - nxt_h1p_conn_ws_pong(task, r, NULL); - return; - } - - if (nxt_slow_path(wsh->opcode == NXT_WEBSOCKET_OP_CLOSE)) { - if (wsh->payload_len >= 2) { - hsize = nxt_websocket_frame_header_size(wsh); - mask = nxt_pointer_to(wsh, hsize - 4); - p = nxt_pointer_to(wsh, hsize); - - code = ((p[0] ^ mask[0]) << 8) + (p[1] ^ mask[1]); - - if (nxt_slow_path(code < 1000 || code >= 5000 - || (code > 1003 && code < 1007) - || (code > 1014 && code < 3000))) - { - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_invalid_close_code, - code); - return; - } - } - - h1p->websocket_closed = 1; - } - - r->state->ready_handler(task, r, NULL); -} - - -static void -nxt_h1p_conn_ws_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - - h1p = data; - - nxt_debug(task, "h1p conn ws error"); - - r = h1p->request; - - h1p->keepalive = 0; - - if (nxt_fast_path(r != NULL)) { - r->state->error_handler(task, r, h1p); - } -} - - -static ssize_t -nxt_h1p_ws_io_read_handler(nxt_task_t *task, nxt_conn_t *c) -{ - size_t size; - ssize_t n; - nxt_buf_t *b; - - b = c->read; - - if (b == NULL) { - /* Enough for control frame. */ - size = 10 + 125; - - b = nxt_buf_mem_alloc(c->mem_pool, size, 0); - if (nxt_slow_path(b == NULL)) { - c->socket.error = NXT_ENOMEM; - return NXT_ERROR; - } - } - - n = c->io->recvbuf(c, b); - - if (n > 0) { - c->read = b; - - } else { - c->read = NULL; - nxt_mp_free(c->mem_pool, b); - } - - return n; -} - - -static void -nxt_h1p_conn_ws_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - - timer = obj; - - nxt_debug(task, "h1p conn ws timeout"); - - c = nxt_read_timer_conn(timer); - c->block_read = 1; - /* - * Disable SO_LINGER off during socket closing - * to send "408 Request Timeout" error response. - */ - c->socket.timedout = 0; - - h1p = c->socket.data; - h1p->keepalive = 0; - - r = h1p->request; - if (nxt_slow_path(r == NULL)) { - return; - } - - hxt_h1p_send_ws_error(task, r, &nxt_ws_err_going_away); -} - - -static const nxt_conn_state_t nxt_h1p_read_ws_frame_payload_state - nxt_aligned(64) = -{ - .ready_handler = nxt_h1p_conn_ws_frame_payload_read, - .close_handler = nxt_h1p_conn_ws_error, - .error_handler = nxt_h1p_conn_ws_error, - - .timer_handler = nxt_h1p_conn_ws_timeout, - .timer_value = nxt_h1p_conn_request_timer_value, - .timer_data = offsetof(nxt_socket_conf_t, websocket_conf.read_timeout), - .timer_autoreset = 1, -}; - - -static void -nxt_h1p_conn_ws_frame_payload_read(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - nxt_event_engine_t *engine; - nxt_websocket_header_t *wsh; - - c = obj; - h1p = data; - - nxt_h1p_conn_ws_keepalive_disable(task, h1p); - - nxt_debug(task, "h1p conn ws frame read"); - - if (nxt_buf_mem_free_size(&c->read->mem) == 0) { - r = h1p->request; - if (nxt_slow_path(r == NULL)) { - return; - } - - wsh = (nxt_websocket_header_t *) r->ws_frame->mem.pos; - - nxt_h1p_conn_ws_frame_process(task, c, h1p, wsh); - - return; - } - - engine = task->thread->engine; - - nxt_conn_read(engine, c); - nxt_h1p_conn_ws_keepalive_enable(task, h1p); -} - - -static void -hxt_h1p_send_ws_error(nxt_task_t *task, nxt_http_request_t *r, - const nxt_ws_error_t *err, ...) -{ - u_char *p; - va_list args; - nxt_buf_t *out; - nxt_str_t desc; - nxt_websocket_header_t *wsh; - u_char buf[125]; - - if (nxt_slow_path(err->args)) { - va_start(args, err); - p = nxt_vsprintf(buf, buf + sizeof(buf), (char *) err->desc.start, - args); - va_end(args); - - desc.start = buf; - desc.length = p - buf; - - } else { - desc = err->desc; - } - - nxt_log(task, NXT_LOG_INFO, "websocket error %d: %V", err->code, &desc); - - out = nxt_http_buf_mem(task, r, 2 + sizeof(err->code) + desc.length); - if (nxt_slow_path(out == NULL)) { - nxt_http_request_error_handler(task, r, r->proto.any); - return; - } - - out->mem.start[0] = 0; - out->mem.start[1] = 0; - - wsh = (nxt_websocket_header_t *) out->mem.start; - p = nxt_websocket_frame_init(wsh, sizeof(err->code) + desc.length); - - wsh->fin = 1; - wsh->opcode = NXT_WEBSOCKET_OP_CLOSE; - - *p++ = (err->code >> 8) & 0xFF; - *p++ = err->code & 0xFF; - - out->mem.free = nxt_cpymem(p, desc.start, desc.length); - out->next = nxt_http_buf_last(r); - - if (out->next != NULL) { - out->next->completion_handler = nxt_h1p_conn_ws_error_sent; - } - - nxt_http_request_send(task, r, out); -} - - -static void -nxt_h1p_conn_ws_error_sent(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_request_t *r; - - r = data; - - nxt_debug(task, "h1p conn ws error sent"); - - r->state->error_handler(task, r, r->proto.any); -} - - -static void -nxt_h1p_conn_ws_pong(nxt_task_t *task, void *obj, void *data) -{ - uint8_t payload_len, i; - nxt_buf_t *b, *out, *next; - nxt_http_request_t *r; - nxt_websocket_header_t *wsh; - uint8_t mask[4]; - - nxt_debug(task, "h1p conn ws pong"); - - r = obj; - b = r->ws_frame; - - wsh = (nxt_websocket_header_t *) b->mem.pos; - payload_len = wsh->payload_len; - - b->mem.pos += 2; - - nxt_memcpy(mask, b->mem.pos, 4); - - b->mem.pos += 4; - - out = nxt_http_buf_mem(task, r, 2 + payload_len); - if (nxt_slow_path(out == NULL)) { - nxt_http_request_error_handler(task, r, r->proto.any); - return; - } - - out->mem.start[0] = 0; - out->mem.start[1] = 0; - - wsh = (nxt_websocket_header_t *) out->mem.start; - out->mem.free = nxt_websocket_frame_init(wsh, payload_len); - - wsh->fin = 1; - wsh->opcode = NXT_WEBSOCKET_OP_PONG; - - for (i = 0; i < payload_len; i++) { - while (nxt_buf_mem_used_size(&b->mem) == 0) { - next = b->next; - b->next = NULL; - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - b->completion_handler, task, b, b->parent); - - b = next; - } - - *out->mem.free++ = *b->mem.pos++ ^ mask[i % 4]; - } - - r->ws_frame = b; - - nxt_http_request_send(task, r, out); - - nxt_http_request_ws_frame_start(task, r, r->ws_frame); -} diff --git a/src/nxt_hash.h b/src/nxt_hash.h deleted file mode 100644 index 01c727d2..00000000 --- a/src/nxt_hash.h +++ /dev/null @@ -1,47 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_HASH_H_INCLUDED_ -#define _NXT_HASH_H_INCLUDED_ - - -typedef struct { - nxt_lvlhsh_t lvlhsh; - const nxt_lvlhsh_proto_t *proto; - void *pool; -} nxt_hash_t; - - -nxt_inline nxt_int_t -nxt_hash_find(nxt_hash_t *h, nxt_lvlhsh_query_t *lhq) -{ - lhq->proto = h->proto; - - return nxt_lvlhsh_find(&h->lvlhsh, lhq); -} - - -nxt_inline nxt_int_t -nxt_hash_insert(nxt_hash_t *h, nxt_lvlhsh_query_t *lhq) -{ - lhq->proto = h->proto; - lhq->pool = h->pool; - - return nxt_lvlhsh_insert(&h->lvlhsh, lhq); -} - - -nxt_inline nxt_int_t -nxt_hash_delete(nxt_hash_t *h, nxt_lvlhsh_query_t *lhq) -{ - lhq->proto = h->proto; - lhq->pool = h->pool; - - return nxt_lvlhsh_delete(&h->lvlhsh, lhq); -} - - -#endif /* _NXT_HASH_H_INCLUDED_ */ diff --git a/src/nxt_hpux_sendfile.c b/src/nxt_hpux_sendfile.c deleted file mode 100644 index df200b64..00000000 --- a/src/nxt_hpux_sendfile.c +++ /dev/null @@ -1,137 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -#ifdef NXT_TEST_BUILD_HPUX_SENDFILE - -ssize_t nxt_hpux_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, - size_t limit); - -static ssize_t nxt_sys_sendfile(int s, int fd, off_t offset, size_t nbytes, - const struct iovec *hdtrl, int flags) -{ - return -1; -} - -#else - -/* sendfile() is not declared if _XOPEN_SOURCE_EXTENDED is defined. */ - -sbsize_t sendfile(int s, int fd, off_t offset, bsize_t nbytes, - const struct iovec *hdtrl, int flags); - -#define nxt_sys_sendfile sendfile - -#endif - - -ssize_t -nxt_hpux_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, size_t limit) -{ - size_t file_size; - ssize_t n; - nxt_buf_t *fb; - nxt_err_t err; - nxt_uint_t nhd, ntr; - struct iovec iov[NXT_IOBUF_MAX], *hdtrl; - nxt_sendbuf_coalesce_t sb; - - sb.buf = b; - sb.iobuf = iov; - sb.nmax = NXT_IOBUF_MAX; - sb.sync = 0; - sb.size = 0; - sb.limit = limit; - - nhd = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); - - if (nhd == 0 && sb.sync) { - return 0; - } - - if (nhd > 1 || sb.buf == NULL || !nxt_buf_is_file(sb.buf)) { - return nxt_event_conn_io_writev(c, iov, nhd); - } - - fb = sb.buf; - - file_size = nxt_sendbuf_file_coalesce(&sb); - - if (file_size == 0) { - return nxt_event_conn_io_writev(c, iov, nhd); - } - - sb.iobuf = &iov[1]; - sb.nmax = 1; - - ntr = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); - - /* - * Disposal of surplus kernel operations - * if there are no headers and trailers. - */ - - if (nhd == 0) { - hdtrl = NULL; - iov[0].iov_base = NULL; - iov[0].iov_len = 0; - - } else { - hdtrl = iov; - } - - if (ntr == 0) { - iov[1].iov_base = NULL; - iov[1].iov_len = 0; - - } else { - hdtrl = iov; - } - - nxt_debug(c->socket.task, "sendfile(%d, %FD, @%O, %uz) hd:%ui tr:%ui", - c->socket.fd, fb->file->fd, fb->file_pos, file_size, - nhd, ntr); - - n = nxt_sys_sendfile(c->socket.fd, fb->file->fd, fb->file_pos, - file_size, hdtrl, 0); - - err = (n == -1) ? nxt_errno : 0; - - nxt_debug(c->socket.task, "sendfile(): %uz", n); - - if (n == -1) { - switch (err) { - - case NXT_EAGAIN: - c->socket.write_ready = 0; - break; - - case NXT_EINTR: - break; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "sendfile(%d, %FD, @%O, %uz) failed \"%FN\" hd:%ui tr:%ui", - c->socket.fd, fb->file_pos, file_size, &fb->file->name, - nhd, ntr); - - return NXT_ERROR; - } - - nxt_debug(c->socket.task, "sendfile() %E", err); - - return 0; - } - - if (n < (ssize_t) sb.size) { - c->socket.write_ready = 0; - } - - return n; -} diff --git a/src/nxt_http.h b/src/nxt_http.h deleted file mode 100644 index e812bd0d..00000000 --- a/src/nxt_http.h +++ /dev/null @@ -1,441 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_HTTP_H_INCLUDED_ -#define _NXT_HTTP_H_INCLUDED_ - -#include - - -typedef enum { - NXT_HTTP_UNSET = -1, - NXT_HTTP_INVALID = 0, - - NXT_HTTP_CONTINUE = 100, - NXT_HTTP_SWITCHING_PROTOCOLS = 101, - - NXT_HTTP_OK = 200, - NXT_HTTP_NO_CONTENT = 204, - - NXT_HTTP_MULTIPLE_CHOICES = 300, - NXT_HTTP_MOVED_PERMANENTLY = 301, - NXT_HTTP_FOUND = 302, - NXT_HTTP_SEE_OTHER = 303, - NXT_HTTP_NOT_MODIFIED = 304, - NXT_HTTP_TEMPORARY_REDIRECT = 307, - NXT_HTTP_PERMANENT_REDIRECT = 308, - - NXT_HTTP_BAD_REQUEST = 400, - NXT_HTTP_FORBIDDEN = 403, - NXT_HTTP_NOT_FOUND = 404, - NXT_HTTP_METHOD_NOT_ALLOWED = 405, - NXT_HTTP_REQUEST_TIMEOUT = 408, - NXT_HTTP_LENGTH_REQUIRED = 411, - NXT_HTTP_PAYLOAD_TOO_LARGE = 413, - NXT_HTTP_URI_TOO_LONG = 414, - NXT_HTTP_UPGRADE_REQUIRED = 426, - NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, - - NXT_HTTP_TO_HTTPS = 497, - - NXT_HTTP_INTERNAL_SERVER_ERROR = 500, - NXT_HTTP_NOT_IMPLEMENTED = 501, - NXT_HTTP_BAD_GATEWAY = 502, - NXT_HTTP_SERVICE_UNAVAILABLE = 503, - NXT_HTTP_GATEWAY_TIMEOUT = 504, - NXT_HTTP_VERSION_NOT_SUPPORTED = 505, - NXT_HTTP_SERVER_ERROR_MAX = 599, - - NXT_HTTP_STATUS_MAX = 999, -} nxt_http_status_t; - - -typedef enum { - NXT_HTTP_TE_NONE = 0, - NXT_HTTP_TE_CHUNKED = 1, - NXT_HTTP_TE_UNSUPPORTED = 2, -} nxt_http_te_t; - - -typedef enum { - NXT_HTTP_PROTO_H1 = 0, - NXT_HTTP_PROTO_H2, - NXT_HTTP_PROTO_DEVNULL, -} nxt_http_protocol_t; - - -typedef struct { - nxt_work_handler_t ready_handler; - nxt_work_handler_t error_handler; -} nxt_http_request_state_t; - - -typedef struct nxt_h1proto_s nxt_h1proto_t; - -struct nxt_h1p_websocket_timer_s { - nxt_timer_t timer; - nxt_h1proto_t *h1p; - nxt_msec_t keepalive_interval; -}; - - -typedef union { - void *any; - nxt_h1proto_t *h1; -} nxt_http_proto_t; - - -#define nxt_http_field_name_set(_field, _name) \ - do { \ - (_field)->name_length = nxt_length(_name); \ - (_field)->name = (u_char *) _name; \ - } while (0) - - -#define nxt_http_field_set(_field, _name, _value) \ - do { \ - (_field)->name_length = nxt_length(_name); \ - (_field)->value_length = nxt_length(_value); \ - (_field)->name = (u_char *) _name; \ - (_field)->value = (u_char *) _value; \ - } while (0) - - -typedef struct { - nxt_list_t *fields; - nxt_http_field_t *date; - nxt_http_field_t *content_type; - nxt_http_field_t *content_length; - nxt_off_t content_length_n; -} nxt_http_response_t; - - -typedef struct nxt_upstream_server_s nxt_upstream_server_t; - -typedef struct { - nxt_http_proto_t proto; - nxt_http_request_t *request; - nxt_upstream_server_t *server; - nxt_list_t *fields; - nxt_buf_t *body; - - nxt_http_status_t status:16; - nxt_http_protocol_t protocol:8; /* 2 bits */ - uint8_t header_received; /* 1 bit */ - uint8_t closed; /* 1 bit */ -} nxt_http_peer_t; - - -struct nxt_http_request_s { - nxt_http_proto_t proto; - nxt_socket_conf_joint_t *conf; - - nxt_mp_t *mem_pool; - - nxt_buf_t *body; - nxt_buf_t *ws_frame; - nxt_buf_t *out; - const nxt_http_request_state_t *state; - - nxt_nsec_t start_time; - - nxt_str_t host; - nxt_str_t server_name; - nxt_str_t request_line; - nxt_str_t target; - nxt_str_t version; - nxt_str_t *method; - nxt_str_t *path; - nxt_str_t *args; - - nxt_str_t args_decoded; - nxt_array_t *arguments; /* of nxt_http_name_value_t */ - nxt_array_t *cookies; /* of nxt_http_name_value_t */ - nxt_list_t *fields; - nxt_http_field_t *content_type; - nxt_http_field_t *content_length; - nxt_http_field_t *cookie; - nxt_http_field_t *referer; - nxt_http_field_t *user_agent; - nxt_http_field_t *authorization; - nxt_off_t content_length_n; - - nxt_sockaddr_t *remote; - nxt_sockaddr_t *local; - nxt_task_t task; - - nxt_timer_t timer; - void *timer_data; - - nxt_tstr_query_t *tstr_query; - nxt_tstr_cache_t tstr_cache; - - nxt_http_action_t *action; - void *req_rpc_data; - -#if (NXT_HAVE_REGEX) - nxt_regex_match_t *regex_match; -#endif - - nxt_http_peer_t *peer; - nxt_buf_t *last; - - nxt_queue_link_t app_link; /* nxt_app_t.ack_waiting_req */ - nxt_event_engine_t *engine; - nxt_work_t err_work; - - nxt_http_response_t resp; - - nxt_http_status_t status:16; - - uint8_t log_route; /* 1 bit */ - - uint8_t pass_count; /* 8 bits */ - uint8_t app_target; - nxt_http_protocol_t protocol:8; /* 2 bits */ - uint8_t tls; /* 1 bit */ - uint8_t logged; /* 1 bit */ - uint8_t header_sent; /* 1 bit */ - uint8_t inconsistent; /* 1 bit */ - uint8_t error; /* 1 bit */ - uint8_t websocket_handshake; /* 1 bit */ -}; - - -typedef struct { - uint16_t hash; - uint16_t name_length; - uint32_t value_length; - u_char *name; - u_char *value; -} nxt_http_name_value_t; - - -typedef enum { - NXT_HTTP_URI_ENCODING_NONE = 0, - NXT_HTTP_URI_ENCODING, - NXT_HTTP_URI_ENCODING_PLUS -} nxt_http_uri_encoding_t; - - -typedef struct nxt_http_route_s nxt_http_route_t; -typedef struct nxt_http_route_rule_s nxt_http_route_rule_t; -typedef struct nxt_http_route_addr_rule_s nxt_http_route_addr_rule_t; - - -typedef struct { - nxt_conf_value_t *rewrite; - nxt_conf_value_t *set_headers; - nxt_conf_value_t *pass; - nxt_conf_value_t *ret; - nxt_conf_value_t *location; - nxt_conf_value_t *proxy; - nxt_conf_value_t *share; - nxt_conf_value_t *index; - nxt_str_t chroot; - nxt_conf_value_t *follow_symlinks; - nxt_conf_value_t *traverse_mounts; - nxt_conf_value_t *types; - nxt_conf_value_t *fallback; -} nxt_http_action_conf_t; - - -struct nxt_http_action_s { - nxt_http_action_t *(*handler)(nxt_task_t *task, - nxt_http_request_t *r, - nxt_http_action_t *action); - union { - void *conf; - nxt_http_route_t *route; - nxt_upstream_t *upstream; - uint32_t upstream_number; - nxt_tstr_t *tstr; - nxt_str_t *pass; - } u; - - nxt_tstr_t *rewrite; - nxt_array_t *set_headers; /* of nxt_http_field_t */ - nxt_http_action_t *fallback; -}; - - -typedef struct { - void (*body_read)(nxt_task_t *task, nxt_http_request_t *r); - void (*local_addr)(nxt_task_t *task, nxt_http_request_t *r); - void (*header_send)(nxt_task_t *task, nxt_http_request_t *r, - nxt_work_handler_t body_handler, void *data); - void (*send)(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out); - nxt_off_t (*body_bytes_sent)(nxt_task_t *task, nxt_http_proto_t proto); - void (*discard)(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *last); - void (*close)(nxt_task_t *task, nxt_http_proto_t proto, - nxt_socket_conf_joint_t *joint); - - void (*peer_connect)(nxt_task_t *task, nxt_http_peer_t *peer); - void (*peer_header_send)(nxt_task_t *task, nxt_http_peer_t *peer); - void (*peer_header_read)(nxt_task_t *task, nxt_http_peer_t *peer); - void (*peer_read)(nxt_task_t *task, nxt_http_peer_t *peer); - void (*peer_close)(nxt_task_t *task, nxt_http_peer_t *peer); - - void (*ws_frame_start)(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *ws_frame); -} nxt_http_proto_table_t; - - -typedef struct { - nxt_str_t *header; - uint32_t header_hash; -} nxt_http_forward_header_t; - - -struct nxt_http_forward_s { - nxt_http_forward_header_t client_ip; - nxt_http_forward_header_t protocol; - nxt_http_route_addr_rule_t *source; - uint8_t recursive; /* 1 bit */ -}; - - -#define NXT_HTTP_DATE_LEN nxt_length("Wed, 31 Dec 1986 16:40:00 GMT") - -nxt_inline u_char * -nxt_http_date(u_char *buf, struct tm *tm) -{ - static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", - "Sat" }; - - static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - return nxt_sprintf(buf, buf + NXT_HTTP_DATE_LEN, - "%s, %02d %s %4d %02d:%02d:%02d GMT", - week[tm->tm_wday], tm->tm_mday, - month[tm->tm_mon], tm->tm_year + 1900, - tm->tm_hour, tm->tm_min, tm->tm_sec); -} - - -nxt_int_t nxt_http_init(nxt_task_t *task); -nxt_int_t nxt_h1p_init(nxt_task_t *task); -nxt_int_t nxt_http_response_hash_init(nxt_task_t *task); - -void nxt_http_conn_init(nxt_task_t *task, void *obj, void *data); -nxt_http_request_t *nxt_http_request_create(nxt_task_t *task); -void nxt_http_request_error(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_status_t status); -void nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r); -void nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r, - nxt_work_handler_t body_handler, void *data); -void nxt_http_request_ws_frame_start(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *ws_frame); -void nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *out); -nxt_buf_t *nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, - size_t size); -nxt_buf_t *nxt_http_buf_last(nxt_http_request_t *r); -void nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data); -void nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data); - -nxt_int_t nxt_http_request_host(void *ctx, nxt_http_field_t *field, - uintptr_t data); -nxt_int_t nxt_http_request_field(void *ctx, nxt_http_field_t *field, - uintptr_t offset); -nxt_int_t nxt_http_request_content_length(void *ctx, nxt_http_field_t *field, - uintptr_t data); - -nxt_array_t *nxt_http_arguments_parse(nxt_http_request_t *r); -nxt_array_t *nxt_http_cookies_parse(nxt_http_request_t *r); - -int64_t nxt_http_field_hash(nxt_mp_t *mp, nxt_str_t *name, - nxt_bool_t case_sensitive, uint8_t encoding); -int64_t nxt_http_argument_hash(nxt_mp_t *mp, nxt_str_t *name); -int64_t nxt_http_header_hash(nxt_mp_t *mp, nxt_str_t *name); -int64_t nxt_http_cookie_hash(nxt_mp_t *mp, nxt_str_t *name); - -nxt_http_routes_t *nxt_http_routes_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *routes_conf); -nxt_http_action_t *nxt_http_action_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_str_t *pass); -nxt_int_t nxt_http_routes_resolve(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf); -nxt_int_t nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass, - nxt_str_t *segments, nxt_uint_t n); -nxt_http_action_t *nxt_http_pass_application(nxt_task_t *task, - nxt_router_conf_t *rtcf, nxt_str_t *name); -nxt_http_route_addr_rule_t *nxt_http_route_addr_rule_create( - nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv); -nxt_int_t nxt_http_route_addr_rule(nxt_http_request_t *r, - nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sockaddr); -nxt_http_route_rule_t *nxt_http_route_types_rule_create(nxt_task_t *task, - nxt_mp_t *mp, nxt_conf_value_t *types); -nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r, - nxt_http_route_rule_t *rule, u_char *start, size_t length); - -nxt_int_t nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *cv, nxt_http_action_t *action); -void nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *action); - -nxt_int_t nxt_upstreams_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *conf); -nxt_int_t nxt_upstreams_joint_create(nxt_router_temp_conf_t *tmcf, - nxt_upstream_t ***upstream_joint); - -nxt_int_t nxt_http_rewrite_init(nxt_router_conf_t *rtcf, - nxt_http_action_t *action, nxt_http_action_conf_t *acf); -nxt_int_t nxt_http_rewrite(nxt_task_t *task, nxt_http_request_t *r); - -nxt_int_t nxt_http_set_headers_init(nxt_router_conf_t *rtcf, - nxt_http_action_t *action, nxt_http_action_conf_t *acf); -nxt_int_t nxt_http_set_headers(nxt_http_request_t *r); - -nxt_int_t nxt_http_return_init(nxt_router_conf_t *rtcf, - nxt_http_action_t *action, nxt_http_action_conf_t *acf); - -nxt_int_t nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_http_action_t *action, nxt_http_action_conf_t *acf); -nxt_int_t nxt_http_static_mtypes_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash); -nxt_int_t nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash, - const nxt_str_t *exten, nxt_str_t *type); -nxt_str_t *nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, - const nxt_str_t *exten); - -nxt_http_action_t *nxt_http_application_handler(nxt_task_t *task, - nxt_http_request_t *r, nxt_http_action_t *action); -nxt_int_t nxt_upstream_find(nxt_upstreams_t *upstreams, nxt_str_t *name, - nxt_http_action_t *action); -nxt_http_action_t *nxt_upstream_proxy_handler(nxt_task_t *task, - nxt_http_request_t *r, nxt_upstream_t *upstream); - -nxt_int_t nxt_http_proxy_init(nxt_mp_t *mp, nxt_http_action_t *action, - nxt_http_action_conf_t *acf); -nxt_int_t nxt_http_proxy_date(void *ctx, nxt_http_field_t *field, - uintptr_t data); -nxt_int_t nxt_http_proxy_content_length(void *ctx, nxt_http_field_t *field, - uintptr_t data); -nxt_int_t nxt_http_proxy_skip(void *ctx, nxt_http_field_t *field, - uintptr_t data); -nxt_buf_t *nxt_http_proxy_buf_mem_alloc(nxt_task_t *task, nxt_http_request_t *r, - size_t size); -void nxt_http_proxy_buf_mem_free(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *b); - -extern nxt_time_string_t nxt_http_date_cache; - -extern nxt_lvlhsh_t nxt_response_fields_hash; - -extern const nxt_http_proto_table_t nxt_http_proto[]; - -void nxt_h1p_websocket_first_frame_start(nxt_task_t *task, - nxt_http_request_t *r, nxt_buf_t *ws_frame); -void nxt_h1p_websocket_frame_start(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *ws_frame); -void nxt_h1p_complete_buffers(nxt_task_t *task, nxt_h1proto_t *h1p, - nxt_bool_t all); -nxt_msec_t nxt_h1p_conn_request_timer_value(nxt_conn_t *c, uintptr_t data); - -extern const nxt_conn_state_t nxt_h1p_idle_close_state; - -#endif /* _NXT_HTTP_H_INCLUDED_ */ diff --git a/src/nxt_http_chunk_parse.c b/src/nxt_http_chunk_parse.c deleted file mode 100644 index b60bc801..00000000 --- a/src/nxt_http_chunk_parse.c +++ /dev/null @@ -1,272 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -#define NXT_HTTP_CHUNK_MIDDLE 0 -#define NXT_HTTP_CHUNK_END_ON_BORDER 1 -#define NXT_HTTP_CHUNK_END 2 - - -#define nxt_size_is_sufficient(cs) \ - (cs < ((__typeof__(cs)) 1 << (sizeof(cs) * 8 - 4))) - - -static nxt_int_t nxt_http_chunk_buffer(nxt_http_chunk_parse_t *hcp, - nxt_buf_t ***tail, nxt_buf_t *in); - - -static void nxt_http_chunk_buf_completion(nxt_task_t *task, void *obj, - void *data); - - -nxt_buf_t * -nxt_http_chunk_parse(nxt_task_t *task, nxt_http_chunk_parse_t *hcp, - nxt_buf_t *in) -{ - u_char c, ch; - nxt_int_t ret; - nxt_buf_t *b, *out, *next, **tail; - enum { - sw_start = 0, - sw_chunk_size, - sw_chunk_size_linefeed, - sw_chunk_end_newline, - sw_chunk_end_linefeed, - sw_chunk, - } state; - - next = NULL; - out = NULL; - tail = &out; - - state = hcp->state; - - for (b = in; b != NULL; b = next) { - - hcp->pos = b->mem.pos; - - while (hcp->pos < b->mem.free) { - /* - * The sw_chunk state is tested outside the switch - * to preserve hcp->pos and to not touch memory. - */ - if (state == sw_chunk) { - ret = nxt_http_chunk_buffer(hcp, &tail, b); - - if (ret == NXT_HTTP_CHUNK_MIDDLE) { - goto next; - } - - if (nxt_slow_path(ret == NXT_ERROR)) { - hcp->error = 1; - return out; - } - - state = sw_chunk_end_newline; - - if (ret == NXT_HTTP_CHUNK_END_ON_BORDER) { - goto next; - } - - /* ret == NXT_HTTP_CHUNK_END */ - } - - ch = *hcp->pos++; - - switch (state) { - - case sw_start: - state = sw_chunk_size; - - c = ch - '0'; - - if (c <= 9) { - hcp->chunk_size = c; - continue; - } - - c = (ch | 0x20) - 'a'; - - if (c <= 5) { - hcp->chunk_size = 0x0A + c; - continue; - } - - goto chunk_error; - - case sw_chunk_size: - - c = ch - '0'; - - if (c > 9) { - c = (ch | 0x20) - 'a'; - - if (nxt_fast_path(c <= 5)) { - c += 0x0A; - - } else if (nxt_fast_path(ch == '\r')) { - state = sw_chunk_size_linefeed; - continue; - - } else { - goto chunk_error; - } - } - - if (nxt_fast_path(nxt_size_is_sufficient(hcp->chunk_size))) { - hcp->chunk_size = (hcp->chunk_size << 4) + c; - continue; - } - - goto chunk_error; - - case sw_chunk_size_linefeed: - if (nxt_fast_path(ch == '\n')) { - - if (hcp->chunk_size != 0) { - state = sw_chunk; - continue; - } - - hcp->last = 1; - state = sw_chunk_end_newline; - continue; - } - - goto chunk_error; - - case sw_chunk_end_newline: - if (nxt_fast_path(ch == '\r')) { - state = sw_chunk_end_linefeed; - continue; - } - - goto chunk_error; - - case sw_chunk_end_linefeed: - if (nxt_fast_path(ch == '\n')) { - - if (!hcp->last) { - state = sw_start; - continue; - } - - return out; - } - - goto chunk_error; - - case sw_chunk: - /* - * This state is processed before the switch. - * It added here just to suppress a warning. - */ - continue; - } - } - - if (b->retain == 0) { - /* No chunk data was found in a buffer. */ - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - b->completion_handler, task, b, b->parent); - - } - - next: - - next = b->next; - b->next = NULL; - } - - hcp->state = state; - - return out; - -chunk_error: - - hcp->chunk_error = 1; - - return out; -} - - -static nxt_int_t -nxt_http_chunk_buffer(nxt_http_chunk_parse_t *hcp, nxt_buf_t ***tail, - nxt_buf_t *in) -{ - u_char *p; - size_t size; - nxt_buf_t *b; - - p = hcp->pos; - size = in->mem.free - p; - - b = nxt_buf_mem_alloc(hcp->mem_pool, 0, 0); - if (nxt_slow_path(b == NULL)) { - return NXT_ERROR; - } - - **tail = b; - *tail = &b->next; - - nxt_mp_retain(hcp->mem_pool); - b->completion_handler = nxt_http_chunk_buf_completion; - - b->parent = in; - in->retain++; - b->mem.pos = p; - b->mem.start = p; - - if (hcp->chunk_size < size) { - p += hcp->chunk_size; - hcp->pos = p; - - b->mem.free = p; - b->mem.end = p; - - return NXT_HTTP_CHUNK_END; - } - - b->mem.free = in->mem.free; - b->mem.end = in->mem.free; - - hcp->chunk_size -= size; - - if (hcp->chunk_size == 0) { - return NXT_HTTP_CHUNK_END_ON_BORDER; - } - - return NXT_HTTP_CHUNK_MIDDLE; -} - - -static void -nxt_http_chunk_buf_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_mp_t *mp; - nxt_buf_t *b, *next, *parent; - - b = obj; - - nxt_debug(task, "buf completion: %p %p", b, b->mem.start); - - nxt_assert(data == b->parent); - - do { - next = b->next; - parent = b->parent; - mp = b->data; - - nxt_mp_free(mp, b); - nxt_mp_release(mp); - - nxt_buf_parent_completion(task, parent); - - b = next; - } while (b != NULL); -} diff --git a/src/nxt_http_error.c b/src/nxt_http_error.c deleted file mode 100644 index 370b12db..00000000 --- a/src/nxt_http_error.c +++ /dev/null @@ -1,104 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -static void nxt_http_request_send_error_body(nxt_task_t *task, void *r, - void *data); - - -static const nxt_http_request_state_t nxt_http_request_send_error_body_state; - - -static const char error[] = - "" - "Error %03d" - "

Error %03d.\r\n"; - -/* Two %03d (4 chars) patterns are replaced by status code (3 chars). */ -#define NXT_HTTP_ERROR_LEN (nxt_length(error) - 2) - - -void -nxt_http_request_error(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_status_t status) -{ - nxt_http_field_t *content_type; - - nxt_debug(task, "http request error: %d", status); - - if (r->header_sent || r->error) { - goto fail; - } - - r->error = (status == NXT_HTTP_INTERNAL_SERVER_ERROR); - - r->status = status; - - r->resp.fields = nxt_list_create(r->mem_pool, 8, sizeof(nxt_http_field_t)); - if (nxt_slow_path(r->resp.fields == NULL)) { - goto fail; - } - - content_type = nxt_list_zero_add(r->resp.fields); - if (nxt_slow_path(content_type == NULL)) { - goto fail; - } - - nxt_http_field_set(content_type, "Content-Type", "text/html"); - - r->resp.content_length = NULL; - r->resp.content_length_n = NXT_HTTP_ERROR_LEN; - - r->state = &nxt_http_request_send_error_body_state; - - nxt_http_request_header_send(task, r, - nxt_http_request_send_error_body, NULL); - return; - -fail: - - nxt_http_request_error_handler(task, r, r->proto.any); -} - - -static const nxt_http_request_state_t nxt_http_request_send_error_body_state - nxt_aligned(64) = -{ - .error_handler = nxt_http_request_error_handler, -}; - - -static void -nxt_http_request_send_error_body(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *out; - nxt_http_request_t *r; - - r = obj; - - nxt_debug(task, "http request send error body"); - - out = nxt_http_buf_mem(task, r, NXT_HTTP_ERROR_LEN); - if (nxt_slow_path(out == NULL)) { - goto fail; - } - - out->mem.free = nxt_sprintf(out->mem.pos, out->mem.end, error, - r->status, r->status); - - out->next = nxt_http_buf_last(r); - - nxt_http_request_send(task, r, out); - - return; - -fail: - - nxt_http_request_error_handler(task, r, r->proto.any); -} diff --git a/src/nxt_http_js.c b/src/nxt_http_js.c deleted file mode 100644 index e3beb8b4..00000000 --- a/src/nxt_http_js.c +++ /dev/null @@ -1,389 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -static njs_int_t nxt_http_js_ext_uri(njs_vm_t *vm, njs_object_prop_t *prop, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval); -static njs_int_t nxt_http_js_ext_host(njs_vm_t *vm, njs_object_prop_t *prop, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval); -static njs_int_t nxt_http_js_ext_remote_addr(njs_vm_t *vm, - njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, - njs_value_t *retval); -static njs_int_t nxt_http_js_ext_get_args(njs_vm_t *vm, - njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, - njs_value_t *retval); -static njs_int_t nxt_http_js_ext_get_header(njs_vm_t *vm, - njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, - njs_value_t *retval); -static njs_int_t nxt_http_js_ext_keys_header(njs_vm_t *vm, - njs_value_t *value, njs_value_t *keys); -static njs_int_t nxt_http_js_ext_get_cookie(njs_vm_t *vm, - njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, - njs_value_t *retval); -static njs_int_t nxt_http_js_ext_keys_cookie(njs_vm_t *vm, njs_value_t *value, - njs_value_t *keys); -static njs_int_t nxt_http_js_ext_get_var(njs_vm_t *vm, njs_object_prop_t *prop, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval); - - -static njs_external_t nxt_http_js_proto[] = { - { - .flags = NJS_EXTERN_PROPERTY, - .name.string = njs_str("uri"), - .enumerable = 1, - .u.property = { - .handler = nxt_http_js_ext_uri, - } - }, - - { - .flags = NJS_EXTERN_PROPERTY, - .name.string = njs_str("host"), - .enumerable = 1, - .u.property = { - .handler = nxt_http_js_ext_host, - } - }, - - { - .flags = NJS_EXTERN_PROPERTY, - .name.string = njs_str("remoteAddr"), - .enumerable = 1, - .u.property = { - .handler = nxt_http_js_ext_remote_addr, - } - }, - - { - .flags = NJS_EXTERN_PROPERTY, - .name.string = njs_str("args"), - .enumerable = 1, - .u.property = { - .handler = nxt_http_js_ext_get_args, - } - }, - - { - .flags = NJS_EXTERN_OBJECT, - .name.string = njs_str("headers"), - .enumerable = 1, - .u.object = { - .enumerable = 1, - .prop_handler = nxt_http_js_ext_get_header, - .keys = nxt_http_js_ext_keys_header, - } - }, - - { - .flags = NJS_EXTERN_OBJECT, - .name.string = njs_str("cookies"), - .enumerable = 1, - .u.object = { - .enumerable = 1, - .prop_handler = nxt_http_js_ext_get_cookie, - .keys = nxt_http_js_ext_keys_cookie, - } - }, - - { - .flags = NJS_EXTERN_OBJECT, - .name.string = njs_str("vars"), - .u.object = { - .prop_handler = nxt_http_js_ext_get_var, - } - }, -}; - - -void -nxt_http_register_js_proto(nxt_js_conf_t *jcf) -{ - nxt_js_set_proto(jcf, nxt_http_js_proto, njs_nitems(nxt_http_js_proto)); -} - - -static njs_int_t -nxt_http_js_ext_uri(njs_vm_t *vm, njs_object_prop_t *prop, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval) -{ - nxt_http_request_t *r; - - r = njs_vm_external(vm, nxt_js_proto_id, value); - if (r == NULL) { - njs_value_undefined_set(retval); - return NJS_DECLINED; - } - - return njs_vm_value_string_set(vm, retval, r->path->start, r->path->length); -} - - -static njs_int_t -nxt_http_js_ext_host(njs_vm_t *vm, njs_object_prop_t *prop, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval) -{ - nxt_http_request_t *r; - - r = njs_vm_external(vm, nxt_js_proto_id, value); - if (r == NULL) { - njs_value_undefined_set(retval); - return NJS_DECLINED; - } - - return njs_vm_value_string_set(vm, retval, r->host.start, r->host.length); -} - - -static njs_int_t -nxt_http_js_ext_remote_addr(njs_vm_t *vm, njs_object_prop_t *prop, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval) -{ - nxt_http_request_t *r; - - r = njs_vm_external(vm, nxt_js_proto_id, value); - if (r == NULL) { - njs_value_undefined_set(retval); - return NJS_DECLINED; - } - - return njs_vm_value_string_set(vm, retval, - nxt_sockaddr_address(r->remote), - r->remote->address_length); -} - - -static njs_int_t -nxt_http_js_ext_get_args(njs_vm_t *vm, njs_object_prop_t *prop, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval) -{ - njs_int_t ret; - njs_value_t *args; - njs_opaque_value_t val; - nxt_http_request_t *r; - - r = njs_vm_external(vm, nxt_js_proto_id, value); - if (r == NULL) { - njs_value_undefined_set(retval); - return NJS_DECLINED; - } - - args = njs_value_arg(&val); - - ret = njs_vm_query_string_parse(vm, r->args->start, - r->args->start + r->args->length, args); - - if (ret == NJS_ERROR) { - return NJS_ERROR; - } - - njs_value_assign(retval, args); - - return NJS_OK; -} - - -static njs_int_t -nxt_http_js_ext_get_header(njs_vm_t *vm, njs_object_prop_t *prop, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval) -{ - njs_int_t rc; - njs_str_t key; - nxt_http_field_t *f; - nxt_http_request_t *r; - - r = njs_vm_external(vm, nxt_js_proto_id, value); - if (r == NULL) { - njs_value_undefined_set(retval); - return NJS_DECLINED; - } - - rc = njs_vm_prop_name(vm, prop, &key); - if (rc != NJS_OK) { - njs_value_undefined_set(retval); - return NJS_DECLINED; - } - - nxt_list_each(f, r->fields) { - - if (key.length == f->name_length - && memcmp(key.start, f->name, f->name_length) == 0) - { - return njs_vm_value_string_set(vm, retval, f->value, - f->value_length); - } - - } nxt_list_loop; - - njs_value_undefined_set(retval); - - return NJS_DECLINED; -} - - -static njs_int_t -nxt_http_js_ext_keys_header(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys) -{ - njs_int_t rc; - nxt_http_field_t *f; - nxt_http_request_t *r; - - rc = njs_vm_array_alloc(vm, keys, 4); - if (rc != NJS_OK) { - return NJS_ERROR; - } - - r = njs_vm_external(vm, nxt_js_proto_id, value); - if (r == NULL) { - return NJS_OK; - } - - nxt_list_each(f, r->fields) { - - value = njs_vm_array_push(vm, keys); - if (value == NULL) { - return NJS_ERROR; - } - - rc = njs_vm_value_string_set(vm, value, f->name, f->name_length); - if (rc != NJS_OK) { - return NJS_ERROR; - } - - } nxt_list_loop; - - return NJS_OK; -} - - -static njs_int_t -nxt_http_js_ext_get_cookie(njs_vm_t *vm, njs_object_prop_t *prop, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval) -{ - njs_int_t rc; - njs_str_t key; - nxt_array_t *cookies; - nxt_http_request_t *r; - nxt_http_name_value_t *nv, *start, *end; - - r = njs_vm_external(vm, nxt_js_proto_id, value); - if (r == NULL) { - njs_value_undefined_set(retval); - return NJS_DECLINED; - } - - rc = njs_vm_prop_name(vm, prop, &key); - if (rc != NJS_OK) { - njs_value_undefined_set(retval); - return NJS_DECLINED; - } - - cookies = nxt_http_cookies_parse(r); - if (nxt_slow_path(cookies == NULL)) { - return NJS_ERROR; - } - - start = cookies->elts; - end = start + cookies->nelts; - - for (nv = start; nv < end; nv++) { - - if (key.length == nv->name_length - && memcmp(key.start, nv->name, nv->name_length) == 0) - { - return njs_vm_value_string_set(vm, retval, nv->value, - nv->value_length); - } - } - - njs_value_undefined_set(retval); - - return NJS_DECLINED; -} - - -static njs_int_t -nxt_http_js_ext_keys_cookie(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys) -{ - njs_int_t rc; - nxt_array_t *cookies; - nxt_http_request_t *r; - nxt_http_name_value_t *nv, *start, *end; - - rc = njs_vm_array_alloc(vm, keys, 4); - if (rc != NJS_OK) { - return NJS_ERROR; - } - - r = njs_vm_external(vm, nxt_js_proto_id, value); - if (r == NULL) { - return NJS_OK; - } - - cookies = nxt_http_cookies_parse(r); - if (nxt_slow_path(cookies == NULL)) { - return NJS_ERROR; - } - - start = cookies->elts; - end = start + cookies->nelts; - - for (nv = start; nv < end; nv++) { - - value = njs_vm_array_push(vm, keys); - if (value == NULL) { - return NJS_ERROR; - } - - rc = njs_vm_value_string_set(vm, value, nv->name, nv->name_length); - if (rc != NJS_OK) { - return NJS_ERROR; - } - } - - return NJS_OK; -} - - -static njs_int_t -nxt_http_js_ext_get_var(njs_vm_t *vm, njs_object_prop_t *prop, - njs_value_t *value, njs_value_t *setval, njs_value_t *retval) -{ - njs_int_t rc; - njs_str_t key; - nxt_str_t name, *vv; - nxt_router_conf_t *rtcf; - nxt_http_request_t *r; - - r = njs_vm_external(vm, nxt_js_proto_id, value); - if (r == NULL) { - njs_value_undefined_set(retval); - return NJS_DECLINED; - } - - rc = njs_vm_prop_name(vm, prop, &key); - if (rc != NJS_OK) { - njs_value_undefined_set(retval); - return NJS_DECLINED; - } - - rtcf = r->conf->socket_conf->router_conf; - - name.start = key.start; - name.length = key.length; - - vv = nxt_var_get(&r->task, rtcf->tstr_state, &r->tstr_cache.var, &name, r); - - if (vv != NULL) { - return njs_vm_value_string_set(vm, retval, vv->start, vv->length); - } - - njs_value_undefined_set(retval); - - return NJS_DECLINED; -} diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c deleted file mode 100644 index 50cbda2b..00000000 --- a/src/nxt_http_parse.c +++ /dev/null @@ -1,1275 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - * Copyright (C) Valentin V. Bartenev - */ - -#include - - -static nxt_int_t nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, - u_char **pos, const u_char *end); -static nxt_int_t nxt_http_parse_request_line(nxt_http_request_parse_t *rp, - u_char **pos, const u_char *end); -static nxt_int_t nxt_http_parse_field_name(nxt_http_request_parse_t *rp, - u_char **pos, const u_char *end); -static nxt_int_t nxt_http_parse_field_value(nxt_http_request_parse_t *rp, - u_char **pos, const u_char *end); -static u_char *nxt_http_lookup_field_end(u_char *p, const u_char *end); -static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp, - u_char **pos, const u_char *end); - -static nxt_int_t nxt_http_field_hash_test(nxt_lvlhsh_query_t *lhq, void *data); - -static nxt_int_t nxt_http_field_hash_collision(nxt_lvlhsh_query_t *lhq, - void *data); - - -#define NXT_HTTP_MAX_FIELD_NAME 0xFF -#define NXT_HTTP_MAX_FIELD_VALUE NXT_INT32_T_MAX - -#define NXT_HTTP_FIELD_LVLHSH_SHIFT 5 - - -typedef enum { - NXT_HTTP_TARGET_SPACE = 1, /* \s */ - NXT_HTTP_TARGET_HASH, /* # */ - NXT_HTTP_TARGET_AGAIN, - NXT_HTTP_TARGET_BAD, /* \0\r\n */ - - /* traps below are used for extended check only */ - - NXT_HTTP_TARGET_SLASH = 5, /* / */ - NXT_HTTP_TARGET_DOT, /* . */ - NXT_HTTP_TARGET_ARGS_MARK, /* ? */ - NXT_HTTP_TARGET_QUOTE_MARK, /* % */ -} nxt_http_target_traps_e; - - -static const uint8_t nxt_http_target_chars[256] nxt_aligned(64) = { - /* \0 \n \r */ - 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - /* \s ! " # $ % & ' ( ) * + , - . / */ - 1, 0, 0, 2, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, - - /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, -}; - - -nxt_inline nxt_http_target_traps_e -nxt_http_parse_target(u_char **pos, const u_char *end) -{ - u_char *p; - nxt_uint_t trap; - - p = *pos; - - while (nxt_fast_path(end - p >= 10)) { - -#define nxt_target_test_char(ch) \ - \ - trap = nxt_http_target_chars[ch]; \ - \ - if (nxt_slow_path(trap != 0)) { \ - *pos = &(ch); \ - return trap; \ - } - -/* enddef */ - - nxt_target_test_char(p[0]); - nxt_target_test_char(p[1]); - nxt_target_test_char(p[2]); - nxt_target_test_char(p[3]); - - nxt_target_test_char(p[4]); - nxt_target_test_char(p[5]); - nxt_target_test_char(p[6]); - nxt_target_test_char(p[7]); - - nxt_target_test_char(p[8]); - nxt_target_test_char(p[9]); - - p += 10; - } - - while (p != end) { - nxt_target_test_char(*p); p++; - } - - return NXT_HTTP_TARGET_AGAIN; -} - - -nxt_int_t -nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mp_t *mp) -{ - rp->mem_pool = mp; - - rp->fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); - if (nxt_slow_path(rp->fields == NULL)) { - return NXT_ERROR; - } - - rp->field_hash = NXT_HTTP_FIELD_HASH_INIT; - - return NXT_OK; -} - - -nxt_int_t -nxt_http_parse_request(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b) -{ - nxt_int_t rc; - - if (rp->handler == NULL) { - rp->handler = &nxt_http_parse_request_line; - } - - do { - rc = rp->handler(rp, &b->pos, b->free); - } while (rc == NXT_OK); - - return rc; -} - - -nxt_int_t -nxt_http_parse_fields(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b) -{ - nxt_int_t rc; - - if (rp->handler == NULL) { - rp->handler = &nxt_http_parse_field_name; - } - - do { - rc = rp->handler(rp, &b->pos, b->free); - } while (rc == NXT_OK); - - return rc; -} - - -static nxt_int_t -nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, - const u_char *end) -{ - u_char *p, ch, *after_slash, *args; - nxt_int_t rc; - nxt_bool_t rest; - nxt_http_ver_t ver; - nxt_http_target_traps_e trap; - - static const nxt_http_ver_t http11 = { "HTTP/1.1" }; - static const nxt_http_ver_t http10 = { "HTTP/1.0" }; - - p = *pos; - - rp->method.start = p; - - for ( ;; ) { - - while (nxt_fast_path(end - p >= 8)) { - -#define nxt_method_test_char(ch) \ - \ - if (nxt_slow_path((ch) < 'A' || (ch) > 'Z')) { \ - p = &(ch); \ - goto method_unusual_char; \ - } - -/* enddef */ - - nxt_method_test_char(p[0]); - nxt_method_test_char(p[1]); - nxt_method_test_char(p[2]); - nxt_method_test_char(p[3]); - - nxt_method_test_char(p[4]); - nxt_method_test_char(p[5]); - nxt_method_test_char(p[6]); - nxt_method_test_char(p[7]); - - p += 8; - } - - while (p != end) { - nxt_method_test_char(*p); p++; - } - - rp->method.length = p - rp->method.start; - - return NXT_AGAIN; - - method_unusual_char: - - ch = *p; - - if (nxt_fast_path(ch == ' ')) { - rp->method.length = p - rp->method.start; - break; - } - - if (ch == '_' || ch == '-') { - p++; - continue; - } - - if (rp->method.start == p && (ch == '\r' || ch == '\n')) { - rp->method.start++; - p++; - continue; - } - - rp->method.length = p - rp->method.start; - - return NXT_HTTP_PARSE_INVALID; - } - - p++; - - if (nxt_slow_path(p == end)) { - return NXT_AGAIN; - } - - /* target */ - - ch = *p; - - if (nxt_slow_path(ch != '/')) { - rc = nxt_http_parse_unusual_target(rp, &p, end); - - if (nxt_slow_path(rc != NXT_OK)) { - return rc; - } - } - - rp->target_start = p; - - after_slash = p + 1; - args = NULL; - rest = 0; - -continue_target: - - for ( ;; ) { - p++; - - trap = nxt_http_parse_target(&p, end); - - switch (trap) { - case NXT_HTTP_TARGET_SLASH: - if (nxt_slow_path(after_slash == p)) { - rp->complex_target = 1; - goto rest_of_target; - } - - after_slash = p + 1; - continue; - - case NXT_HTTP_TARGET_DOT: - if (nxt_slow_path(after_slash == p)) { - rp->complex_target = 1; - goto rest_of_target; - } - - continue; - - case NXT_HTTP_TARGET_ARGS_MARK: - args = p + 1; - goto rest_of_target; - - case NXT_HTTP_TARGET_SPACE: - rp->target_end = p; - goto space_after_target; -#if 0 - case NXT_HTTP_TARGET_QUOTE_MARK: - rp->quoted_target = 1; - goto rest_of_target; -#else - case NXT_HTTP_TARGET_QUOTE_MARK: -#endif - case NXT_HTTP_TARGET_HASH: - rp->complex_target = 1; - goto rest_of_target; - - case NXT_HTTP_TARGET_AGAIN: - rp->target_end = p; - return NXT_AGAIN; - - case NXT_HTTP_TARGET_BAD: - rp->target_end = p; - return NXT_HTTP_PARSE_INVALID; - } - - nxt_unreachable(); - } - -rest_of_target: - - rest = 1; - - for ( ;; ) { - p++; - - trap = nxt_http_parse_target(&p, end); - - switch (trap) { - case NXT_HTTP_TARGET_SPACE: - rp->target_end = p; - goto space_after_target; - - case NXT_HTTP_TARGET_HASH: - rp->complex_target = 1; - continue; - - case NXT_HTTP_TARGET_AGAIN: - rp->target_end = p; - return NXT_AGAIN; - - case NXT_HTTP_TARGET_BAD: - rp->target_end = p; - return NXT_HTTP_PARSE_INVALID; - - default: - continue; - } - - nxt_unreachable(); - } - -space_after_target: - - if (nxt_slow_path(end - p < 10)) { - - do { - p++; - - if (p == end) { - return NXT_AGAIN; - } - - } while (*p == ' '); - - if (memcmp(p, "HTTP/", nxt_min(end - p, 5)) == 0) { - - switch (end - p) { - case 8: - if (p[7] < '0' || p[7] > '9') { - break; - } - /* Fall through. */ - case 7: - if (p[6] != '.') { - break; - } - /* Fall through. */ - case 6: - if (p[5] < '0' || p[5] > '9') { - break; - } - /* Fall through. */ - default: - return NXT_AGAIN; - } - } - - //rp->space_in_target = 1; - - if (rest) { - goto rest_of_target; - } - - goto continue_target; - } - - /* " HTTP/1.1\r\n" or " HTTP/1.1\n" */ - - if (nxt_slow_path(p[9] != '\r' && p[9] != '\n')) { - - if (p[1] == ' ') { - /* surplus space after tartet */ - p++; - goto space_after_target; - } - - //rp->space_in_target = 1; - - if (rest) { - goto rest_of_target; - } - - goto continue_target; - } - - nxt_memcpy(ver.str, &p[1], 8); - - if (nxt_fast_path(ver.ui64 == http11.ui64 - || ver.ui64 == http10.ui64 - || (memcmp(ver.str, "HTTP/1.", 7) == 0 - && ver.s.minor >= '0' && ver.s.minor <= '9'))) - { - rp->version.ui64 = ver.ui64; - - p += 9; - if (nxt_fast_path(*p == '\r')) { - - if (nxt_slow_path(p + 1 == end)) { - return NXT_AGAIN; - } - - if (nxt_slow_path(p[1] != '\n')) { - return NXT_HTTP_PARSE_INVALID; - } - - *pos = p + 2; - - } else { - *pos = p + 1; - } - - rp->request_line_end = p; - - if (rp->complex_target != 0 -#if 0 - || rp->quoted_target != 0 -#endif - ) - { - rc = nxt_http_parse_complex_target(rp); - - if (nxt_slow_path(rc != NXT_OK)) { - return rc; - } - - return nxt_http_parse_field_name(rp, pos, end); - } - - rp->path.start = rp->target_start; - - if (args != NULL) { - rp->path.length = args - rp->target_start - 1; - - rp->args.length = rp->target_end - args; - rp->args.start = args; - - } else { - rp->path.length = rp->target_end - rp->target_start; - } - - return nxt_http_parse_field_name(rp, pos, end); - } - - if (memcmp(ver.s.prefix, "HTTP/", 5) == 0 - && ver.s.major >= '0' && ver.s.major <= '9' - && ver.s.point == '.' - && ver.s.minor >= '0' && ver.s.minor <= '9') - { - rp->version.ui64 = ver.ui64; - return NXT_HTTP_PARSE_UNSUPPORTED_VERSION; - } - - return NXT_HTTP_PARSE_INVALID; -} - - -static nxt_int_t -nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, u_char **pos, - const u_char *end) -{ - u_char *p, ch; - - p = *pos; - - ch = *p; - - if (ch == ' ') { - /* skip surplus spaces before target */ - - do { - p++; - - if (nxt_slow_path(p == end)) { - return NXT_AGAIN; - } - - ch = *p; - - } while (ch == ' '); - - if (ch == '/') { - *pos = p; - return NXT_OK; - } - } - - /* absolute path or '*' */ - - /* TODO */ - - return NXT_HTTP_PARSE_INVALID; -} - - -static nxt_int_t -nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos, - const u_char *end) -{ - u_char *p, c; - size_t len; - uint32_t hash; - - static const u_char normal[256] nxt_aligned(64) = - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - /* \s ! " # $ % & ' ( ) * + , . / : ; < = > ? */ - "\0\1\0\1\1\1\1\1\0\0\1\1\0" "-" "\1\0" "0123456789" "\0\0\0\0\0\0" - - /* @ [ \ ] ^ _ */ - "\0" "abcdefghijklmnopqrstuvwxyz" "\0\0\0\1\1" - /* ` { | } ~ */ - "\1" "abcdefghijklmnopqrstuvwxyz" "\0\1\0\1\0" - - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - - p = *pos + rp->field_name.length; - hash = rp->field_hash; - - while (nxt_fast_path(end - p >= 8)) { - -#define nxt_field_name_test_char(ch) \ - \ - c = normal[ch]; \ - \ - if (nxt_slow_path(c <= '\1')) { \ - if (c == '\0') { \ - p = &(ch); \ - goto name_end; \ - } \ - \ - rp->skip_field = rp->discard_unsafe_fields; \ - c = ch; \ - } \ - \ - hash = nxt_http_field_hash_char(hash, c); - -/* enddef */ - - nxt_field_name_test_char(p[0]); - nxt_field_name_test_char(p[1]); - nxt_field_name_test_char(p[2]); - nxt_field_name_test_char(p[3]); - - nxt_field_name_test_char(p[4]); - nxt_field_name_test_char(p[5]); - nxt_field_name_test_char(p[6]); - nxt_field_name_test_char(p[7]); - - p += 8; - } - - while (nxt_fast_path(p != end)) { - nxt_field_name_test_char(*p); p++; - } - - len = p - *pos; - - if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) { - return NXT_HTTP_PARSE_TOO_LARGE_FIELD; - } - - rp->field_hash = hash; - rp->field_name.length = len; - - rp->handler = &nxt_http_parse_field_name; - - return NXT_AGAIN; - -name_end: - - if (nxt_fast_path(*p == ':')) { - if (nxt_slow_path(p == *pos)) { - return NXT_HTTP_PARSE_INVALID; - } - - len = p - *pos; - - if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) { - return NXT_HTTP_PARSE_TOO_LARGE_FIELD; - } - - rp->field_hash = hash; - - rp->field_name.length = len; - rp->field_name.start = *pos; - - *pos = p + 1; - - return nxt_http_parse_field_value(rp, pos, end); - } - - if (nxt_slow_path(p != *pos)) { - return NXT_HTTP_PARSE_INVALID; - } - - return nxt_http_parse_field_end(rp, pos, end); -} - - -static nxt_int_t -nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos, - const u_char *end) -{ - u_char *p, *start, ch; - size_t len; - - p = *pos; - - for ( ;; ) { - if (nxt_slow_path(p == end)) { - *pos = p; - rp->handler = &nxt_http_parse_field_value; - return NXT_AGAIN; - } - - ch = *p; - - if (ch != ' ' && ch != '\t') { - break; - } - - p++; - } - - start = p; - - p += rp->field_value.length; - - for ( ;; ) { - p = nxt_http_lookup_field_end(p, end); - - if (nxt_slow_path(p == end)) { - *pos = start; - - len = p - start; - - if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) { - return NXT_HTTP_PARSE_TOO_LARGE_FIELD; - } - - rp->field_value.length = len; - rp->handler = &nxt_http_parse_field_value; - return NXT_AGAIN; - } - - ch = *p; - - if (nxt_fast_path(ch == '\r' || ch == '\n')) { - break; - } - - if (ch != '\t') { - return NXT_HTTP_PARSE_INVALID; - } - - p++; - } - - *pos = p; - - if (nxt_fast_path(p != start)) { - - while (p[-1] == ' ' || p[-1] == '\t') { - p--; - } - } - - len = p - start; - - if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) { - return NXT_HTTP_PARSE_TOO_LARGE_FIELD; - } - - rp->field_value.length = len; - rp->field_value.start = start; - - return nxt_http_parse_field_end(rp, pos, end); -} - - -static u_char * -nxt_http_lookup_field_end(u_char *p, const u_char *end) -{ - while (nxt_fast_path(end - p >= 16)) { - -#define nxt_field_end_test_char(ch) \ - \ - if (nxt_slow_path((ch) < 0x20)) { \ - return &(ch); \ - } - -/* enddef */ - - nxt_field_end_test_char(p[0]); - nxt_field_end_test_char(p[1]); - nxt_field_end_test_char(p[2]); - nxt_field_end_test_char(p[3]); - - nxt_field_end_test_char(p[4]); - nxt_field_end_test_char(p[5]); - nxt_field_end_test_char(p[6]); - nxt_field_end_test_char(p[7]); - - nxt_field_end_test_char(p[8]); - nxt_field_end_test_char(p[9]); - nxt_field_end_test_char(p[10]); - nxt_field_end_test_char(p[11]); - - nxt_field_end_test_char(p[12]); - nxt_field_end_test_char(p[13]); - nxt_field_end_test_char(p[14]); - nxt_field_end_test_char(p[15]); - - p += 16; - } - - while (nxt_fast_path(end - p >= 4)) { - - nxt_field_end_test_char(p[0]); - nxt_field_end_test_char(p[1]); - nxt_field_end_test_char(p[2]); - nxt_field_end_test_char(p[3]); - - p += 4; - } - - switch (end - p) { - case 3: - nxt_field_end_test_char(*p); p++; - /* Fall through. */ - case 2: - nxt_field_end_test_char(*p); p++; - /* Fall through. */ - case 1: - nxt_field_end_test_char(*p); p++; - /* Fall through. */ - case 0: - break; - default: - nxt_unreachable(); - } - - return p; -} - - -static nxt_int_t -nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, - const u_char *end) -{ - u_char *p; - nxt_http_field_t *field; - - p = *pos; - - if (nxt_fast_path(*p == '\r')) { - p++; - - if (nxt_slow_path(p == end)) { - rp->handler = &nxt_http_parse_field_end; - return NXT_AGAIN; - } - } - - if (nxt_fast_path(*p == '\n')) { - *pos = p + 1; - - if (rp->field_name.length != 0) { - if (rp->skip_field) { - rp->skip_field = 0; - - } else { - field = nxt_list_add(rp->fields); - - if (nxt_slow_path(field == NULL)) { - return NXT_ERROR; - } - - field->hash = nxt_http_field_hash_end(rp->field_hash); - field->skip = 0; - field->hopbyhop = 0; - - field->name_length = rp->field_name.length; - field->value_length = rp->field_value.length; - field->name = rp->field_name.start; - field->value = rp->field_value.start; - } - - rp->field_hash = NXT_HTTP_FIELD_HASH_INIT; - - rp->field_name.length = 0; - rp->field_value.length = 0; - - rp->handler = &nxt_http_parse_field_name; - return NXT_OK; - } - - return NXT_DONE; - } - - return NXT_HTTP_PARSE_INVALID; -} - - -#define nxt_http_is_normal(c) \ - (nxt_fast_path((nxt_http_normal[c / 8] & (1 << (c & 7))) != 0)) - - -static const uint8_t nxt_http_normal[32] nxt_aligned(32) = { - - /* \0 \r \n */ - 0xFE, 0xDB, 0xFF, 0xFF, /* 1111 1110 1101 1011 1111 1111 1111 1111 */ - - /* '&%$ #"! /.-, |*)( 7654 3210 ?>=< ;:98 */ - 0xD6, 0x37, 0xFF, 0x7F, /* 1101 0110 0011 0111 1111 1111 0111 1111 */ - - /* GFED CBA@ ONML KJIH WVUT SRQP _^]\ [ZYX */ - 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - - /* gfed cba` onml kjih wvut srqp ~}| {zyx */ - 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - - 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ -}; - - -nxt_int_t -nxt_http_parse_complex_target(nxt_http_request_parse_t *rp) -{ - u_char *p, *u, c, ch, high, *args; - - enum { - sw_normal = 0, - sw_slash, - sw_dot, - sw_dot_dot, - sw_quoted, - sw_quoted_second, - } state, saved_state; - - nxt_prefetch(nxt_http_normal); - - state = sw_normal; - saved_state = sw_normal; - p = rp->target_start; - - u = nxt_mp_alloc(rp->mem_pool, rp->target_end - p + 1); - if (nxt_slow_path(u == NULL)) { - return NXT_ERROR; - } - - rp->path.length = 0; - rp->path.start = u; - - high = '\0'; - args = NULL; - - while (p < rp->target_end) { - - ch = *p++; - - again: - - switch (state) { - - case sw_normal: - - if (nxt_http_is_normal(ch)) { - *u++ = ch; - continue; - } - - switch (ch) { - case '/': - state = sw_slash; - *u++ = ch; - continue; - case '%': - saved_state = state; - state = sw_quoted; - continue; - case '?': - args = p; - goto args; - case '#': - goto done; - default: - *u++ = ch; - continue; - } - - break; - - case sw_slash: - - if (nxt_http_is_normal(ch)) { - state = sw_normal; - *u++ = ch; - continue; - } - - switch (ch) { - case '/': - continue; - case '.': - state = sw_dot; - *u++ = ch; - continue; - case '%': - saved_state = state; - state = sw_quoted; - continue; - case '?': - args = p; - goto args; - case '#': - goto done; - default: - state = sw_normal; - *u++ = ch; - continue; - } - - break; - - case sw_dot: - - if (nxt_http_is_normal(ch)) { - state = sw_normal; - *u++ = ch; - continue; - } - - switch (ch) { - case '/': - state = sw_slash; - u--; - continue; - case '.': - state = sw_dot_dot; - *u++ = ch; - continue; - case '%': - saved_state = state; - state = sw_quoted; - continue; - case '?': - u--; - args = p; - goto args; - case '#': - u--; - goto done; - default: - state = sw_normal; - *u++ = ch; - continue; - } - - break; - - case sw_dot_dot: - - if (nxt_http_is_normal(ch)) { - state = sw_normal; - *u++ = ch; - continue; - } - - switch (ch) { - - case '/': - case '?': - case '#': - u -= 5; - - for ( ;; ) { - if (u < rp->path.start) { - return NXT_HTTP_PARSE_INVALID; - } - - if (*u == '/') { - u++; - break; - } - - u--; - } - - if (ch == '?') { - args = p; - goto args; - } - - if (ch == '#') { - goto done; - } - - state = sw_slash; - break; - - case '%': - saved_state = state; - state = sw_quoted; - continue; - - default: - state = sw_normal; - *u++ = ch; - continue; - } - - break; - - case sw_quoted: - //rp->quoted_target = 1; - - if (ch >= '0' && ch <= '9') { - high = (u_char) (ch - '0'); - state = sw_quoted_second; - continue; - } - - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'f') { - high = (u_char) (c - 'a' + 10); - state = sw_quoted_second; - continue; - } - - return NXT_HTTP_PARSE_INVALID; - - case sw_quoted_second: - if (ch >= '0' && ch <= '9') { - ch = (u_char) ((high << 4) + ch - '0'); - - if (ch == '%') { - state = sw_normal; - *u++ = '%'; - - if (rp->encoded_slashes) { - *u++ = '2'; - *u++ = '5'; - } - - continue; - } - - if (ch == '#') { - state = sw_normal; - *u++ = '#'; - continue; - } - - if (ch == '\0') { - return NXT_HTTP_PARSE_INVALID; - } - - state = saved_state; - goto again; - } - - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'f') { - ch = (u_char) ((high << 4) + c - 'a' + 10); - - if (ch == '?') { - state = sw_normal; - *u++ = ch; - continue; - } - - if (ch == '/' && rp->encoded_slashes) { - state = sw_normal; - *u++ = '%'; - *u++ = '2'; - *u++ = p[-1]; /* 'f' or 'F' */ - continue; - } - - state = saved_state; - goto again; - } - - return NXT_HTTP_PARSE_INVALID; - } - } - - if (state >= sw_dot) { - if (state >= sw_quoted) { - return NXT_HTTP_PARSE_INVALID; - } - - /* "/." and "/.." must be normalized similar to "/./" and "/../". */ - ch = '/'; - goto again; - } - -args: - - for (/* void */; p < rp->target_end; p++) { - if (*p == '#') { - break; - } - } - - if (args != NULL) { - rp->args.length = p - args; - rp->args.start = args; - } - -done: - - rp->path.length = u - rp->path.start; - - return NXT_OK; -} - - -const nxt_lvlhsh_proto_t nxt_http_fields_hash_proto nxt_aligned(64) = { - NXT_LVLHSH_BUCKET_SIZE(64), - { NXT_HTTP_FIELD_LVLHSH_SHIFT, 0, 0, 0, 0, 0, 0, 0 }, - nxt_http_field_hash_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -static nxt_int_t -nxt_http_field_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_http_field_proc_t *field; - - field = data; - - if (nxt_strcasestr_eq(&lhq->key, &field->name)) { - return NXT_OK; - } - - return NXT_DECLINED; -} - - -static nxt_int_t -nxt_http_field_hash_collision(nxt_lvlhsh_query_t *lhq, void *data) -{ - return NXT_OK; -} - - -nxt_int_t -nxt_http_fields_hash(nxt_lvlhsh_t *hash, - nxt_http_field_proc_t items[], nxt_uint_t count) -{ - u_char ch; - uint32_t key; - nxt_str_t *name; - nxt_int_t ret; - nxt_uint_t i, j; - nxt_lvlhsh_query_t lhq; - - lhq.replace = 0; - lhq.proto = &nxt_http_fields_hash_proto; - - for (i = 0; i < count; i++) { - key = NXT_HTTP_FIELD_HASH_INIT; - name = &items[i].name; - - for (j = 0; j < name->length; j++) { - ch = nxt_lowcase(name->start[j]); - key = nxt_http_field_hash_char(key, ch); - } - - lhq.key_hash = nxt_http_field_hash_end(key) & 0xFFFF; - lhq.key = *name; - lhq.value = &items[i]; - - ret = nxt_lvlhsh_insert(hash, &lhq); - - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -nxt_uint_t -nxt_http_fields_hash_collisions(nxt_lvlhsh_t *hash, - nxt_http_field_proc_t items[], nxt_uint_t count, nxt_bool_t level) -{ - u_char ch; - uint32_t key, mask; - nxt_str_t *name; - nxt_uint_t colls, i, j; - nxt_lvlhsh_proto_t proto; - nxt_lvlhsh_query_t lhq; - - proto = nxt_http_fields_hash_proto; - proto.test = nxt_http_field_hash_collision; - - lhq.replace = 0; - lhq.proto = &proto; - - mask = level ? (1 << NXT_HTTP_FIELD_LVLHSH_SHIFT) - 1 : 0xFFFF; - - colls = 0; - - for (i = 0; i < count; i++) { - key = NXT_HTTP_FIELD_HASH_INIT; - name = &items[i].name; - - for (j = 0; j < name->length; j++) { - ch = nxt_lowcase(name->start[j]); - key = nxt_http_field_hash_char(key, ch); - } - - lhq.key_hash = nxt_http_field_hash_end(key) & mask; - lhq.value = &items[i]; - - if (nxt_lvlhsh_insert(hash, &lhq) == NXT_DECLINED) { - colls++; - } - } - - return colls; -} - - -nxt_int_t -nxt_http_fields_process(nxt_list_t *fields, nxt_lvlhsh_t *hash, void *ctx) -{ - nxt_int_t ret; - nxt_http_field_t *field; - - nxt_list_each(field, fields) { - - ret = nxt_http_field_process(field, hash, ctx); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - } nxt_list_loop; - - return NXT_OK; -} diff --git a/src/nxt_http_parse.h b/src/nxt_http_parse.h deleted file mode 100644 index fa95e842..00000000 --- a/src/nxt_http_parse.h +++ /dev/null @@ -1,159 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - * Copyright (C) Valentin V. Bartenev - */ - -#ifndef _NXT_HTTP_PARSER_H_INCLUDED_ -#define _NXT_HTTP_PARSER_H_INCLUDED_ - - -typedef enum { - NXT_HTTP_PARSE_INVALID = 1, - NXT_HTTP_PARSE_UNSUPPORTED_VERSION, - NXT_HTTP_PARSE_TOO_LARGE_FIELD, -} nxt_http_parse_error_t; - - -typedef struct nxt_http_request_parse_s nxt_http_request_parse_t; -typedef struct nxt_http_field_s nxt_http_field_t; -typedef struct nxt_http_fields_hash_s nxt_http_fields_hash_t; - - -typedef union { - u_char str[8]; - uint64_t ui64; - - struct { - u_char prefix[5]; - u_char major; - u_char point; - u_char minor; - } s; -} nxt_http_ver_t; - - -struct nxt_http_request_parse_s { - nxt_int_t (*handler)(nxt_http_request_parse_t *rp, - u_char **pos, const u_char *end); - - nxt_str_t method; - - u_char *target_start; - u_char *target_end; - u_char *request_line_end; - - nxt_str_t path; - nxt_str_t args; - - nxt_http_ver_t version; - - nxt_list_t *fields; - nxt_mp_t *mem_pool; - - nxt_str_t field_name; - nxt_str_t field_value; - - uint32_t field_hash; - - uint8_t skip_field; /* 1 bit */ - uint8_t discard_unsafe_fields; /* 1 bit */ - - /* target with "/." */ - uint8_t complex_target; /* 1 bit */ -#if 0 - /* target with "%" */ - uint8_t quoted_target; /* 1 bit */ - /* target with " " */ - uint8_t space_in_target; /* 1 bit */ -#endif - /* Preserve encoded '/' (%2F) and '%' (%25). */ - uint8_t encoded_slashes; /* 1 bit */ -}; - - -typedef nxt_int_t (*nxt_http_field_handler_t)(void *ctx, - nxt_http_field_t *field, - uintptr_t data); - - -typedef struct { - nxt_str_t name; - nxt_http_field_handler_t handler; - uintptr_t data; -} nxt_http_field_proc_t; - - -struct nxt_http_field_s { - uint16_t hash; - uint8_t skip:1; - uint8_t hopbyhop:1; - uint8_t name_length; - uint32_t value_length; - u_char *name; - u_char *value; -}; - - -typedef struct { - u_char *pos; - nxt_mp_t *mem_pool; - - uint64_t chunk_size; - - uint8_t state; - uint8_t last; /* 1 bit */ - uint8_t chunk_error; /* 1 bit */ - uint8_t error; /* 1 bit */ -} nxt_http_chunk_parse_t; - - -#define NXT_HTTP_FIELD_HASH_INIT 159406U -#define nxt_http_field_hash_char(h, c) (((h) << 4) + (h) + (c)) -#define nxt_http_field_hash_end(h) (((h) >> 16) ^ (h)) - - -nxt_int_t nxt_http_parse_request_init(nxt_http_request_parse_t *rp, - nxt_mp_t *mp); -nxt_int_t nxt_http_parse_request(nxt_http_request_parse_t *rp, - nxt_buf_mem_t *b); -nxt_int_t nxt_http_parse_fields(nxt_http_request_parse_t *rp, - nxt_buf_mem_t *b); - -nxt_int_t nxt_http_fields_hash(nxt_lvlhsh_t *hash, - nxt_http_field_proc_t items[], nxt_uint_t count); -nxt_uint_t nxt_http_fields_hash_collisions(nxt_lvlhsh_t *hash, - nxt_http_field_proc_t items[], nxt_uint_t count, nxt_bool_t level); -nxt_int_t nxt_http_fields_process(nxt_list_t *fields, nxt_lvlhsh_t *hash, - void *ctx); - -nxt_int_t nxt_http_parse_complex_target(nxt_http_request_parse_t *rp); -nxt_buf_t *nxt_http_chunk_parse(nxt_task_t *task, nxt_http_chunk_parse_t *hcp, - nxt_buf_t *in); - - -extern const nxt_lvlhsh_proto_t nxt_http_fields_hash_proto; - -nxt_inline nxt_int_t -nxt_http_field_process(nxt_http_field_t *field, nxt_lvlhsh_t *hash, void *ctx) -{ - nxt_lvlhsh_query_t lhq; - nxt_http_field_proc_t *proc; - - lhq.proto = &nxt_http_fields_hash_proto; - - lhq.key_hash = field->hash; - lhq.key.length = field->name_length; - lhq.key.start = field->name; - - if (nxt_lvlhsh_find(hash, &lhq) != NXT_OK) { - return NXT_OK; - } - - proc = lhq.value; - - return proc->handler(ctx, field, proc->data); -} - - -#endif /* _NXT_HTTP_PARSER_H_INCLUDED_ */ diff --git a/src/nxt_http_proxy.c b/src/nxt_http_proxy.c deleted file mode 100644 index 6aa3aabb..00000000 --- a/src/nxt_http_proxy.c +++ /dev/null @@ -1,432 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -struct nxt_upstream_proxy_s { - nxt_sockaddr_t *sockaddr; - uint8_t protocol; -}; - - -static void nxt_http_proxy_server_get(nxt_task_t *task, - nxt_upstream_server_t *us); -static void nxt_http_proxy_upstream_ready(nxt_task_t *task, - nxt_upstream_server_t *us); -static void nxt_http_proxy_upstream_error(nxt_task_t *task, - nxt_upstream_server_t *us); -static nxt_http_action_t *nxt_http_proxy(nxt_task_t *task, - nxt_http_request_t *r, nxt_http_action_t *action); -static void nxt_http_proxy_header_send(nxt_task_t *task, void *obj, void *data); -static void nxt_http_proxy_header_sent(nxt_task_t *task, void *obj, void *data); -static void nxt_http_proxy_header_read(nxt_task_t *task, void *obj, void *data); -static void nxt_http_proxy_send_body(nxt_task_t *task, void *obj, void *data); -static void nxt_http_proxy_buf_mem_completion(nxt_task_t *task, void *obj, - void *data); -static void nxt_http_proxy_error(nxt_task_t *task, void *obj, void *data); - - -static const nxt_http_request_state_t nxt_http_proxy_header_send_state; -static const nxt_http_request_state_t nxt_http_proxy_header_sent_state; -static const nxt_http_request_state_t nxt_http_proxy_header_read_state; -static const nxt_http_request_state_t nxt_http_proxy_read_state; - - -static const nxt_upstream_server_proto_t nxt_upstream_simple_proto = { - .get = nxt_http_proxy_server_get, -}; - - -static const nxt_upstream_peer_state_t nxt_upstream_proxy_state = { - .ready = nxt_http_proxy_upstream_ready, - .error = nxt_http_proxy_upstream_error, -}; - - -nxt_int_t -nxt_http_proxy_init(nxt_mp_t *mp, nxt_http_action_t *action, - nxt_http_action_conf_t *acf) -{ - nxt_str_t name; - nxt_sockaddr_t *sa; - nxt_upstream_t *up; - nxt_upstream_proxy_t *proxy; - - sa = NULL; - nxt_conf_get_string(acf->proxy, &name); - - if (nxt_str_start(&name, "http://", 7)) { - name.length -= 7; - name.start += 7; - - sa = nxt_sockaddr_parse(mp, &name); - if (nxt_slow_path(sa == NULL)) { - return NXT_ERROR; - } - - sa->type = SOCK_STREAM; - } - - if (sa != NULL) { - up = nxt_mp_alloc(mp, sizeof(nxt_upstream_t)); - if (nxt_slow_path(up == NULL)) { - return NXT_ERROR; - } - - up->name.length = sa->length; - up->name.start = nxt_sockaddr_start(sa); - up->proto = &nxt_upstream_simple_proto; - - proxy = nxt_mp_alloc(mp, sizeof(nxt_upstream_proxy_t)); - if (nxt_slow_path(proxy == NULL)) { - return NXT_ERROR; - } - - proxy->sockaddr = sa; - proxy->protocol = NXT_HTTP_PROTO_H1; - up->type.proxy = proxy; - - action->u.upstream = up; - action->handler = nxt_http_proxy; - } - - return NXT_OK; -} - - -static nxt_http_action_t * -nxt_http_proxy(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *action) -{ - nxt_upstream_t *u; - - u = action->u.upstream; - - nxt_debug(task, "http proxy: \"%V\"", &u->name); - - return nxt_upstream_proxy_handler(task, r, u); -} - - -nxt_http_action_t * -nxt_upstream_proxy_handler(nxt_task_t *task, nxt_http_request_t *r, - nxt_upstream_t *upstream) -{ - nxt_http_peer_t *peer; - nxt_upstream_server_t *us; - - us = nxt_mp_zalloc(r->mem_pool, sizeof(nxt_upstream_server_t)); - if (nxt_slow_path(us == NULL)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - return NULL; - } - - peer = nxt_mp_zalloc(r->mem_pool, sizeof(nxt_http_peer_t)); - if (nxt_slow_path(peer == NULL)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - return NULL; - } - - peer->request = r; - r->peer = peer; - - nxt_mp_retain(r->mem_pool); - - us->state = &nxt_upstream_proxy_state; - us->peer.http = peer; - peer->server = us; - - us->upstream = upstream; - upstream->proto->get(task, us); - - return NULL; -} - - -static void -nxt_http_proxy_server_get(nxt_task_t *task, nxt_upstream_server_t *us) -{ - nxt_upstream_proxy_t *proxy; - - proxy = us->upstream->type.proxy; - - us->sockaddr = proxy->sockaddr; - us->protocol = proxy->protocol; - - us->state->ready(task, us); -} - - -static void -nxt_http_proxy_upstream_ready(nxt_task_t *task, nxt_upstream_server_t *us) -{ - nxt_http_peer_t *peer; - - peer = us->peer.http; - - peer->protocol = us->protocol; - - peer->request->state = &nxt_http_proxy_header_send_state; - - nxt_http_proto[peer->protocol].peer_connect(task, peer); -} - - -static void -nxt_http_proxy_upstream_error(nxt_task_t *task, nxt_upstream_server_t *us) -{ - nxt_http_request_t *r; - - r = us->peer.http->request; - - nxt_mp_release(r->mem_pool); - - nxt_http_request_error(task, r, NXT_HTTP_BAD_GATEWAY); -} - - -static const nxt_http_request_state_t nxt_http_proxy_header_send_state - nxt_aligned(64) = -{ - .ready_handler = nxt_http_proxy_header_send, - .error_handler = nxt_http_proxy_error, -}; - - -static void -nxt_http_proxy_header_send(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - r = obj; - peer = data; - r->state = &nxt_http_proxy_header_sent_state; - - nxt_http_proto[peer->protocol].peer_header_send(task, peer); -} - - -static const nxt_http_request_state_t nxt_http_proxy_header_sent_state - nxt_aligned(64) = -{ - .ready_handler = nxt_http_proxy_header_sent, - .error_handler = nxt_http_proxy_error, -}; - - -static void -nxt_http_proxy_header_sent(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - r = obj; - peer = data; - r->state = &nxt_http_proxy_header_read_state; - - nxt_http_proto[peer->protocol].peer_header_read(task, peer); -} - - -static const nxt_http_request_state_t nxt_http_proxy_header_read_state - nxt_aligned(64) = -{ - .ready_handler = nxt_http_proxy_header_read, - .error_handler = nxt_http_proxy_error, -}; - - -static void -nxt_http_proxy_header_read(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_peer_t *peer; - nxt_http_field_t *f, *field; - nxt_http_request_t *r; - - r = obj; - peer = data; - - r->status = peer->status; - - nxt_debug(task, "http proxy status: %d", peer->status); - - nxt_list_each(field, peer->fields) { - - nxt_debug(task, "http proxy header: \"%*s: %*s\"", - (size_t) field->name_length, field->name, - (size_t) field->value_length, field->value); - - if (!field->skip) { - f = nxt_list_add(r->resp.fields); - if (nxt_slow_path(f == NULL)) { - nxt_http_proxy_error(task, r, peer); - return; - } - - *f = *field; - } - - } nxt_list_loop; - - r->state = &nxt_http_proxy_read_state; - - nxt_http_request_header_send(task, r, nxt_http_proxy_send_body, peer); -} - - -static const nxt_http_request_state_t nxt_http_proxy_read_state - nxt_aligned(64) = -{ - .ready_handler = nxt_http_proxy_send_body, - .error_handler = nxt_http_proxy_error, -}; - - -static void -nxt_http_proxy_send_body(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *out; - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - r = obj; - peer = data; - out = peer->body; - - if (out != NULL) { - peer->body = NULL; - nxt_http_request_send(task, r, out); - } - - if (!peer->closed) { - nxt_http_proto[peer->protocol].peer_read(task, peer); - - } else { - nxt_http_proto[peer->protocol].peer_close(task, peer); - - nxt_mp_release(r->mem_pool); - } -} - - -nxt_buf_t * -nxt_http_proxy_buf_mem_alloc(nxt_task_t *task, nxt_http_request_t *r, - size_t size) -{ - nxt_buf_t *b; - - b = nxt_event_engine_buf_mem_alloc(task->thread->engine, size); - if (nxt_fast_path(b != NULL)) { - b->completion_handler = nxt_http_proxy_buf_mem_completion; - b->parent = r; - nxt_mp_retain(r->mem_pool); - - } else { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - } - - return b; -} - - -static void -nxt_http_proxy_buf_mem_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *b, *next; - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - b = obj; - r = data; - - peer = r->peer; - - do { - next = b->next; - - nxt_http_proxy_buf_mem_free(task, r, b); - - b = next; - } while (b != NULL); - - if (!peer->closed) { - nxt_http_proto[peer->protocol].peer_read(task, peer); - } -} - - -void -nxt_http_proxy_buf_mem_free(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *b) -{ - nxt_event_engine_buf_mem_free(task->thread->engine, b); - - nxt_mp_release(r->mem_pool); -} - - -static void -nxt_http_proxy_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_peer_t *peer; - nxt_http_request_t *r; - - r = obj; - peer = r->peer; - - nxt_http_proto[peer->protocol].peer_close(task, peer); - - nxt_mp_release(r->mem_pool); - - nxt_http_request_error(&r->task, r, peer->status); -} - - -nxt_int_t -nxt_http_proxy_date(void *ctx, nxt_http_field_t *field, uintptr_t data) -{ - nxt_http_request_t *r; - - r = ctx; - - r->resp.date = field; - - return NXT_OK; -} - - -nxt_int_t -nxt_http_proxy_content_length(void *ctx, nxt_http_field_t *field, - uintptr_t data) -{ - nxt_off_t n; - nxt_http_request_t *r; - - r = ctx; - - r->resp.content_length = field; - - n = nxt_off_t_parse(field->value, field->value_length); - - if (nxt_fast_path(n >= 0)) { - r->resp.content_length_n = n; - } - - return NXT_OK; -} - - -nxt_int_t -nxt_http_proxy_skip(void *ctx, nxt_http_field_t *field, uintptr_t data) -{ - field->skip = 1; - - return NXT_OK; -} diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c deleted file mode 100644 index f8d8d887..00000000 --- a/src/nxt_http_request.c +++ /dev/null @@ -1,1318 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp); -static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data); -static nxt_int_t nxt_http_request_forward(nxt_task_t *task, - nxt_http_request_t *r, nxt_http_forward_t *forward); -static void nxt_http_request_forward_client_ip(nxt_http_request_t *r, - nxt_http_forward_t *forward, nxt_array_t *fields); -static nxt_sockaddr_t *nxt_http_request_client_ip_sockaddr( - nxt_http_request_t *r, u_char *start, size_t len); -static void nxt_http_request_forward_protocol(nxt_http_request_t *r, - nxt_http_field_t *field); -static void nxt_http_request_ready(nxt_task_t *task, void *obj, void *data); -static void nxt_http_request_proto_info(nxt_task_t *task, - nxt_http_request_t *r); -static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, - void *data); -static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data); -static nxt_int_t nxt_http_request_access_log(nxt_task_t *task, - nxt_http_request_t *r, nxt_router_conf_t *rtcf); - -static u_char *nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, - struct tm *tm, size_t size, const char *format); - -static nxt_http_name_value_t *nxt_http_argument(nxt_array_t *array, - u_char *name, size_t name_length, uint32_t hash, u_char *start, - const u_char *end); -static nxt_int_t nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, - const u_char *end); -static nxt_http_name_value_t *nxt_http_cookie(nxt_array_t *array, u_char *name, - size_t name_length, u_char *start, const u_char *end); - - -#define NXT_HTTP_COOKIE_HASH \ - (nxt_http_field_hash_end( \ - nxt_http_field_hash_char( \ - nxt_http_field_hash_char( \ - nxt_http_field_hash_char( \ - nxt_http_field_hash_char( \ - nxt_http_field_hash_char( \ - nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT, \ - 'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF) - - -static const nxt_http_request_state_t nxt_http_request_init_state; -static const nxt_http_request_state_t nxt_http_request_body_state; - - -nxt_time_string_t nxt_http_date_cache = { - (nxt_atomic_uint_t) -1, - nxt_http_date_cache_handler, - NULL, - NXT_HTTP_DATE_LEN, - NXT_THREAD_TIME_GMT, - NXT_THREAD_TIME_SEC, -}; - - -nxt_int_t -nxt_http_init(nxt_task_t *task) -{ - nxt_int_t ret; - - ret = nxt_h1p_init(task); - - if (ret != NXT_OK) { - return ret; - } - - return nxt_http_response_hash_init(task); -} - - -nxt_int_t -nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data) -{ - nxt_int_t ret; - nxt_str_t host; - nxt_http_request_t *r; - - r = ctx; - - if (nxt_slow_path(r->host.start != NULL)) { - return NXT_HTTP_BAD_REQUEST; - } - - host.length = field->value_length; - host.start = field->value; - - ret = nxt_http_validate_host(&host, r->mem_pool); - - if (nxt_fast_path(ret == NXT_OK)) { - r->host = host; - } - - return ret; -} - - -static nxt_int_t -nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp) -{ - u_char *h, ch; - size_t i, dot_pos, host_length; - nxt_bool_t lowcase; - - enum { - sw_usual, - sw_literal, - sw_rest - } state; - - dot_pos = host->length; - host_length = host->length; - - h = host->start; - - lowcase = 0; - state = sw_usual; - - for (i = 0; i < host->length; i++) { - ch = h[i]; - - if (ch > ']') { - /* Short path. */ - continue; - } - - switch (ch) { - - case '.': - if (dot_pos == i - 1) { - return NXT_HTTP_BAD_REQUEST; - } - - dot_pos = i; - break; - - case ':': - if (state == sw_usual) { - host_length = i; - state = sw_rest; - } - - break; - - case '[': - if (i == 0) { - state = sw_literal; - } - - break; - - case ']': - if (state == sw_literal) { - host_length = i + 1; - state = sw_rest; - } - - break; - - case '/': - return NXT_HTTP_BAD_REQUEST; - - default: - if (ch >= 'A' && ch <= 'Z') { - lowcase = 1; - } - - break; - } - } - - if (dot_pos == host_length - 1) { - host_length--; - } - - host->length = host_length; - - if (lowcase) { - host->start = nxt_mp_nget(mp, host_length); - if (nxt_slow_path(host->start == NULL)) { - return NXT_HTTP_INTERNAL_SERVER_ERROR; - } - - nxt_memcpy_lowcase(host->start, h, host_length); - } - - return NXT_OK; -} - - -nxt_int_t -nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset) -{ - nxt_http_request_t *r; - - r = ctx; - - nxt_value_at(nxt_http_field_t *, r, offset) = field; - - return NXT_OK; -} - - -nxt_int_t -nxt_http_request_content_length(void *ctx, nxt_http_field_t *field, - uintptr_t data) -{ - nxt_off_t n, max_body_size; - nxt_http_request_t *r; - - r = ctx; - - if (nxt_fast_path(r->content_length == NULL)) { - r->content_length = field; - - n = nxt_off_t_parse(field->value, field->value_length); - - if (nxt_fast_path(n >= 0)) { - r->content_length_n = n; - - max_body_size = r->conf->socket_conf->max_body_size; - - if (nxt_slow_path(n > max_body_size)) { - return NXT_HTTP_PAYLOAD_TOO_LARGE; - } - - return NXT_OK; - } - } - - return NXT_HTTP_BAD_REQUEST; -} - - -nxt_http_request_t * -nxt_http_request_create(nxt_task_t *task) -{ - nxt_mp_t *mp; - nxt_buf_t *last; - nxt_http_request_t *r; - - mp = nxt_mp_create(4096, 128, 512, 32); - if (nxt_slow_path(mp == NULL)) { - return NULL; - } - - r = nxt_mp_zget(mp, sizeof(nxt_http_request_t)); - if (nxt_slow_path(r == NULL)) { - goto fail; - } - - r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); - if (nxt_slow_path(r->resp.fields == NULL)) { - goto fail; - } - - last = nxt_mp_zget(mp, NXT_BUF_SYNC_SIZE); - if (nxt_slow_path(last == NULL)) { - goto fail; - } - - nxt_buf_set_sync(last); - nxt_buf_set_last(last); - last->completion_handler = nxt_http_request_done; - last->parent = r; - r->last = last; - - r->mem_pool = mp; - r->content_length_n = -1; - r->resp.content_length_n = -1; - r->state = &nxt_http_request_init_state; - - r->start_time = nxt_thread_monotonic_time(task->thread); - - task->thread->engine->requests_cnt++; - - r->tstr_cache.var.pool = mp; - - return r; - -fail: - - nxt_mp_release(mp); - - return NULL; -} - - -static const nxt_http_request_state_t nxt_http_request_init_state - nxt_aligned(64) = -{ - .ready_handler = nxt_http_request_start, - .error_handler = nxt_http_request_close_handler, -}; - - -static void -nxt_http_request_start(nxt_task_t *task, void *obj, void *data) -{ - nxt_int_t ret; - nxt_socket_conf_t *skcf; - nxt_http_request_t *r; - - r = obj; - - r->state = &nxt_http_request_body_state; - - skcf = r->conf->socket_conf; - - if (skcf->forwarded != NULL) { - ret = nxt_http_request_forward(task, r, skcf->forwarded); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - } - - if (skcf->client_ip != NULL) { - ret = nxt_http_request_forward(task, r, skcf->client_ip); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - } - - nxt_http_request_read_body(task, r); - - return; - -fail: - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); -} - - -static nxt_int_t -nxt_http_request_forward(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_forward_t *forward) -{ - nxt_int_t ret; - nxt_array_t *client_ip_fields; - nxt_http_field_t *f, **fields, *protocol_field; - nxt_http_forward_header_t *client_ip, *protocol; - - ret = nxt_http_route_addr_rule(r, forward->source, r->remote); - if (ret <= 0) { - return NXT_OK; - } - - client_ip = &forward->client_ip; - protocol = &forward->protocol; - - if (client_ip->header != NULL) { - client_ip_fields = nxt_array_create(r->mem_pool, 1, - sizeof(nxt_http_field_t *)); - if (nxt_slow_path(client_ip_fields == NULL)) { - return NXT_ERROR; - } - - } else { - client_ip_fields = NULL; - } - - protocol_field = NULL; - - nxt_list_each(f, r->fields) { - if (client_ip_fields != NULL - && f->hash == client_ip->header_hash - && f->value_length > 0 - && f->name_length == client_ip->header->length - && nxt_memcasecmp(f->name, client_ip->header->start, - client_ip->header->length) == 0) - { - fields = nxt_array_add(client_ip_fields); - if (nxt_slow_path(fields == NULL)) { - return NXT_ERROR; - } - - *fields = f; - } - - if (protocol->header != NULL - && protocol_field == NULL - && f->hash == protocol->header_hash - && f->value_length > 0 - && f->name_length == protocol->header->length - && nxt_memcasecmp(f->name, protocol->header->start, - protocol->header->length) == 0) - { - protocol_field = f; - } - } nxt_list_loop; - - if (client_ip_fields != NULL) { - nxt_http_request_forward_client_ip(r, forward, client_ip_fields); - } - - if (protocol_field != NULL) { - nxt_http_request_forward_protocol(r, protocol_field); - } - - return NXT_OK; -} - - -static void -nxt_http_request_forward_client_ip(nxt_http_request_t *r, - nxt_http_forward_t *forward, nxt_array_t *fields) -{ - u_char *start, *p; - nxt_int_t ret, i, len; - nxt_sockaddr_t *sa, *prev_sa; - nxt_http_field_t **f; - - prev_sa = r->remote; - f = (nxt_http_field_t **) fields->elts; - - i = fields->nelts; - - while (i-- > 0) { - start = f[i]->value; - len = f[i]->value_length; - - do { - for (p = start + len - 1; p > start; p--, len--) { - if (*p != ' ' && *p != ',') { - break; - } - } - - for (/* void */; p > start; p--) { - if (*p == ' ' || *p == ',') { - p++; - break; - } - } - - sa = nxt_http_request_client_ip_sockaddr(r, p, len - (p - start)); - if (nxt_slow_path(sa == NULL)) { - if (prev_sa != NULL) { - r->remote = prev_sa; - } - - return; - } - - if (!forward->recursive) { - r->remote = sa; - return; - } - - ret = nxt_http_route_addr_rule(r, forward->source, sa); - if (ret <= 0 || (i == 0 && p == start)) { - r->remote = sa; - return; - } - - prev_sa = sa; - len = p - 1 - start; - - } while (len > 0); - } -} - - -static nxt_sockaddr_t * -nxt_http_request_client_ip_sockaddr(nxt_http_request_t *r, u_char *start, - size_t len) -{ - nxt_str_t addr; - nxt_sockaddr_t *sa; - - addr.start = start; - addr.length = len; - - sa = nxt_sockaddr_parse_optport(r->mem_pool, &addr); - if (nxt_slow_path(sa == NULL)) { - return NULL; - } - - switch (sa->u.sockaddr.sa_family) { - case AF_INET: - if (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY) { - return NULL; - } - - break; - -#if (NXT_INET6) - case AF_INET6: - if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr)) { - return NULL; - } - - break; -#endif /* NXT_INET6 */ - - default: - return NULL; - } - - return sa; -} - - -static void -nxt_http_request_forward_protocol(nxt_http_request_t *r, - nxt_http_field_t *field) -{ - if (field->value_length == 4) { - if (nxt_memcasecmp(field->value, "http", 4) == 0) { - r->tls = 0; - } - - } else if (field->value_length == 5) { - if (nxt_memcasecmp(field->value, "https", 5) == 0) { - r->tls = 1; - } - - } else if (field->value_length == 2) { - if (nxt_memcasecmp(field->value, "on", 2) == 0) { - r->tls = 1; - } - } -} - - -static const nxt_http_request_state_t nxt_http_request_body_state - nxt_aligned(64) = -{ - .ready_handler = nxt_http_request_ready, - .error_handler = nxt_http_request_close_handler, -}; - - -static void -nxt_http_request_ready(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_action_t *action; - nxt_http_request_t *r; - - r = obj; - action = r->conf->socket_conf->action; - - nxt_http_request_action(task, r, action); -} - - -void -nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *action) -{ - nxt_int_t ret; - - if (nxt_fast_path(action != NULL)) { - - do { - ret = nxt_http_rewrite(task, r); - if (nxt_slow_path(ret != NXT_OK)) { - break; - } - - action = action->handler(task, r, action); - - if (action == NULL) { - return; - } - - if (action == NXT_HTTP_ACTION_ERROR) { - break; - } - - } while (r->pass_count++ < 255); - } - - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); -} - - -nxt_http_action_t * -nxt_http_application_handler(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *action) -{ - nxt_debug(task, "http application handler"); - - /* - * TODO: need an application flag to get local address - * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go. - */ - nxt_http_request_proto_info(task, r); - - if (r->host.length != 0) { - r->server_name = r->host; - - } else { - nxt_str_set(&r->server_name, "localhost"); - } - - nxt_router_process_http_request(task, r, action); - - return NULL; -} - - -static void -nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r) -{ - if (nxt_fast_path(r->proto.any != NULL)) { - nxt_http_proto[r->protocol].local_addr(task, r); - } -} - - -void -nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r) -{ - if (nxt_fast_path(r->proto.any != NULL)) { - nxt_http_proto[r->protocol].body_read(task, r); - } -} - - -void -nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r, - nxt_work_handler_t body_handler, void *data) -{ - u_char *p, *end, *server_string; - nxt_int_t ret; - nxt_http_field_t *server, *date, *content_length; - nxt_socket_conf_t *skcf; - - ret = nxt_http_set_headers(r); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - /* - * TODO: "Server", "Date", and "Content-Length" processing should be moved - * to the last header filter. - */ - - server = nxt_list_zero_add(r->resp.fields); - if (nxt_slow_path(server == NULL)) { - goto fail; - } - - skcf = r->conf->socket_conf; - server_string = (u_char *) (skcf->server_version ? NXT_SERVER : NXT_NAME); - - nxt_http_field_name_set(server, "Server"); - server->value = server_string; - server->value_length = nxt_strlen(server_string); - - if (r->resp.date == NULL) { - date = nxt_list_zero_add(r->resp.fields); - if (nxt_slow_path(date == NULL)) { - goto fail; - } - - nxt_http_field_name_set(date, "Date"); - - p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size); - if (nxt_slow_path(p == NULL)) { - goto fail; - } - - (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p); - - date->value = p; - date->value_length = nxt_http_date_cache.size; - - r->resp.date = date; - } - - if (r->resp.content_length_n != -1 - && (r->resp.content_length == NULL || r->resp.content_length->skip)) - { - content_length = nxt_list_zero_add(r->resp.fields); - if (nxt_slow_path(content_length == NULL)) { - goto fail; - } - - nxt_http_field_name_set(content_length, "Content-Length"); - - p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); - if (nxt_slow_path(p == NULL)) { - goto fail; - } - - content_length->value = p; - end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n); - content_length->value_length = end - p; - - r->resp.content_length = content_length; - } - - if (nxt_fast_path(r->proto.any != NULL)) { - nxt_http_proto[r->protocol].header_send(task, r, body_handler, data); - } - - return; - -fail: - - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); -} - - -void -nxt_http_request_ws_frame_start(nxt_task_t *task, nxt_http_request_t *r, - nxt_buf_t *ws_frame) -{ - if (r->proto.any != NULL) { - nxt_http_proto[r->protocol].ws_frame_start(task, r, ws_frame); - } -} - - -void -nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) -{ - if (nxt_fast_path(r->proto.any != NULL)) { - nxt_http_proto[r->protocol].send(task, r, out); - } -} - - -nxt_buf_t * -nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size) -{ - nxt_buf_t *b; - - b = nxt_buf_mem_alloc(r->mem_pool, size, 0); - if (nxt_fast_path(b != NULL)) { - b->completion_handler = nxt_http_request_mem_buf_completion; - b->parent = r; - nxt_mp_retain(r->mem_pool); - - } else { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - } - - return b; -} - - -static void -nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *b, *next; - nxt_http_request_t *r; - - b = obj; - r = data; - - do { - next = b->next; - - nxt_mp_free(r->mem_pool, b); - nxt_mp_release(r->mem_pool); - - b = next; - } while (b != NULL); -} - - -nxt_buf_t * -nxt_http_buf_last(nxt_http_request_t *r) -{ - nxt_buf_t *last; - - last = r->last; - r->last = NULL; - - return last; -} - - -static void -nxt_http_request_done(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_request_t *r; - - r = data; - - nxt_debug(task, "http request done"); - - nxt_http_request_close_handler(task, r, r->proto.any); -} - - -void -nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_proto_t proto; - nxt_http_request_t *r; - - r = obj; - proto.any = data; - - nxt_debug(task, "http request error handler"); - - r->error = 1; - - if (nxt_fast_path(proto.any != NULL)) { - nxt_http_proto[r->protocol].discard(task, r, nxt_http_buf_last(r)); - } -} - - -void -nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_int_t ret; - nxt_http_proto_t proto; - nxt_router_conf_t *rtcf; - nxt_http_request_t *r; - nxt_http_protocol_t protocol; - nxt_socket_conf_joint_t *conf; - - r = obj; - proto.any = data; - - conf = r->conf; - rtcf = conf->socket_conf->router_conf; - - if (!r->logged) { - r->logged = 1; - - if (rtcf->access_log != NULL) { - ret = nxt_http_request_access_log(task, r, rtcf); - if (ret == NXT_OK) { - return; - } - } - } - - nxt_debug(task, "http request close handler"); - - r->proto.any = NULL; - - if (r->body != NULL && nxt_buf_is_file(r->body) - && r->body->file->fd != -1) - { - nxt_fd_close(r->body->file->fd); - - r->body->file->fd = -1; - } - - if (r->tstr_query != NULL) { - nxt_tstr_query_release(r->tstr_query); - } - - if (nxt_fast_path(proto.any != NULL)) { - protocol = r->protocol; - - nxt_http_proto[protocol].close(task, proto, conf); - - nxt_mp_release(r->mem_pool); - } -} - - -static nxt_int_t -nxt_http_request_access_log(nxt_task_t *task, nxt_http_request_t *r, - nxt_router_conf_t *rtcf) -{ - nxt_int_t ret; - nxt_str_t str; - nxt_bool_t expr; - nxt_router_access_log_t *access_log; - - access_log = rtcf->access_log; - - expr = 1; - - if (rtcf->log_expr != NULL) { - - if (nxt_tstr_is_const(rtcf->log_expr)) { - nxt_tstr_str(rtcf->log_expr, &str); - - } else { - ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, - &r->tstr_cache, r, r->mem_pool); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_DECLINED; - } - - nxt_tstr_query(task, r->tstr_query, rtcf->log_expr, &str); - - if (nxt_slow_path(nxt_tstr_query_failed(r->tstr_query))) { - return NXT_DECLINED; - } - } - - if (str.length == 0 - || nxt_str_eq(&str, "0", 1) - || nxt_str_eq(&str, "false", 5) - || nxt_str_eq(&str, "null", 4) - || nxt_str_eq(&str, "undefined", 9)) - { - expr = 0; - } - } - - if (rtcf->log_negate ^ expr) { - access_log->handler(task, r, access_log, rtcf->log_format); - return NXT_OK; - } - - return NXT_DECLINED; -} - - -static u_char * -nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, struct tm *tm, - size_t size, const char *format) -{ - return nxt_http_date(buf, tm); -} - - -nxt_array_t * -nxt_http_arguments_parse(nxt_http_request_t *r) -{ - size_t name_length; - u_char *p, *dst, *dst_start, *start, *end, *name; - uint8_t d0, d1; - uint32_t hash; - nxt_array_t *args; - nxt_http_name_value_t *nv; - - if (r->arguments != NULL) { - return r->arguments; - } - - args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); - if (nxt_slow_path(args == NULL)) { - return NULL; - } - - hash = NXT_HTTP_FIELD_HASH_INIT; - name = NULL; - name_length = 0; - - dst_start = nxt_mp_nget(r->mem_pool, r->args->length); - if (nxt_slow_path(dst_start == NULL)) { - return NULL; - } - - r->args_decoded.start = dst_start; - - start = r->args->start; - end = start + r->args->length; - - for (p = start, dst = dst_start; p < end; p++, dst++) { - *dst = *p; - - switch (*p) { - case '=': - if (name == NULL) { - name_length = dst - dst_start; - name = dst_start; - dst_start = dst + 1; - } - - continue; - - case '&': - if (name_length != 0 || dst != dst_start) { - nv = nxt_http_argument(args, name, name_length, hash, dst_start, - dst); - if (nxt_slow_path(nv == NULL)) { - return NULL; - } - } - - hash = NXT_HTTP_FIELD_HASH_INIT; - name_length = 0; - name = NULL; - dst_start = dst + 1; - - continue; - - case '+': - *dst = ' '; - - break; - - case '%': - if (nxt_slow_path(end - p <= 2)) { - break; - } - - d0 = nxt_hex2int[p[1]]; - d1 = nxt_hex2int[p[2]]; - - if (nxt_slow_path((d0 | d1) >= 16)) { - break; - } - - p += 2; - *dst = (d0 << 4) + d1; - - break; - } - - if (name == NULL) { - hash = nxt_http_field_hash_char(hash, *dst); - } - } - - r->args_decoded.length = dst - r->args_decoded.start; - - if (name_length != 0 || dst != dst_start) { - nv = nxt_http_argument(args, name, name_length, hash, dst_start, dst); - if (nxt_slow_path(nv == NULL)) { - return NULL; - } - } - - r->arguments = args; - - return args; -} - - -static nxt_http_name_value_t * -nxt_http_argument(nxt_array_t *array, u_char *name, size_t name_length, - uint32_t hash, u_char *start, const u_char *end) -{ - size_t length; - nxt_http_name_value_t *nv; - - nv = nxt_array_add(array); - if (nxt_slow_path(nv == NULL)) { - return NULL; - } - - nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; - - length = end - start; - - if (name == NULL) { - name_length = length; - name = start; - length = 0; - } - - nv->name_length = name_length; - nv->value_length = length; - nv->name = name; - nv->value = start; - - return nv; -} - - -nxt_array_t * -nxt_http_cookies_parse(nxt_http_request_t *r) -{ - nxt_int_t ret; - nxt_array_t *cookies; - nxt_http_field_t *f; - - if (r->cookies != NULL) { - return r->cookies; - } - - cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); - if (nxt_slow_path(cookies == NULL)) { - return NULL; - } - - nxt_list_each(f, r->fields) { - - if (f->hash != NXT_HTTP_COOKIE_HASH - || f->name_length != 6 - || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0) - { - continue; - } - - ret = nxt_http_cookie_parse(cookies, f->value, - f->value + f->value_length); - if (ret != NXT_OK) { - return NULL; - } - - } nxt_list_loop; - - r->cookies = cookies; - - return cookies; -} - - -static nxt_int_t -nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, const u_char *end) -{ - size_t name_length; - u_char c, *p, *name; - nxt_http_name_value_t *nv; - - name = NULL; - name_length = 0; - - for (p = start; p < end; p++) { - c = *p; - - if (c == '=' && name == NULL) { - while (start[0] == ' ') { start++; } - - name_length = p - start; - name = start; - - start = p + 1; - - } else if (c == ';') { - if (name != NULL) { - nv = nxt_http_cookie(cookies, name, name_length, start, p); - if (nxt_slow_path(nv == NULL)) { - return NXT_ERROR; - } - } - - name = NULL; - start = p + 1; - } - } - - if (name != NULL) { - nv = nxt_http_cookie(cookies, name, name_length, start, p); - if (nxt_slow_path(nv == NULL)) { - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -static nxt_http_name_value_t * -nxt_http_cookie(nxt_array_t *array, u_char *name, size_t name_length, - u_char *start, const u_char *end) -{ - u_char c, *p; - uint32_t hash; - nxt_http_name_value_t *nv; - - nv = nxt_array_add(array); - if (nxt_slow_path(nv == NULL)) { - return NULL; - } - - nv->name_length = name_length; - nv->name = name; - - hash = NXT_HTTP_FIELD_HASH_INIT; - - for (p = name; p < name + name_length; p++) { - c = *p; - hash = nxt_http_field_hash_char(hash, c); - } - - nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; - - while (start < end && end[-1] == ' ') { end--; } - - nv->value_length = end - start; - nv->value = start; - - return nv; -} - - -int64_t -nxt_http_field_hash(nxt_mp_t *mp, nxt_str_t *name, nxt_bool_t case_sensitive, - uint8_t encoding) -{ - u_char c, *p, *src, *start, *end, plus; - uint8_t d0, d1; - uint32_t hash; - nxt_str_t str; - nxt_uint_t i; - - str.length = name->length; - - str.start = nxt_mp_nget(mp, str.length); - if (nxt_slow_path(str.start == NULL)) { - return -1; - } - - p = str.start; - - hash = NXT_HTTP_FIELD_HASH_INIT; - - if (encoding == NXT_HTTP_URI_ENCODING_NONE) { - for (i = 0; i < name->length; i++) { - c = name->start[i]; - *p++ = c; - - c = case_sensitive ? c : nxt_lowcase(c); - hash = nxt_http_field_hash_char(hash, c); - } - - goto end; - } - - plus = (encoding == NXT_HTTP_URI_ENCODING_PLUS) ? ' ' : '+'; - - start = name->start; - end = start + name->length; - - for (src = start; src < end; src++) { - c = *src; - - switch (c) { - case '%': - if (nxt_slow_path(end - src <= 2)) { - return -1; - } - - d0 = nxt_hex2int[src[1]]; - d1 = nxt_hex2int[src[2]]; - src += 2; - - if (nxt_slow_path((d0 | d1) >= 16)) { - return -1; - } - - c = (d0 << 4) + d1; - *p++ = c; - break; - - case '+': - c = plus; - *p++ = c; - break; - - default: - *p++ = c; - break; - } - - c = case_sensitive ? c : nxt_lowcase(c); - hash = nxt_http_field_hash_char(hash, c); - } - - str.length = p - str.start; - -end: - - *name = str; - - return nxt_http_field_hash_end(hash) & 0xFFFF; -} - - -int64_t -nxt_http_argument_hash(nxt_mp_t *mp, nxt_str_t *name) -{ - return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_PLUS); -} - - -int64_t -nxt_http_header_hash(nxt_mp_t *mp, nxt_str_t *name) -{ - u_char c, *p; - uint32_t i, hash; - nxt_str_t str; - - str.length = name->length; - - str.start = nxt_mp_nget(mp, str.length); - if (nxt_slow_path(str.start == NULL)) { - return -1; - } - - p = str.start; - hash = NXT_HTTP_FIELD_HASH_INIT; - - for (i = 0; i < name->length; i++) { - c = name->start[i]; - - if (c >= 'A' && c <= 'Z') { - *p = c | 0x20; - - } else if (c == '_') { - *p = '-'; - - } else { - *p = c; - } - - hash = nxt_http_field_hash_char(hash, *p); - p++; - } - - *name = str; - - return nxt_http_field_hash_end(hash) & 0xFFFF; -} - - -int64_t -nxt_http_cookie_hash(nxt_mp_t *mp, nxt_str_t *name) -{ - return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_NONE); -} diff --git a/src/nxt_http_response.c b/src/nxt_http_response.c deleted file mode 100644 index 55a4686c..00000000 --- a/src/nxt_http_response.c +++ /dev/null @@ -1,87 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -static nxt_int_t nxt_http_response_status(void *ctx, nxt_http_field_t *field, - uintptr_t data); -static nxt_int_t nxt_http_response_skip(void *ctx, nxt_http_field_t *field, - uintptr_t data); -static nxt_int_t nxt_http_response_field(void *ctx, nxt_http_field_t *field, - uintptr_t offset); - - -nxt_lvlhsh_t nxt_response_fields_hash; - -static nxt_http_field_proc_t nxt_response_fields[] = { - { nxt_string("Status"), &nxt_http_response_status, 0 }, - { nxt_string("Server"), &nxt_http_response_skip, 0 }, - { nxt_string("Date"), &nxt_http_response_field, - offsetof(nxt_http_request_t, resp.date) }, - { nxt_string("Connection"), &nxt_http_response_skip, 0 }, - { nxt_string("Content-Type"), &nxt_http_response_field, - offsetof(nxt_http_request_t, resp.content_type) }, - { nxt_string("Content-Length"), &nxt_http_response_field, - offsetof(nxt_http_request_t, resp.content_length) }, - { nxt_string("Upgrade"), &nxt_http_response_skip, 0 }, - { nxt_string("Sec-WebSocket-Accept"), &nxt_http_response_skip, 0 }, -}; - - -nxt_int_t -nxt_http_response_hash_init(nxt_task_t *task) -{ - return nxt_http_fields_hash(&nxt_response_fields_hash, - nxt_response_fields, nxt_nitems(nxt_response_fields)); -} - - -nxt_int_t -nxt_http_response_status(void *ctx, nxt_http_field_t *field, - uintptr_t data) -{ - nxt_int_t status; - nxt_http_request_t *r; - - r = ctx; - - field->skip = 1; - - if (field->value_length >= 3) { - status = nxt_int_parse(field->value, 3); - - if (status >= 100 && status <= 999) { - r->status = status; - return NXT_OK; - } - } - - return NXT_ERROR; -} - - -nxt_int_t -nxt_http_response_skip(void *ctx, nxt_http_field_t *field, uintptr_t data) -{ - field->skip = 1; - - return NXT_OK; -} - - -nxt_int_t -nxt_http_response_field(void *ctx, nxt_http_field_t *field, uintptr_t offset) -{ - nxt_http_request_t *r; - - r = ctx; - - nxt_value_at(nxt_http_field_t *, r, offset) = field; - - return NXT_OK; -} diff --git a/src/nxt_http_return.c b/src/nxt_http_return.c deleted file mode 100644 index b50e4ad0..00000000 --- a/src/nxt_http_return.c +++ /dev/null @@ -1,234 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -typedef struct { - nxt_http_status_t status; - nxt_tstr_t *location; - nxt_str_t encoded; -} nxt_http_return_conf_t; - - -typedef struct { - nxt_str_t location; - nxt_str_t encoded; -} nxt_http_return_ctx_t; - - -static nxt_http_action_t *nxt_http_return(nxt_task_t *task, - nxt_http_request_t *r, nxt_http_action_t *action); -static nxt_int_t nxt_http_return_encode(nxt_mp_t *mp, nxt_str_t *encoded, - const nxt_str_t *location); -static void nxt_http_return_send_ready(nxt_task_t *task, void *obj, void *data); -static void nxt_http_return_send_error(nxt_task_t *task, void *obj, void *data); - - -static const nxt_http_request_state_t nxt_http_return_send_state; - - -nxt_int_t -nxt_http_return_init(nxt_router_conf_t *rtcf, nxt_http_action_t *action, - nxt_http_action_conf_t *acf) -{ - nxt_mp_t *mp; - nxt_str_t str; - nxt_http_return_conf_t *conf; - - mp = rtcf->mem_pool; - - conf = nxt_mp_zget(mp, sizeof(nxt_http_return_conf_t)); - if (nxt_slow_path(conf == NULL)) { - return NXT_ERROR; - } - - action->handler = nxt_http_return; - action->u.conf = conf; - - conf->status = nxt_conf_get_number(acf->ret); - - if (acf->location == NULL) { - return NXT_OK; - } - - nxt_conf_get_string(acf->location, &str); - - conf->location = nxt_tstr_compile(rtcf->tstr_state, &str, 0); - if (nxt_slow_path(conf->location == NULL)) { - return NXT_ERROR; - } - - if (nxt_tstr_is_const(conf->location)) { - nxt_tstr_str(conf->location, &str); - return nxt_http_return_encode(mp, &conf->encoded, &str); - } - - return NXT_OK; -} - - -nxt_http_action_t * -nxt_http_return(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *action) -{ - nxt_int_t ret; - nxt_router_conf_t *rtcf; - nxt_http_return_ctx_t *ctx; - nxt_http_return_conf_t *conf; - - conf = action->u.conf; - -#if (NXT_DEBUG) - nxt_str_t loc; - - if (conf->location == NULL) { - nxt_str_set(&loc, ""); - - } else { - nxt_tstr_str(conf->location, &loc); - } - - nxt_debug(task, "http return: %d (loc: \"%V\")", conf->status, &loc); -#endif - - if (conf->status >= NXT_HTTP_BAD_REQUEST - && conf->status <= NXT_HTTP_SERVER_ERROR_MAX) - { - nxt_http_request_error(task, r, conf->status); - return NULL; - } - - if (conf->location == NULL) { - ctx = NULL; - - } else { - ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_return_ctx_t)); - if (nxt_slow_path(ctx == NULL)) { - goto fail; - } - } - - r->status = conf->status; - r->resp.content_length_n = 0; - - if (ctx == NULL || nxt_tstr_is_const(conf->location)) { - if (ctx != NULL) { - ctx->encoded = conf->encoded; - } - - nxt_http_return_send_ready(task, r, ctx); - - } else { - rtcf = r->conf->socket_conf->router_conf; - - ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, - &r->tstr_cache, r, r->mem_pool); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - nxt_tstr_query(task, r->tstr_query, conf->location, &ctx->location); - - nxt_tstr_query_resolve(task, r->tstr_query, ctx, - nxt_http_return_send_ready, - nxt_http_return_send_error); - } - - return NULL; - -fail: - - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - return NULL; -} - - -static nxt_int_t -nxt_http_return_encode(nxt_mp_t *mp, nxt_str_t *encoded, - const nxt_str_t *location) -{ - nxt_uint_t encode; - - if (nxt_is_complex_uri_encoded(location->start, location->length)) { - *encoded = *location; - - return NXT_OK; - } - - encode = nxt_encode_complex_uri(NULL, location->start, location->length); - encoded->length = location->length + encode * 2; - - encoded->start = nxt_mp_nget(mp, encoded->length); - if (nxt_slow_path(encoded->start == NULL)) { - return NXT_ERROR; - } - - nxt_encode_complex_uri(encoded->start, location->start, location->length); - - return NXT_OK; -} - - -static void -nxt_http_return_send_ready(nxt_task_t *task, void *obj, void *data) -{ - nxt_int_t ret; - nxt_http_field_t *field; - nxt_http_request_t *r; - nxt_http_return_ctx_t *ctx; - - r = obj; - ctx = data; - - if (ctx != NULL) { - if (ctx->location.length > 0) { - ret = nxt_http_return_encode(r->mem_pool, &ctx->encoded, - &ctx->location); - if (nxt_slow_path(ret == NXT_ERROR)) { - goto fail; - } - } - - field = nxt_list_zero_add(r->resp.fields); - if (nxt_slow_path(field == NULL)) { - goto fail; - } - - nxt_http_field_name_set(field, "Location"); - - field->value = ctx->encoded.start; - field->value_length = ctx->encoded.length; - } - - r->state = &nxt_http_return_send_state; - - nxt_http_request_header_send(task, r, NULL, NULL); - - return; - -fail: - - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); -} - - -static void -nxt_http_return_send_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_request_t *r; - - r = obj; - - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); -} - - -static const nxt_http_request_state_t nxt_http_return_send_state - nxt_aligned(64) = -{ - .error_handler = nxt_http_request_error_handler, -}; diff --git a/src/nxt_http_rewrite.c b/src/nxt_http_rewrite.c deleted file mode 100644 index fb216eeb..00000000 --- a/src/nxt_http_rewrite.c +++ /dev/null @@ -1,111 +0,0 @@ - -/* - * Copyright (C) Zhidao HONG - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -nxt_int_t -nxt_http_rewrite_init(nxt_router_conf_t *rtcf, nxt_http_action_t *action, - nxt_http_action_conf_t *acf) -{ - nxt_str_t str; - - nxt_conf_get_string(acf->rewrite, &str); - - action->rewrite = nxt_tstr_compile(rtcf->tstr_state, &str, 0); - if (nxt_slow_path(action->rewrite == NULL)) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -nxt_int_t -nxt_http_rewrite(nxt_task_t *task, nxt_http_request_t *r) -{ - u_char *p; - nxt_int_t ret; - nxt_str_t str, encoded_path, target; - nxt_router_conf_t *rtcf; - nxt_http_action_t *action; - nxt_http_request_parse_t rp; - - action = r->action; - - if (action == NULL || action->rewrite == NULL) { - return NXT_OK; - } - - if (nxt_tstr_is_const(action->rewrite)) { - nxt_tstr_str(action->rewrite, &str); - - } else { - rtcf = r->conf->socket_conf->router_conf; - - ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, - &r->tstr_cache, r, r->mem_pool); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - nxt_tstr_query(task, r->tstr_query, action->rewrite, &str); - - if (nxt_slow_path(nxt_tstr_query_failed(r->tstr_query))) { - return NXT_ERROR; - } - } - - nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); - - rp.mem_pool = r->mem_pool; - - rp.target_start = str.start; - rp.target_end = str.start + str.length; - - ret = nxt_http_parse_complex_target(&rp); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - p = (rp.args.length > 0) ? rp.args.start - 1 : rp.target_end; - - encoded_path.start = rp.target_start; - encoded_path.length = p - encoded_path.start; - - if (r->args->length == 0) { - r->target = encoded_path; - - } else { - target.length = encoded_path.length + 1 + r->args->length; - - target.start = nxt_mp_alloc(r->mem_pool, target.length); - if (target.start == NULL) { - return NXT_ERROR; - } - - p = nxt_cpymem(target.start, encoded_path.start, encoded_path.length); - *p++ = '?'; - nxt_memcpy(p, r->args->start, r->args->length); - - r->target = target; - r->args->start = p; - } - - r->path = nxt_mp_alloc(r->mem_pool, sizeof(nxt_str_t)); - if (nxt_slow_path(r->path == NULL)) { - return NXT_ERROR; - } - - *r->path = rp.path; - - if (nxt_slow_path(r->log_route)) { - nxt_log(task, NXT_LOG_NOTICE, "URI rewritten to \"%V\"", &r->target); - } - - return NXT_OK; -} diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c deleted file mode 100644 index 4a64d5c1..00000000 --- a/src/nxt_http_route.c +++ /dev/null @@ -1,2209 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include - - -typedef enum { - NXT_HTTP_ROUTE_TABLE = 0, - NXT_HTTP_ROUTE_STRING, - NXT_HTTP_ROUTE_STRING_PTR, - NXT_HTTP_ROUTE_HEADER, - NXT_HTTP_ROUTE_ARGUMENT, - NXT_HTTP_ROUTE_COOKIE, - NXT_HTTP_ROUTE_SCHEME, - NXT_HTTP_ROUTE_QUERY, - NXT_HTTP_ROUTE_SOURCE, - NXT_HTTP_ROUTE_DESTINATION, -} nxt_http_route_object_t; - - -typedef enum { - NXT_HTTP_ROUTE_PATTERN_EXACT = 0, - NXT_HTTP_ROUTE_PATTERN_BEGIN, - NXT_HTTP_ROUTE_PATTERN_END, - NXT_HTTP_ROUTE_PATTERN_SUBSTRING, -} nxt_http_route_pattern_type_t; - - -typedef enum { - NXT_HTTP_ROUTE_PATTERN_NOCASE = 0, - NXT_HTTP_ROUTE_PATTERN_LOWCASE, - NXT_HTTP_ROUTE_PATTERN_UPCASE, -} nxt_http_route_pattern_case_t; - - -typedef struct { - nxt_conf_value_t *host; - nxt_conf_value_t *uri; - nxt_conf_value_t *method; - nxt_conf_value_t *headers; - nxt_conf_value_t *arguments; - nxt_conf_value_t *cookies; - nxt_conf_value_t *scheme; - nxt_conf_value_t *query; - nxt_conf_value_t *source; - nxt_conf_value_t *destination; -} nxt_http_route_match_conf_t; - - -typedef struct { - u_char *start; - uint32_t length; - nxt_http_route_pattern_type_t type:8; -} nxt_http_route_pattern_slice_t; - - -typedef struct { - union { - nxt_array_t *pattern_slices; -#if (NXT_HAVE_REGEX) - nxt_regex_t *regex; -#endif - } u; - uint32_t min_length; - - uint8_t case_sensitive; /* 1 bit */ - uint8_t negative; /* 1 bit */ - uint8_t any; /* 1 bit */ -#if (NXT_HAVE_REGEX) - uint8_t regex; /* 1 bit */ -#endif -} nxt_http_route_pattern_t; - - -typedef struct { - uint16_t hash; - uint16_t name_length; - uint32_t value_length; - u_char *name; - u_char *value; -} nxt_http_cookie_t; - - -struct nxt_http_route_rule_s { - /* The object must be the first field. */ - nxt_http_route_object_t object:8; - uint32_t items; - - union { - uintptr_t offset; - - struct { - u_char *start; - uint16_t hash; - uint16_t length; - } name; - } u; - - nxt_http_route_pattern_t pattern[0]; -}; - - -typedef struct { - uint32_t items; - nxt_http_route_rule_t *rule[0]; -} nxt_http_route_ruleset_t; - - -typedef struct { - /* The object must be the first field. */ - nxt_http_route_object_t object:8; - uint32_t items; - nxt_http_route_ruleset_t *ruleset[0]; -} nxt_http_route_table_t; - - -struct nxt_http_route_addr_rule_s { - /* The object must be the first field. */ - nxt_http_route_object_t object:8; - uint32_t items; - nxt_http_route_addr_pattern_t addr_pattern[0]; -}; - - -typedef union { - nxt_http_route_rule_t *rule; - nxt_http_route_table_t *table; - nxt_http_route_addr_rule_t *addr_rule; -} nxt_http_route_test_t; - - -typedef struct { - uint32_t items; - nxt_http_action_t action; - nxt_http_route_test_t test[0]; -} nxt_http_route_match_t; - - -struct nxt_http_route_s { - nxt_str_t name; - uint32_t items; - nxt_http_route_match_t *match[0]; -}; - - -struct nxt_http_routes_s { - uint32_t items; - nxt_http_route_t *route[0]; -}; - - -static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); -static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); -static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task, - nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object, - nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding); -static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task, - nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, - nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding); -static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task, - nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name, - nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding); -static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task, - nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive, - nxt_http_route_pattern_case_t pattern_case, - nxt_http_uri_encoding_t encoding); -static int nxt_http_pattern_compare(const void *one, const void *two); -static int nxt_http_addr_pattern_compare(const void *one, const void *two); -static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, - nxt_http_route_pattern_case_t pattern_case, - nxt_http_uri_encoding_t encoding); -static nxt_int_t nxt_http_route_decode_str(nxt_str_t *str, - nxt_http_uri_encoding_t encoding); -static nxt_int_t nxt_http_route_pattern_slice(nxt_array_t *slices, - nxt_str_t *test, - nxt_http_route_pattern_type_t type, - nxt_http_uri_encoding_t encoding, - nxt_http_route_pattern_case_t pattern_case); - -static nxt_int_t nxt_http_route_resolve(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route); -static nxt_int_t nxt_http_action_resolve(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action); -static nxt_http_action_t *nxt_http_pass_var(nxt_task_t *task, - nxt_http_request_t *r, nxt_http_action_t *action); -static void nxt_http_pass_query_ready(nxt_task_t *task, void *obj, void *data); -static void nxt_http_pass_query_error(nxt_task_t *task, void *obj, void *data); -static nxt_int_t nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf, - nxt_str_t *pass, nxt_http_action_t *action); -static nxt_int_t nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name, - nxt_http_action_t *action); - -static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task, - nxt_http_request_t *r, nxt_http_action_t *start); -static nxt_http_action_t *nxt_http_route_match(nxt_task_t *task, - nxt_http_request_t *r, nxt_http_route_match_t *match); -static nxt_int_t nxt_http_route_table(nxt_http_request_t *r, - nxt_http_route_table_t *table); -static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r, - nxt_http_route_ruleset_t *ruleset); -static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r, - nxt_http_route_rule_t *rule); -static nxt_int_t nxt_http_route_header(nxt_http_request_t *r, - nxt_http_route_rule_t *rule); -static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r, - nxt_http_route_rule_t *rule); -static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r, - nxt_http_route_rule_t *rule, nxt_array_t *array); -static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r, - nxt_http_route_rule_t *rule); -static nxt_int_t nxt_http_route_query(nxt_http_request_t *r, - nxt_http_route_rule_t *rule); -static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r, - nxt_http_route_rule_t *rule); -static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r, - nxt_http_route_rule_t *rule, nxt_array_t *array); -static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r, - nxt_http_route_pattern_t *pattern, u_char *start, size_t length); -static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test, - size_t length, nxt_bool_t case_sensitive); - - -nxt_http_routes_t * -nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *routes_conf) -{ - size_t size; - uint32_t i, n, next; - nxt_mp_t *mp; - nxt_str_t name, *string; - nxt_bool_t object; - nxt_conf_value_t *route_conf; - nxt_http_route_t *route; - nxt_http_routes_t *routes; - - object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT); - n = object ? nxt_conf_object_members_count(routes_conf) : 1; - size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *); - - mp = tmcf->router_conf->mem_pool; - - routes = nxt_mp_alloc(mp, size); - if (nxt_slow_path(routes == NULL)) { - return NULL; - } - - routes->items = n; - - if (object) { - next = 0; - - for (i = 0; i < n; i++) { - route_conf = nxt_conf_next_object_member(routes_conf, &name, &next); - - route = nxt_http_route_create(task, tmcf, route_conf); - if (nxt_slow_path(route == NULL)) { - return NULL; - } - - routes->route[i] = route; - - string = nxt_str_dup(mp, &route->name, &name); - if (nxt_slow_path(string == NULL)) { - return NULL; - } - } - - } else { - route = nxt_http_route_create(task, tmcf, routes_conf); - if (nxt_slow_path(route == NULL)) { - return NULL; - } - - routes->route[0] = route; - - route->name.length = 0; - route->name.start = NULL; - } - - return routes; -} - - -static nxt_conf_map_t nxt_http_route_match_conf[] = { - { - nxt_string("scheme"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_route_match_conf_t, scheme) - }, - { - nxt_string("host"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_route_match_conf_t, host), - }, - - { - nxt_string("uri"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_route_match_conf_t, uri), - }, - - { - nxt_string("method"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_route_match_conf_t, method), - }, - - { - nxt_string("headers"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_route_match_conf_t, headers), - }, - - { - nxt_string("arguments"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_route_match_conf_t, arguments), - }, - - { - nxt_string("cookies"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_route_match_conf_t, cookies), - }, - - { - nxt_string("query"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_route_match_conf_t, query), - }, - - { - nxt_string("source"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_route_match_conf_t, source), - }, - - { - nxt_string("destination"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_route_match_conf_t, destination), - }, -}; - - -static nxt_http_route_t * -nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *cv) -{ - size_t size; - uint32_t i, n; - nxt_conf_value_t *value; - nxt_http_route_t *route; - nxt_http_route_match_t *match, **m; - - n = nxt_conf_array_elements_count(cv); - size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *); - - route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size); - if (nxt_slow_path(route == NULL)) { - return NULL; - } - - route->items = n; - m = &route->match[0]; - - for (i = 0; i < n; i++) { - value = nxt_conf_get_array_element(cv, i); - - match = nxt_http_route_match_create(task, tmcf, value); - if (match == NULL) { - return NULL; - } - - *m++ = match; - } - - return route; -} - - -static nxt_http_route_match_t * -nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *cv) -{ - size_t size; - uint32_t n; - nxt_mp_t *mp; - nxt_int_t ret; - nxt_conf_value_t *match_conf, *action_conf; - nxt_http_route_test_t *test; - nxt_http_route_rule_t *rule; - nxt_http_route_table_t *table; - nxt_http_route_match_t *match; - nxt_http_route_addr_rule_t *addr_rule; - nxt_http_route_match_conf_t mtcf; - - static nxt_str_t match_path = nxt_string("/match"); - static nxt_str_t action_path = nxt_string("/action"); - - match_conf = nxt_conf_get_path(cv, &match_path); - - n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0; - size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_test_t *); - - mp = tmcf->router_conf->mem_pool; - - match = nxt_mp_alloc(mp, size); - if (nxt_slow_path(match == NULL)) { - return NULL; - } - - match->items = n; - - action_conf = nxt_conf_get_path(cv, &action_path); - if (nxt_slow_path(action_conf == NULL)) { - return NULL; - } - - ret = nxt_http_action_init(task, tmcf, action_conf, &match->action); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - if (n == 0) { - return match; - } - - nxt_memzero(&mtcf, sizeof(mtcf)); - - ret = nxt_conf_map_object(tmcf->mem_pool, - match_conf, nxt_http_route_match_conf, - nxt_nitems(nxt_http_route_match_conf), &mtcf); - if (ret != NXT_OK) { - return NULL; - } - - test = &match->test[0]; - - if (mtcf.scheme != NULL) { - rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1, - NXT_HTTP_ROUTE_PATTERN_NOCASE, - NXT_HTTP_URI_ENCODING_NONE); - if (rule == NULL) { - return NULL; - } - - rule->object = NXT_HTTP_ROUTE_SCHEME; - test->rule = rule; - test++; - } - - if (mtcf.host != NULL) { - rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1, - NXT_HTTP_ROUTE_PATTERN_LOWCASE, - NXT_HTTP_URI_ENCODING_NONE); - if (rule == NULL) { - return NULL; - } - - rule->u.offset = offsetof(nxt_http_request_t, host); - rule->object = NXT_HTTP_ROUTE_STRING; - test->rule = rule; - test++; - } - - if (mtcf.uri != NULL) { - rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1, - NXT_HTTP_ROUTE_PATTERN_NOCASE, - NXT_HTTP_URI_ENCODING); - if (rule == NULL) { - return NULL; - } - - rule->u.offset = offsetof(nxt_http_request_t, path); - rule->object = NXT_HTTP_ROUTE_STRING_PTR; - test->rule = rule; - test++; - } - - if (mtcf.method != NULL) { - rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1, - NXT_HTTP_ROUTE_PATTERN_UPCASE, - NXT_HTTP_URI_ENCODING_NONE); - if (rule == NULL) { - return NULL; - } - - rule->u.offset = offsetof(nxt_http_request_t, method); - rule->object = NXT_HTTP_ROUTE_STRING_PTR; - test->rule = rule; - test++; - } - - if (mtcf.headers != NULL) { - table = nxt_http_route_table_create(task, mp, mtcf.headers, - NXT_HTTP_ROUTE_HEADER, 0, - NXT_HTTP_URI_ENCODING_NONE); - if (table == NULL) { - return NULL; - } - - test->table = table; - test++; - } - - if (mtcf.arguments != NULL) { - table = nxt_http_route_table_create(task, mp, mtcf.arguments, - NXT_HTTP_ROUTE_ARGUMENT, 1, - NXT_HTTP_URI_ENCODING_PLUS); - if (table == NULL) { - return NULL; - } - - test->table = table; - test++; - } - - if (mtcf.cookies != NULL) { - table = nxt_http_route_table_create(task, mp, mtcf.cookies, - NXT_HTTP_ROUTE_COOKIE, 1, - NXT_HTTP_URI_ENCODING_NONE); - if (table == NULL) { - return NULL; - } - - test->table = table; - test++; - } - - if (mtcf.query != NULL) { - rule = nxt_http_route_rule_create(task, mp, mtcf.query, 1, - NXT_HTTP_ROUTE_PATTERN_NOCASE, - NXT_HTTP_URI_ENCODING_PLUS); - if (rule == NULL) { - return NULL; - } - - rule->object = NXT_HTTP_ROUTE_QUERY; - test->rule = rule; - test++; - } - - if (mtcf.source != NULL) { - addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.source); - if (addr_rule == NULL) { - return NULL; - } - - addr_rule->object = NXT_HTTP_ROUTE_SOURCE; - test->addr_rule = addr_rule; - test++; - } - - if (mtcf.destination != NULL) { - addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.destination); - if (addr_rule == NULL) { - return NULL; - } - - addr_rule->object = NXT_HTTP_ROUTE_DESTINATION; - test->addr_rule = addr_rule; - test++; - } - - return match; -} - - -static nxt_conf_map_t nxt_http_route_action_conf[] = { - { - nxt_string("rewrite"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, rewrite) - }, - { - nxt_string("response_headers"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, set_headers) - }, - { - nxt_string("pass"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, pass) - }, - { - nxt_string("return"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, ret) - }, - { - nxt_string("location"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, location) - }, - { - nxt_string("proxy"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, proxy) - }, - { - nxt_string("share"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, share) - }, - { - nxt_string("index"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, index) - }, - { - nxt_string("chroot"), - NXT_CONF_MAP_STR, - offsetof(nxt_http_action_conf_t, chroot) - }, - { - nxt_string("follow_symlinks"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, follow_symlinks) - }, - { - nxt_string("traverse_mounts"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, traverse_mounts) - }, - { - nxt_string("types"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, types) - }, - { - nxt_string("fallback"), - NXT_CONF_MAP_PTR, - offsetof(nxt_http_action_conf_t, fallback) - }, -}; - - -nxt_int_t -nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *cv, nxt_http_action_t *action) -{ - nxt_mp_t *mp; - nxt_int_t ret; - nxt_str_t pass; - nxt_router_conf_t *rtcf; - nxt_http_action_conf_t acf; - - nxt_memzero(&acf, sizeof(acf)); - - ret = nxt_conf_map_object(tmcf->mem_pool, cv, nxt_http_route_action_conf, - nxt_nitems(nxt_http_route_action_conf), &acf); - if (ret != NXT_OK) { - return ret; - } - - nxt_memzero(action, sizeof(nxt_http_action_t)); - - rtcf = tmcf->router_conf; - mp = rtcf->mem_pool; - - if (acf.rewrite != NULL) { - ret = nxt_http_rewrite_init(rtcf, action, &acf); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - } - - if (acf.set_headers != NULL) { - ret = nxt_http_set_headers_init(rtcf, action, &acf); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - } - - if (acf.ret != NULL) { - return nxt_http_return_init(rtcf, action, &acf); - } - - if (acf.share != NULL) { - return nxt_http_static_init(task, tmcf, action, &acf); - } - - if (acf.proxy != NULL) { - return nxt_http_proxy_init(mp, action, &acf); - } - - nxt_conf_get_string(acf.pass, &pass); - - action->u.tstr = nxt_tstr_compile(rtcf->tstr_state, &pass, 0); - if (nxt_slow_path(action->u.tstr == NULL)) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_http_route_table_t * -nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *table_cv, nxt_http_route_object_t object, - nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding) -{ - size_t size; - uint32_t i, n; - nxt_conf_value_t *ruleset_cv; - nxt_http_route_table_t *table; - nxt_http_route_ruleset_t *ruleset; - - n = nxt_conf_array_elements_count_or_1(table_cv); - size = sizeof(nxt_http_route_table_t) - + n * sizeof(nxt_http_route_ruleset_t *); - - table = nxt_mp_alloc(mp, size); - if (nxt_slow_path(table == NULL)) { - return NULL; - } - - table->items = n; - table->object = NXT_HTTP_ROUTE_TABLE; - - for (i = 0; i < n; i++) { - ruleset_cv = nxt_conf_get_array_element_or_itself(table_cv, i); - - ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, object, - case_sensitive, encoding); - if (nxt_slow_path(ruleset == NULL)) { - return NULL; - } - - table->ruleset[i] = ruleset; - } - - return table; -} - - -static nxt_http_route_ruleset_t * -nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, - nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding) -{ - size_t size; - uint32_t i, n, next; - nxt_str_t name; - nxt_conf_value_t *rule_cv; - nxt_http_route_rule_t *rule; - nxt_http_route_ruleset_t *ruleset; - - n = nxt_conf_object_members_count(ruleset_cv); - size = sizeof(nxt_http_route_ruleset_t) - + n * sizeof(nxt_http_route_rule_t *); - - ruleset = nxt_mp_alloc(mp, size); - if (nxt_slow_path(ruleset == NULL)) { - return NULL; - } - - ruleset->items = n; - - next = 0; - - /* - * A workaround for GCC 10 with -flto -O2 flags that warns about "name" - * may be uninitialized in nxt_http_route_rule_name_create(). - */ - nxt_str_null(&name); - - for (i = 0; i < n; i++) { - rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next); - - rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name, - case_sensitive, encoding); - if (nxt_slow_path(rule == NULL)) { - return NULL; - } - - rule->object = object; - ruleset->rule[i] = rule; - } - - return ruleset; -} - - -static nxt_http_route_rule_t * -nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive, - nxt_http_uri_encoding_t encoding) -{ - int64_t hash; - nxt_http_route_rule_t *rule; - - rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive, - NXT_HTTP_ROUTE_PATTERN_NOCASE, - encoding); - if (nxt_slow_path(rule == NULL)) { - return NULL; - } - - hash = nxt_http_field_hash(mp, name, case_sensitive, encoding); - if (nxt_slow_path(hash == -1)) { - return NULL; - } - - rule->u.name.hash = hash; - rule->u.name.start = name->start; - rule->u.name.length = name->length; - - return rule; -} - - -static nxt_http_route_rule_t * -nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *cv, nxt_bool_t case_sensitive, - nxt_http_route_pattern_case_t pattern_case, - nxt_http_uri_encoding_t encoding) -{ - size_t size; - uint32_t i, n; - nxt_int_t ret; - nxt_conf_value_t *value; - nxt_http_route_rule_t *rule; - nxt_http_route_pattern_t *pattern; - - n = nxt_conf_array_elements_count_or_1(cv); - size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t); - - rule = nxt_mp_alloc(mp, size); - if (nxt_slow_path(rule == NULL)) { - return NULL; - } - - rule->items = n; - - pattern = &rule->pattern[0]; - - nxt_conf_array_qsort(cv, nxt_http_pattern_compare); - - for (i = 0; i < n; i++) { - pattern[i].case_sensitive = case_sensitive; - value = nxt_conf_get_array_element_or_itself(cv, i); - - ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i], - pattern_case, encoding); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - } - - return rule; -} - - -nxt_http_route_addr_rule_t * -nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *cv) -{ - size_t size; - uint32_t i, n; - nxt_conf_value_t *value; - nxt_http_route_addr_rule_t *addr_rule; - nxt_http_route_addr_pattern_t *pattern; - - n = nxt_conf_array_elements_count_or_1(cv); - - size = sizeof(nxt_http_route_addr_rule_t) - + n * sizeof(nxt_http_route_addr_pattern_t); - - addr_rule = nxt_mp_alloc(mp, size); - if (nxt_slow_path(addr_rule == NULL)) { - return NULL; - } - - addr_rule->items = n; - - for (i = 0; i < n; i++) { - pattern = &addr_rule->addr_pattern[i]; - value = nxt_conf_get_array_element_or_itself(cv, i); - - if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) { - return NULL; - } - } - - if (n > 1) { - nxt_qsort(addr_rule->addr_pattern, addr_rule->items, - sizeof(nxt_http_route_addr_pattern_t), - nxt_http_addr_pattern_compare); - } - - return addr_rule; -} - - -nxt_http_route_rule_t * -nxt_http_route_types_rule_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *types) -{ - return nxt_http_route_rule_create(task, mp, types, 0, - NXT_HTTP_ROUTE_PATTERN_LOWCASE, - NXT_HTTP_URI_ENCODING_NONE); -} - - -static int -nxt_http_pattern_compare(const void *one, const void *two) -{ - nxt_str_t test; - nxt_bool_t negative1, negative2; - nxt_conf_value_t *value; - - value = (nxt_conf_value_t *) one; - nxt_conf_get_string(value, &test); - negative1 = (test.length != 0 && test.start[0] == '!'); - - value = (nxt_conf_value_t *) two; - nxt_conf_get_string(value, &test); - negative2 = (test.length != 0 && test.start[0] == '!'); - - return (negative2 - negative1); -} - - -static int -nxt_http_addr_pattern_compare(const void *one, const void *two) -{ - const nxt_http_route_addr_pattern_t *p1, *p2; - - p1 = one; - p2 = two; - - return (p2->base.negative - p1->base.negative); -} - - -static nxt_int_t -nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, - nxt_http_route_pattern_case_t pattern_case, - nxt_http_uri_encoding_t encoding) -{ - u_char c, *p, *end; - nxt_str_t test, tmp; - nxt_int_t ret; - nxt_array_t *slices; -#if (NXT_HAVE_REGEX) - nxt_regex_t *re; - nxt_regex_err_t err; -#endif - nxt_http_route_pattern_type_t type; - nxt_http_route_pattern_slice_t *slice; - - type = NXT_HTTP_ROUTE_PATTERN_EXACT; - - nxt_conf_get_string(cv, &test); - - pattern->u.pattern_slices = NULL; - pattern->negative = 0; - pattern->any = 1; - pattern->min_length = 0; -#if (NXT_HAVE_REGEX) - pattern->regex = 0; -#endif - - if (test.length != 0 && test.start[0] == '!') { - test.start++; - test.length--; - - pattern->negative = 1; - pattern->any = 0; - } - - if (test.length > 0 && test.start[0] == '~') { -#if (NXT_HAVE_REGEX) - test.start++; - test.length--; - - re = nxt_regex_compile(mp, &test, &err); - if (nxt_slow_path(re == NULL)) { - if (err.offset < test.length) { - nxt_alert(task, "nxt_regex_compile(%V) failed: %s at offset %d", - &test, err.msg, (int) err.offset); - return NXT_ERROR; - } - - nxt_alert(task, "nxt_regex_compile(%V) failed %s", &test, err.msg); - - return NXT_ERROR; - } - - pattern->u.regex = re; - pattern->regex = 1; - - return NXT_OK; - -#else - return NXT_ERROR; -#endif - } - - slices = nxt_array_create(mp, 1, sizeof(nxt_http_route_pattern_slice_t)); - if (nxt_slow_path(slices == NULL)) { - return NXT_ERROR; - } - - pattern->u.pattern_slices = slices; - - if (test.length == 0) { - slice = nxt_array_add(slices); - if (nxt_slow_path(slice == NULL)) { - return NXT_ERROR; - } - - slice->type = NXT_HTTP_ROUTE_PATTERN_EXACT; - slice->start = NULL; - slice->length = 0; - - return NXT_OK; - } - - if (test.start[0] == '*') { - /* 'type' is no longer 'EXACT', assume 'END'. */ - type = NXT_HTTP_ROUTE_PATTERN_END; - test.start++; - test.length--; - } - - if (type == NXT_HTTP_ROUTE_PATTERN_EXACT) { - tmp.start = test.start; - - p = memchr(test.start, '*', test.length); - - if (p == NULL) { - /* No '*' found - EXACT pattern. */ - tmp.length = test.length; - type = NXT_HTTP_ROUTE_PATTERN_EXACT; - - test.start += test.length; - test.length = 0; - - } else { - /* '*' found - BEGIN pattern. */ - tmp.length = p - test.start; - type = NXT_HTTP_ROUTE_PATTERN_BEGIN; - - test.start = p + 1; - test.length -= tmp.length + 1; - } - - ret = nxt_http_route_pattern_slice(slices, &tmp, type, encoding, - pattern_case); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - pattern->min_length += tmp.length; - } - - end = test.start + test.length; - - if (test.length != 0 && end[-1] != '*') { - p = end - 1; - - while (p != test.start) { - c = *p--; - - if (c == '*') { - p += 2; - break; - } - } - - tmp.start = p; - tmp.length = end - p; - - test.length -= tmp.length; - end = p; - - ret = nxt_http_route_pattern_slice(slices, &tmp, - NXT_HTTP_ROUTE_PATTERN_END, - encoding, pattern_case); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - pattern->min_length += tmp.length; - } - - tmp.start = test.start; - tmp.length = 0; - - p = tmp.start; - - while (p != end) { - c = *p++; - - if (c != '*') { - tmp.length++; - continue; - } - - if (tmp.length == 0) { - tmp.start = p; - continue; - } - - ret = nxt_http_route_pattern_slice(slices, &tmp, - NXT_HTTP_ROUTE_PATTERN_SUBSTRING, - encoding, pattern_case); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - pattern->min_length += tmp.length; - - tmp.start = p; - tmp.length = 0; - } - - if (tmp.length != 0) { - ret = nxt_http_route_pattern_slice(slices, &tmp, - NXT_HTTP_ROUTE_PATTERN_SUBSTRING, - encoding, pattern_case); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - pattern->min_length += tmp.length; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_route_decode_str(nxt_str_t *str, nxt_http_uri_encoding_t encoding) -{ - u_char *start, *end; - - switch (encoding) { - case NXT_HTTP_URI_ENCODING_NONE: - break; - - case NXT_HTTP_URI_ENCODING: - start = str->start; - - end = nxt_decode_uri(start, start, str->length); - if (nxt_slow_path(end == NULL)) { - return NXT_ERROR; - } - - str->length = end - start; - break; - - case NXT_HTTP_URI_ENCODING_PLUS: - start = str->start; - - end = nxt_decode_uri_plus(start, start, str->length); - if (nxt_slow_path(end == NULL)) { - return NXT_ERROR; - } - - str->length = end - start; - break; - - default: - nxt_unreachable(); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_route_pattern_slice(nxt_array_t *slices, - nxt_str_t *test, nxt_http_route_pattern_type_t type, - nxt_http_uri_encoding_t encoding, - nxt_http_route_pattern_case_t pattern_case) -{ - u_char *start; - nxt_int_t ret; - nxt_http_route_pattern_slice_t *slice; - - ret = nxt_http_route_decode_str(test, encoding); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - start = nxt_mp_nget(slices->mem_pool, test->length); - if (nxt_slow_path(start == NULL)) { - return NXT_ERROR; - } - - switch (pattern_case) { - - case NXT_HTTP_ROUTE_PATTERN_UPCASE: - nxt_memcpy_upcase(start, test->start, test->length); - break; - - case NXT_HTTP_ROUTE_PATTERN_LOWCASE: - nxt_memcpy_lowcase(start, test->start, test->length); - break; - - case NXT_HTTP_ROUTE_PATTERN_NOCASE: - nxt_memcpy(start, test->start, test->length); - break; - } - - slice = nxt_array_add(slices); - if (nxt_slow_path(slice == NULL)) { - return NXT_ERROR; - } - - slice->type = type; - slice->start = start; - slice->length = test->length; - - return NXT_OK; -} - - -nxt_int_t -nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) -{ - nxt_int_t ret; - nxt_http_route_t **route, **end; - nxt_http_routes_t *routes; - - routes = tmcf->router_conf->routes; - - if (routes != NULL) { - route = &routes->route[0]; - end = route + routes->items; - - while (route < end) { - ret = nxt_http_route_resolve(task, tmcf, *route); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - route++; - } - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_http_route_t *route) -{ - nxt_int_t ret; - nxt_http_route_match_t **match, **end; - - match = &route->match[0]; - end = match + route->items; - - while (match < end) { - ret = nxt_http_action_resolve(task, tmcf, &(*match)->action); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - match++; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_http_action_t *action) -{ - nxt_int_t ret; - nxt_str_t pass; - - if (action->handler != NULL) { - if (action->fallback != NULL) { - return nxt_http_action_resolve(task, tmcf, action->fallback); - } - - return NXT_OK; - } - - if (nxt_tstr_is_const(action->u.tstr)) { - nxt_tstr_str(action->u.tstr, &pass); - - ret = nxt_http_pass_find(tmcf->mem_pool, tmcf->router_conf, &pass, - action); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - } else { - action->handler = nxt_http_pass_var; - } - - return NXT_OK; -} - - -static nxt_http_action_t * -nxt_http_pass_var(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *action) -{ - nxt_int_t ret; - nxt_str_t str; - nxt_tstr_t *tstr; - nxt_router_conf_t *rtcf; - - tstr = action->u.tstr; - - nxt_tstr_str(tstr, &str); - - nxt_debug(task, "http pass: \"%V\"", &str); - - rtcf = r->conf->socket_conf->router_conf; - - ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, &r->tstr_cache, - r, r->mem_pool); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - action = nxt_mp_zget(r->mem_pool, - sizeof(nxt_http_action_t) + sizeof(nxt_str_t)); - if (nxt_slow_path(action == NULL)) { - goto fail; - } - - action->u.pass = nxt_pointer_to(action, sizeof(nxt_http_action_t)); - - nxt_tstr_query(task, r->tstr_query, tstr, action->u.pass); - nxt_tstr_query_resolve(task, r->tstr_query, action, - nxt_http_pass_query_ready, - nxt_http_pass_query_error); - return NULL; - -fail: - - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - return NULL; -} - - -static void -nxt_http_pass_query_ready(nxt_task_t *task, void *obj, void *data) -{ - nxt_int_t ret; - nxt_router_conf_t *rtcf; - nxt_http_action_t *action; - nxt_http_status_t status; - nxt_http_request_t *r; - - r = obj; - action = data; - rtcf = r->conf->socket_conf->router_conf; - - nxt_debug(task, "http pass lookup: %V", action->u.pass); - - ret = nxt_http_pass_find(r->mem_pool, rtcf, action->u.pass, action); - - if (ret != NXT_OK) { - status = (ret == NXT_DECLINED) ? NXT_HTTP_NOT_FOUND - : NXT_HTTP_INTERNAL_SERVER_ERROR; - - nxt_http_request_error(task, r, status); - return; - } - - nxt_http_request_action(task, r, action); -} - - -static void -nxt_http_pass_query_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_request_t *r; - - r = obj; - - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); -} - - -static nxt_int_t -nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf, nxt_str_t *pass, - nxt_http_action_t *action) -{ - nxt_int_t ret; - nxt_str_t segments[3]; - - ret = nxt_http_pass_segments(mp, pass, segments, 3); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - if (nxt_str_eq(&segments[0], "applications", 12)) { - return nxt_router_application_init(rtcf, &segments[1], &segments[2], - action); - } - - if (segments[2].length == 0) { - if (nxt_str_eq(&segments[0], "upstreams", 9)) { - return nxt_upstream_find(rtcf->upstreams, &segments[1], action); - } - - if (nxt_str_eq(&segments[0], "routes", 6)) { - return nxt_http_route_find(rtcf->routes, &segments[1], action); - } - } - - return NXT_DECLINED; -} - - -nxt_int_t -nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass, nxt_str_t *segments, - nxt_uint_t n) -{ - u_char *p; - nxt_str_t rest; - - if (nxt_slow_path(nxt_str_dup(mp, &rest, pass) == NULL)) { - return NXT_ERROR; - } - - nxt_memzero(segments, n * sizeof(nxt_str_t)); - - do { - p = memchr(rest.start, '/', rest.length); - - if (p != NULL) { - n--; - - if (n == 0) { - return NXT_DECLINED; - } - - segments->length = p - rest.start; - segments->start = rest.start; - - rest.length -= segments->length + 1; - rest.start = p + 1; - - } else { - n = 0; - *segments = rest; - } - - if (segments->length == 0) { - return NXT_DECLINED; - } - - p = nxt_decode_uri(segments->start, segments->start, segments->length); - if (p == NULL) { - return NXT_DECLINED; - } - - segments->length = p - segments->start; - segments++; - - } while (n); - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name, - nxt_http_action_t *action) -{ - nxt_http_route_t **route, **end; - - if (routes == NULL) { - return NXT_DECLINED; - } - - route = &routes->route[0]; - end = route + routes->items; - - while (route < end) { - if (nxt_strstr_eq(&(*route)->name, name)) { - action->u.route = *route; - action->handler = nxt_http_route_handler; - - return NXT_OK; - } - - route++; - } - - return NXT_DECLINED; -} - - -nxt_http_action_t * -nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_str_t *pass) -{ - nxt_mp_t *mp; - nxt_int_t ret; - nxt_router_conf_t *rtcf; - nxt_http_action_t *action; - - rtcf = tmcf->router_conf; - mp = rtcf->mem_pool; - - action = nxt_mp_zalloc(mp, sizeof(nxt_http_action_t)); - if (nxt_slow_path(action == NULL)) { - return NULL; - } - - action->u.tstr = nxt_tstr_compile(rtcf->tstr_state, pass, 0); - if (nxt_slow_path(action->u.tstr == NULL)) { - return NULL; - } - - action->handler = NULL; - - ret = nxt_http_action_resolve(task, tmcf, action); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - return action; -} - - -/* COMPATIBILITY: listener application. */ - -nxt_http_action_t * -nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf, - nxt_str_t *name) -{ - nxt_http_action_t *action; - - action = nxt_mp_zalloc(rtcf->mem_pool, sizeof(nxt_http_action_t)); - if (nxt_slow_path(action == NULL)) { - return NULL; - } - - (void) nxt_router_application_init(rtcf, name, NULL, action); - - return action; -} - - -static nxt_http_action_t * -nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *start) -{ - size_t i; - nxt_http_route_t *route; - nxt_http_action_t *action; - - route = start->u.route; - - for (i = 0; i < route->items; i++) { - action = nxt_http_route_match(task, r, route->match[i]); - - if (nxt_slow_path(r->log_route)) { - uint32_t lvl = (action == NULL) ? NXT_LOG_INFO : NXT_LOG_NOTICE; - const char *sel = (action == NULL) ? "discarded" : "selected"; - - if (route->name.length == 0) { - nxt_log(task, lvl, "\"routes/%z\" %s", i, sel); - } else { - nxt_log(task, lvl, "\"routes/%V/%z\" %s", &route->name, i, sel); - } - } - - if (action != NULL) { - - if (action != NXT_HTTP_ACTION_ERROR) { - r->action = action; - } - - return action; - } - } - - nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND); - - return NULL; -} - - -static nxt_http_action_t * -nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_route_match_t *match) -{ - nxt_int_t ret; - nxt_http_route_test_t *test, *end; - - test = &match->test[0]; - end = test + match->items; - - while (test < end) { - switch (test->rule->object) { - case NXT_HTTP_ROUTE_TABLE: - ret = nxt_http_route_table(r, test->table); - break; - case NXT_HTTP_ROUTE_SOURCE: - ret = nxt_http_route_addr_rule(r, test->addr_rule, r->remote); - break; - case NXT_HTTP_ROUTE_DESTINATION: - if (r->local == NULL && nxt_fast_path(r->proto.any != NULL)) { - nxt_http_proto[r->protocol].local_addr(task, r); - } - - ret = nxt_http_route_addr_rule(r, test->addr_rule, r->local); - break; - default: - ret = nxt_http_route_rule(r, test->rule); - break; - } - - if (ret <= 0) { - /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */ - return (nxt_http_action_t *) (intptr_t) ret; - } - - test++; - } - - return &match->action; -} - - -static nxt_int_t -nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) -{ - nxt_int_t ret; - nxt_http_route_ruleset_t **ruleset, **end; - - ret = 1; - ruleset = &table->ruleset[0]; - end = ruleset + table->items; - - while (ruleset < end) { - ret = nxt_http_route_ruleset(r, *ruleset); - - if (ret != 0) { - return ret; - } - - ruleset++; - } - - return ret; -} - - -static nxt_int_t -nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset) -{ - nxt_int_t ret; - nxt_http_route_rule_t **rule, **end; - - rule = &ruleset->rule[0]; - end = rule + ruleset->items; - - while (rule < end) { - ret = nxt_http_route_rule(r, *rule); - - if (ret <= 0) { - return ret; - } - - rule++; - } - - return 1; -} - - -static nxt_int_t -nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) -{ - void *p, **pp; - u_char *start; - size_t length; - nxt_str_t *s; - - switch (rule->object) { - - case NXT_HTTP_ROUTE_HEADER: - return nxt_http_route_header(r, rule); - - case NXT_HTTP_ROUTE_ARGUMENT: - return nxt_http_route_arguments(r, rule); - - case NXT_HTTP_ROUTE_COOKIE: - return nxt_http_route_cookies(r, rule); - - case NXT_HTTP_ROUTE_SCHEME: - return nxt_http_route_scheme(r, rule); - - case NXT_HTTP_ROUTE_QUERY: - return nxt_http_route_query(r, rule); - - default: - break; - } - - p = nxt_pointer_to(r, rule->u.offset); - - if (rule->object == NXT_HTTP_ROUTE_STRING) { - s = p; - - } else { - /* NXT_HTTP_ROUTE_STRING_PTR */ - pp = p; - s = *pp; - - if (s == NULL) { - return 0; - } - } - - length = s->length; - start = s->start; - - return nxt_http_route_test_rule(r, rule, start, length); -} - - -static nxt_int_t -nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p, - nxt_sockaddr_t *sa) -{ -#if (NXT_INET6) - uint32_t i; -#endif - in_port_t in_port; - nxt_int_t match; - struct sockaddr_in *sin; -#if (NXT_INET6) - struct sockaddr_in6 *sin6; -#endif - nxt_http_route_addr_base_t *base; - - base = &p->base; - - switch (sa->u.sockaddr.sa_family) { - - case AF_INET: - - match = (base->addr_family == AF_INET - || base->addr_family == AF_UNSPEC); - if (!match) { - break; - } - - sin = &sa->u.sockaddr_in; - in_port = ntohs(sin->sin_port); - - match = (in_port >= base->port.start && in_port <= base->port.end); - if (!match) { - break; - } - - switch (base->match_type) { - - case NXT_HTTP_ROUTE_ADDR_ANY: - break; - - case NXT_HTTP_ROUTE_ADDR_EXACT: - match = (memcmp(&sin->sin_addr, &p->addr.v4.start, - sizeof(struct in_addr)) - == 0); - break; - - case NXT_HTTP_ROUTE_ADDR_RANGE: - match = (memcmp(&sin->sin_addr, &p->addr.v4.start, - sizeof(struct in_addr)) >= 0 - && memcmp(&sin->sin_addr, &p->addr.v4.end, - sizeof(struct in_addr)) <= 0); - break; - - case NXT_HTTP_ROUTE_ADDR_CIDR: - match = ((sin->sin_addr.s_addr & p->addr.v4.end) - == p->addr.v4.start); - break; - - default: - nxt_unreachable(); - } - - break; - -#if (NXT_INET6) - case AF_INET6: - - match = (base->addr_family == AF_INET6 - || base->addr_family == AF_UNSPEC); - if (!match) { - break; - } - - sin6 = &sa->u.sockaddr_in6; - in_port = ntohs(sin6->sin6_port); - - match = (in_port >= base->port.start && in_port <= base->port.end); - if (!match) { - break; - } - - switch (base->match_type) { - - case NXT_HTTP_ROUTE_ADDR_ANY: - break; - - case NXT_HTTP_ROUTE_ADDR_EXACT: - match = (memcmp(&sin6->sin6_addr, &p->addr.v6.start, - sizeof(struct in6_addr)) - == 0); - break; - - case NXT_HTTP_ROUTE_ADDR_RANGE: - match = (memcmp(&sin6->sin6_addr, &p->addr.v6.start, - sizeof(struct in6_addr)) >= 0 - && memcmp(&sin6->sin6_addr, &p->addr.v6.end, - sizeof(struct in6_addr)) <= 0); - break; - - case NXT_HTTP_ROUTE_ADDR_CIDR: - for (i = 0; i < 16; i++) { - match = ((sin6->sin6_addr.s6_addr[i] - & p->addr.v6.end.s6_addr[i]) - == p->addr.v6.start.s6_addr[i]); - - if (!match) { - break; - } - } - - break; - - default: - nxt_unreachable(); - } - - break; -#endif - -#if (NXT_HAVE_UNIX_DOMAIN) - case AF_UNIX: - - match = (base->addr_family == AF_UNIX); - break; -#endif - - default: - match = 0; - break; - } - - return match ^ base->negative; -} - - -nxt_int_t -nxt_http_route_addr_rule(nxt_http_request_t *r, - nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa) -{ - uint32_t n; - nxt_bool_t matches; - nxt_http_route_addr_pattern_t *p; - - n = addr_rule->items; - - if (n == 0) { - return 0; - } - - p = &addr_rule->addr_pattern[0] - 1; - - do { - p++; - n--; - - matches = nxt_http_route_addr_pattern_match(p, sa); - - if (p->base.negative) { - if (matches) { - continue; - } - - return 0; - } - - if (matches) { - return 1; - } - - } while (n > 0); - - return p->base.negative; -} - - -static nxt_int_t -nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) -{ - nxt_int_t ret; - nxt_http_field_t *f; - - ret = 0; - - nxt_list_each(f, r->fields) { - - if (rule->u.name.hash != f->hash - || rule->u.name.length != f->name_length - || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length) - != 0) - { - continue; - } - - ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NXT_ERROR; - } - - if (ret == 0) { - return ret; - } - - } nxt_list_loop; - - return ret; -} - - -static nxt_int_t -nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule) -{ - nxt_array_t *arguments; - - arguments = nxt_http_arguments_parse(r); - if (nxt_slow_path(arguments == NULL)) { - return -1; - } - - return nxt_http_route_test_argument(r, rule, arguments); -} - - -static nxt_int_t -nxt_http_route_test_argument(nxt_http_request_t *r, - nxt_http_route_rule_t *rule, nxt_array_t *array) -{ - nxt_int_t ret; - nxt_http_name_value_t *nv, *end; - - ret = 0; - - nv = array->elts; - end = nv + array->nelts; - - while (nv < end) { - - if (rule->u.name.hash == nv->hash - && rule->u.name.length == nv->name_length - && memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) - { - ret = nxt_http_route_test_rule(r, rule, nv->value, - nv->value_length); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NXT_ERROR; - } - - if (ret == 0) { - break; - } - } - - nv++; - } - - return ret; -} - - -static nxt_int_t -nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule) -{ - nxt_bool_t https; - nxt_http_route_pattern_slice_t *pattern_slice; - - pattern_slice = rule->pattern[0].u.pattern_slices->elts; - https = (pattern_slice->length == nxt_length("https")); - - return (r->tls == https); -} - - -static nxt_int_t -nxt_http_route_query(nxt_http_request_t *r, nxt_http_route_rule_t *rule) -{ - nxt_array_t *arguments; - - arguments = nxt_http_arguments_parse(r); - if (nxt_slow_path(arguments == NULL)) { - return -1; - } - - return nxt_http_route_test_rule(r, rule, r->args_decoded.start, - r->args_decoded.length); -} - - -static nxt_int_t -nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule) -{ - nxt_array_t *cookies; - - cookies = nxt_http_cookies_parse(r); - if (nxt_slow_path(cookies == NULL)) { - return -1; - } - - return nxt_http_route_test_cookie(r, rule, cookies); -} - - -static nxt_int_t -nxt_http_route_test_cookie(nxt_http_request_t *r, - nxt_http_route_rule_t *rule, nxt_array_t *array) -{ - nxt_int_t ret; - nxt_http_name_value_t *nv, *end; - - ret = 0; - - nv = array->elts; - end = nv + array->nelts; - - while (nv < end) { - - if (rule->u.name.hash == nv->hash - && rule->u.name.length == nv->name_length - && memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) - { - ret = nxt_http_route_test_rule(r, rule, nv->value, - nv->value_length); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NXT_ERROR; - } - - if (ret == 0) { - break; - } - } - - nv++; - } - - return ret; -} - - -nxt_int_t -nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, - u_char *start, size_t length) -{ - nxt_int_t ret; - nxt_http_route_pattern_t *pattern, *end; - - ret = 1; - pattern = &rule->pattern[0]; - end = pattern + rule->items; - - while (pattern < end) { - ret = nxt_http_route_pattern(r, pattern, start, length); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NXT_ERROR; - } - - /* nxt_http_route_pattern() returns either 1 or 0. */ - ret ^= pattern->negative; - - if (pattern->any == ret) { - return ret; - } - - pattern++; - } - - return ret; -} - - -static nxt_int_t -nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, - u_char *start, size_t length) -{ - u_char *p, *end, *test; - size_t test_length; - uint32_t i; - nxt_array_t *pattern_slices; - nxt_http_route_pattern_slice_t *pattern_slice; - -#if (NXT_HAVE_REGEX) - if (pattern->regex) { - if (r->regex_match == NULL) { - r->regex_match = nxt_regex_match_create(r->mem_pool, 0); - if (nxt_slow_path(r->regex_match == NULL)) { - return NXT_ERROR; - } - } - - return nxt_regex_match(pattern->u.regex, start, length, r->regex_match); - } -#endif - - if (length < pattern->min_length) { - return 0; - } - - nxt_assert(pattern->u.pattern_slices != NULL); - - pattern_slices = pattern->u.pattern_slices; - pattern_slice = pattern_slices->elts; - end = start + length; - - for (i = 0; i < pattern_slices->nelts; i++, pattern_slice++) { - test = pattern_slice->start; - test_length = pattern_slice->length; - - switch (pattern_slice->type) { - case NXT_HTTP_ROUTE_PATTERN_EXACT: - return ((length == pattern->min_length) && - nxt_http_route_memcmp(start, test, test_length, - pattern->case_sensitive)); - - case NXT_HTTP_ROUTE_PATTERN_BEGIN: - if (nxt_http_route_memcmp(start, test, test_length, - pattern->case_sensitive)) - { - start += test_length; - break; - } - - return 0; - - case NXT_HTTP_ROUTE_PATTERN_END: - p = end - test_length; - - if (nxt_http_route_memcmp(p, test, test_length, - pattern->case_sensitive)) - { - end = p; - break; - } - - return 0; - - case NXT_HTTP_ROUTE_PATTERN_SUBSTRING: - if (pattern->case_sensitive) { - p = nxt_memstrn(start, end, (char *) test, test_length); - - } else { - p = nxt_memcasestrn(start, end, (char *) test, test_length); - } - - if (p == NULL) { - return 0; - } - - start = p + test_length; - } - } - - return 1; -} - - -static nxt_int_t -nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length, - nxt_bool_t case_sensitive) -{ - nxt_int_t n; - - if (case_sensitive) { - n = memcmp(start, test, test_length); - - } else { - n = nxt_memcasecmp(start, test, test_length); - } - - return (n == 0); -} diff --git a/src/nxt_http_route_addr.c b/src/nxt_http_route_addr.c deleted file mode 100644 index 5a0d7679..00000000 --- a/src/nxt_http_route_addr.c +++ /dev/null @@ -1,346 +0,0 @@ - -/* - * Copyright (C) Axel Duch - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -#if (NXT_INET6) -static nxt_bool_t nxt_valid_ipv6_blocks(u_char *c, size_t len); -#endif - - -nxt_int_t -nxt_http_route_addr_pattern_parse(nxt_mp_t *mp, - nxt_http_route_addr_pattern_t *pattern, nxt_conf_value_t *cv) -{ - u_char *delim; - nxt_int_t ret, cidr_prefix; - nxt_str_t addr, port; - nxt_http_route_addr_base_t *base; - nxt_http_route_addr_range_t *inet; - - if (nxt_conf_type(cv) != NXT_CONF_STRING) { - return NXT_ADDR_PATTERN_CV_TYPE_ERROR; - } - - nxt_conf_get_string(cv, &addr); - - base = &pattern->base; - - if (addr.length > 0 && addr.start[0] == '!') { - addr.start++; - addr.length--; - - base->negative = 1; - - } else { - base->negative = 0; - } - - if (nxt_str_eq(&addr, "unix", 4)) { -#if (NXT_HAVE_UNIX_DOMAIN) - base->addr_family = AF_UNIX; - - return NXT_OK; -#else - return NXT_ADDR_PATTERN_NO_UNIX_ERROR; -#endif - } - - if (nxt_slow_path(addr.length < 2)) { - return NXT_ADDR_PATTERN_LENGTH_ERROR; - } - - nxt_str_null(&port); - - if (addr.start[0] == '*' && addr.start[1] == ':') { - port.start = addr.start + 2; - port.length = addr.length - 2; - base->addr_family = AF_UNSPEC; - base->match_type = NXT_HTTP_ROUTE_ADDR_ANY; - - goto parse_port; - } - - if (nxt_inet6_probe(&addr)) { -#if (NXT_INET6) - u_char *end; - uint8_t i; - nxt_int_t len; - nxt_http_route_in6_addr_range_t *inet6; - - base->addr_family = AF_INET6; - - if (addr.start[0] == '[') { - addr.start++; - addr.length--; - - end = addr.start + addr.length; - - port.start = nxt_rmemstrn(addr.start, end, "]:", 2); - if (nxt_slow_path(port.start == NULL)) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - addr.length = port.start - addr.start; - port.start += nxt_length("]:"); - port.length = end - port.start; - } - - inet6 = &pattern->addr.v6; - - delim = memchr(addr.start, '-', addr.length); - if (delim != NULL) { - len = delim - addr.start; - if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, len))) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - ret = nxt_inet6_addr(&inet6->start, addr.start, len); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - len = addr.start + addr.length - delim - 1; - if (nxt_slow_path(!nxt_valid_ipv6_blocks(delim + 1, len))) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - ret = nxt_inet6_addr(&inet6->end, delim + 1, len); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - if (nxt_slow_path(memcmp(&inet6->start, &inet6->end, - sizeof(struct in6_addr)) > 0)) - { - return NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR; - } - - base->match_type = NXT_HTTP_ROUTE_ADDR_RANGE; - - goto parse_port; - } - - delim = memchr(addr.start, '/', addr.length); - if (delim != NULL) { - cidr_prefix = nxt_int_parse(delim + 1, - addr.start + addr.length - (delim + 1)); - if (nxt_slow_path(cidr_prefix < 0 || cidr_prefix > 128)) { - return NXT_ADDR_PATTERN_CIDR_ERROR; - } - - addr.length = delim - addr.start; - if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, - addr.length))) - { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - ret = nxt_inet6_addr(&inet6->start, addr.start, addr.length); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - if (nxt_slow_path(cidr_prefix == 0)) { - base->match_type = NXT_HTTP_ROUTE_ADDR_ANY; - - goto parse_port; - } - - if (nxt_slow_path(cidr_prefix == 128)) { - base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT; - - goto parse_port; - } - - base->match_type = NXT_HTTP_ROUTE_ADDR_CIDR; - - for (i = 0; i < sizeof(struct in6_addr); i++) { - if (cidr_prefix >= 8) { - inet6->end.s6_addr[i] = 0xFF; - cidr_prefix -= 8; - - continue; - } - - if (cidr_prefix > 0) { - inet6->end.s6_addr[i] = 0xFF & (0xFF << (8 - cidr_prefix)); - inet6->start.s6_addr[i] &= inet6->end.s6_addr[i]; - cidr_prefix = 0; - - continue; - } - - inet6->start.s6_addr[i] = 0; - inet6->end.s6_addr[i] = 0; - } - - goto parse_port; - } - - base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT; - - if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, addr.length))) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - ret = nxt_inet6_addr(&inet6->start, addr.start, addr.length); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - goto parse_port; -#endif - return NXT_ADDR_PATTERN_NO_IPv6_ERROR; - } - - base->addr_family = AF_INET; - - delim = memchr(addr.start, ':', addr.length); - if (delim != NULL) { - port.start = delim + 1; - port.length = addr.start + addr.length - port.start; - addr.length = delim - addr.start; - } - - inet = &pattern->addr.v4; - - delim = memchr(addr.start, '-', addr.length); - if (delim != NULL) { - inet->start = nxt_inet_addr(addr.start, delim - addr.start); - if (nxt_slow_path(inet->start == INADDR_NONE)) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - inet->end = nxt_inet_addr(delim + 1, - addr.start + addr.length - (delim + 1)); - if (nxt_slow_path(inet->end == INADDR_NONE)) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - if (nxt_slow_path(memcmp(&inet->start, &inet->end, - sizeof(struct in_addr)) > 0)) - { - return NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR; - } - - base->match_type = NXT_HTTP_ROUTE_ADDR_RANGE; - - goto parse_port; - } - - delim = memchr(addr.start, '/', addr.length); - if (delim != NULL) { - cidr_prefix = nxt_int_parse(delim + 1, - addr.start + addr.length - (delim + 1)); - if (nxt_slow_path(cidr_prefix < 0 || cidr_prefix > 32)) { - return NXT_ADDR_PATTERN_CIDR_ERROR; - } - - addr.length = delim - addr.start; - inet->end = htonl(0xFFFFFFFF & (0xFFFFFFFFULL << (32 - cidr_prefix))); - - inet->start = nxt_inet_addr(addr.start, addr.length) & inet->end; - if (nxt_slow_path(inet->start == INADDR_NONE)) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - if (cidr_prefix == 0) { - base->match_type = NXT_HTTP_ROUTE_ADDR_ANY; - - goto parse_port; - } - - if (cidr_prefix < 32) { - base->match_type = NXT_HTTP_ROUTE_ADDR_CIDR; - - goto parse_port; - } - } - - inet->start = nxt_inet_addr(addr.start, addr.length); - if (nxt_slow_path(inet->start == INADDR_NONE)) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT; - -parse_port: - - if (port.length == 0) { - if (nxt_slow_path(port.start != NULL)) { - return NXT_ADDR_PATTERN_FORMAT_ERROR; - } - - base->port.start = 0; - base->port.end = 65535; - - return NXT_OK; - } - - delim = memchr(port.start, '-', port.length - 1); - if (delim != NULL) { - ret = nxt_int_parse(port.start, delim - port.start); - if (nxt_slow_path(ret < 0 || ret > 65535)) { - return NXT_ADDR_PATTERN_PORT_ERROR; - } - - base->port.start = ret; - - ret = nxt_int_parse(delim + 1, port.start + port.length - (delim + 1)); - if (nxt_slow_path(ret < base->port.start || ret > 65535)) { - return NXT_ADDR_PATTERN_PORT_ERROR; - } - - base->port.end = ret; - - } else { - ret = nxt_int_parse(port.start, port.length); - if (nxt_slow_path(ret < 0 || ret > 65535)) { - return NXT_ADDR_PATTERN_PORT_ERROR; - } - - base->port.start = ret; - base->port.end = ret; - } - - return NXT_OK; -} - - -#if (NXT_INET6) - -static nxt_bool_t -nxt_valid_ipv6_blocks(u_char *c, size_t len) -{ - u_char *end; - nxt_uint_t colon_gap; - - end = c + len; - colon_gap = 0; - - while (c != end) { - if (*c == ':') { - colon_gap = 0; - c++; - - continue; - } - - colon_gap++; - c++; - - if (nxt_slow_path(colon_gap > 4)) { - return 0; - } - } - - return 1; -} - -#endif diff --git a/src/nxt_http_route_addr.h b/src/nxt_http_route_addr.h deleted file mode 100644 index 2deda6f8..00000000 --- a/src/nxt_http_route_addr.h +++ /dev/null @@ -1,74 +0,0 @@ - -/* - * Copyright (C) Axel Duch - * Copyright (C) NGINX, Inc. - */ - -#include - -#ifndef _NXT_HTTP_ROUTE_ADDR_H_INCLUDED_ -#define _NXT_HTTP_ROUTE_ADDR_H_INCLUDED_ - - -enum { - NXT_HTTP_ROUTE_ADDR_ANY = 0, - NXT_HTTP_ROUTE_ADDR_RANGE, - NXT_HTTP_ROUTE_ADDR_EXACT, - NXT_HTTP_ROUTE_ADDR_CIDR, -}; - - -enum { - NXT_ADDR_PATTERN_PORT_ERROR = NXT_OK + 1, - NXT_ADDR_PATTERN_CV_TYPE_ERROR, - NXT_ADDR_PATTERN_LENGTH_ERROR, - NXT_ADDR_PATTERN_FORMAT_ERROR, - NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR, - NXT_ADDR_PATTERN_CIDR_ERROR, - NXT_ADDR_PATTERN_NO_IPv6_ERROR, - NXT_ADDR_PATTERN_NO_UNIX_ERROR, -}; - - -typedef struct { - in_addr_t start; - in_addr_t end; -} nxt_http_route_addr_range_t; - - -#if (NXT_INET6) -typedef struct { - struct in6_addr start; - struct in6_addr end; -} nxt_http_route_in6_addr_range_t; -#endif - - -typedef struct { - uint8_t match_type:2; - uint8_t negative:1; - uint8_t addr_family; - - struct { - uint16_t start; - uint16_t end; - } port; -} nxt_http_route_addr_base_t; - - -typedef struct { - nxt_http_route_addr_base_t base; - - union { - nxt_http_route_addr_range_t v4; -#if (NXT_INET6) - nxt_http_route_in6_addr_range_t v6; -#endif - } addr; -} nxt_http_route_addr_pattern_t; - - -NXT_EXPORT nxt_int_t nxt_http_route_addr_pattern_parse(nxt_mp_t *mp, - nxt_http_route_addr_pattern_t *pattern, nxt_conf_value_t *cv); - -#endif /* _NXT_HTTP_ROUTE_ADDR_H_INCLUDED_ */ diff --git a/src/nxt_http_set_headers.c b/src/nxt_http_set_headers.c deleted file mode 100644 index 25dd7478..00000000 --- a/src/nxt_http_set_headers.c +++ /dev/null @@ -1,176 +0,0 @@ - -/* - * Copyright (C) Zhidao HONG - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -typedef struct { - nxt_str_t name; - nxt_tstr_t *value; -} nxt_http_header_val_t; - - -nxt_int_t -nxt_http_set_headers_init(nxt_router_conf_t *rtcf, nxt_http_action_t *action, - nxt_http_action_conf_t *acf) - { - uint32_t next; - nxt_str_t str, name; - nxt_array_t *headers; - nxt_conf_value_t *value; - nxt_http_header_val_t *hv; - - headers = nxt_array_create(rtcf->mem_pool, 4, - sizeof(nxt_http_header_val_t)); - if (nxt_slow_path(headers == NULL)) { - return NXT_ERROR; - } - - action->set_headers = headers; - - next = 0; - - for ( ;; ) { - value = nxt_conf_next_object_member(acf->set_headers, &name, &next); - if (value == NULL) { - break; - } - - hv = nxt_array_zero_add(headers); - if (nxt_slow_path(hv == NULL)) { - return NXT_ERROR; - } - - hv->name.length = name.length; - - hv->name.start = nxt_mp_nget(rtcf->mem_pool, name.length); - if (nxt_slow_path(hv->name.start == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy(hv->name.start, name.start, name.length); - - if (nxt_conf_type(value) == NXT_CONF_STRING) { - nxt_conf_get_string(value, &str); - - hv->value = nxt_tstr_compile(rtcf->tstr_state, &str, 0); - if (nxt_slow_path(hv->value == NULL)) { - return NXT_ERROR; - } - } - } - - return NXT_OK; -} - - -static nxt_http_field_t * -nxt_http_resp_header_find(nxt_http_request_t *r, u_char *name, size_t length) -{ - nxt_http_field_t *f; - - nxt_list_each(f, r->resp.fields) { - - if (f->skip) { - continue; - } - - if (length == f->name_length - && nxt_memcasecmp(name, f->name, f->name_length) == 0) - { - return f; - } - - } nxt_list_loop; - - return NULL; -} - - -nxt_int_t -nxt_http_set_headers(nxt_http_request_t *r) -{ - nxt_int_t ret; - nxt_uint_t i, n; - nxt_str_t *value; - nxt_http_field_t *f; - nxt_router_conf_t *rtcf; - nxt_http_action_t *action; - nxt_http_header_val_t *hv, *header; - - action = r->action; - - if (action == NULL || action->set_headers == NULL) { - return NXT_OK; - } - - if ((r->status < NXT_HTTP_OK || r->status >= NXT_HTTP_BAD_REQUEST)) { - return NXT_OK; - } - - rtcf = r->conf->socket_conf->router_conf; - - header = action->set_headers->elts; - n = action->set_headers->nelts; - - value = nxt_mp_zalloc(r->mem_pool, sizeof(nxt_str_t) * n); - if (nxt_slow_path(value == NULL)) { - return NXT_ERROR; - } - - for (i = 0; i < n; i++) { - hv = &header[i]; - - if (hv->value == NULL) { - continue; - } - - if (nxt_tstr_is_const(hv->value)) { - nxt_tstr_str(hv->value, &value[i]); - - } else { - ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, - &r->tstr_cache, r, r->mem_pool); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - nxt_tstr_query(&r->task, r->tstr_query, hv->value, &value[i]); - - if (nxt_slow_path(nxt_tstr_query_failed(r->tstr_query))) { - return NXT_ERROR; - } - } - } - - for (i = 0; i < n; i++) { - hv = &header[i]; - - f = nxt_http_resp_header_find(r, hv->name.start, hv->name.length); - - if (value[i].start != NULL) { - - if (f == NULL) { - f = nxt_list_zero_add(r->resp.fields); - if (nxt_slow_path(f == NULL)) { - return NXT_ERROR; - } - - f->name = hv->name.start; - f->name_length = hv->name.length; - } - - f->value = value[i].start; - f->value_length = value[i].length; - - } else if (f != NULL) { - f->skip = 1; - } - } - - return NXT_OK; -} diff --git a/src/nxt_http_static.c b/src/nxt_http_static.c deleted file mode 100644 index ee25015e..00000000 --- a/src/nxt_http_static.c +++ /dev/null @@ -1,1102 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -typedef struct { - nxt_tstr_t *tstr; -#if (NXT_HAVE_OPENAT2) - u_char *fname; -#endif - uint8_t is_const; /* 1 bit */ -} nxt_http_static_share_t; - - -typedef struct { - nxt_uint_t nshares; - nxt_http_static_share_t *shares; - nxt_str_t index; -#if (NXT_HAVE_OPENAT2) - nxt_tstr_t *chroot; - nxt_uint_t resolve; -#endif - nxt_http_route_rule_t *types; -} nxt_http_static_conf_t; - - -typedef struct { - nxt_http_action_t *action; - nxt_str_t share; -#if (NXT_HAVE_OPENAT2) - nxt_str_t chroot; -#endif - uint32_t share_idx; - uint8_t need_body; /* 1 bit */ -} nxt_http_static_ctx_t; - - -#define NXT_HTTP_STATIC_BUF_COUNT 2 -#define NXT_HTTP_STATIC_BUF_SIZE (128 * 1024) - - -static nxt_http_action_t *nxt_http_static(nxt_task_t *task, - nxt_http_request_t *r, nxt_http_action_t *action); -static void nxt_http_static_iterate(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_static_ctx_t *ctx); -static void nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data); -static void nxt_http_static_send_error(nxt_task_t *task, void *obj, void *data); -static void nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_static_ctx_t *ctx, nxt_http_status_t status); -#if (NXT_HAVE_OPENAT2) -static u_char *nxt_http_static_chroot_match(u_char *chr, u_char *shr); -#endif -static void nxt_http_static_extract_extension(nxt_str_t *path, - nxt_str_t *exten); -static void nxt_http_static_body_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_http_static_buf_completion(nxt_task_t *task, void *obj, - void *data); - -static nxt_int_t nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, - void *data); -static void *nxt_http_static_mtypes_hash_alloc(void *data, size_t size); -static void nxt_http_static_mtypes_hash_free(void *data, void *p); - - -static const nxt_http_request_state_t nxt_http_static_send_state; - - -nxt_int_t -nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_http_action_t *action, nxt_http_action_conf_t *acf) -{ - uint32_t i; - nxt_mp_t *mp; - nxt_str_t str, *ret; - nxt_tstr_t *tstr; - nxt_conf_value_t *cv; - nxt_router_conf_t *rtcf; - nxt_http_static_conf_t *conf; - - rtcf = tmcf->router_conf; - mp = rtcf->mem_pool; - - conf = nxt_mp_zget(mp, sizeof(nxt_http_static_conf_t)); - if (nxt_slow_path(conf == NULL)) { - return NXT_ERROR; - } - - action->handler = nxt_http_static; - action->u.conf = conf; - - conf->nshares = nxt_conf_array_elements_count_or_1(acf->share); - conf->shares = nxt_mp_zget(mp, sizeof(nxt_http_static_share_t) - * conf->nshares); - if (nxt_slow_path(conf->shares == NULL)) { - return NXT_ERROR; - } - - for (i = 0; i < conf->nshares; i++) { - cv = nxt_conf_get_array_element_or_itself(acf->share, i); - nxt_conf_get_string(cv, &str); - - tstr = nxt_tstr_compile(rtcf->tstr_state, &str, NXT_TSTR_STRZ); - if (nxt_slow_path(tstr == NULL)) { - return NXT_ERROR; - } - - conf->shares[i].tstr = tstr; - conf->shares[i].is_const = nxt_tstr_is_const(tstr); - } - - if (acf->index == NULL) { - nxt_str_set(&conf->index, "index.html"); - - } else { - ret = nxt_conf_get_string_dup(acf->index, mp, &conf->index); - if (nxt_slow_path(ret == NULL)) { - return NXT_ERROR; - } - } - -#if (NXT_HAVE_OPENAT2) - if (acf->chroot.length > 0) { - nxt_str_t chr, shr; - nxt_bool_t is_const; - - conf->chroot = nxt_tstr_compile(rtcf->tstr_state, &acf->chroot, - NXT_TSTR_STRZ); - if (nxt_slow_path(conf->chroot == NULL)) { - return NXT_ERROR; - } - - is_const = nxt_tstr_is_const(conf->chroot); - - for (i = 0; i < conf->nshares; i++) { - conf->shares[i].is_const &= is_const; - - if (conf->shares[i].is_const) { - nxt_tstr_str(conf->chroot, &chr); - nxt_tstr_str(conf->shares[i].tstr, &shr); - - conf->shares[i].fname = nxt_http_static_chroot_match(chr.start, - shr.start); - } - } - } - - if (acf->follow_symlinks != NULL - && !nxt_conf_get_boolean(acf->follow_symlinks)) - { - conf->resolve |= RESOLVE_NO_SYMLINKS; - } - - if (acf->traverse_mounts != NULL - && !nxt_conf_get_boolean(acf->traverse_mounts)) - { - conf->resolve |= RESOLVE_NO_XDEV; - } -#endif - - if (acf->types != NULL) { - conf->types = nxt_http_route_types_rule_create(task, mp, acf->types); - if (nxt_slow_path(conf->types == NULL)) { - return NXT_ERROR; - } - } - - if (acf->fallback != NULL) { - action->fallback = nxt_mp_alloc(mp, sizeof(nxt_http_action_t)); - if (nxt_slow_path(action->fallback == NULL)) { - return NXT_ERROR; - } - - return nxt_http_action_init(task, tmcf, acf->fallback, - action->fallback); - } - - return NXT_OK; -} - - -static nxt_http_action_t * -nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *action) -{ - nxt_bool_t need_body; - nxt_http_static_ctx_t *ctx; - - if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) { - - if (!nxt_str_eq(r->method, "HEAD", 4)) { - if (action->fallback != NULL) { - if (nxt_slow_path(r->log_route)) { - nxt_log(task, NXT_LOG_NOTICE, "\"fallback\" taken"); - } - return action->fallback; - } - - nxt_http_request_error(task, r, NXT_HTTP_METHOD_NOT_ALLOWED); - return NULL; - } - - need_body = 0; - - } else { - need_body = 1; - } - - ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_static_ctx_t)); - if (nxt_slow_path(ctx == NULL)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - return NULL; - } - - ctx->action = action; - ctx->need_body = need_body; - - nxt_http_static_iterate(task, r, ctx); - - return NULL; -} - - -static void -nxt_http_static_iterate(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_static_ctx_t *ctx) -{ - nxt_int_t ret; - nxt_router_conf_t *rtcf; - nxt_http_static_conf_t *conf; - nxt_http_static_share_t *share; - - conf = ctx->action->u.conf; - - share = &conf->shares[ctx->share_idx]; - -#if (NXT_DEBUG) - nxt_str_t shr; - nxt_str_t idx; - - nxt_tstr_str(share->tstr, &shr); - idx = conf->index; - -#if (NXT_HAVE_OPENAT2) - nxt_str_t chr; - - if (conf->chroot != NULL) { - nxt_tstr_str(conf->chroot, &chr); - - } else { - nxt_str_set(&chr, ""); - } - - nxt_debug(task, "http static: \"%V\", index: \"%V\" (chroot: \"%V\")", - &shr, &idx, &chr); -#else - nxt_debug(task, "http static: \"%V\", index: \"%V\"", &shr, &idx); -#endif -#endif /* NXT_DEBUG */ - - if (share->is_const) { - nxt_tstr_str(share->tstr, &ctx->share); - -#if (NXT_HAVE_OPENAT2) - if (conf->chroot != NULL && ctx->share_idx == 0) { - nxt_tstr_str(conf->chroot, &ctx->chroot); - } -#endif - - nxt_http_static_send_ready(task, r, ctx); - - } else { - rtcf = r->conf->socket_conf->router_conf; - - ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, - &r->tstr_cache, r, r->mem_pool); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - nxt_tstr_query(task, r->tstr_query, share->tstr, &ctx->share); - -#if (NXT_HAVE_OPENAT2) - if (conf->chroot != NULL && ctx->share_idx == 0) { - nxt_tstr_query(task, r->tstr_query, conf->chroot, &ctx->chroot); - } -#endif - - nxt_tstr_query_resolve(task, r->tstr_query, ctx, - nxt_http_static_send_ready, - nxt_http_static_send_error); - } -} - - -static void -nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data) -{ - size_t length, encode; - u_char *p, *fname; - struct tm tm; - nxt_buf_t *fb; - nxt_int_t ret; - nxt_str_t *shr, *index, exten, *mtype; - nxt_uint_t level; - nxt_file_t *f, file; - nxt_file_info_t fi; - nxt_http_field_t *field; - nxt_http_status_t status; - nxt_router_conf_t *rtcf; - nxt_http_action_t *action; - nxt_http_request_t *r; - nxt_work_handler_t body_handler; - nxt_http_static_ctx_t *ctx; - nxt_http_static_conf_t *conf; - - r = obj; - ctx = data; - action = ctx->action; - conf = action->u.conf; - rtcf = r->conf->socket_conf->router_conf; - - f = NULL; - mtype = NULL; - - shr = &ctx->share; - index = &conf->index; - - if (shr->start[shr->length - 1] == '/') { - nxt_http_static_extract_extension(index, &exten); - - length = shr->length + index->length; - - fname = nxt_mp_nget(r->mem_pool, length + 1); - if (nxt_slow_path(fname == NULL)) { - goto fail; - } - - p = fname; - p = nxt_cpymem(p, shr->start, shr->length); - p = nxt_cpymem(p, index->start, index->length); - *p = '\0'; - - } else { - if (conf->types == NULL) { - nxt_str_null(&exten); - - } else { - nxt_http_static_extract_extension(shr, &exten); - mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten); - - ret = nxt_http_route_test_rule(r, conf->types, mtype->start, - mtype->length); - if (nxt_slow_path(ret == NXT_ERROR)) { - goto fail; - } - - if (ret == 0) { - nxt_http_static_next(task, r, ctx, NXT_HTTP_FORBIDDEN); - return; - } - } - - fname = ctx->share.start; - } - - nxt_memzero(&file, sizeof(nxt_file_t)); - - file.name = fname; - -#if (NXT_HAVE_OPENAT2) - if (conf->resolve != 0 || ctx->chroot.length > 0) { - nxt_str_t *chr; - nxt_uint_t resolve; - nxt_http_static_share_t *share; - - share = &conf->shares[ctx->share_idx]; - - resolve = conf->resolve; - chr = &ctx->chroot; - - if (chr->length > 0) { - resolve |= RESOLVE_IN_ROOT; - - fname = share->is_const - ? share->fname - : nxt_http_static_chroot_match(chr->start, file.name); - - if (fname != NULL) { - file.name = chr->start; - ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, - 0); - - } else { - file.error = NXT_EACCES; - ret = NXT_ERROR; - } - - } else if (fname[0] == '/') { - file.name = (u_char *) "/"; - ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 0); - - } else { - file.name = (u_char *) "."; - file.fd = AT_FDCWD; - ret = NXT_OK; - } - - if (nxt_fast_path(ret == NXT_OK)) { - nxt_file_t af; - - af = file; - nxt_memzero(&file, sizeof(nxt_file_t)); - file.name = fname; - - ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY, - NXT_FILE_OPEN, 0, af.fd, resolve); - - if (af.fd != AT_FDCWD) { - nxt_file_close(task, &af); - } - } - - } else { - ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); - } - -#else - ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); -#endif - - if (nxt_slow_path(ret != NXT_OK)) { - - switch (file.error) { - - /* - * For Unix domain sockets "errno" is set to: - * - ENXIO on Linux; - * - EOPNOTSUPP on *BSD, MacOSX, and Solaris. - */ - - case NXT_ENOENT: - case NXT_ENOTDIR: - case NXT_ENAMETOOLONG: -#if (NXT_LINUX) - case NXT_ENXIO: -#else - case NXT_EOPNOTSUPP: -#endif - level = NXT_LOG_ERR; - status = NXT_HTTP_NOT_FOUND; - break; - - case NXT_EACCES: -#if (NXT_HAVE_OPENAT2) - case NXT_ELOOP: - case NXT_EXDEV: -#endif - level = NXT_LOG_ERR; - status = NXT_HTTP_FORBIDDEN; - break; - - default: - level = NXT_LOG_ALERT; - status = NXT_HTTP_INTERNAL_SERVER_ERROR; - break; - } - - if (status != NXT_HTTP_NOT_FOUND) { -#if (NXT_HAVE_OPENAT2) - nxt_str_t *chr = &ctx->chroot; - - if (chr->length > 0) { - nxt_log(task, level, "opening \"%s\" at \"%V\" failed %E", - fname, chr, file.error); - - } else { - nxt_log(task, level, "opening \"%s\" failed %E", - fname, file.error); - } - -#else - nxt_log(task, level, "opening \"%s\" failed %E", fname, file.error); -#endif - } - - if (level == NXT_LOG_ERR) { - nxt_http_static_next(task, r, ctx, status); - return; - } - - goto fail; - } - - f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t)); - if (nxt_slow_path(f == NULL)) { - nxt_file_close(task, &file); - goto fail; - } - - *f = file; - - ret = nxt_file_info(f, &fi); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - if (nxt_fast_path(nxt_is_file(&fi))) { - r->status = NXT_HTTP_OK; - r->resp.content_length_n = nxt_file_size(&fi); - - field = nxt_list_zero_add(r->resp.fields); - if (nxt_slow_path(field == NULL)) { - goto fail; - } - - nxt_http_field_name_set(field, "Last-Modified"); - - p = nxt_mp_nget(r->mem_pool, NXT_HTTP_DATE_LEN); - if (nxt_slow_path(p == NULL)) { - goto fail; - } - - nxt_localtime(nxt_file_mtime(&fi), &tm); - - field->value = p; - field->value_length = nxt_http_date(p, &tm) - p; - - field = nxt_list_zero_add(r->resp.fields); - if (nxt_slow_path(field == NULL)) { - goto fail; - } - - nxt_http_field_name_set(field, "ETag"); - - length = NXT_TIME_T_HEXLEN + NXT_OFF_T_HEXLEN + 3; - - p = nxt_mp_nget(r->mem_pool, length); - if (nxt_slow_path(p == NULL)) { - goto fail; - } - - field->value = p; - field->value_length = nxt_sprintf(p, p + length, "\"%xT-%xO\"", - nxt_file_mtime(&fi), - nxt_file_size(&fi)) - - p; - - if (exten.start == NULL) { - nxt_http_static_extract_extension(shr, &exten); - } - - if (mtype == NULL) { - mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten); - } - - if (mtype->length != 0) { - field = nxt_list_zero_add(r->resp.fields); - if (nxt_slow_path(field == NULL)) { - goto fail; - } - - nxt_http_field_name_set(field, "Content-Type"); - - field->value = mtype->start; - field->value_length = mtype->length; - } - - if (ctx->need_body && nxt_file_size(&fi) > 0) { - fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE); - if (nxt_slow_path(fb == NULL)) { - goto fail; - } - - fb->file = f; - fb->file_end = nxt_file_size(&fi); - - r->out = fb; - - body_handler = &nxt_http_static_body_handler; - - } else { - nxt_file_close(task, f); - body_handler = NULL; - } - - } else { - /* Not a file. */ - nxt_file_close(task, f); - - if (nxt_slow_path(!nxt_is_dir(&fi) - || shr->start[shr->length - 1] == '/')) - { - nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file", - f->name); - - nxt_http_static_next(task, r, ctx, NXT_HTTP_NOT_FOUND); - return; - } - - f = NULL; - - r->status = NXT_HTTP_MOVED_PERMANENTLY; - r->resp.content_length_n = 0; - - field = nxt_list_zero_add(r->resp.fields); - if (nxt_slow_path(field == NULL)) { - goto fail; - } - - nxt_http_field_name_set(field, "Location"); - - encode = nxt_encode_uri(NULL, r->path->start, r->path->length); - length = r->path->length + encode * 2 + 1; - - if (r->args->length > 0) { - length += 1 + r->args->length; - } - - p = nxt_mp_nget(r->mem_pool, length); - if (nxt_slow_path(p == NULL)) { - goto fail; - } - - field->value = p; - field->value_length = length; - - if (encode > 0) { - p = (u_char *) nxt_encode_uri(p, r->path->start, r->path->length); - - } else { - p = nxt_cpymem(p, r->path->start, r->path->length); - } - - *p++ = '/'; - - if (r->args->length > 0) { - *p++ = '?'; - nxt_memcpy(p, r->args->start, r->args->length); - } - - body_handler = NULL; - } - - nxt_http_request_header_send(task, r, body_handler, NULL); - - r->state = &nxt_http_static_send_state; - return; - -fail: - - if (f != NULL) { - nxt_file_close(task, f); - } - - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); -} - - -static void -nxt_http_static_send_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_request_t *r; - - r = obj; - - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); -} - - -static void -nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_static_ctx_t *ctx, nxt_http_status_t status) -{ - nxt_http_action_t *action; - nxt_http_static_conf_t *conf; - - action = ctx->action; - conf = action->u.conf; - - ctx->share_idx++; - - if (ctx->share_idx < conf->nshares) { - nxt_http_static_iterate(task, r, ctx); - return; - } - - if (action->fallback != NULL) { - if (nxt_slow_path(r->log_route)) { - nxt_log(task, NXT_LOG_NOTICE, "\"fallback\" taken"); - } - - r->action = action->fallback; - nxt_http_request_action(task, r, action->fallback); - return; - } - - nxt_http_request_error(task, r, status); -} - - -#if (NXT_HAVE_OPENAT2) - -static u_char * -nxt_http_static_chroot_match(u_char *chr, u_char *shr) -{ - if (*chr != *shr) { - return NULL; - } - - chr++; - shr++; - - for ( ;; ) { - if (*shr == '\0') { - return NULL; - } - - if (*chr == *shr) { - chr++; - shr++; - continue; - } - - if (*chr == '\0') { - break; - } - - if (*chr == '/') { - if (chr[-1] == '/') { - chr++; - continue; - } - - } else if (*shr == '/') { - if (shr[-1] == '/') { - shr++; - continue; - } - } - - return NULL; - } - - if (shr[-1] != '/' && *shr != '/') { - return NULL; - } - - while (*shr == '/') { - shr++; - } - - return (*shr != '\0') ? shr : NULL; -} - -#endif - - -static void -nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten) -{ - u_char ch, *p, *end; - - end = path->start + path->length; - p = end; - - while (p > path->start) { - p--; - ch = *p; - - switch (ch) { - case '/': - p++; - /* Fall through. */ - case '.': - goto extension; - } - } - -extension: - - exten->length = end - p; - exten->start = p; -} - - -static void -nxt_http_static_body_handler(nxt_task_t *task, void *obj, void *data) -{ - size_t alloc; - nxt_buf_t *fb, *b, **next, *out; - nxt_off_t rest; - nxt_int_t n; - nxt_work_queue_t *wq; - nxt_http_request_t *r; - - r = obj; - fb = r->out; - - rest = fb->file_end - fb->file_pos; - out = NULL; - next = &out; - n = 0; - - do { - alloc = nxt_min(rest, NXT_HTTP_STATIC_BUF_SIZE); - - b = nxt_buf_mem_alloc(r->mem_pool, alloc, 0); - if (nxt_slow_path(b == NULL)) { - goto fail; - } - - b->completion_handler = nxt_http_static_buf_completion; - b->parent = r; - - nxt_mp_retain(r->mem_pool); - - *next = b; - next = &b->next; - - rest -= alloc; - - } while (rest > 0 && ++n < NXT_HTTP_STATIC_BUF_COUNT); - - wq = &task->thread->engine->fast_work_queue; - - nxt_sendbuf_drain(task, wq, out); - return; - -fail: - - while (out != NULL) { - b = out; - out = b->next; - - nxt_mp_free(r->mem_pool, b); - nxt_mp_release(r->mem_pool); - } -} - - -static const nxt_http_request_state_t nxt_http_static_send_state - nxt_aligned(64) = -{ - .error_handler = nxt_http_request_error_handler, -}; - - -static void -nxt_http_static_buf_completion(nxt_task_t *task, void *obj, void *data) -{ - ssize_t n, size; - nxt_buf_t *b, *fb, *next; - nxt_off_t rest; - nxt_http_request_t *r; - - b = obj; - r = data; - -complete_buf: - - fb = r->out; - - if (nxt_slow_path(fb == NULL || r->error)) { - goto clean; - } - - rest = fb->file_end - fb->file_pos; - size = nxt_buf_mem_size(&b->mem); - - size = nxt_min(rest, (nxt_off_t) size); - - n = nxt_file_read(fb->file, b->mem.start, size, fb->file_pos); - - if (nxt_slow_path(n == NXT_ERROR)) { - nxt_http_request_error_handler(task, r, r->proto.any); - goto clean; - } - - next = b->next; - - if (n == rest) { - nxt_file_close(task, fb->file); - r->out = NULL; - - b->next = nxt_http_buf_last(r); - - } else { - fb->file_pos += n; - b->next = NULL; - } - - b->mem.pos = b->mem.start; - b->mem.free = b->mem.pos + n; - - nxt_http_request_send(task, r, b); - - if (next != NULL) { - b = next; - goto complete_buf; - } - - return; - -clean: - - do { - next = b->next; - - nxt_mp_free(r->mem_pool, b); - nxt_mp_release(r->mem_pool); - - b = next; - } while (b != NULL); - - if (fb != NULL) { - nxt_file_close(task, fb->file); - r->out = NULL; - } -} - - -nxt_int_t -nxt_http_static_mtypes_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash) -{ - nxt_str_t *type, exten; - nxt_int_t ret; - nxt_uint_t i; - - static const struct { - nxt_str_t type; - const char *exten; - } default_types[] = { - - { nxt_string("text/html"), ".html" }, - { nxt_string("text/html"), ".htm" }, - { nxt_string("text/css"), ".css" }, - - { nxt_string("image/svg+xml"), ".svg" }, - { nxt_string("image/webp"), ".webp" }, - { nxt_string("image/png"), ".png" }, - { nxt_string("image/apng"), ".apng" }, - { nxt_string("image/jpeg"), ".jpeg" }, - { nxt_string("image/jpeg"), ".jpg" }, - { nxt_string("image/gif"), ".gif" }, - { nxt_string("image/x-icon"), ".ico" }, - - { nxt_string("image/avif"), ".avif" }, - { nxt_string("image/avif-sequence"), ".avifs" }, - - { nxt_string("font/woff"), ".woff" }, - { nxt_string("font/woff2"), ".woff2" }, - { nxt_string("font/otf"), ".otf" }, - { nxt_string("font/ttf"), ".ttf" }, - - { nxt_string("text/plain"), ".txt" }, - { nxt_string("text/markdown"), ".md" }, - { nxt_string("text/x-rst"), ".rst" }, - - { nxt_string("application/javascript"), ".js" }, - { nxt_string("application/json"), ".json" }, - { nxt_string("application/xml"), ".xml" }, - { nxt_string("application/rss+xml"), ".rss" }, - { nxt_string("application/atom+xml"), ".atom" }, - { nxt_string("application/pdf"), ".pdf" }, - - { nxt_string("application/zip"), ".zip" }, - - { nxt_string("audio/mpeg"), ".mp3" }, - { nxt_string("audio/ogg"), ".ogg" }, - { nxt_string("audio/midi"), ".midi" }, - { nxt_string("audio/midi"), ".mid" }, - { nxt_string("audio/flac"), ".flac" }, - { nxt_string("audio/aac"), ".aac" }, - { nxt_string("audio/wav"), ".wav" }, - - { nxt_string("video/mpeg"), ".mpeg" }, - { nxt_string("video/mpeg"), ".mpg" }, - { nxt_string("video/mp4"), ".mp4" }, - { nxt_string("video/webm"), ".webm" }, - { nxt_string("video/x-msvideo"), ".avi" }, - - { nxt_string("application/octet-stream"), ".exe" }, - { nxt_string("application/octet-stream"), ".bin" }, - { nxt_string("application/octet-stream"), ".dll" }, - { nxt_string("application/octet-stream"), ".iso" }, - { nxt_string("application/octet-stream"), ".img" }, - { nxt_string("application/octet-stream"), ".msi" }, - - { nxt_string("application/octet-stream"), ".deb" }, - { nxt_string("application/octet-stream"), ".rpm" }, - - { nxt_string("application/x-httpd-php"), ".php" }, - }; - - for (i = 0; i < nxt_nitems(default_types); i++) { - type = (nxt_str_t *) &default_types[i].type; - - exten.start = (u_char *) default_types[i].exten; - exten.length = nxt_strlen(exten.start); - - ret = nxt_http_static_mtypes_hash_add(mp, hash, &exten, type); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -static const nxt_lvlhsh_proto_t nxt_http_static_mtypes_hash_proto - nxt_aligned(64) = -{ - NXT_LVLHSH_DEFAULT, - nxt_http_static_mtypes_hash_test, - nxt_http_static_mtypes_hash_alloc, - nxt_http_static_mtypes_hash_free, -}; - - -typedef struct { - nxt_str_t exten; - nxt_str_t *type; -} nxt_http_static_mtype_t; - - -nxt_int_t -nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash, - const nxt_str_t *exten, nxt_str_t *type) -{ - nxt_lvlhsh_query_t lhq; - nxt_http_static_mtype_t *mtype; - - mtype = nxt_mp_get(mp, sizeof(nxt_http_static_mtype_t)); - if (nxt_slow_path(mtype == NULL)) { - return NXT_ERROR; - } - - mtype->exten = *exten; - mtype->type = type; - - lhq.key = *exten; - lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length); - lhq.replace = 1; - lhq.value = mtype; - lhq.proto = &nxt_http_static_mtypes_hash_proto; - lhq.pool = mp; - - return nxt_lvlhsh_insert(hash, &lhq); -} - - -nxt_str_t * -nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, const nxt_str_t *exten) -{ - nxt_lvlhsh_query_t lhq; - nxt_http_static_mtype_t *mtype; - - static nxt_str_t empty = nxt_string(""); - - lhq.key = *exten; - lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length); - lhq.proto = &nxt_http_static_mtypes_hash_proto; - - if (nxt_lvlhsh_find(hash, &lhq) == NXT_OK) { - mtype = lhq.value; - return mtype->type; - } - - return ∅ -} - - -static nxt_int_t -nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_http_static_mtype_t *mtype; - - mtype = data; - - return nxt_strcasestr_eq(&lhq->key, &mtype->exten) ? NXT_OK : NXT_DECLINED; -} - - -static void * -nxt_http_static_mtypes_hash_alloc(void *data, size_t size) -{ - return nxt_mp_align(data, size, size); -} - - -static void -nxt_http_static_mtypes_hash_free(void *data, void *p) -{ - nxt_mp_free(data, p); -} diff --git a/src/nxt_http_variables.c b/src/nxt_http_variables.c deleted file mode 100644 index 85ae6004..00000000 --- a/src/nxt_http_variables.c +++ /dev/null @@ -1,778 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -static nxt_int_t nxt_http_var_dollar(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_request_time(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_method(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_request_uri(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_uri(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data); -static nxt_int_t nxt_http_var_host(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data); -static nxt_int_t nxt_http_var_remote_addr(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_time_local(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static u_char *nxt_http_log_date(u_char *buf, nxt_realtime_t *now, - struct tm *tm, size_t size, const char *format); -static nxt_int_t nxt_http_var_request_line(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_request_id(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_referer(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_response_connection(nxt_task_t *task, - nxt_str_t *str, void *ctx, void *data); -static nxt_int_t nxt_http_var_response_content_length(nxt_task_t *task, - nxt_str_t *str, void *ctx, void *data); -static nxt_int_t nxt_http_var_response_transfer_encoding(nxt_task_t *task, - nxt_str_t *str, void *ctx, void *data); -static nxt_int_t nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data); -static nxt_int_t nxt_http_var_header(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); -static nxt_int_t nxt_http_var_response_header(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data); - - -static nxt_var_decl_t nxt_http_vars[] = { - { - .name = nxt_string("dollar"), - .handler = nxt_http_var_dollar, - .cacheable = 1, - }, { - .name = nxt_string("request_time"), - .handler = nxt_http_var_request_time, - .cacheable = 1, - }, { - .name = nxt_string("method"), - .handler = nxt_http_var_method, - .cacheable = 1, - }, { - .name = nxt_string("request_uri"), - .handler = nxt_http_var_request_uri, - .cacheable = 1, - }, { - .name = nxt_string("uri"), - .handler = nxt_http_var_uri, - .cacheable = 0, - }, { - .name = nxt_string("host"), - .handler = nxt_http_var_host, - .cacheable = 1, - }, { - .name = nxt_string("remote_addr"), - .handler = nxt_http_var_remote_addr, - .cacheable = 1, - }, { - .name = nxt_string("time_local"), - .handler = nxt_http_var_time_local, - .cacheable = 1, - }, { - .name = nxt_string("request_line"), - .handler = nxt_http_var_request_line, - .cacheable = 1, - }, { - .name = nxt_string("request_id"), - .handler = nxt_http_var_request_id, - .cacheable = 1, - }, { - .name = nxt_string("status"), - .handler = nxt_http_var_status, - .cacheable = 1, - }, { - .name = nxt_string("body_bytes_sent"), - .handler = nxt_http_var_body_bytes_sent, - .cacheable = 1, - }, { - .name = nxt_string("header_referer"), - .handler = nxt_http_var_referer, - .cacheable = 1, - }, { - .name = nxt_string("response_header_connection"), - .handler = nxt_http_var_response_connection, - .cacheable = 1, - }, { - .name = nxt_string("response_header_content_length"), - .handler = nxt_http_var_response_content_length, - .cacheable = 1, - }, { - .name = nxt_string("response_header_transfer_encoding"), - .handler = nxt_http_var_response_transfer_encoding, - .cacheable = 1, - }, { - .name = nxt_string("header_user_agent"), - .handler = nxt_http_var_user_agent, - .cacheable = 1, - }, -}; - - -nxt_int_t -nxt_http_register_variables(void) -{ - return nxt_var_register(nxt_http_vars, nxt_nitems(nxt_http_vars)); -} - - -nxt_int_t -nxt_http_unknown_var_ref(nxt_mp_t *mp, nxt_var_ref_t *ref, nxt_str_t *name) -{ - int64_t hash; - nxt_str_t str, *lower; - - if (nxt_str_start(name, "response_header_", 16)) { - ref->handler = nxt_http_var_response_header; - ref->cacheable = 0; - - str.start = name->start + 16; - str.length = name->length - 16; - - if (str.length == 0) { - return NXT_ERROR; - } - - lower = nxt_str_alloc(mp, str.length); - if (nxt_slow_path(lower == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy_lowcase(lower->start, str.start, str.length); - - ref->data = lower; - - return NXT_OK; - } - - if (nxt_str_start(name, "header_", 7)) { - ref->handler = nxt_http_var_header; - ref->cacheable = 1; - - str.start = name->start + 7; - str.length = name->length - 7; - - if (str.length == 0) { - return NXT_ERROR; - } - - hash = nxt_http_header_hash(mp, &str); - if (nxt_slow_path(hash == -1)) { - return NXT_ERROR; - } - - } else if (nxt_str_start(name, "arg_", 4)) { - ref->handler = nxt_http_var_arg; - ref->cacheable = 1; - - str.start = name->start + 4; - str.length = name->length - 4; - - if (str.length == 0) { - return NXT_ERROR; - } - - hash = nxt_http_argument_hash(mp, &str); - if (nxt_slow_path(hash == -1)) { - return NXT_ERROR; - } - - } else if (nxt_str_start(name, "cookie_", 7)) { - ref->handler = nxt_http_var_cookie; - ref->cacheable = 1; - - str.start = name->start + 7; - str.length = name->length - 7; - - if (str.length == 0) { - return NXT_ERROR; - } - - hash = nxt_http_cookie_hash(mp, &str); - if (nxt_slow_path(hash == -1)) { - return NXT_ERROR; - } - - } else { - return NXT_ERROR; - } - - ref->data = nxt_var_field_new(mp, &str, (uint32_t) hash); - if (nxt_slow_path(ref->data == NULL)) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_dollar(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_str_set(str, "$"); - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_request_time(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data) -{ - u_char *p; - nxt_msec_t ms; - nxt_nsec_t now; - nxt_http_request_t *r; - - r = ctx; - - now = nxt_thread_monotonic_time(task->thread); - ms = (now - r->start_time) / 1000000; - - str->start = nxt_mp_nget(r->mem_pool, NXT_TIME_T_LEN + 4); - if (nxt_slow_path(str->start == NULL)) { - return NXT_ERROR; - } - - p = nxt_sprintf(str->start, str->start + NXT_TIME_T_LEN, "%T.%03M", - (nxt_time_t) ms / 1000, ms % 1000); - - str->length = p - str->start; - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_method(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_http_request_t *r; - - r = ctx; - - *str = *r->method; - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_request_uri(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data) -{ - nxt_http_request_t *r; - - r = ctx; - - *str = r->target; - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_uri(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_http_request_t *r; - - r = ctx; - - *str = *r->path; - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_host(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_http_request_t *r; - - r = ctx; - - *str = r->host; - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_remote_addr(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data) -{ - nxt_http_request_t *r; - - r = ctx; - - str->length = r->remote->address_length; - str->start = nxt_sockaddr_address(r->remote); - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_time_local(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_http_request_t *r; - - static nxt_time_string_t date_cache = { - (nxt_atomic_uint_t) -1, - nxt_http_log_date, - "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", - nxt_length("31/Dec/1986:19:40:00 +0300"), - NXT_THREAD_TIME_LOCAL, - NXT_THREAD_TIME_SEC, - }; - - r = ctx; - - str->length = date_cache.size; - - str->start = nxt_mp_nget(r->mem_pool, str->length); - if (nxt_slow_path(str->start == NULL)) { - return NXT_ERROR; - } - - str->length = nxt_thread_time_string(task->thread, &date_cache, str->start) - - str->start; - - return NXT_OK; -} - - -static u_char * -nxt_http_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, - size_t size, const char *format) -{ - u_char sign; - time_t gmtoff; - - static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - gmtoff = nxt_timezone(tm) / 60; - - if (gmtoff < 0) { - gmtoff = -gmtoff; - sign = '-'; - - } else { - sign = '+'; - } - - return nxt_sprintf(buf, buf + size, format, - tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, - tm->tm_hour, tm->tm_min, tm->tm_sec, - sign, gmtoff / 60, gmtoff % 60); -} - - -static nxt_int_t -nxt_http_var_request_line(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data) -{ - nxt_http_request_t *r; - - r = ctx; - - *str = r->request_line; - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_request_id(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data) -{ - nxt_random_t *rand; - nxt_http_request_t *r; - - r = ctx; - - str->start = nxt_mp_nget(r->mem_pool, 32); - if (nxt_slow_path(str->start == NULL)) { - return NXT_ERROR; - } - - str->length = 32; - - rand = &task->thread->random; - - (void) nxt_sprintf(str->start, str->start + 32, "%08xD%08xD%08xD%08xD", - nxt_random(rand), nxt_random(rand), - nxt_random(rand), nxt_random(rand)); - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data) -{ - u_char *p; - nxt_off_t bytes; - nxt_http_request_t *r; - - r = ctx; - - str->start = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); - if (nxt_slow_path(str->start == NULL)) { - return NXT_ERROR; - } - - bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto); - - p = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN, "%O", bytes); - - str->length = p - str->start; - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_http_request_t *r; - - r = ctx; - - str->start = nxt_mp_nget(r->mem_pool, 3); - if (nxt_slow_path(str->start == NULL)) { - return NXT_ERROR; - } - - (void) nxt_sprintf(str->start, str->start + 3, "%03d", r->status); - - str->length = 3; - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_referer(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_http_request_t *r; - - r = ctx; - - if (r->referer != NULL) { - str->start = r->referer->value; - str->length = r->referer->value_length; - - } else { - nxt_str_null(str); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_http_request_t *r; - - r = ctx; - - if (r->user_agent != NULL) { - str->start = r->user_agent->value; - str->length = r->user_agent->value_length; - - } else { - nxt_str_null(str); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_response_connection(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data) -{ - nxt_int_t conn; - nxt_bool_t http11; - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - - static const nxt_str_t connection[3] = { - nxt_string("close"), - nxt_string("keep-alive"), - nxt_string("Upgrade"), - }; - - r = ctx; - h1p = r->proto.h1; - - conn = -1; - - if (r->websocket_handshake && r->status == NXT_HTTP_SWITCHING_PROTOCOLS) { - conn = 2; - - } else { - http11 = nxt_h1p_is_http11(h1p); - - if (http11 ^ h1p->keepalive) { - conn = h1p->keepalive; - } - } - - if (conn >= 0) { - *str = connection[conn]; - - } else { - nxt_str_null(str); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_response_content_length(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data) -{ - u_char *p; - nxt_http_request_t *r; - - r = ctx; - - if (r->resp.content_length != NULL) { - str->length = r->resp.content_length->value_length; - str->start = r->resp.content_length->value; - - return NXT_OK; - } - - if (r->resp.content_length_n >= 0) { - str->start = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); - if (str->start == NULL) { - return NXT_ERROR; - } - - p = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN, - "%O", r->resp.content_length_n); - - str->length = p - str->start; - - return NXT_OK; - } - - nxt_str_null(str); - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_response_transfer_encoding(nxt_task_t *task, nxt_str_t *str, - void *ctx, void *data) -{ - nxt_http_request_t *r; - - r = ctx; - - if (r->proto.h1->chunked) { - nxt_str_set(str, "chunked"); - - } else { - nxt_str_null(str); - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_array_t *args; - nxt_var_field_t *vf; - nxt_http_request_t *r; - nxt_http_name_value_t *nv, *start; - - r = ctx; - vf = data; - - args = nxt_http_arguments_parse(r); - if (nxt_slow_path(args == NULL)) { - return NXT_ERROR; - } - - start = args->elts; - nv = start + args->nelts - 1; - - while (nv >= start) { - - if (vf->hash == nv->hash - && vf->name.length == nv->name_length - && memcmp(vf->name.start, nv->name, nv->name_length) == 0) - { - str->start = nv->value; - str->length = nv->value_length; - - return NXT_OK; - } - - nv--; - } - - nxt_str_null(str); - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_header(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_var_field_t *vf; - nxt_http_field_t *f; - nxt_http_request_t *r; - - r = ctx; - vf = data; - - nxt_list_each(f, r->fields) { - - if (vf->hash == f->hash - && vf->name.length == f->name_length - && nxt_strncasecmp(vf->name.start, f->name, f->name_length) == 0) - { - str->start = f->value; - str->length = f->value_length; - - return NXT_OK; - } - - } nxt_list_loop; - - nxt_str_null(str); - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data) -{ - nxt_array_t *cookies; - nxt_var_field_t *vf; - nxt_http_request_t *r; - nxt_http_name_value_t *nv, *end; - - r = ctx; - vf = data; - - cookies = nxt_http_cookies_parse(r); - if (nxt_slow_path(cookies == NULL)) { - return NXT_ERROR; - } - - nv = cookies->elts; - end = nv + cookies->nelts; - - while (nv < end) { - - if (vf->hash == nv->hash - && vf->name.length == nv->name_length - && memcmp(vf->name.start, nv->name, nv->name_length) == 0) - { - str->start = nv->value; - str->length = nv->value_length; - - return NXT_OK; - } - - nv++; - } - - nxt_str_null(str); - - return NXT_OK; -} - - -static int -nxt_http_field_name_cmp(nxt_str_t *name, nxt_http_field_t *field) -{ - size_t i; - u_char c1, c2; - - if (name->length != field->name_length) { - return 1; - } - - for (i = 0; i < name->length; i++) { - c1 = name->start[i]; - c2 = field->name[i]; - - if (c2 >= 'A' && c2 <= 'Z') { - c2 |= 0x20; - - } else if (c2 == '-') { - c2 = '_'; - } - - if (c1 != c2) { - return 1; - } - } - - return 0; -} - - -static nxt_int_t -nxt_http_var_response_header(nxt_task_t *task, nxt_str_t *str, void *ctx, - void *data) -{ - nxt_str_t *name; - nxt_http_field_t *f; - nxt_http_request_t *r; - - r = ctx; - name = data; - - nxt_list_each(f, r->resp.fields) { - - if (f->skip) { - continue; - } - - if (nxt_http_field_name_cmp(name, f) == 0) { - str->start = f->value; - str->length = f->value_length; - - return NXT_OK; - } - - } nxt_list_loop; - - nxt_str_null(str); - - return NXT_OK; -} diff --git a/src/nxt_http_websocket.c b/src/nxt_http_websocket.c deleted file mode 100644 index 1968633e..00000000 --- a/src/nxt_http_websocket.c +++ /dev/null @@ -1,155 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include - - -static void nxt_http_websocket_client(nxt_task_t *task, void *obj, void *data); -static void nxt_http_websocket_error_handler(nxt_task_t *task, void *obj, - void *data); - - -const nxt_http_request_state_t nxt_http_websocket - nxt_aligned(64) = -{ - .ready_handler = nxt_http_websocket_client, - .error_handler = nxt_http_websocket_error_handler, -}; - - -static void -nxt_http_websocket_client(nxt_task_t *task, void *obj, void *data) -{ - size_t frame_size, used_size, copy_size, buf_free_size; - size_t chunk_copy_size; - nxt_buf_t *out, *buf, **out_tail, *b, *next; - nxt_int_t res; - nxt_http_request_t *r; - nxt_request_rpc_data_t *req_rpc_data; - nxt_websocket_header_t *wsh; - - r = obj; - req_rpc_data = r->req_rpc_data; - - if (nxt_slow_path(req_rpc_data == NULL)) { - nxt_debug(task, "websocket client frame for destroyed request"); - - return; - } - - nxt_debug(task, "http websocket client frame"); - - wsh = (nxt_websocket_header_t *) r->ws_frame->mem.pos; - - frame_size = nxt_websocket_frame_header_size(wsh) - + nxt_websocket_frame_payload_len(wsh); - - buf = NULL; - buf_free_size = 0; - out = NULL; - out_tail = &out; - - b = r->ws_frame; - - while (b != NULL && frame_size > 0) { - used_size = nxt_buf_mem_used_size(&b->mem); - copy_size = nxt_min(used_size, frame_size); - - while (copy_size > 0) { - if (buf == NULL || buf_free_size == 0) { - buf_free_size = nxt_min(frame_size, PORT_MMAP_DATA_SIZE); - - buf = nxt_port_mmap_get_buf(task, &req_rpc_data->app->outgoing, - buf_free_size); - - *out_tail = buf; - out_tail = &buf->next; - } - - chunk_copy_size = nxt_min(buf_free_size, copy_size); - - buf->mem.free = nxt_cpymem(buf->mem.free, b->mem.pos, - chunk_copy_size); - - copy_size -= chunk_copy_size; - b->mem.pos += chunk_copy_size; - buf_free_size -= chunk_copy_size; - } - - frame_size -= copy_size; - next = b->next; - b->next = NULL; - - if (nxt_buf_mem_used_size(&b->mem) == 0) { - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - b->completion_handler, task, b, b->parent); - - r->ws_frame = next; - } - - b = next; - } - - res = nxt_port_socket_write(task, req_rpc_data->app_port, - NXT_PORT_MSG_WEBSOCKET, -1, - req_rpc_data->stream, - task->thread->engine->port->id, out); - if (nxt_slow_path(res != NXT_OK)) { - // TODO: handle - } - - b = r->ws_frame; - - if (b != NULL) { - used_size = nxt_buf_mem_used_size(&b->mem); - - if (used_size > 0) { - nxt_memmove(b->mem.start, b->mem.pos, used_size); - - b->mem.pos = b->mem.start; - b->mem.free = b->mem.start + used_size; - } - } - - nxt_http_request_ws_frame_start(task, r, r->ws_frame); -} - - -static void -nxt_http_websocket_error_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_request_t *r; - nxt_request_rpc_data_t *req_rpc_data; - - nxt_debug(task, "http websocket error handler"); - - r = obj; - req_rpc_data = r->req_rpc_data; - - if (req_rpc_data == NULL) { - nxt_debug(task, " req_rpc_data is NULL"); - goto close_handler; - } - - if (req_rpc_data->app_port == NULL) { - nxt_debug(task, " app_port is NULL"); - goto close_handler; - } - - (void) nxt_port_socket_write(task, req_rpc_data->app_port, - NXT_PORT_MSG_WEBSOCKET_LAST, - -1, req_rpc_data->stream, - task->thread->engine->port->id, NULL); - -close_handler: - - nxt_http_request_close_handler(task, obj, data); -} diff --git a/src/nxt_isolation.c b/src/nxt_isolation.c deleted file mode 100644 index ed5e0d76..00000000 --- a/src/nxt_isolation.c +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include - -#if (NXT_HAVE_MNTENT_H) -#include -#endif - - -static nxt_int_t nxt_isolation_set(nxt_task_t *task, - nxt_conf_value_t *isolation, nxt_process_t *process); - -#if (NXT_HAVE_CGROUP) -static nxt_int_t nxt_isolation_set_cgroup(nxt_task_t *task, - nxt_conf_value_t *isolation, nxt_process_t *process); -#endif - -#if (NXT_HAVE_LINUX_NS) -static nxt_int_t nxt_isolation_set_namespaces(nxt_task_t *task, - nxt_conf_value_t *isolation, nxt_process_t *process); -static nxt_int_t nxt_isolation_clone_flags(nxt_task_t *task, - nxt_conf_value_t *namespaces, nxt_clone_t *clone); -#endif - -#if (NXT_HAVE_CLONE_NEWUSER) -static nxt_int_t nxt_isolation_set_creds(nxt_task_t *task, - nxt_conf_value_t *isolation, nxt_process_t *process); -static nxt_int_t nxt_isolation_credential_map(nxt_task_t *task, - nxt_mp_t *mem_pool, nxt_conf_value_t *map_array, - nxt_clone_credential_map_t *map); -static nxt_int_t nxt_isolation_vldt_creds(nxt_task_t *task, - nxt_process_t *process); -#endif - -#if (NXT_HAVE_ISOLATION_ROOTFS) -static nxt_int_t nxt_isolation_set_rootfs(nxt_task_t *task, - nxt_conf_value_t *isolation, nxt_process_t *process); -static nxt_int_t nxt_isolation_set_automount(nxt_task_t *task, - nxt_conf_value_t *isolation, nxt_process_t *process); -static nxt_int_t nxt_isolation_set_mounts(nxt_task_t *task, - nxt_process_t *process, nxt_str_t *app_type); -static nxt_int_t nxt_isolation_set_lang_mounts(nxt_task_t *task, - nxt_process_t *process, nxt_array_t *syspaths); -static int nxt_cdecl nxt_isolation_mount_compare(const void *v1, - const void *v2); -static void nxt_isolation_unmount_all(nxt_task_t *task, nxt_process_t *process); - -#if (NXT_HAVE_LINUX_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) -static nxt_int_t nxt_isolation_pivot_root(nxt_task_t *task, const char *rootfs); -static nxt_int_t nxt_isolation_make_private_mount(nxt_task_t *task, - const char *rootfs); -nxt_inline int nxt_pivot_root(const char *new_root, const char *old_root); -#endif - -static nxt_int_t nxt_isolation_chroot(nxt_task_t *task, const char *path); -#endif - -#if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) -static nxt_int_t nxt_isolation_set_new_privs(nxt_task_t *task, - nxt_conf_value_t *isolation, nxt_process_t *process); -#endif - - -nxt_int_t -nxt_isolation_main_prefork(nxt_task_t *task, nxt_process_t *process, - nxt_mp_t *mp) -{ - nxt_int_t cap_setid; - nxt_int_t ret; - nxt_runtime_t *rt; - nxt_common_app_conf_t *app_conf; - - rt = task->thread->runtime; - app_conf = process->data.app; - cap_setid = rt->capabilities.setid; - -#if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) - process->isolation.new_privs = 1; -#endif - - if (app_conf->isolation != NULL) { - ret = nxt_isolation_set(task, app_conf->isolation, process); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - } - -#if (NXT_HAVE_CLONE_NEWUSER) - if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) { - cap_setid = 1; - } -#endif - - if (cap_setid) { - ret = nxt_process_creds_set(task, process, &app_conf->user, - &app_conf->group); - - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - } else { - if (!nxt_str_eq(&app_conf->user, (u_char *) rt->user_cred.user, - nxt_strlen(rt->user_cred.user))) - { - nxt_alert(task, "cannot set user \"%V\" for app \"%V\": " - "missing capabilities", &app_conf->user, &app_conf->name); - - return NXT_ERROR; - } - - if (app_conf->group.length > 0 - && !nxt_str_eq(&app_conf->group, (u_char *) rt->group, - nxt_strlen(rt->group))) - { - nxt_alert(task, "cannot set group \"%V\" for app \"%V\": " - "missing capabilities", &app_conf->group, - &app_conf->name); - - return NXT_ERROR; - } - } - -#if (NXT_HAVE_ISOLATION_ROOTFS) - if (process->isolation.rootfs != NULL) { - nxt_int_t has_mnt; - - ret = nxt_isolation_set_mounts(task, process, &app_conf->type); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - -#if (NXT_HAVE_CLONE_NEWNS) - has_mnt = nxt_is_clone_flag_set(process->isolation.clone.flags, NEWNS); -#else - has_mnt = 0; -#endif - - if (process->user_cred->uid == 0 && !has_mnt) { - nxt_log(task, NXT_LOG_WARN, - "setting user \"root\" with \"rootfs\" is unsafe without " - "\"mount\" namespace isolation"); - } - } -#endif - -#if (NXT_HAVE_CLONE_NEWUSER) - ret = nxt_isolation_vldt_creds(task, process); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } -#endif - - return NXT_OK; -} - - -static nxt_int_t -nxt_isolation_set(nxt_task_t *task, nxt_conf_value_t *isolation, - nxt_process_t *process) -{ -#if (NXT_HAVE_CGROUP) - if (nxt_slow_path(nxt_isolation_set_cgroup(task, isolation, process) - != NXT_OK)) - { - return NXT_ERROR; - } -#endif - -#if (NXT_HAVE_LINUX_NS) - if (nxt_slow_path(nxt_isolation_set_namespaces(task, isolation, process) - != NXT_OK)) - { - return NXT_ERROR; - } -#endif - -#if (NXT_HAVE_CLONE_NEWUSER) - if (nxt_slow_path(nxt_isolation_set_creds(task, isolation, process) - != NXT_OK)) - { - return NXT_ERROR; - } -#endif - -#if (NXT_HAVE_ISOLATION_ROOTFS) - if (nxt_slow_path(nxt_isolation_set_rootfs(task, isolation, process) - != NXT_OK)) - { - return NXT_ERROR; - } - - if (nxt_slow_path(nxt_isolation_set_automount(task, isolation, process) - != NXT_OK)) - { - return NXT_ERROR; - } -#endif - -#if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) - if (nxt_slow_path(nxt_isolation_set_new_privs(task, isolation, process) - != NXT_OK)) - { - return NXT_ERROR; - } -#endif - - return NXT_OK; -} - - -#if (NXT_HAVE_CGROUP) - -static nxt_int_t -nxt_isolation_set_cgroup(nxt_task_t *task, nxt_conf_value_t *isolation, - nxt_process_t *process) -{ - nxt_str_t str; - nxt_conf_value_t *obj; - - static nxt_str_t cgname = nxt_string("cgroup"); - static nxt_str_t path = nxt_string("path"); - - obj = nxt_conf_get_object_member(isolation, &cgname, NULL); - if (obj == NULL) { - return NXT_OK; - } - - obj = nxt_conf_get_object_member(obj, &path, NULL); - if (obj == NULL) { - return NXT_ERROR; - } - - nxt_conf_get_string(obj, &str); - process->isolation.cgroup.path = nxt_mp_alloc(process->mem_pool, - str.length + 1); - nxt_memcpy(process->isolation.cgroup.path, str.start, str.length); - process->isolation.cgroup.path[str.length] = '\0'; - - process->isolation.cgroup_cleanup = nxt_cgroup_cleanup; - - return NXT_OK; -} - -#endif - - -#if (NXT_HAVE_LINUX_NS) - -static nxt_int_t -nxt_isolation_set_namespaces(nxt_task_t *task, nxt_conf_value_t *isolation, - nxt_process_t *process) -{ - nxt_int_t ret; - nxt_conf_value_t *obj; - - static nxt_str_t nsname = nxt_string("namespaces"); - - obj = nxt_conf_get_object_member(isolation, &nsname, NULL); - if (obj != NULL) { - ret = nxt_isolation_clone_flags(task, obj, &process->isolation.clone); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - - return NXT_OK; -} - -#endif - - -#if (NXT_HAVE_CLONE_NEWUSER) - -static nxt_int_t -nxt_isolation_set_creds(nxt_task_t *task, nxt_conf_value_t *isolation, - nxt_process_t *process) -{ - nxt_int_t ret; - nxt_clone_t *clone; - nxt_conf_value_t *array; - - static nxt_str_t uidname = nxt_string("uidmap"); - static nxt_str_t gidname = nxt_string("gidmap"); - - clone = &process->isolation.clone; - - array = nxt_conf_get_object_member(isolation, &uidname, NULL); - if (array != NULL) { - ret = nxt_isolation_credential_map(task, process->mem_pool, array, - &clone->uidmap); - - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - - array = nxt_conf_get_object_member(isolation, &gidname, NULL); - if (array != NULL) { - ret = nxt_isolation_credential_map(task, process->mem_pool, array, - &clone->gidmap); - - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_isolation_credential_map(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *map_array, nxt_clone_credential_map_t *map) -{ - nxt_int_t ret; - nxt_uint_t i; - nxt_conf_value_t *obj; - - static nxt_conf_map_t nxt_clone_map_entry_conf[] = { - { - nxt_string("container"), - NXT_CONF_MAP_INT64, - offsetof(nxt_clone_map_entry_t, container), - }, - - { - nxt_string("host"), - NXT_CONF_MAP_INT64, - offsetof(nxt_clone_map_entry_t, host), - }, - - { - nxt_string("size"), - NXT_CONF_MAP_INT64, - offsetof(nxt_clone_map_entry_t, size), - }, - }; - - map->size = nxt_conf_array_elements_count(map_array); - - if (map->size == 0) { - return NXT_OK; - } - - map->map = nxt_mp_alloc(mp, map->size * sizeof(nxt_clone_map_entry_t)); - if (nxt_slow_path(map->map == NULL)) { - return NXT_ERROR; - } - - for (i = 0; i < map->size; i++) { - obj = nxt_conf_get_array_element(map_array, i); - - ret = nxt_conf_map_object(mp, obj, nxt_clone_map_entry_conf, - nxt_nitems(nxt_clone_map_entry_conf), - map->map + i); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "clone map entry map error"); - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_isolation_vldt_creds(nxt_task_t *task, nxt_process_t *process) -{ - nxt_int_t ret; - nxt_clone_t *clone; - nxt_credential_t *creds; - - clone = &process->isolation.clone; - creds = process->user_cred; - - if (clone->uidmap.size == 0 && clone->gidmap.size == 0) { - return NXT_OK; - } - - if (!nxt_is_clone_flag_set(clone->flags, NEWUSER)) { - if (nxt_slow_path(clone->uidmap.size > 0)) { - nxt_log(task, NXT_LOG_ERR, "\"uidmap\" is set but " - "\"isolation.namespaces.credential\" is false or unset"); - - return NXT_ERROR; - } - - if (nxt_slow_path(clone->gidmap.size > 0)) { - nxt_log(task, NXT_LOG_ERR, "\"gidmap\" is set but " - "\"isolation.namespaces.credential\" is false or unset"); - - return NXT_ERROR; - } - - return NXT_OK; - } - - ret = nxt_clone_vldt_credential_uidmap(task, &clone->uidmap, creds); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - return nxt_clone_vldt_credential_gidmap(task, &clone->gidmap, creds); -} - -#endif - - -#if (NXT_HAVE_LINUX_NS) - -static nxt_int_t -nxt_isolation_clone_flags(nxt_task_t *task, nxt_conf_value_t *namespaces, - nxt_clone_t *clone) -{ - uint32_t index; - nxt_str_t name; - nxt_int_t flag; - nxt_conf_value_t *value; - - index = 0; - - for ( ;; ) { - value = nxt_conf_next_object_member(namespaces, &name, &index); - - if (value == NULL) { - break; - } - - flag = 0; - -#if (NXT_HAVE_CLONE_NEWUSER) - if (nxt_str_eq(&name, "credential", 10)) { - flag = CLONE_NEWUSER; - } -#endif - -#if (NXT_HAVE_CLONE_NEWPID) - if (nxt_str_eq(&name, "pid", 3)) { - flag = CLONE_NEWPID; - } -#endif - -#if (NXT_HAVE_CLONE_NEWNET) - if (nxt_str_eq(&name, "network", 7)) { - flag = CLONE_NEWNET; - } -#endif - -#if (NXT_HAVE_CLONE_NEWUTS) - if (nxt_str_eq(&name, "uname", 5)) { - flag = CLONE_NEWUTS; - } -#endif - -#if (NXT_HAVE_CLONE_NEWNS) - if (nxt_str_eq(&name, "mount", 5)) { - flag = CLONE_NEWNS; - } -#endif - -#if (NXT_HAVE_CLONE_NEWCGROUP) - if (nxt_str_eq(&name, "cgroup", 6)) { - flag = CLONE_NEWCGROUP; - } -#endif - - if (!flag) { - nxt_alert(task, "unknown namespace flag: \"%V\"", &name); - return NXT_ERROR; - } - - if (nxt_conf_get_boolean(value)) { - clone->flags |= flag; - } - } - - return NXT_OK; -} - -#endif - - -#if (NXT_HAVE_ISOLATION_ROOTFS) - -static nxt_int_t -nxt_isolation_set_rootfs(nxt_task_t *task, nxt_conf_value_t *isolation, - nxt_process_t *process) -{ - nxt_str_t str; - nxt_conf_value_t *obj; - - static nxt_str_t rootfs_name = nxt_string("rootfs"); - - obj = nxt_conf_get_object_member(isolation, &rootfs_name, NULL); - if (obj != NULL) { - nxt_conf_get_string(obj, &str); - - if (nxt_slow_path(str.length <= 1 || str.start[0] != '/')) { - nxt_log(task, NXT_LOG_ERR, "rootfs requires an absolute path other " - "than \"/\" but given \"%V\"", &str); - - return NXT_ERROR; - } - - if (str.start[str.length - 1] == '/') { - str.length--; - } - - process->isolation.rootfs = nxt_mp_alloc(process->mem_pool, - str.length + 1); - - if (nxt_slow_path(process->isolation.rootfs == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy(process->isolation.rootfs, str.start, str.length); - - process->isolation.rootfs[str.length] = '\0'; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_isolation_set_automount(nxt_task_t *task, nxt_conf_value_t *isolation, - nxt_process_t *process) -{ - nxt_conf_value_t *conf, *value; - nxt_process_automount_t *automount; - - static nxt_str_t automount_name = nxt_string("automount"); - static nxt_str_t langdeps_name = nxt_string("language_deps"); - static nxt_str_t tmp_name = nxt_string("tmpfs"); - static nxt_str_t proc_name = nxt_string("procfs"); - - automount = &process->isolation.automount; - - automount->language_deps = 1; - automount->tmpfs = 1; - automount->procfs = 1; - - conf = nxt_conf_get_object_member(isolation, &automount_name, NULL); - if (conf != NULL) { - value = nxt_conf_get_object_member(conf, &langdeps_name, NULL); - if (value != NULL) { - automount->language_deps = nxt_conf_get_boolean(value); - } - - value = nxt_conf_get_object_member(conf, &tmp_name, NULL); - if (value != NULL) { - automount->tmpfs = nxt_conf_get_boolean(value); - } - - value = nxt_conf_get_object_member(conf, &proc_name, NULL); - if (value != NULL) { - automount->procfs = nxt_conf_get_boolean(value); - } - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_isolation_set_mounts(nxt_task_t *task, nxt_process_t *process, - nxt_str_t *app_type) -{ - nxt_int_t ret, cap_chroot; - nxt_runtime_t *rt; - nxt_app_lang_module_t *lang; - - rt = task->thread->runtime; - cap_chroot = rt->capabilities.chroot; - lang = nxt_app_lang_module(rt, app_type); - - nxt_assert(lang != NULL); - -#if (NXT_HAVE_CLONE_NEWUSER) - if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) { - cap_chroot = 1; - } -#endif - - if (!cap_chroot) { - nxt_log(task, NXT_LOG_ERR, "The \"rootfs\" field requires privileges"); - return NXT_ERROR; - } - - ret = nxt_isolation_set_lang_mounts(task, process, lang->mounts); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - process->isolation.cleanup = nxt_isolation_unmount_all; - - return NXT_OK; -} - - -static nxt_int_t -nxt_isolation_set_lang_mounts(nxt_task_t *task, nxt_process_t *process, - nxt_array_t *lang_mounts) -{ - u_char *p; - size_t i, n, rootfs_len, len; - nxt_mp_t *mp; - nxt_array_t *mounts; - const u_char *rootfs; - nxt_fs_mount_t *mnt, *lang_mnt; - - mp = process->mem_pool; - - /* copy to init mem pool */ - mounts = nxt_array_copy(mp, NULL, lang_mounts); - if (mounts == NULL) { - return NXT_ERROR; - } - - n = mounts->nelts; - mnt = mounts->elts; - lang_mnt = lang_mounts->elts; - - rootfs = process->isolation.rootfs; - rootfs_len = nxt_strlen(rootfs); - - for (i = 0; i < n; i++) { - len = nxt_strlen(lang_mnt[i].dst); - - mnt[i].dst = nxt_mp_alloc(mp, rootfs_len + len + 1); - if (nxt_slow_path(mnt[i].dst == NULL)) { - return NXT_ERROR; - } - - p = nxt_cpymem(mnt[i].dst, rootfs, rootfs_len); - p = nxt_cpymem(p, lang_mnt[i].dst, len); - *p = '\0'; - } - - if (process->isolation.automount.tmpfs) { - mnt = nxt_array_add(mounts); - if (nxt_slow_path(mnt == NULL)) { - return NXT_ERROR; - } - - mnt->src = (u_char *) "tmpfs"; - mnt->name = (u_char *) "tmpfs"; - mnt->type = NXT_FS_TMP; - mnt->flags = (NXT_FS_FLAGS_NOSUID - | NXT_FS_FLAGS_NODEV - | NXT_FS_FLAGS_NOEXEC); - mnt->data = (u_char *) "size=1m,mode=1777"; - mnt->builtin = 1; - mnt->deps = 0; - - mnt->dst = nxt_mp_nget(mp, rootfs_len + nxt_length("/tmp") + 1); - if (nxt_slow_path(mnt->dst == NULL)) { - return NXT_ERROR; - } - - p = nxt_cpymem(mnt->dst, rootfs, rootfs_len); - p = nxt_cpymem(p, "/tmp", 4); - *p = '\0'; - } - - if (process->isolation.automount.procfs) { - mnt = nxt_array_add(mounts); - if (nxt_slow_path(mnt == NULL)) { - return NXT_ERROR; - } - - mnt->name = (u_char *) "proc"; - mnt->type = NXT_FS_PROC; - mnt->src = (u_char *) "none"; - mnt->dst = nxt_mp_nget(mp, rootfs_len + nxt_length("/proc") + 1); - if (nxt_slow_path(mnt->dst == NULL)) { - return NXT_ERROR; - } - - p = nxt_cpymem(mnt->dst, rootfs, rootfs_len); - p = nxt_cpymem(p, "/proc", 5); - *p = '\0'; - - mnt->data = (u_char *) ""; - mnt->flags = NXT_FS_FLAGS_NOEXEC | NXT_FS_FLAGS_NOSUID; - mnt->builtin = 1; - mnt->deps = 0; - } - - qsort(mounts->elts, mounts->nelts, sizeof(nxt_fs_mount_t), - nxt_isolation_mount_compare); - - process->isolation.mounts = mounts; - - return NXT_OK; -} - - -static int nxt_cdecl -nxt_isolation_mount_compare(const void *v1, const void *v2) -{ - const nxt_fs_mount_t *mnt1, *mnt2; - - mnt1 = v1; - mnt2 = v2; - - return nxt_strlen(mnt1->src) > nxt_strlen(mnt2->src); -} - - -void -nxt_isolation_unmount_all(nxt_task_t *task, nxt_process_t *process) -{ - size_t n; - nxt_array_t *mounts; - nxt_runtime_t *rt; - nxt_fs_mount_t *mnt; - nxt_process_automount_t *automount; - - rt = task->thread->runtime; - - if (!rt->capabilities.setid) { - return; - } - - nxt_debug(task, "unmount all (%s)", process->name); - - automount = &process->isolation.automount; - mounts = process->isolation.mounts; - n = mounts->nelts; - mnt = mounts->elts; - - while (n > 0) { - n--; - - if (mnt[n].deps && !automount->language_deps) { - continue; - } - - nxt_fs_unmount(mnt[n].dst); - } -} - - -nxt_int_t -nxt_isolation_prepare_rootfs(nxt_task_t *task, nxt_process_t *process) -{ - size_t i, n; - nxt_int_t ret; - struct stat st; - nxt_array_t *mounts; - const u_char *dst; - nxt_fs_mount_t *mnt; - nxt_process_automount_t *automount; - - automount = &process->isolation.automount; - mounts = process->isolation.mounts; - - n = mounts->nelts; - mnt = mounts->elts; - - for (i = 0; i < n; i++) { - dst = mnt[i].dst; - - if (mnt[i].deps && !automount->language_deps) { - continue; - } - - if (nxt_slow_path(mnt[i].type == NXT_FS_BIND - && stat((const char *) mnt[i].src, &st) != 0)) - { - nxt_log(task, NXT_LOG_WARN, "host path not found: %s", mnt[i].src); - continue; - } - - ret = nxt_fs_mkdir_all(dst, S_IRWXU | S_IRWXG | S_IRWXO); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "mkdir(%s) %E", dst, nxt_errno); - goto undo; - } - - ret = nxt_fs_mount(task, &mnt[i]); - if (nxt_slow_path(ret != NXT_OK)) { - goto undo; - } - } - - return NXT_OK; - -undo: - - n = i + 1; - - for (i = 0; i < n; i++) { - nxt_fs_unmount(mnt[i].dst); - } - - return NXT_ERROR; -} - - -#if (NXT_HAVE_LINUX_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) - -nxt_int_t -nxt_isolation_change_root(nxt_task_t *task, nxt_process_t *process) -{ - char *rootfs; - nxt_int_t ret; - - rootfs = (char *) process->isolation.rootfs; - - nxt_debug(task, "change root: %s", rootfs); - - if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWNS)) { - ret = nxt_isolation_pivot_root(task, rootfs); - - } else { - ret = nxt_isolation_chroot(task, rootfs); - } - - if (nxt_fast_path(ret == NXT_OK)) { - if (nxt_slow_path(chdir("/") < 0)) { - nxt_alert(task, "chdir(\"/\") %E", nxt_errno); - return NXT_ERROR; - } - } - - return ret; -} - - -/* - * pivot_root(2) can only be safely used with containers, otherwise it can - * umount(2) the global root filesystem and screw up the machine. - */ - -static nxt_int_t -nxt_isolation_pivot_root(nxt_task_t *task, const char *path) -{ - /* - * This implementation makes use of a kernel trick that works for ages - * and now documented in Linux kernel 5. - * https://lore.kernel.org/linux-man/87r24piwhm.fsf@x220.int.ebiederm.org/T/ - */ - - if (nxt_slow_path(mount("", "/", "", MS_SLAVE|MS_REC, "") != 0)) { - nxt_alert(task, "mount(\"/\", MS_SLAVE|MS_REC) failed: %E", nxt_errno); - return NXT_ERROR; - } - - if (nxt_slow_path(nxt_isolation_make_private_mount(task, path) != NXT_OK)) { - return NXT_ERROR; - } - - if (nxt_slow_path(mount(path, path, "bind", MS_BIND|MS_REC, "") != 0)) { - nxt_alert(task, "error bind mounting rootfs %E", nxt_errno); - return NXT_ERROR; - } - - if (nxt_slow_path(chdir(path) != 0)) { - nxt_alert(task, "failed to chdir(%s) %E", path, nxt_errno); - return NXT_ERROR; - } - - if (nxt_slow_path(nxt_pivot_root(".", ".") != 0)) { - nxt_alert(task, "failed to pivot_root %E", nxt_errno); - return NXT_ERROR; - } - - /* - * Demote the oldroot mount to avoid unmounts getting propagated to - * the host. - */ - if (nxt_slow_path(mount("", ".", "", MS_SLAVE | MS_REC, NULL) != 0)) { - nxt_alert(task, "failed to bind mount rootfs %E", nxt_errno); - return NXT_ERROR; - } - - if (nxt_slow_path(umount2(".", MNT_DETACH) != 0)) { - nxt_alert(task, "failed to umount old root directory %E", nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_isolation_make_private_mount(nxt_task_t *task, const char *rootfs) -{ - char *parent_mnt; - FILE *procfile; - u_char **mounts; - size_t len; - uint8_t *shared; - nxt_int_t ret, index, nmounts; - struct mntent *ent; - - static const char *mount_path = "/proc/self/mounts"; - - ret = NXT_ERROR; - ent = NULL; - shared = NULL; - procfile = NULL; - parent_mnt = NULL; - - nmounts = 256; - - mounts = nxt_malloc(nmounts * sizeof(uintptr_t)); - if (nxt_slow_path(mounts == NULL)) { - goto fail; - } - - shared = nxt_malloc(nmounts); - if (nxt_slow_path(shared == NULL)) { - goto fail; - } - - procfile = setmntent(mount_path, "r"); - if (nxt_slow_path(procfile == NULL)) { - nxt_alert(task, "failed to open %s %E", mount_path, nxt_errno); - - goto fail; - } - - index = 0; - -again: - - for ( ; index < nmounts; index++) { - ent = getmntent(procfile); - if (ent == NULL) { - nmounts = index; - break; - } - - mounts[index] = (u_char *) strdup(ent->mnt_dir); - shared[index] = hasmntopt(ent, "shared") != NULL; - } - - if (ent != NULL) { - /* there are still entries to be read */ - - nmounts *= 2; - mounts = nxt_realloc(mounts, nmounts); - if (nxt_slow_path(mounts == NULL)) { - goto fail; - } - - shared = nxt_realloc(shared, nmounts); - if (nxt_slow_path(shared == NULL)) { - goto fail; - } - - goto again; - } - - for (index = 0; index < nmounts; index++) { - if (nxt_strcmp(mounts[index], rootfs) == 0) { - parent_mnt = (char *) rootfs; - break; - } - } - - if (parent_mnt == NULL) { - len = nxt_strlen(rootfs); - - parent_mnt = nxt_malloc(len + 1); - if (parent_mnt == NULL) { - goto fail; - } - - nxt_memcpy(parent_mnt, rootfs, len); - parent_mnt[len] = '\0'; - - if (parent_mnt[len - 1] == '/') { - parent_mnt[len - 1] = '\0'; - len--; - } - - for ( ;; ) { - for (index = 0; index < nmounts; index++) { - if (nxt_strcmp(mounts[index], parent_mnt) == 0) { - goto found; - } - } - - if (len == 1 && parent_mnt[0] == '/') { - nxt_alert(task, "parent mount not found"); - goto fail; - } - - /* parent dir */ - while (parent_mnt[len - 1] != '/' && len > 0) { - len--; - } - - if (nxt_slow_path(len == 0)) { - nxt_alert(task, "parent mount not found"); - goto fail; - } - - if (len == 1) { - parent_mnt[len] = '\0'; /* / */ - } else { - parent_mnt[len - 1] = '\0'; /* / */ - } - } - } - -found: - - if (shared[index]) { - if (nxt_slow_path(mount("", parent_mnt, "", MS_PRIVATE, "") != 0)) { - nxt_alert(task, "mount(\"\", \"%s\", MS_PRIVATE) %E", parent_mnt, - nxt_errno); - - goto fail; - } - } - - ret = NXT_OK; - -fail: - - if (procfile != NULL) { - endmntent(procfile); - } - - if (mounts != NULL) { - for (index = 0; index < nmounts; index++) { - nxt_free(mounts[index]); - } - - nxt_free(mounts); - } - - if (shared != NULL) { - nxt_free(shared); - } - - if (parent_mnt != NULL && parent_mnt != rootfs) { - nxt_free(parent_mnt); - } - - return ret; -} - - -nxt_inline int -nxt_pivot_root(const char *new_root, const char *old_root) -{ - return syscall(SYS_pivot_root, new_root, old_root); -} - - -#else /* !(NXT_HAVE_LINUX_PIVOT_ROOT) || !(NXT_HAVE_CLONE_NEWNS) */ - - -nxt_int_t -nxt_isolation_change_root(nxt_task_t *task, nxt_process_t *process) -{ - char *rootfs; - - rootfs = (char *) process->isolation.rootfs; - - nxt_debug(task, "change root: %s", rootfs); - - if (nxt_fast_path(nxt_isolation_chroot(task, rootfs) == NXT_OK)) { - if (nxt_slow_path(chdir("/") < 0)) { - nxt_alert(task, "chdir(\"/\") %E", nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; - } - - return NXT_ERROR; -} - -#endif - - -static nxt_int_t -nxt_isolation_chroot(nxt_task_t *task, const char *path) -{ - if (nxt_slow_path(chroot(path) < 0)) { - nxt_alert(task, "chroot(%s) %E", path, nxt_errno); - return NXT_ERROR; - } - - return NXT_OK; -} - -#endif /* NXT_HAVE_ISOLATION_ROOTFS */ - - -#if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) - -static nxt_int_t -nxt_isolation_set_new_privs(nxt_task_t *task, nxt_conf_value_t *isolation, - nxt_process_t *process) -{ - nxt_conf_value_t *obj; - - static nxt_str_t new_privs_name = nxt_string("new_privs"); - - obj = nxt_conf_get_object_member(isolation, &new_privs_name, NULL); - if (obj != NULL) { - process->isolation.new_privs = nxt_conf_get_boolean(obj); - } - - return NXT_OK; -} - -#endif diff --git a/src/nxt_isolation.h b/src/nxt_isolation.h deleted file mode 100644 index b1bfc33c..00000000 --- a/src/nxt_isolation.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_ISOLATION_H_INCLUDED_ -#define _NXT_ISOLATION_H_INCLUDED_ - - -nxt_int_t nxt_isolation_main_prefork(nxt_task_t *task, nxt_process_t *process, - nxt_mp_t *mp); - -#if (NXT_HAVE_ISOLATION_ROOTFS) -nxt_int_t nxt_isolation_prepare_rootfs(nxt_task_t *task, - nxt_process_t *process); -nxt_int_t nxt_isolation_change_root(nxt_task_t *task, nxt_process_t *process); -#endif - -#endif /* _NXT_ISOLATION_H_INCLUDED_ */ diff --git a/src/nxt_java.c b/src/nxt_java.c deleted file mode 100644 index 75c8ee19..00000000 --- a/src/nxt_java.c +++ /dev/null @@ -1,760 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "java/nxt_jni_Thread.h" -#include "java/nxt_jni_Context.h" -#include "java/nxt_jni_Request.h" -#include "java/nxt_jni_Response.h" -#include "java/nxt_jni_InputStream.h" -#include "java/nxt_jni_OutputStream.h" -#include "java/nxt_jni_URLClassLoader.h" - -#include "nxt_jars.h" - -#include NXT_JAVA_MOUNTS_H - -static nxt_int_t nxt_java_setup(nxt_task_t *task, nxt_process_t *process, - nxt_common_app_conf_t *conf); -static nxt_int_t nxt_java_start(nxt_task_t *task, - nxt_process_data_t *data); -static void nxt_java_request_handler(nxt_unit_request_info_t *req); -static void nxt_java_websocket_handler(nxt_unit_websocket_frame_t *ws); -static void nxt_java_close_handler(nxt_unit_request_info_t *req); -static int nxt_java_ready_handler(nxt_unit_ctx_t *ctx); -static void *nxt_java_thread_func(void *main_ctx); -static int nxt_java_init_threads(nxt_java_app_conf_t *c); -static void nxt_java_join_threads(nxt_unit_ctx_t *ctx, - nxt_java_app_conf_t *c); - -static uint32_t compat[] = { - NXT_VERNUM, NXT_DEBUG, -}; - -char *nxt_java_modules; - -static pthread_t *nxt_java_threads; -static pthread_attr_t *nxt_java_thread_attr; - - -#define NXT_STRING(x) _NXT_STRING(x) -#define _NXT_STRING(x) #x - -NXT_EXPORT nxt_app_module_t nxt_app_module = { - sizeof(compat), - compat, - nxt_string("java"), - NXT_STRING(NXT_JAVA_VERSION), - nxt_java_mounts, - nxt_nitems(nxt_java_mounts), - nxt_java_setup, - nxt_java_start, -}; - -typedef struct { - JavaVM *jvm; - jobject cl; - jobject ctx; - nxt_java_app_conf_t *conf; -} nxt_java_data_t; - - -static nxt_int_t -nxt_java_setup(nxt_task_t *task, nxt_process_t *process, - nxt_common_app_conf_t *conf) -{ - char *path, *relpath, *p, *rootfs; - size_t jars_dir_len, rootfs_len; - const char *unit_jars; - - rootfs = (char *) process->isolation.rootfs; - rootfs_len = 0; - - unit_jars = conf->u.java.unit_jars; - if (unit_jars == NULL) { - if (rootfs != NULL) { - unit_jars = "/"; - } else { - unit_jars = NXT_JARS; - } - } - - relpath = strdup(unit_jars); - if (nxt_slow_path(relpath == NULL)) { - return NXT_ERROR; - } - - if (rootfs != NULL) { - jars_dir_len = strlen(unit_jars); - rootfs_len = strlen(rootfs); - - path = nxt_malloc(jars_dir_len + rootfs_len + 1); - if (nxt_slow_path(path == NULL)) { - free(relpath); - return NXT_ERROR; - } - - p = nxt_cpymem(path, process->isolation.rootfs, rootfs_len); - p = nxt_cpymem(p, relpath, jars_dir_len); - *p = '\0'; - - free(relpath); - - } else { - path = relpath; - } - - nxt_java_modules = realpath(path, NULL); - if (nxt_java_modules == NULL) { - nxt_alert(task, "realpath(\"%s\") failed %E", path, nxt_errno); - goto free; - } - - if (rootfs != NULL && strlen(path) > rootfs_len) { - nxt_java_modules = path + rootfs_len; - } - - nxt_debug(task, "JAVA MODULES: %s", nxt_java_modules); - - return NXT_OK; - -free: - - nxt_free(path); - - return NXT_ERROR; -} - - -static char ** -nxt_java_module_jars(const char *jars[], int jar_count) -{ - char **res, *jurl; - uint8_t pathsep; - nxt_int_t modules_len, jlen, i; - const char **jar; - - res = nxt_malloc(jar_count * sizeof(char*)); - if (res == NULL) { - return NULL; - } - - modules_len = nxt_strlen(nxt_java_modules); - - pathsep = nxt_java_modules[modules_len - 1] == '/'; - - for (i = 0, jar = jars; *jar != NULL; jar++) { - jlen = nxt_length("file:") + modules_len - + (!pathsep ? nxt_length("/") : 0) - + nxt_strlen(*jar) + 1; - - jurl = nxt_malloc(jlen); - if (jurl == NULL) { - return NULL; - } - - res[i++] = jurl; - - jurl = nxt_cpymem(jurl, "file:", nxt_length("file:")); - jurl = nxt_cpymem(jurl, nxt_java_modules, modules_len); - - if (!pathsep) { - *jurl++ = '/'; - } - - jurl = nxt_cpymem(jurl, *jar, nxt_strlen(*jar)); - *jurl++ = '\0'; - } - - return res; -} - - -static nxt_int_t -nxt_java_start(nxt_task_t *task, nxt_process_data_t *data) -{ - jint rc; - char *opt, *real_path; - char **classpath_arr, **unit_jars, **system_jars; - JavaVM *jvm; - JNIEnv *env; - jobject cl, classpath; - nxt_str_t str; - nxt_int_t opt_len, real_path_len; - nxt_uint_t i, unit_jars_count, classpath_count; - nxt_uint_t system_jars_count; - JavaVMOption *jvm_opt; - JavaVMInitArgs jvm_args; - nxt_unit_ctx_t *ctx; - nxt_unit_init_t java_init; - nxt_java_data_t java_data; - nxt_conf_value_t *value; - nxt_java_app_conf_t *c; - nxt_common_app_conf_t *app_conf; - - //setenv("ASAN_OPTIONS", "handle_segv=0", 1); - - jvm_args.version = JNI_VERSION_1_6; - jvm_args.nOptions = 0; - jvm_args.ignoreUnrecognized = 0; - - app_conf = data->app; - c = &app_conf->u.java; - - if (c->options != NULL) { - jvm_args.nOptions += nxt_conf_array_elements_count(c->options); - } - - jvm_opt = nxt_malloc(jvm_args.nOptions * sizeof(JavaVMOption)); - if (jvm_opt == NULL) { - nxt_alert(task, "failed to allocate jvm_opt"); - return NXT_ERROR; - } - - jvm_args.options = jvm_opt; - - unit_jars_count = nxt_nitems(nxt_java_unit_jars) - 1; - - unit_jars = nxt_java_module_jars(nxt_java_unit_jars, unit_jars_count); - if (unit_jars == NULL) { - nxt_alert(task, "failed to allocate buffer for unit_jars array"); - - return NXT_ERROR; - } - - system_jars_count = nxt_nitems(nxt_java_system_jars) - 1; - - system_jars = nxt_java_module_jars(nxt_java_system_jars, system_jars_count); - if (system_jars == NULL) { - nxt_alert(task, "failed to allocate buffer for system_jars array"); - - return NXT_ERROR; - } - - if (c->options != NULL) { - - for (i = 0; /* void */ ; i++) { - value = nxt_conf_get_array_element(c->options, i); - if (value == NULL) { - break; - } - - nxt_conf_get_string(value, &str); - - opt = nxt_malloc(str.length + 1); - if (opt == NULL) { - nxt_alert(task, "failed to allocate jvm_opt"); - return NXT_ERROR; - } - - memcpy(opt, str.start, str.length); - opt[str.length] = '\0'; - - jvm_opt[i].optionString = opt; - } - } - - if (c->classpath != NULL) { - classpath_count = nxt_conf_array_elements_count(c->classpath); - classpath_arr = nxt_malloc(classpath_count * sizeof(char *)); - - for (i = 0; /* void */ ; i++) { - value = nxt_conf_get_array_element(c->classpath, i); - if (value == NULL) { - break; - } - - nxt_conf_get_string(value, &str); - - opt_len = str.length + 1; - - char *sc = memchr(str.start, ':', str.length); - if (sc == NULL && str.start[0] == '/') { - opt_len += nxt_length("file:"); - } - - opt = nxt_malloc(opt_len); - if (opt == NULL) { - nxt_alert(task, "failed to allocate classpath"); - return NXT_ERROR; - } - - if (sc == NULL && str.start[0] != '/') { - nxt_memcpy(opt, str.start, str.length); - opt[str.length] = '\0'; - - real_path = realpath(opt, NULL); - if (real_path == NULL) { - nxt_alert(task, "realpath(%s) failed: %E", opt, nxt_errno); - return NXT_ERROR; - } - - real_path_len = nxt_strlen(real_path); - - free(opt); - - opt_len = nxt_length("file:") + real_path_len + 1; - - opt = nxt_malloc(opt_len); - if (opt == NULL) { - nxt_alert(task, "failed to allocate classpath"); - return NXT_ERROR; - } - - } else { - real_path = (char *) str.start; /* I love this cast! */ - real_path_len = str.length; - } - - classpath_arr[i] = opt; - - if (sc == NULL) { - opt = nxt_cpymem(opt, "file:", nxt_length("file:")); - } - - opt = nxt_cpymem(opt, real_path, real_path_len); - *opt = '\0'; - } - - } else { - classpath_count = 0; - classpath_arr = NULL; - } - - rc = JNI_CreateJavaVM(&jvm, (void **) &env, &jvm_args); - if (rc != JNI_OK) { - nxt_alert(task, "failed to create Java VM: %d", (int) rc); - return NXT_ERROR; - } - - rc = nxt_java_initThread(env); - if (rc != NXT_UNIT_OK) { - nxt_alert(task, "nxt_java_initThread() failed"); - goto env_failed; - } - - rc = nxt_java_initURLClassLoader(env); - if (rc != NXT_UNIT_OK) { - nxt_alert(task, "nxt_java_initURLClassLoader() failed"); - goto env_failed; - } - - cl = nxt_java_newURLClassLoader(env, system_jars_count, system_jars); - if (cl == NULL) { - nxt_alert(task, "nxt_java_newURLClassLoader failed"); - goto env_failed; - } - - nxt_java_setContextClassLoader(env, cl); - - cl = nxt_java_newURLClassLoader_parent(env, unit_jars_count, unit_jars, cl); - if (cl == NULL) { - nxt_alert(task, "nxt_java_newURLClassLoader_parent failed"); - goto env_failed; - } - - nxt_java_setContextClassLoader(env, cl); - - rc = nxt_java_initContext(env, cl); - if (rc != NXT_UNIT_OK) { - nxt_alert(task, "nxt_java_initContext() failed"); - goto env_failed; - } - - rc = nxt_java_initRequest(env, cl); - if (rc != NXT_UNIT_OK) { - nxt_alert(task, "nxt_java_initRequest() failed"); - goto env_failed; - } - - rc = nxt_java_initResponse(env, cl); - if (rc != NXT_UNIT_OK) { - nxt_alert(task, "nxt_java_initResponse() failed"); - goto env_failed; - } - - rc = nxt_java_initInputStream(env, cl); - if (rc != NXT_UNIT_OK) { - nxt_alert(task, "nxt_java_initInputStream() failed"); - goto env_failed; - } - - rc = nxt_java_initOutputStream(env, cl); - if (rc != NXT_UNIT_OK) { - nxt_alert(task, "nxt_java_initOutputStream() failed"); - goto env_failed; - } - - nxt_java_jni_init(env); - if (rc != NXT_UNIT_OK) { - nxt_alert(task, "nxt_java_jni_init() failed"); - goto env_failed; - } - - classpath = nxt_java_newURLs(env, classpath_count, classpath_arr); - if (classpath == NULL) { - nxt_alert(task, "nxt_java_newURLs failed"); - goto env_failed; - } - - java_data.jvm = jvm; - java_data.cl = cl; - java_data.ctx = nxt_java_startContext(env, c->webapp, classpath); - java_data.conf = c; - - if ((*env)->ExceptionCheck(env)) { - nxt_alert(task, "Unhandled exception in application start"); - (*env)->ExceptionDescribe(env); - return NXT_ERROR; - } - - rc = nxt_java_init_threads(c); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - return NXT_ERROR; - } - - nxt_unit_default_init(task, &java_init, app_conf); - - java_init.callbacks.request_handler = nxt_java_request_handler; - java_init.callbacks.websocket_handler = nxt_java_websocket_handler; - java_init.callbacks.close_handler = nxt_java_close_handler; - java_init.callbacks.ready_handler = nxt_java_ready_handler; - java_init.request_data_size = sizeof(nxt_java_request_data_t); - java_init.data = &java_data; - java_init.ctx_data = env; - - ctx = nxt_unit_init(&java_init); - if (nxt_slow_path(ctx == NULL)) { - nxt_alert(task, "nxt_unit_init() failed"); - return NXT_ERROR; - } - - rc = nxt_unit_run(ctx); - - nxt_java_join_threads(ctx, c); - - nxt_java_stopContext(env, java_data.ctx); - - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - } - - nxt_unit_done(ctx); - - (*jvm)->DestroyJavaVM(jvm); - - exit(rc); - - return NXT_OK; - -env_failed: - - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - } - - return NXT_ERROR; -} - - -static void -nxt_java_request_handler(nxt_unit_request_info_t *req) -{ - JNIEnv *env; - jobject jreq, jresp; - nxt_java_data_t *java_data; - nxt_java_request_data_t *data; - - java_data = req->unit->data; - env = req->ctx->data; - data = req->data; - - jreq = nxt_java_newRequest(env, java_data->ctx, req); - if (jreq == NULL) { - nxt_unit_req_alert(req, "failed to create Request instance"); - - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - nxt_unit_request_done(req, NXT_UNIT_ERROR); - return; - } - - jresp = nxt_java_newResponse(env, req); - if (jresp == NULL) { - nxt_unit_req_alert(req, "failed to create Response instance"); - - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - (*env)->DeleteLocalRef(env, jreq); - - nxt_unit_request_done(req, NXT_UNIT_ERROR); - return; - } - - data->header_size = 10 * 1024; - data->buf_size = 32 * 1024; /* from Jetty */ - data->jreq = jreq; - data->jresp = jresp; - data->buf = NULL; - - nxt_unit_request_group_dup_fields(req); - - nxt_java_service(env, java_data->ctx, jreq, jresp); - - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - if (!nxt_unit_response_is_init(req)) { - nxt_unit_response_init(req, 200, 0, 0); - } - - if (!nxt_unit_response_is_sent(req)) { - nxt_unit_response_send(req); - } - - if (data->buf != NULL) { - nxt_unit_buf_send(data->buf); - - data->buf = NULL; - } - - if (nxt_unit_response_is_websocket(req)) { - data->jreq = (*env)->NewGlobalRef(env, jreq); - data->jresp = (*env)->NewGlobalRef(env, jresp); - - } else { - nxt_unit_request_done(req, NXT_UNIT_OK); - } - - (*env)->DeleteLocalRef(env, jresp); - (*env)->DeleteLocalRef(env, jreq); -} - - -static void -nxt_java_websocket_handler(nxt_unit_websocket_frame_t *ws) -{ - void *b; - JNIEnv *env; - jobject jbuf; - nxt_java_request_data_t *data; - - env = ws->req->ctx->data; - data = ws->req->data; - - b = malloc(ws->payload_len); - if (b != NULL) { - nxt_unit_websocket_read(ws, b, ws->payload_len); - - jbuf = (*env)->NewDirectByteBuffer(env, b, ws->payload_len); - if (jbuf != NULL) { - nxt_java_Request_websocket(env, data->jreq, jbuf, - ws->header->opcode, ws->header->fin); - - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } - - (*env)->DeleteLocalRef(env, jbuf); - } - - free(b); - } - - nxt_unit_websocket_done(ws); -} - - -static void -nxt_java_close_handler(nxt_unit_request_info_t *req) -{ - JNIEnv *env; - nxt_java_request_data_t *data; - - env = req->ctx->data; - data = req->data; - - nxt_java_Request_close(env, data->jreq); - - (*env)->DeleteGlobalRef(env, data->jresp); - (*env)->DeleteGlobalRef(env, data->jreq); - - nxt_unit_request_done(req, NXT_UNIT_OK); -} - - -static int -nxt_java_ready_handler(nxt_unit_ctx_t *ctx) -{ - int res; - uint32_t i; - nxt_java_data_t *java_data; - nxt_java_app_conf_t *c; - - java_data = ctx->unit->data; - c = java_data->conf; - - if (c->threads <= 1) { - return NXT_UNIT_OK; - } - - for (i = 0; i < c->threads - 1; i++) { - res = pthread_create(&nxt_java_threads[i], nxt_java_thread_attr, - nxt_java_thread_func, ctx); - - if (nxt_fast_path(res == 0)) { - nxt_unit_debug(ctx, "thread #%d created", (int) (i + 1)); - - } else { - nxt_unit_alert(ctx, "thread #%d create failed: %s (%d)", - (int) (i + 1), strerror(res), res); - - return NXT_UNIT_ERROR; - } - } - - return NXT_UNIT_OK; -} - - -static void * -nxt_java_thread_func(void *data) -{ - int rc; - JavaVM *jvm; - JNIEnv *env; - nxt_unit_ctx_t *main_ctx, *ctx; - nxt_java_data_t *java_data; - - main_ctx = data; - - nxt_unit_debug(main_ctx, "worker thread start"); - - java_data = main_ctx->unit->data; - jvm = java_data->jvm; - - rc = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL); - if (rc != JNI_OK) { - nxt_unit_alert(main_ctx, "failed to attach Java VM: %d", (int) rc); - return NULL; - } - - nxt_java_setContextClassLoader(env, java_data->cl); - - ctx = nxt_unit_ctx_alloc(main_ctx, env); - if (nxt_slow_path(ctx == NULL)) { - goto fail; - } - - (void) nxt_unit_run(ctx); - - nxt_unit_done(ctx); - -fail: - - (*jvm)->DetachCurrentThread(jvm); - - nxt_unit_debug(NULL, "worker thread end"); - - return NULL; -} - - -static int -nxt_java_init_threads(nxt_java_app_conf_t *c) -{ - int res; - static pthread_attr_t attr; - - if (c->threads <= 1) { - return NXT_UNIT_OK; - } - - if (c->thread_stack_size > 0) { - res = pthread_attr_init(&attr); - if (nxt_slow_path(res != 0)) { - nxt_unit_alert(NULL, "thread attr init failed: %s (%d)", - strerror(res), res); - - return NXT_UNIT_ERROR; - } - - res = pthread_attr_setstacksize(&attr, c->thread_stack_size); - if (nxt_slow_path(res != 0)) { - nxt_unit_alert(NULL, "thread attr set stack size failed: %s (%d)", - strerror(res), res); - - return NXT_UNIT_ERROR; - } - - nxt_java_thread_attr = &attr; - } - - nxt_java_threads = nxt_unit_malloc(NULL, - sizeof(pthread_t) * (c->threads - 1)); - if (nxt_slow_path(nxt_java_threads == NULL)) { - nxt_unit_alert(NULL, "Failed to allocate thread id array"); - - return NXT_UNIT_ERROR; - } - - memset(nxt_java_threads, 0, sizeof(pthread_t) * (c->threads - 1)); - - return NXT_UNIT_OK; -} - - -static void -nxt_java_join_threads(nxt_unit_ctx_t *ctx, nxt_java_app_conf_t *c) -{ - int res; - uint32_t i; - - if (nxt_java_threads == NULL) { - return; - } - - for (i = 0; i < c->threads - 1; i++) { - if ((uintptr_t) nxt_java_threads[i] == 0) { - continue; - } - - res = pthread_join(nxt_java_threads[i], NULL); - - if (nxt_fast_path(res == 0)) { - nxt_unit_debug(ctx, "thread #%d joined", (int) i); - - } else { - nxt_unit_alert(ctx, "thread #%d join failed: %s (%d)", - (int) i, strerror(res), res); - } - } - - nxt_unit_free(ctx, nxt_java_threads); -} - - diff --git a/src/nxt_job.c b/src/nxt_job.c deleted file mode 100644 index 56073953..00000000 --- a/src/nxt_job.c +++ /dev/null @@ -1,199 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static void nxt_job_thread_trampoline(nxt_task_t *task, void *obj, void *data); -static void nxt_job_thread_return_handler(nxt_task_t *task, void *obj, - void *data); - - -void * -nxt_job_create(nxt_mp_t *mp, size_t size) -{ - size_t cache_size; - nxt_job_t *job; - - if (mp == NULL) { - mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { - return NULL; - } - - job = nxt_mp_zget(mp, size); - cache_size = 0; - - } else { - job = nxt_mp_zalloc(mp, size); - cache_size = size; - } - - if (nxt_slow_path(job == NULL)) { - return NULL; - } - - job->cache_size = (uint16_t) cache_size; - job->mem_pool = mp; - nxt_job_set_name(job, "job"); - - /* Allow safe nxt_queue_remove() in nxt_job_destroy(). */ - nxt_queue_self(&job->link); - - return job; -} - - -void -nxt_job_init(nxt_job_t *job, size_t size) -{ - nxt_memzero(job, size); - - nxt_job_set_name(job, "job"); - - nxt_queue_self(&job->link); -} - - -void -nxt_job_destroy(nxt_task_t *task, void *data) -{ - nxt_job_t *job; - - job = data; - - nxt_queue_remove(&job->link); - - if (job->cache_size == 0) { - - if (job->mem_pool != NULL) { - nxt_mp_destroy(job->mem_pool); - } - - } else { - nxt_mp_free(job->mem_pool, job); - } -} - - -#if 0 - -nxt_int_t -nxt_job_cleanup_add(nxt_mp_t *mp, nxt_job_t *job) -{ - nxt_mem_pool_cleanup_t *mpcl; - - mpcl = nxt_mem_pool_cleanup(mp, 0); - - if (nxt_fast_path(mpcl != NULL)) { - mpcl->handler = nxt_job_destroy; - mpcl->data = job; - return NXT_OK; - } - - return NXT_ERROR; -} - -#endif - - -/* - * The (void *) casts in nxt_thread_pool_post() and nxt_event_engine_post() - * calls and to the "nxt_work_handler_t" are required by Sun C. - */ - -void -nxt_job_start(nxt_task_t *task, nxt_job_t *job, nxt_work_handler_t handler) -{ - nxt_debug(task, "%s start", job->name); - - if (job->thread_pool != NULL) { - nxt_int_t ret; - - job->engine = task->thread->engine; - - nxt_work_set(&job->work, nxt_job_thread_trampoline, - job->task, job, (void *) handler); - - ret = nxt_thread_pool_post(job->thread_pool, &job->work); - - if (ret == NXT_OK) { - return; - } - - handler = job->abort_handler; - } - - handler(job->task, job, job->data); -} - - -/* A trampoline function is called by a thread pool thread. */ - -static void -nxt_job_thread_trampoline(nxt_task_t *task, void *obj, void *data) -{ - nxt_job_t *job; - nxt_work_handler_t handler; - - job = obj; - handler = (nxt_work_handler_t) data; - - nxt_debug(task, "%s thread", job->name); - - if (nxt_slow_path(job->cancel)) { - nxt_job_return(task, job, job->abort_handler); - - } else { - handler(job->task, job, job->data); - } -} - - -void -nxt_job_return(nxt_task_t *task, nxt_job_t *job, nxt_work_handler_t handler) -{ - nxt_debug(task, "%s return", job->name); - - if (job->engine != NULL) { - /* A return function is called in thread pool thread context. */ - - nxt_work_set(&job->work, nxt_job_thread_return_handler, - job->task, job, (void *) handler); - - nxt_event_engine_post(job->engine, &job->work); - - return; - } - - if (nxt_slow_path(job->cancel)) { - nxt_debug(task, "%s cancellation", job->name); - handler = job->abort_handler; - } - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - handler, job->task, job, job->data); -} - - -static void -nxt_job_thread_return_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_job_t *job; - nxt_work_handler_t handler; - - job = obj; - handler = (nxt_work_handler_t) data; - - job->task->thread = task->thread; - - if (nxt_slow_path(job->cancel)) { - nxt_debug(task, "%s cancellation", job->name); - handler = job->abort_handler; - } - - handler(job->task, job, job->data); -} diff --git a/src/nxt_job.h b/src/nxt_job.h deleted file mode 100644 index 0495c484..00000000 --- a/src/nxt_job.h +++ /dev/null @@ -1,86 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JOB_H_INCLUDED_ -#define _NXT_JOB_H_INCLUDED_ - - -/* - * A job may run by separate thread, so each job should have its - * its own mem_pool. A job itself is allocated from this mem_pool. - * On job completion a job initiator can destroy the job at once - * with nxt_job_destroy() or can postpone the destruction with - * nxt_job_cleanup_add(), if the initiator uses data from the job's - * mem_pool. - * - * Several child jobs may run in context of another job in the same - * thread. In this case the child job may use a mem_pool of the - * parent job and the child job is allocated using the mem_pool's cache. - * nxt_job_destroy() just returns the job to the cache. All job - * allocations however still remain in the parent mem_pool. - * - * The first thread in job thread pool is created on demand. If this - * operation fails the job abort handler is called. It also is called - * if the job is canceled. To avoid race condition the abort handler - * always runs in context of a thread initiated the job. The abort - * handler may be as simple as nxt_job_destroy(). - */ - - -typedef struct { - void *data; - - nxt_task_t *task; - - nxt_work_handler_t abort_handler; - - uint16_t cache_size; - uint8_t cancel; /* 1 bit */ - - nxt_mp_t *mem_pool; - nxt_queue_link_t link; - - nxt_thread_pool_t *thread_pool; - nxt_event_engine_t *engine; - nxt_log_t *log; - - nxt_work_t work; - -#if (NXT_DEBUG) - const char *name; -#endif - -} nxt_job_t; - - -NXT_EXPORT void *nxt_job_create(nxt_mp_t *mp, size_t size); -NXT_EXPORT void nxt_job_init(nxt_job_t *job, size_t size); -NXT_EXPORT void nxt_job_destroy(nxt_task_t *task, void *data); -NXT_EXPORT nxt_int_t nxt_job_cleanup_add(nxt_mp_t *mp, nxt_job_t *job); - -NXT_EXPORT void nxt_job_start(nxt_task_t *task, nxt_job_t *job, - nxt_work_handler_t handler); -NXT_EXPORT void nxt_job_return(nxt_task_t *task, nxt_job_t *job, - nxt_work_handler_t handler); - - -#define nxt_job_cancel(job) \ - (job)->cancel = 1 - - -#if (NXT_DEBUG) - -#define nxt_job_set_name(job, text) \ - (job)->name = text - -#else - -#define nxt_job_set_name(job, text) - -#endif - - -#endif /* _NXT_JOB_H_INCLUDED_ */ diff --git a/src/nxt_job_cache_file.c b/src/nxt_job_cache_file.c deleted file mode 100644 index 13f01a45..00000000 --- a/src/nxt_job_cache_file.c +++ /dev/null @@ -1,24 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - - -#include - - -nxt_job_cache_file_t * -nxt_job_cache_file_create(nxt_mp_t *mp) -{ - nxt_job_cache_file_t *jbc; - - jbc = nxt_job_create(mp, sizeof(nxt_job_cache_file_t)); - - if (nxt_fast_path(jbc != NULL)) { - jbc->file.fd = NXT_FILE_INVALID; - jbc->read_required = nxt_job_file_read_required; - } - - return jbc; -} diff --git a/src/nxt_js.c b/src/nxt_js.c deleted file mode 100644 index 6885afb7..00000000 --- a/src/nxt_js.c +++ /dev/null @@ -1,489 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - - -struct nxt_js_s { - uint32_t index; -}; - - -typedef struct { - nxt_str_t name; - nxt_str_t text; -} nxt_js_module_t; - - -struct nxt_js_conf_s { - nxt_mp_t *pool; - njs_vm_t *vm; - njs_uint_t protos; - njs_external_t *proto; - nxt_str_t init; - nxt_array_t *modules; /* of nxt_js_module_t */ - nxt_array_t *funcs; - uint8_t test; /* 1 bit */ -}; - - -njs_mod_t * -nxt_js_module_loader(njs_vm_t *vm, njs_external_ptr_t external, njs_str_t *name) -{ - nxt_str_t text; - nxt_uint_t i, n; - nxt_js_conf_t *jcf; - nxt_js_module_t *modules, *module; - - jcf = external; - - module = NULL; - - n = jcf->modules->nelts; - modules = jcf->modules->elts; - - for (i = 0; i < n; i++) { - if (nxt_strstr_eq(name, &modules[i].name)) { - module = &modules[i]; - break; - } - } - - if (module == NULL) { - return NULL; - } - - text.length = module->text.length; - - text.start = njs_mp_alloc(vm->mem_pool, text.length); - if (nxt_slow_path(text.start == NULL)) { - return NULL; - } - - nxt_memcpy(text.start, module->text.start, text.length); - - return njs_vm_compile_module(vm, name, &text.start, - &text.start[text.length]); -} - - -static njs_vm_ops_t nxt_js_ops = { - NULL, - NULL, - nxt_js_module_loader, - NULL, -}; - - -njs_int_t nxt_js_proto_id; - - -nxt_js_conf_t * -nxt_js_conf_new(nxt_mp_t *mp, nxt_bool_t test) -{ - nxt_js_conf_t *jcf; - - jcf = nxt_mp_zget(mp, sizeof(nxt_js_conf_t)); - if (nxt_slow_path(jcf == NULL)) { - return NULL; - } - - jcf->pool = mp; - jcf->test = test; - - jcf->modules = nxt_array_create(mp, 4, sizeof(nxt_js_module_t)); - if (nxt_slow_path(jcf->modules == NULL)) { - return NULL; - } - - jcf->funcs = nxt_array_create(mp, 4, sizeof(nxt_str_t)); - if (nxt_slow_path(jcf->funcs == NULL)) { - return NULL; - } - - return jcf; -} - - -void -nxt_js_conf_release(nxt_js_conf_t *jcf) -{ - njs_vm_destroy(jcf->vm); -} - - -void -nxt_js_set_proto(nxt_js_conf_t *jcf, njs_external_t *proto, njs_uint_t n) -{ - jcf->protos = n; - jcf->proto = proto; -} - - -static njs_vm_t * -nxt_js_vm_create(nxt_js_conf_t *jcf) -{ - u_char *p; - size_t size; - nxt_uint_t i; - njs_vm_opt_t opts; - nxt_js_module_t *module, *mod; - - static nxt_str_t import_str = nxt_string("import"); - static nxt_str_t from_str = nxt_string("from"); - static nxt_str_t global_str = nxt_string("globalThis"); - - njs_vm_opt_init(&opts); - - opts.backtrace = 1; - - opts.file.start = (u_char *) "default"; - opts.file.length = 7; - - if (jcf->test || jcf->modules->nelts == 0) { - goto done; - } - - opts.ops = &nxt_js_ops; - opts.external = jcf; - - size = 0; - module = jcf->modules->elts; - - for (i = 0; i < jcf->modules->nelts; i++) { - mod = &module[i]; - - size += import_str.length + 1 + mod->name.length + 1 - + from_str.length + 2 + mod->name.length + 3; - - size += global_str.length + 1 + mod->name.length + 3 - + mod->name.length + 2; - } - - p = nxt_mp_nget(jcf->pool, size); - if (nxt_slow_path(p == NULL)) { - return NULL; - } - - jcf->init.length = size; - jcf->init.start = p; - - for (i = 0; i < jcf->modules->nelts; i++) { - mod = &module[i]; - - p = nxt_cpymem(p, import_str.start, import_str.length); - *p++ = ' '; - - p = nxt_cpymem(p, mod->name.start, mod->name.length); - *p++ = ' '; - - p = nxt_cpymem(p, from_str.start, from_str.length); - *p++ = ' '; - - *p++ = '\"'; - p = nxt_cpymem(p, mod->name.start, mod->name.length); - *p++ = '\"'; - *p++ = ';'; - *p++ = '\n'; - - p = nxt_cpymem(p, global_str.start, global_str.length); - *p++ = '.'; - - p = nxt_cpymem(p, mod->name.start, mod->name.length); - *p++ = ' '; - *p++ = '='; - *p++ = ' '; - - p = nxt_cpymem(p, mod->name.start, mod->name.length); - *p++ = ';'; - *p++ = '\n'; - } - -done: - - return njs_vm_create(&opts); -} - - -nxt_int_t -nxt_js_add_module(nxt_js_conf_t *jcf, nxt_str_t *name, nxt_str_t *text) -{ - nxt_js_module_t *module; - - module = nxt_array_add(jcf->modules); - if (nxt_slow_path(module == NULL)) { - return NXT_ERROR; - } - - module->name = *name; - - module->text.length = text->length; - module->text.start = nxt_mp_nget(jcf->pool, text->length); - if (nxt_slow_path(module->text.start == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy(module->text.start, text->start, text->length); - - return NXT_OK; -} - - -nxt_js_t * -nxt_js_add_tpl(nxt_js_conf_t *jcf, nxt_str_t *str, nxt_bool_t strz) -{ - size_t size; - u_char *p, *start; - nxt_js_t *js; - nxt_str_t *func; - - static nxt_str_t func_str = nxt_string("function(uri, host, remoteAddr, " - "args, headers, cookies, vars) {" - " return "); - - /* - * Appending a terminating null character if strz is true. - */ - static nxt_str_t strz_str = nxt_string(" + '\\x00'"); - - size = func_str.length + str->length + 1; - - if (strz) { - size += strz_str.length; - } - - start = nxt_mp_nget(jcf->pool, size); - if (nxt_slow_path(start == NULL)) { - return NULL; - } - - p = start; - - p = nxt_cpymem(p, func_str.start, func_str.length); - p = nxt_cpymem(p, str->start, str->length); - - if (strz) { - p = nxt_cpymem(p, strz_str.start, strz_str.length); - } - - *p++ = '}'; - - js = nxt_mp_get(jcf->pool, sizeof(nxt_js_t)); - if (nxt_slow_path(js == NULL)) { - return NULL; - } - - func = nxt_array_add(jcf->funcs); - if (nxt_slow_path(func == NULL)) { - return NULL; - } - - func->start = start; - func->length = p - start; - - js->index = jcf->funcs->nelts - 1; - - return js; -} - - -nxt_int_t -nxt_js_compile(nxt_js_conf_t *jcf) -{ - size_t size; - u_char *p, *start; - njs_int_t ret; - nxt_str_t *func; - nxt_uint_t i; - - if (jcf->test) { - return NXT_OK; - } - - jcf->vm = nxt_js_vm_create(jcf); - if (nxt_slow_path(jcf->vm == NULL)) { - return NXT_ERROR; - } - - size = jcf->init.length + 2; - func = jcf->funcs->elts; - - for (i = 0; i < jcf->funcs->nelts; i++) { - size += func[i].length + 1; - } - - start = nxt_mp_nget(jcf->pool, size); - if (nxt_slow_path(start == NULL)) { - return NXT_ERROR; - } - - p = nxt_cpymem(start, jcf->init.start, jcf->init.length); - *p++ = '['; - - func = jcf->funcs->elts; - - for (i = 0; i < jcf->funcs->nelts; i++) { - p = nxt_cpymem(p, func[i].start, func[i].length); - *p++ = ','; - } - - *p++ = ']'; - - nxt_js_proto_id = njs_vm_external_prototype(jcf->vm, jcf->proto, - jcf->protos); - if (nxt_slow_path(nxt_js_proto_id < 0)) { - return NXT_ERROR; - } - - ret = njs_vm_compile(jcf->vm, &start, p); - - return (ret == NJS_OK) ? NXT_OK : NXT_ERROR; -} - - -nxt_int_t -nxt_js_test(nxt_js_conf_t *jcf, nxt_str_t *str, u_char *error) -{ - u_char *start; - njs_vm_t *vm; - njs_int_t ret; - - vm = nxt_js_vm_create(jcf); - if (nxt_slow_path(vm == NULL)) { - return NXT_ERROR; - } - - start = nxt_mp_nget(jcf->pool, str->length); - if (nxt_slow_path(start == NULL)) { - goto fail; - } - - nxt_memcpy(start, str->start, str->length); - - ret = njs_vm_compile(vm, &start, start + str->length); - - if (nxt_slow_path(ret != NJS_OK)) { - (void) nxt_js_error(vm, error); - goto fail; - } - - njs_vm_destroy(vm); - - return NXT_OK; - -fail: - - njs_vm_destroy(vm); - - return NXT_ERROR; -} - - -nxt_int_t -nxt_js_call(nxt_task_t *task, nxt_js_conf_t *jcf, nxt_js_cache_t *cache, - nxt_js_t *js, nxt_str_t *str, void *ctx) -{ - njs_vm_t *vm; - njs_int_t ret; - njs_str_t res; - njs_uint_t i, n; - njs_value_t *value; - njs_function_t *func; - njs_opaque_value_t retval, opaque_value, arguments[7]; - - static const njs_str_t js_args[] = { - njs_str("uri"), - njs_str("host"), - njs_str("remoteAddr"), - njs_str("args"), - njs_str("headers"), - njs_str("cookies"), - njs_str("vars"), - }; - - vm = cache->vm; - - if (vm == NULL) { - vm = njs_vm_clone(jcf->vm, ctx); - if (nxt_slow_path(vm == NULL)) { - return NXT_ERROR; - } - - cache->vm = vm; - - ret = njs_vm_start(vm, &cache->array); - if (ret != NJS_OK) { - return NXT_ERROR; - } - } - - value = njs_vm_array_prop(vm, &cache->array, js->index, &opaque_value); - func = njs_value_function(value); - - ret = njs_vm_external_create(vm, njs_value_arg(&opaque_value), - nxt_js_proto_id, ctx, 0); - if (nxt_slow_path(ret != NJS_OK)) { - return NXT_ERROR; - } - - n = nxt_nitems(js_args); - - for (i = 0; i < n; i++) { - value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), - &js_args[i], &arguments[i]); - if (nxt_slow_path(value == NULL)) { - return NXT_ERROR; - } - } - - ret = njs_vm_invoke(vm, func, njs_value_arg(&arguments), n, - njs_value_arg(&retval)); - - if (ret != NJS_OK) { - ret = njs_vm_exception_string(vm, &res); - if (ret == NJS_OK) { - nxt_alert(task, "js exception: %V", &res); - } - - return NXT_ERROR; - } - - ret = njs_vm_value_string(vm, &res, njs_value_arg(&retval)); - - str->length = res.length; - str->start = res.start; - - return NXT_OK; -} - - -void -nxt_js_release(nxt_js_cache_t *cache) -{ - if (cache->vm != NULL) { - njs_vm_destroy(cache->vm); - } -} - - -nxt_int_t -nxt_js_error(njs_vm_t *vm, u_char *error) -{ - njs_int_t ret; - njs_str_t res; - nxt_str_t err; - - ret = njs_vm_exception_string(vm, &res); - if (nxt_slow_path(ret != NJS_OK)) { - return NXT_ERROR; - } - - err.start = res.start; - err.length = res.length; - - nxt_sprintf(error, error + NXT_MAX_ERROR_STR, "\"%V\"%Z", &err); - - return NXT_OK; -} diff --git a/src/nxt_js.h b/src/nxt_js.h deleted file mode 100644 index 48f036b8..00000000 --- a/src/nxt_js.h +++ /dev/null @@ -1,45 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JS_H_INCLUDED_ -#define _NXT_JS_H_INCLUDED_ - -#if (NXT_HAVE_NJS) - -#include - - -typedef struct nxt_js_s nxt_js_t; -typedef struct nxt_js_conf_s nxt_js_conf_t; - - -typedef struct { - njs_vm_t *vm; - njs_value_t array; -} nxt_js_cache_t; - - -njs_mod_t *nxt_js_module_loader(njs_vm_t *vm, njs_external_ptr_t external, - njs_str_t *name); -nxt_js_conf_t *nxt_js_conf_new(nxt_mp_t *mp, nxt_bool_t test); -void nxt_js_conf_release(nxt_js_conf_t *jcf); -void nxt_js_set_proto(nxt_js_conf_t *jcf, njs_external_t *proto, nxt_uint_t n); -nxt_int_t nxt_js_add_module(nxt_js_conf_t *jcf, nxt_str_t *name, - nxt_str_t *text); -nxt_js_t *nxt_js_add_tpl(nxt_js_conf_t *jcf, nxt_str_t *str, nxt_bool_t strz); -nxt_int_t nxt_js_compile(nxt_js_conf_t *jcf); -nxt_int_t nxt_js_test(nxt_js_conf_t *jcf, nxt_str_t *str, u_char *error); -nxt_int_t nxt_js_call(nxt_task_t *task, nxt_js_conf_t *jcf, - nxt_js_cache_t *cache, nxt_js_t *js, nxt_str_t *str, void *ctx); -void nxt_js_release(nxt_js_cache_t *cache); -nxt_int_t nxt_js_error(njs_vm_t *vm, u_char *error); - - -extern njs_int_t nxt_js_proto_id; - - -#endif /* NXT_HAVE_NJS */ - -#endif /* _NXT_JS_H_INCLUDED_ */ diff --git a/src/nxt_kqueue_engine.c b/src/nxt_kqueue_engine.c deleted file mode 100644 index a7a5a29e..00000000 --- a/src/nxt_kqueue_engine.c +++ /dev/null @@ -1,1028 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * kqueue() has been introduced in FreeBSD 4.1 and then was ported - * to OpenBSD 2.9, MacOSX 10.3 (Panther), and NetBSD 2.0. - * DragonFlyBSD inherited it with FreeBSD 4 code base. - * - * NOTE_REVOKE has been introduced in FreeBSD 4.3 and then was ported - * to OpenBSD 2.9, MacOSX 10.3 (Panther), and NetBSD 2.0. - * DragonFlyBSD inherited it with FreeBSD 4 code base. - * - * EVFILT_TIMER has been introduced in FreeBSD 4.4-STABLE and then was - * ported to NetBSD 2.0, MacOSX 10.4 (Tiger), and OpenBSD 4.2. - * DragonFlyBSD inherited it with FreeBSD 4 code base. - * - * EVFILT_USER and EV_DISPATCH have been introduced in MacOSX 10.6 (Snow - * Leopard) as part of the Grand Central Dispatch framework - * and then were ported to FreeBSD 8.0-STABLE as part of the - * libdispatch support. - */ - - -/* - * EV_DISPATCH is better because it just disables an event on delivery - * whilst EV_ONESHOT deletes the event. This eliminates in-kernel memory - * deallocation and probable subsequent allocation with a lock acquiring. - */ -#ifdef EV_DISPATCH -#define NXT_KEVENT_ONESHOT EV_DISPATCH -#else -#define NXT_KEVENT_ONESHOT EV_ONESHOT -#endif - - -#if (NXT_NETBSD) -/* NetBSD defines the kevent.udata field as intptr_t. */ - -#define nxt_kevent_set_udata(udata) (intptr_t) (udata) -#define nxt_kevent_get_udata(udata) (void *) (udata) - -#else -#define nxt_kevent_set_udata(udata) (void *) (udata) -#define nxt_kevent_get_udata(udata) (udata) -#endif - - -static nxt_int_t nxt_kqueue_create(nxt_event_engine_t *engine, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_kqueue_free(nxt_event_engine_t *engine); -static void nxt_kqueue_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static void nxt_kqueue_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static void nxt_kqueue_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static nxt_bool_t nxt_kqueue_close(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_kqueue_enable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_kqueue_enable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_kqueue_disable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_kqueue_disable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_kqueue_block_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_kqueue_block_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_kqueue_oneshot_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_kqueue_oneshot_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_kqueue_enable_accept(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_kqueue_enable_file(nxt_event_engine_t *engine, - nxt_file_event_t *ev); -static void nxt_kqueue_close_file(nxt_event_engine_t *engine, - nxt_file_event_t *ev); -static void nxt_kqueue_fd_set(nxt_event_engine_t *engine, nxt_fd_event_t *ev, - nxt_int_t filter, nxt_uint_t flags); -static struct kevent *nxt_kqueue_get_kevent(nxt_event_engine_t *engine); -static void nxt_kqueue_error(nxt_event_engine_t *engine); -static void nxt_kqueue_fd_error_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_kqueue_file_error_handler(nxt_task_t *task, void *obj, - void *data); -static nxt_int_t nxt_kqueue_add_signal(nxt_event_engine_t *engine, - const nxt_sig_event_t *sigev); -#if (NXT_HAVE_EVFILT_USER) -static nxt_int_t nxt_kqueue_enable_post(nxt_event_engine_t *engine, - nxt_work_handler_t handler); -static void nxt_kqueue_signal(nxt_event_engine_t *engine, nxt_uint_t signo); -#endif -static void nxt_kqueue_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); - -static void nxt_kqueue_conn_io_connect(nxt_task_t *task, void *obj, - void *data); -static void nxt_kqueue_conn_connected(nxt_task_t *task, void *obj, - void *data); -static void nxt_kqueue_listen_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_kqueue_conn_io_accept(nxt_task_t *task, void *obj, - void *data); -static void nxt_kqueue_conn_io_read(nxt_task_t *task, void *obj, - void *data); -static ssize_t nxt_kqueue_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); - - -static nxt_conn_io_t nxt_kqueue_conn_io = { - .connect = nxt_kqueue_conn_io_connect, - .accept = nxt_kqueue_conn_io_accept, - - .read = nxt_kqueue_conn_io_read, - .recvbuf = nxt_kqueue_conn_io_recvbuf, - .recv = nxt_conn_io_recv, - - .write = nxt_conn_io_write, - .sendbuf = nxt_conn_io_sendbuf, - -#if (NXT_HAVE_FREEBSD_SENDFILE) - .old_sendbuf = nxt_freebsd_event_conn_io_sendfile, -#elif (NXT_HAVE_MACOSX_SENDFILE) - .old_sendbuf = nxt_macosx_event_conn_io_sendfile, -#else - .old_sendbuf = nxt_event_conn_io_sendbuf, -#endif - - .writev = nxt_event_conn_io_writev, - .send = nxt_event_conn_io_send, -}; - - -const nxt_event_interface_t nxt_kqueue_engine = { - "kqueue", - nxt_kqueue_create, - nxt_kqueue_free, - nxt_kqueue_enable, - nxt_kqueue_disable, - nxt_kqueue_delete, - nxt_kqueue_close, - nxt_kqueue_enable_read, - nxt_kqueue_enable_write, - nxt_kqueue_disable_read, - nxt_kqueue_disable_write, - nxt_kqueue_block_read, - nxt_kqueue_block_write, - nxt_kqueue_oneshot_read, - nxt_kqueue_oneshot_write, - nxt_kqueue_enable_accept, - nxt_kqueue_enable_file, - nxt_kqueue_close_file, -#if (NXT_HAVE_EVFILT_USER) - nxt_kqueue_enable_post, - nxt_kqueue_signal, -#else - NULL, - NULL, -#endif - nxt_kqueue_poll, - - &nxt_kqueue_conn_io, - - NXT_FILE_EVENTS, - NXT_SIGNAL_EVENTS, -}; - - -static nxt_int_t -nxt_kqueue_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - const nxt_sig_event_t *sigev; - - engine->u.kqueue.fd = -1; - engine->u.kqueue.mchanges = mchanges; - engine->u.kqueue.mevents = mevents; - engine->u.kqueue.pid = nxt_pid; - - engine->u.kqueue.changes = nxt_malloc(sizeof(struct kevent) * mchanges); - if (engine->u.kqueue.changes == NULL) { - goto fail; - } - - engine->u.kqueue.events = nxt_malloc(sizeof(struct kevent) * mevents); - if (engine->u.kqueue.events == NULL) { - goto fail; - } - - engine->u.kqueue.fd = kqueue(); - if (engine->u.kqueue.fd == -1) { - nxt_alert(&engine->task, "kqueue() failed %E", nxt_errno); - goto fail; - } - - nxt_debug(&engine->task, "kqueue(): %d", engine->u.kqueue.fd); - - if (engine->signals != NULL) { - for (sigev = engine->signals->sigev; sigev->signo != 0; sigev++) { - if (nxt_kqueue_add_signal(engine, sigev) != NXT_OK) { - goto fail; - } - } - } - - return NXT_OK; - -fail: - - nxt_kqueue_free(engine); - - return NXT_ERROR; -} - - -static void -nxt_kqueue_free(nxt_event_engine_t *engine) -{ - nxt_fd_t fd; - - fd = engine->u.kqueue.fd; - - nxt_debug(&engine->task, "kqueue %d free", fd); - - if (fd != -1 && engine->u.kqueue.pid == nxt_pid) { - /* kqueue is not inherited by fork() */ - - if (close(fd) != 0) { - nxt_alert(&engine->task, "kqueue close(%d) failed %E", - fd, nxt_errno); - } - } - - nxt_free(engine->u.kqueue.events); - nxt_free(engine->u.kqueue.changes); - - nxt_memzero(&engine->u.kqueue, sizeof(nxt_kqueue_engine_t)); -} - - -static void -nxt_kqueue_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_kqueue_enable_read(engine, ev); - nxt_kqueue_enable_write(engine, ev); -} - - -/* - * EV_DISABLE is better because it eliminates in-kernel memory - * deallocation and probable subsequent allocation with a lock acquiring. - */ - -static void -nxt_kqueue_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_INACTIVE; - nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DISABLE); - } - - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_INACTIVE; - nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DISABLE); - } -} - - -static void -nxt_kqueue_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_INACTIVE; - nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DELETE); - } - - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_INACTIVE; - nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DELETE); - } -} - - -/* - * kqueue(2): - * - * Calling close() on a file descriptor will remove any kevents that - * reference the descriptor. - * - * So nxt_kqueue_close() returns true only if there are pending events. - */ - -static nxt_bool_t -nxt_kqueue_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - struct kevent *kev, *end; - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - end = &engine->u.kqueue.changes[engine->u.kqueue.nchanges]; - - for (kev = engine->u.kqueue.changes; kev < end; kev++) { - if (kev->ident == (uintptr_t) ev->fd) { - return 1; - } - } - - return 0; -} - - -/* - * The kqueue event engine uses only three states: inactive, blocked, and - * active. An active oneshot event is marked as it is in the default - * state. The event will be converted eventually to the default EV_CLEAR - * mode after it will become inactive after delivery. - */ - -static void -nxt_kqueue_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read == NXT_EVENT_INACTIVE) { - nxt_kqueue_fd_set(engine, ev, EVFILT_READ, - EV_ADD | EV_ENABLE | EV_CLEAR); - } - - ev->read = NXT_EVENT_ACTIVE; -} - - -static void -nxt_kqueue_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->write == NXT_EVENT_INACTIVE) { - nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, - EV_ADD | EV_ENABLE | EV_CLEAR); - } - - ev->write = NXT_EVENT_ACTIVE; -} - - -static void -nxt_kqueue_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - - nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DISABLE); -} - - -static void -nxt_kqueue_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->write = NXT_EVENT_INACTIVE; - - nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DISABLE); -} - - -static void -nxt_kqueue_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_kqueue_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_kqueue_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->write = NXT_EVENT_ACTIVE; - - nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, - EV_ADD | EV_ENABLE | NXT_KEVENT_ONESHOT); -} - - -static void -nxt_kqueue_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->write = NXT_EVENT_ACTIVE; - - nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, - EV_ADD | EV_ENABLE | NXT_KEVENT_ONESHOT); -} - - -static void -nxt_kqueue_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_ACTIVE; - ev->read_handler = nxt_kqueue_listen_handler; - - nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_ADD | EV_ENABLE); -} - - -static void -nxt_kqueue_enable_file(nxt_event_engine_t *engine, nxt_file_event_t *ev) -{ - struct kevent *kev; - - const nxt_int_t flags = EV_ADD | EV_ENABLE | EV_ONESHOT; - const nxt_uint_t fflags = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND - | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE; - - nxt_debug(&engine->task, "kevent(%d) set: id:%d ft:%i fl:%04Xd, ff:%04XuD", - engine->u.kqueue.fd, ev->file->fd, EVFILT_VNODE, flags, fflags); - - kev = nxt_kqueue_get_kevent(engine); - - kev->ident = ev->file->fd; - kev->filter = EVFILT_VNODE; - kev->flags = flags; - kev->fflags = fflags; - kev->data = 0; - kev->udata = nxt_kevent_set_udata(ev); -} - - -static void -nxt_kqueue_close_file(nxt_event_engine_t *engine, nxt_file_event_t *ev) -{ - /* TODO: pending event. */ -} - - -static void -nxt_kqueue_fd_set(nxt_event_engine_t *engine, nxt_fd_event_t *ev, - nxt_int_t filter, nxt_uint_t flags) -{ - struct kevent *kev; - - nxt_debug(ev->task, "kevent(%d) set event: id:%d ft:%i fl:%04Xui", - engine->u.kqueue.fd, ev->fd, filter, flags); - - kev = nxt_kqueue_get_kevent(engine); - - kev->ident = ev->fd; - kev->filter = filter; - kev->flags = flags; - kev->fflags = 0; - kev->data = 0; - kev->udata = nxt_kevent_set_udata(ev); -} - - -static struct kevent * -nxt_kqueue_get_kevent(nxt_event_engine_t *engine) -{ - int ret, nchanges; - - nchanges = engine->u.kqueue.nchanges; - - if (nxt_slow_path(nchanges >= engine->u.kqueue.mchanges)) { - - nxt_debug(&engine->task, "kevent(%d) changes:%d", - engine->u.kqueue.fd, nchanges); - - ret = kevent(engine->u.kqueue.fd, engine->u.kqueue.changes, nchanges, - NULL, 0, NULL); - - if (nxt_slow_path(ret != 0)) { - nxt_alert(&engine->task, "kevent(%d) failed %E", - engine->u.kqueue.fd, nxt_errno); - - nxt_kqueue_error(engine); - } - - engine->u.kqueue.nchanges = 0; - } - - return &engine->u.kqueue.changes[engine->u.kqueue.nchanges++]; -} - - -static void -nxt_kqueue_error(nxt_event_engine_t *engine) -{ - struct kevent *kev, *end; - nxt_fd_event_t *ev; - nxt_file_event_t *fev; - nxt_work_queue_t *wq; - - wq = &engine->fast_work_queue; - end = &engine->u.kqueue.changes[engine->u.kqueue.nchanges]; - - for (kev = engine->u.kqueue.changes; kev < end; kev++) { - - switch (kev->filter) { - - case EVFILT_READ: - case EVFILT_WRITE: - ev = nxt_kevent_get_udata(kev->udata); - nxt_work_queue_add(wq, nxt_kqueue_fd_error_handler, - ev->task, ev, ev->data); - break; - - case EVFILT_VNODE: - fev = nxt_kevent_get_udata(kev->udata); - nxt_work_queue_add(wq, nxt_kqueue_file_error_handler, - fev->task, fev, fev->data); - break; - } - } -} - - -static void -nxt_kqueue_fd_error_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_fd_event_t *ev; - - ev = obj; - - nxt_debug(task, "kqueue fd error handler fd:%d", ev->fd); - - if (ev->kq_eof && ev->kq_errno != 0) { - ev->error = ev->kq_errno; - nxt_log(task, nxt_socket_error_level(ev->kq_errno), - "kevent() reported error on descriptor %d %E", - ev->fd, ev->kq_errno); - } - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - ev->error = ev->kq_errno; - - ev->error_handler(task, ev, data); -} - - -static void -nxt_kqueue_file_error_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_file_event_t *ev; - - ev = obj; - - nxt_debug(task, "kqueue file error handler fd:%d", ev->file->fd); - - ev->handler(task, ev, data); -} - - -static nxt_int_t -nxt_kqueue_add_signal(nxt_event_engine_t *engine, const nxt_sig_event_t *sigev) -{ - int signo; - struct kevent kev; - struct sigaction sa; - - signo = sigev->signo; - - nxt_memzero(&sa, sizeof(struct sigaction)); - sigemptyset(&sa.sa_mask); - - /* - * SIGCHLD must not be set to SIG_IGN, since kqueue cannot catch - * this signal. It should be set to SIG_DFL instead. And although - * SIGCHLD default action is also ignoring, nevertheless SIG_DFL - * allows kqueue to catch the signal. - */ - sa.sa_handler = (signo == SIGCHLD) ? SIG_DFL : SIG_IGN; - - if (sigaction(signo, &sa, NULL) != 0) { - nxt_alert(&engine->task, "sigaction(%d) failed %E", signo, nxt_errno); - - return NXT_ERROR; - } - - nxt_debug(&engine->task, "kevent(%d) signo:%d (%s)", - engine->u.kqueue.fd, signo, sigev->name); - - kev.ident = signo; - kev.filter = EVFILT_SIGNAL; - kev.flags = EV_ADD; - kev.fflags = 0; - kev.data = 0; - kev.udata = nxt_kevent_set_udata(sigev); - - if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) == 0) { - return NXT_OK; - } - - nxt_alert(&engine->task, "kevent(%d) failed %E", kqueue, nxt_errno); - - return NXT_ERROR; -} - - -#if (NXT_HAVE_EVFILT_USER) - -static nxt_int_t -nxt_kqueue_enable_post(nxt_event_engine_t *engine, nxt_work_handler_t handler) -{ - struct kevent kev; - - /* EVFILT_USER must be added to a kqueue before it can be triggered. */ - - kev.ident = 0; - kev.filter = EVFILT_USER; - kev.flags = EV_ADD | EV_CLEAR; - kev.fflags = 0; - kev.data = 0; - kev.udata = NULL; - - engine->u.kqueue.post_handler = handler; - - if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) == 0) { - return NXT_OK; - } - - nxt_alert(&engine->task, "kevent(%d) failed %E", - engine->u.kqueue.fd, nxt_errno); - - return NXT_ERROR; -} - - -static void -nxt_kqueue_signal(nxt_event_engine_t *engine, nxt_uint_t signo) -{ - struct kevent kev; - - /* - * kqueue has a builtin signal processing support, so the function - * is used only to post events and the signo argument is ignored. - */ - - kev.ident = 0; - kev.filter = EVFILT_USER; - kev.flags = 0; - kev.fflags = NOTE_TRIGGER; - kev.data = 0; - kev.udata = NULL; - - if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) != 0) { - nxt_alert(&engine->task, "kevent(%d) failed %E", - engine->u.kqueue.fd, nxt_errno); - } -} - -#endif - - -static void -nxt_kqueue_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) -{ - int nevents; - void *obj, *data; - nxt_int_t i; - nxt_err_t err; - nxt_uint_t level; - nxt_bool_t error, eof; - nxt_task_t *task; - struct kevent *kev; - nxt_fd_event_t *ev; - nxt_sig_event_t *sigev; - struct timespec ts, *tp; - nxt_file_event_t *fev; - nxt_work_queue_t *wq; - nxt_work_handler_t handler; - - if (timeout == NXT_INFINITE_MSEC) { - tp = NULL; - - } else { - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (timeout % 1000) * 1000000; - tp = &ts; - } - - nxt_debug(&engine->task, "kevent(%d) changes:%d timeout:%M", - engine->u.kqueue.fd, engine->u.kqueue.nchanges, timeout); - - nevents = kevent(engine->u.kqueue.fd, - engine->u.kqueue.changes, engine->u.kqueue.nchanges, - engine->u.kqueue.events, engine->u.kqueue.mevents, tp); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(engine->task.thread); - - nxt_debug(&engine->task, "kevent(%d): %d", engine->u.kqueue.fd, nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - - nxt_log(&engine->task, level, "kevent(%d) failed %E", - engine->u.kqueue.fd, err); - - if (err != NXT_EINTR) { - nxt_kqueue_error(engine); - } - - return; - } - - engine->u.kqueue.nchanges = 0; - - for (i = 0; i < nevents; i++) { - - error = 0; - - kev = &engine->u.kqueue.events[i]; - - nxt_debug(&engine->task, - (kev->ident > 0x8000000 && kev->ident != (uintptr_t) -1) ? - "kevent: id:%p ft:%d fl:%04Xd ff:%d d:%d ud:%p": - "kevent: id:%d ft:%d fl:%04Xd ff:%d d:%d ud:%p", - kev->ident, kev->filter, kev->flags, kev->fflags, - kev->data, kev->udata); - - if (nxt_slow_path(kev->flags & EV_ERROR)) { - nxt_alert(&engine->task, - "kevent(%d) error %E on ident:%d filter:%d", - engine->u.kqueue.fd, kev->data, kev->ident, kev->filter); - error = 1; - } - - task = &engine->task; - wq = &engine->fast_work_queue; - handler = nxt_kqueue_fd_error_handler; - obj = nxt_kevent_get_udata(kev->udata); - - switch (kev->filter) { - - case EVFILT_READ: - ev = obj; - ev->read_ready = 1; - ev->kq_available = (int32_t) kev->data; - err = kev->fflags; - eof = (kev->flags & EV_EOF) != 0; - ev->kq_errno = err; - ev->kq_eof |= eof; - - if (ev->read <= NXT_EVENT_BLOCKED) { - nxt_debug(ev->task, "blocked read event fd:%d", ev->fd); - continue; - } - - if ((kev->flags & NXT_KEVENT_ONESHOT) != 0) { - ev->read = NXT_EVENT_INACTIVE; - } - - if (nxt_slow_path(ev->kq_available == 0 && eof && err != 0)) { - error = 1; - } - - if (nxt_fast_path(!error)) { - handler = ev->read_handler; - wq = ev->read_work_queue; - } - - task = ev->task; - data = ev->data; - - break; - - case EVFILT_WRITE: - ev = obj; - ev->write_ready = 1; - err = kev->fflags; - eof = (kev->flags & EV_EOF) != 0; - ev->kq_errno = err; - ev->kq_eof |= eof; - - if (ev->write <= NXT_EVENT_BLOCKED) { - nxt_debug(ev->task, "blocked write event fd:%d", ev->fd); - continue; - } - - if ((kev->flags & NXT_KEVENT_ONESHOT) != 0) { - ev->write = NXT_EVENT_INACTIVE; - } - - if (nxt_slow_path(eof && err != 0)) { - error = 1; - } - - if (nxt_fast_path(!error)) { - handler = ev->write_handler; - wq = ev->write_work_queue; - } - - task = ev->task; - data = ev->data; - - break; - - case EVFILT_VNODE: - fev = obj; - handler = fev->handler; - task = fev->task; - data = fev->data; - break; - - case EVFILT_SIGNAL: - sigev = obj; - obj = (void *) kev->ident; - handler = sigev->handler; - data = (void *) sigev->name; - break; - -#if (NXT_HAVE_EVFILT_USER) - - case EVFILT_USER: - handler = engine->u.kqueue.post_handler; - data = NULL; - break; - -#endif - - default: - -#if (NXT_DEBUG) - nxt_alert(&engine->task, - "unexpected kevent(%d) filter %d on ident %d", - engine->u.kqueue.fd, kev->filter, kev->ident); -#endif - - continue; - } - - nxt_work_queue_add(wq, handler, task, obj, data); - } -} - - -/* - * nxt_kqueue_event_conn_io_connect() eliminates the - * getsockopt() syscall to test pending connect() error. - */ - -static void -nxt_kqueue_conn_io_connect(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_event_engine_t *engine; - nxt_work_handler_t handler; - const nxt_event_conn_state_t *state; - - c = obj; - - state = c->write_state; - - switch (nxt_socket_connect(task, c->socket.fd, c->remote)) { - - case NXT_OK: - c->socket.write_ready = 1; - handler = state->ready_handler; - break; - - case NXT_AGAIN: - c->socket.write_handler = nxt_kqueue_conn_connected; - c->socket.error_handler = nxt_conn_connect_error; - - engine = task->thread->engine; - nxt_conn_timer(engine, c, state, &c->write_timer); - - nxt_kqueue_enable_write(engine, &c->socket); - return; - - case NXT_DECLINED: - handler = state->close_handler; - break; - - default: /* NXT_ERROR */ - handler = state->error_handler; - break; - } - - nxt_work_queue_add(c->write_work_queue, handler, task, c, data); -} - - -static void -nxt_kqueue_conn_connected(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "kqueue conn connected fd:%d", c->socket.fd); - - c->socket.write = NXT_EVENT_BLOCKED; - - if (c->write_state->timer_autoreset) { - nxt_timer_disable(task->thread->engine, &c->write_timer); - } - - nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler, - task, c, data); -} - - -static void -nxt_kqueue_listen_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_listen_event_t *lev; - - lev = obj; - - nxt_debug(task, "kevent fd:%d avail:%D", - lev->socket.fd, lev->socket.kq_available); - - lev->ready = nxt_min(lev->batch, (uint32_t) lev->socket.kq_available); - - nxt_kqueue_conn_io_accept(task, lev, data); -} - - -static void -nxt_kqueue_conn_io_accept(nxt_task_t *task, void *obj, void *data) -{ - socklen_t socklen; - nxt_conn_t *c; - nxt_socket_t s; - struct sockaddr *sa; - nxt_listen_event_t *lev; - - lev = obj; - c = lev->next; - - lev->ready--; - lev->socket.read_ready = (lev->ready != 0); - - lev->socket.kq_available--; - lev->socket.read_ready = (lev->socket.kq_available != 0); - - sa = &c->remote->u.sockaddr; - socklen = c->remote->socklen; - /* - * The returned socklen is ignored here, - * see comment in nxt_conn_io_accept(). - */ - s = accept(lev->socket.fd, sa, &socklen); - - if (s != -1) { - c->socket.fd = s; - - nxt_debug(task, "accept(%d): %d", lev->socket.fd, s); - - nxt_conn_accept(task, lev, c); - return; - } - - nxt_conn_accept_error(task, lev, "accept", nxt_errno); -} - - -/* - * nxt_kqueue_conn_io_read() is just a wrapper to eliminate the - * readv() or recv() syscall if a remote side just closed connection. - */ - -static void -nxt_kqueue_conn_io_read(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "kqueue conn read fd:%d", c->socket.fd); - - if (c->socket.kq_available == 0 && c->socket.kq_eof) { - nxt_debug(task, "kevent fd:%d eof", c->socket.fd); - - c->socket.closed = 1; - nxt_work_queue_add(c->read_work_queue, c->read_state->close_handler, - task, c, data); - return; - } - - nxt_conn_io_read(task, c, data); -} - - -/* - * nxt_kqueue_conn_io_recvbuf() is just wrapper around standard - * nxt_conn_io_recvbuf() to eliminate the readv() or recv() syscalls - * if there is no pending data or a remote side closed connection. - */ - -static ssize_t -nxt_kqueue_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b) -{ - ssize_t n; - - if (c->socket.kq_available == 0 && c->socket.kq_eof) { - c->socket.closed = 1; - return 0; - } - - n = nxt_conn_io_recvbuf(c, b); - - if (n > 0) { - c->socket.kq_available -= n; - - if (c->socket.kq_available < 0) { - c->socket.kq_available = 0; - } - - nxt_debug(c->socket.task, "kevent fd:%d avail:%D eof:%d", - c->socket.fd, c->socket.kq_available, c->socket.kq_eof); - - c->socket.read_ready = (c->socket.kq_available != 0 - || c->socket.kq_eof); - } - - return n; -} diff --git a/src/nxt_lib.c b/src/nxt_lib.c deleted file mode 100644 index aba07dda..00000000 --- a/src/nxt_lib.c +++ /dev/null @@ -1,157 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_uint_t nxt_ncpu = 1; -nxt_uint_t nxt_pagesize; -nxt_task_t nxt_main_task; -nxt_atomic_t nxt_task_ident; - -nxt_thread_declare_data(nxt_thread_t, nxt_thread_context); - - -#if (NXT_DEBUG && NXT_FREEBSD) -/* - * Fill memory with 0xA5 after malloc() and with 0x5A before free(). - * malloc() options variable has to override the libc symbol, otherwise - * it has no effect. - */ -#if __FreeBSD_version < 1000011 -const char *_malloc_options = "J"; -#else -const char *malloc_conf = "junk:true"; -#endif -#endif - - -nxt_int_t -nxt_lib_start(const char *app, char **argv, char ***envp) -{ - int n; - nxt_int_t flags; - nxt_bool_t update; - nxt_thread_t *thread; - - flags = nxt_stderr_start(); - - nxt_log_start(app); - - nxt_pid = getpid(); - nxt_ppid = getppid(); - nxt_euid = geteuid(); - nxt_egid = getegid(); - -#if (NXT_DEBUG) - - nxt_main_log.level = NXT_LOG_DEBUG; - -#if (NXT_HAVE_MALLOPT) - /* Fill memory with 0xAA after malloc() and with 0x55 before free(). */ - mallopt(M_PERTURB, 0x55); -#endif - -#if (NXT_MACOSX) - /* Fill memory with 0xAA after malloc() and with 0x55 before free(). */ - setenv("MallocScribble", "1", 0); -#endif - -#endif /* NXT_DEBUG */ - - /* Thread log is required for nxt_malloc() in nxt_strerror_start(). */ - - nxt_thread_init_data(nxt_thread_context); - thread = nxt_thread(); - thread->log = &nxt_main_log; - - thread->handle = nxt_thread_handle(); - thread->time.signal = -1; - nxt_thread_time_update(thread); - - nxt_main_task.thread = thread; - nxt_main_task.log = thread->log; - nxt_main_task.ident = nxt_task_next_ident(); - - if (nxt_strerror_start() != NXT_OK) { - return NXT_ERROR; - } - - if (flags != -1) { - nxt_debug(&nxt_main_task, "stderr flags: 0x%04Xd", flags); - } - -#ifdef _SC_NPROCESSORS_ONLN - /* Linux, FreeBSD, Solaris, MacOSX. */ - n = sysconf(_SC_NPROCESSORS_ONLN); - -#elif (NXT_HPUX) - n = mpctl(MPC_GETNUMSPUS, NULL, NULL); - -#else - n = 0; - -#endif - - nxt_debug(&nxt_main_task, "ncpu: %d", n); - - if (n > 1) { - nxt_ncpu = n; - } - - nxt_thread_spin_init(nxt_ncpu, 0); - - nxt_random_init(&thread->random); - - nxt_pagesize = getpagesize(); - - nxt_debug(&nxt_main_task, "pagesize: %ui", nxt_pagesize); - - if (argv != NULL) { - update = (argv[0] == app); - - nxt_process_arguments(&nxt_main_task, argv, envp); - - if (update) { - nxt_log_start(nxt_process_argv[0]); - } - } - - return NXT_OK; -} - - -void -nxt_lib_stop(void) -{ - /* TODO: stop engines */ - -#if 0 - - for ( ;; ) { - nxt_thread_pool_t *tp; - - nxt_thread_spin_lock(&rt->lock); - - tp = rt->thread_pools; - rt->thread_pools = (tp != NULL) ? tp->next : NULL; - - nxt_thread_spin_unlock(&rt->lock); - - if (tp == NULL) { - break; - } - - nxt_thread_pool_destroy(tp); - } - -#else - - exit(0); - nxt_unreachable(); - -#endif -} diff --git a/src/nxt_linux_sendfile.c b/src/nxt_linux_sendfile.c deleted file mode 100644 index 0e772ffb..00000000 --- a/src/nxt_linux_sendfile.c +++ /dev/null @@ -1,239 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * sendfile() has been introduced in Linux 2.2. - * It supported 32-bit offsets only. - * - * Linux 2.4.21 has introduced sendfile64(). However, even on 64-bit - * platforms it returns EINVAL if the count argument is more than 2G-1 bytes. - * In Linux 2.6.17 sendfile() has been internally changed to splice() - * and this limitation has gone. - */ - -#ifdef NXT_TEST_BUILD_LINUX_SENDFILE - -#define MSG_NOSIGNAL 0x4000 -#define MSG_MORE 0x8000 - -ssize_t nxt_linux_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, - size_t limit); - -static ssize_t nxt_sys_sendfile(int out_fd, int in_fd, off_t *offset, - size_t count) -{ - return -1; -} - -#else -#define nxt_sys_sendfile sendfile -#endif - - -static ssize_t nxt_linux_send(nxt_event_conn_t *c, void *buf, size_t size, - nxt_uint_t flags); -static ssize_t nxt_linux_sendmsg(nxt_event_conn_t *c, - nxt_sendbuf_coalesce_t *sb, nxt_uint_t niov, nxt_uint_t flags); - - -ssize_t -nxt_linux_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, - size_t limit) -{ - size_t size; - ssize_t n; - nxt_buf_t *fb; - nxt_err_t err; - nxt_off_t offset; - nxt_uint_t niov, flags; - struct iovec iov[NXT_IOBUF_MAX]; - nxt_sendbuf_coalesce_t sb; - - sb.buf = b; - sb.iobuf = iov; - sb.nmax = NXT_IOBUF_MAX; - sb.sync = 0; - sb.size = 0; - sb.limit = limit; - - niov = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); - - if (niov == 0 && sb.sync) { - return 0; - } - - fb = (sb.buf != NULL && nxt_buf_is_file(sb.buf)) ? sb.buf : NULL; - - if (niov != 0) { - - flags = MSG_NOSIGNAL; - - if (fb != NULL) { - /* - * The Linux-specific MSG_MORE flag is cheaper - * than additional setsockopt(TCP_CORK) syscall. - */ - flags |= MSG_MORE; - } - - if (niov == 1) { - /* - * Disposal of surplus kernel msghdr - * and iovec copy-in operations. - */ - return nxt_linux_send(c, iov->iov_base, iov->iov_len, flags); - } - - return nxt_linux_sendmsg(c, &sb, niov, flags); - } - - size = nxt_sendbuf_file_coalesce(&sb); - - nxt_debug(c->socket.task, "sendfile(%d, %FD, @%O, %uz)", - c->socket.fd, fb->file->fd, fb->file_pos, size); - - offset = fb->file_pos; - - n = nxt_sys_sendfile(c->socket.fd, fb->file->fd, &offset, size); - - err = (n == -1) ? nxt_errno : 0; - - nxt_debug(c->socket.task, "sendfile(): %z", n); - - if (n == -1) { - switch (err) { - - case NXT_EAGAIN: - c->socket.write_ready = 0; - break; - - case NXT_EINTR: - break; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "sendfile(%d, %FD, %O, %uz) failed %E \"%FN\"", - c->socket.fd, fb->file->fd, fb->file_pos, size, - err, fb->file->name); - - return NXT_ERROR; - } - - nxt_debug(c->socket.task, "sendfile() %E", err); - - return 0; - } - - if (n < (ssize_t) size) { - c->socket.write_ready = 0; - } - - return n; -} - - -static ssize_t -nxt_linux_send(nxt_event_conn_t *c, void *buf, size_t size, nxt_uint_t flags) -{ - ssize_t n; - nxt_err_t err; - - n = send(c->socket.fd, buf, size, flags); - - err = (n == -1) ? nxt_errno : 0; - - nxt_debug(c->socket.task, "send(%d, %p, %uz, 0x%uXi): %z", - c->socket.fd, buf, size, flags, n); - - if (n == -1) { - switch (err) { - - case NXT_EAGAIN: - c->socket.write_ready = 0; - break; - - case NXT_EINTR: - break; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "send(%d, %p, %uz, 0x%uXi) failed %E", - c->socket.fd, buf, size, flags, err); - - return NXT_ERROR; - } - - nxt_debug(c->socket.task, "send() %E", err); - - return 0; - } - - if (n < (ssize_t) size) { - c->socket.write_ready = 0; - } - - return n; -} - - -static ssize_t -nxt_linux_sendmsg(nxt_event_conn_t *c, nxt_sendbuf_coalesce_t *sb, - nxt_uint_t niov, nxt_uint_t flags) -{ - ssize_t n; - nxt_err_t err; - struct msghdr msg; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = sb->iobuf; - msg.msg_iovlen = niov; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - - n = sendmsg(c->socket.fd, &msg, flags); - - err = (n == -1) ? nxt_errno : 0; - - nxt_debug(c->socket.task, "sendmsg(%d, %ui, 0x%uXi): %z", - c->socket.fd, niov, flags, n); - - if (n == -1) { - switch (err) { - - case NXT_EAGAIN: - c->socket.write_ready = 0; - break; - - case NXT_EINTR: - break; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "sendmsg(%d, %ui, 0x%uXi) failed %E", - c->socket.fd, niov, flags, err); - - return NXT_ERROR; - } - - nxt_debug(c->socket.task, "sendmsg() %E", err); - - return 0; - } - - if (n < (ssize_t) sb->size) { - c->socket.write_ready = 0; - } - - return n; -} diff --git a/src/nxt_list.c b/src/nxt_list.c deleted file mode 100644 index cab925cb..00000000 --- a/src/nxt_list.c +++ /dev/null @@ -1,108 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_list_t * -nxt_list_create(nxt_mp_t *mp, nxt_uint_t n, size_t size) -{ - nxt_list_t *list; - - list = nxt_mp_get(mp, sizeof(nxt_list_t) + n * size); - - if (nxt_fast_path(list != NULL)) { - list->last = &list->part; - list->size = size; - list->nalloc = n; - list->mem_pool = mp; - list->part.next = NULL; - list->part.nelts = 0; - } - - return list; -} - - -void * -nxt_list_add(nxt_list_t *list) -{ - void *elt; - nxt_list_part_t *last; - - last = list->last; - - if (last->nelts == list->nalloc) { - - /* The last list part is filled up, allocating a new list part. */ - - last = nxt_mp_get(list->mem_pool, - sizeof(nxt_list_part_t) + list->nalloc * list->size); - - if (nxt_slow_path(last == NULL)) { - return NULL; - } - - last->next = NULL; - last->nelts = 0; - - list->last->next = last; - list->last = last; - } - - elt = nxt_pointer_to(nxt_list_data(last), last->nelts * list->size); - last->nelts++; - - return elt; -} - - -void * -nxt_list_zero_add(nxt_list_t *list) -{ - void *p; - - p = nxt_list_add(list); - - if (nxt_fast_path(p != NULL)) { - nxt_memzero(p, list->size); - } - - return p; -} - - -void * -nxt_list_next(nxt_list_t *list, nxt_list_next_t *next) -{ - if (next->part != NULL) { - next->elt++; - - if (next->elt < next->part->nelts) { - return nxt_list_next_value(list, next); - } - - next->part = next->part->next; - - if (next->part != NULL) { - next->elt = 0; - return nxt_list_data(next->part); - } - - } else { - next->part = nxt_list_part(list); - /* - * The first list part is allocated together with - * a nxt_list_t itself and it may never be NULL. - */ - if (next->part->nelts != 0) { - return nxt_list_data(next->part); - } - - } - - return NULL; -} diff --git a/src/nxt_list.h b/src/nxt_list.h deleted file mode 100644 index dc948e03..00000000 --- a/src/nxt_list.h +++ /dev/null @@ -1,127 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_LIST_H_INCLUDED_ -#define _NXT_LIST_H_INCLUDED_ - - -typedef struct nxt_list_part_s nxt_list_part_t; - -struct nxt_list_part_s { - nxt_list_part_t *next; - uintptr_t nelts; - char data[]; -}; - - -typedef struct { - nxt_list_part_t *last; -#if (NXT_64BIT) - uint32_t size; - uint32_t nalloc; -#else - uint16_t size; - uint16_t nalloc; -#endif - nxt_mp_t *mem_pool; - nxt_list_part_t part; -} nxt_list_t; - - -typedef struct { - nxt_list_part_t *part; - uintptr_t elt; -} nxt_list_next_t; - - -#define nxt_list_part(list) \ - (&(list)->part) - - -#define nxt_list_data(part) \ - ((void *) part->data) - - -#define nxt_list_first(list) \ - nxt_list_data(nxt_list_part(list)) - - -nxt_inline void * -nxt_list_elt(nxt_list_t *list, nxt_uint_t n) -{ - nxt_list_part_t *part; - - if (nxt_fast_path((list) != NULL)) { - part = nxt_list_part(list); - - while (part != NULL) { - if (n < (nxt_uint_t) part->nelts) { - return nxt_pointer_to(nxt_list_data(part), n * (list)->size); - } - - n -= (nxt_uint_t) part->nelts; - part = part->next; - } - } - - return NULL; -} - - -#define nxt_list_each(elt, list) \ - do { \ - if (nxt_fast_path((list) != NULL)) { \ - void *_end; \ - nxt_list_part_t *_part = nxt_list_part(list); \ - \ - do { \ - elt = nxt_list_data(_part); \ - \ - for (_end = (elt + _part->nelts); elt != _end; elt++) { \ - -#define nxt_list_loop \ - } \ - \ - _part = _part->next; \ - \ - } while (_part != NULL); \ - } \ - } while (0) - - -NXT_EXPORT nxt_list_t *nxt_list_create(nxt_mp_t *mp, nxt_uint_t n, size_t size); -NXT_EXPORT void *nxt_list_add(nxt_list_t *list); -NXT_EXPORT void *nxt_list_zero_add(nxt_list_t *list); - -NXT_EXPORT void *nxt_list_next(nxt_list_t *list, nxt_list_next_t *next); - - -#define nxt_list_next_value(list, next) \ - (nxt_pointer_to(nxt_list_data((next)->part), (next)->elt * (list)->size)) - - -nxt_inline nxt_uint_t -nxt_list_nelts(nxt_list_t *list) -{ - nxt_uint_t n; - nxt_list_part_t *part; - - n = 0; - - if (nxt_fast_path((list) != NULL)) { - part = nxt_list_part(list); - - do { - n += (nxt_uint_t) part->nelts; - part = part->next; - } while (part != NULL); - } - - return n; -} - - -#endif /* _NXT_LIST_H_INCLUDED_ */ diff --git a/src/nxt_listen_socket.c b/src/nxt_listen_socket.c deleted file mode 100644 index 047c1ef9..00000000 --- a/src/nxt_listen_socket.c +++ /dev/null @@ -1,394 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static u_char *nxt_listen_socket_log_handler(void *ctx, u_char *pos, - u_char *last); - - -nxt_int_t -nxt_listen_socket(nxt_task_t *task, nxt_socket_t s, int backlog) -{ - nxt_debug(task, "listen(%d, %d)", s, backlog); - - if (nxt_fast_path(listen(s, backlog) == 0)) { - return NXT_OK; - } - - nxt_alert(task, "listen(%d, %d) failed %E", s, backlog, nxt_socket_errno); - - return NXT_ERROR; -} - - -nxt_int_t -nxt_listen_socket_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_listen_socket_t *ls) -{ - nxt_log_t log, *old; - nxt_uint_t family; - nxt_socket_t s; - nxt_thread_t *thr; - nxt_sockaddr_t *sa; -#if (NXT_HAVE_UNIX_DOMAIN) - int ret; - u_char *p; - nxt_err_t err; - nxt_socket_t ts; - nxt_sockaddr_t *orig_sa; - nxt_file_name_t *name, *tmp; - nxt_file_access_t access; -#endif - - sa = ls->sockaddr; - - thr = nxt_thread(); - old = thr->log; - log = *thr->log; - log.ctx_handler = nxt_listen_socket_log_handler; - log.ctx = sa; - thr->log = &log; - - family = sa->u.sockaddr.sa_family; - - s = nxt_socket_create(task, family, sa->type, 0, ls->flags); - if (s == -1) { - goto fail; - } - - if (nxt_socket_setsockopt(task, s, SOL_SOCKET, SO_REUSEADDR, 1) != NXT_OK) { - goto fail; - } - -#if (NXT_INET6 && defined IPV6_V6ONLY) - - if (family == AF_INET6 && ls->ipv6only) { - int ipv6only; - - ipv6only = (ls->ipv6only == 1); - - /* Ignore possible error. TODO: why? */ - (void) nxt_socket_setsockopt(task, s, IPPROTO_IPV6, IPV6_V6ONLY, - ipv6only); - } - -#endif - -#if 0 - - /* Ignore possible error. TODO: why? */ - (void) nxt_socket_setsockopt(task, s, SOL_SOCKET, SO_SNDBUF, 8192); - -#endif - - if (ls->read_after_accept) { - nxt_socket_defer_accept(task, s, sa); - } - -#if (NXT_HAVE_UNIX_DOMAIN) - - if (family == AF_UNIX - && sa->type == SOCK_STREAM - && sa->u.sockaddr_un.sun_path[0] != '\0') - { - orig_sa = sa; - - sa = nxt_sockaddr_alloc(mp, sa->socklen + 4, sa->length + 4); - if (sa == NULL) { - goto fail; - } - - sa->type = SOCK_STREAM; - sa->u.sockaddr_un.sun_family = AF_UNIX; - - p = nxt_cpystr((u_char *) sa->u.sockaddr_un.sun_path, - (u_char *) orig_sa->u.sockaddr_un.sun_path); - nxt_memcpy(p, ".tmp", 4); - - nxt_sockaddr_text(sa); - - (void) unlink(sa->u.sockaddr_un.sun_path); - - } else { - orig_sa = NULL; - } - -#endif - - if (nxt_socket_bind(task, s, sa) != NXT_OK) { - goto fail; - } - -#if (NXT_HAVE_UNIX_DOMAIN) - - if (family == AF_UNIX) { - const char *user; - const char *group; - nxt_runtime_t *rt = thr->runtime; - - name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; - access = rt->control_mode > 0 ? rt->control_mode : S_IRUSR | S_IWUSR; - - if (nxt_file_set_access(name, access) != NXT_OK) { - goto listen_fail; - } - - user = rt->control_user; - group = rt->control_group; - - if (nxt_file_chown(name, user, group) != NXT_OK) { - goto listen_fail; - } - } - -#endif - - nxt_debug(task, "listen(%d, %d)", s, ls->backlog); - - if (listen(s, ls->backlog) != 0) { - nxt_alert(task, "listen(%d, %d) failed %E", - s, ls->backlog, nxt_socket_errno); - goto listen_fail; - } - -#if (NXT_HAVE_UNIX_DOMAIN) - - if (orig_sa != NULL) { - ts = nxt_socket_create(task, AF_UNIX, SOCK_STREAM, 0, 0); - if (ts == -1) { - goto listen_fail; - } - - ret = connect(ts, &orig_sa->u.sockaddr, orig_sa->socklen); - - err = nxt_socket_errno; - - nxt_socket_close(task, ts); - - if (ret == 0) { - nxt_alert(task, "connect(%d, %*s) socket already in use", - ts, (size_t) orig_sa->length, - nxt_sockaddr_start(orig_sa)); - - goto listen_fail; - } - - if (err != NXT_ENOENT && err != NXT_ECONNREFUSED) { - nxt_alert(task, "connect(%d, %*s) failed %E", - ts, (size_t) orig_sa->length, - nxt_sockaddr_start(orig_sa), err); - - goto listen_fail; - } - - tmp = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; - name = (nxt_file_name_t *) orig_sa->u.sockaddr_un.sun_path; - - if (nxt_file_rename(tmp, name) != NXT_OK) { - goto listen_fail; - } - } - -#endif - - ls->socket = s; - thr->log = old; - - return NXT_OK; - -listen_fail: - -#if (NXT_HAVE_UNIX_DOMAIN) - - if (family == AF_UNIX) { - name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; - - (void) nxt_file_delete(name); - } - -#endif - -fail: - - if (s != -1) { - nxt_socket_close(task, s); - } - - thr->log = old; - - return NXT_ERROR; -} - - -nxt_int_t -nxt_listen_socket_update(nxt_task_t *task, nxt_listen_socket_t *ls, - nxt_listen_socket_t *prev) -{ - nxt_log_t log, *old; - nxt_thread_t *thr; - - ls->socket = prev->socket; - - thr = nxt_thread(); - old = thr->log; - log = *thr->log; - log.ctx_handler = nxt_listen_socket_log_handler; - log.ctx = ls->sockaddr; - thr->log = &log; - - nxt_debug(task, "listen(%d, %d)", ls->socket, ls->backlog); - - if (listen(ls->socket, ls->backlog) != 0) { - nxt_alert(task, "listen(%d, %d) failed %E", - ls->socket, ls->backlog, nxt_socket_errno); - goto fail; - } - - thr->log = old; - - return NXT_OK; - -fail: - - thr->log = old; - - return NXT_ERROR; -} - - -void -nxt_listen_socket_remote_size(nxt_listen_socket_t *ls) -{ - switch (ls->sockaddr->u.sockaddr.sa_family) { - -#if (NXT_INET6) - - case AF_INET6: - ls->socklen = sizeof(struct sockaddr_in6); - ls->address_length = NXT_INET6_ADDR_STR_LEN; - - break; - -#endif - -#if (NXT_HAVE_UNIX_DOMAIN) - - case AF_UNIX: - /* - * A remote socket is usually unbound and thus has unspecified Unix - * domain sockaddr_un which can be shortcut to 3 bytes. To handle - * a bound remote socket correctly ls->socklen should be larger, see - * comment in nxt_socket.h. - */ - ls->socklen = offsetof(struct sockaddr_un, sun_path) + 1; - ls->address_length = nxt_length("unix:"); - - break; - -#endif - - default: - case AF_INET: - ls->socklen = sizeof(struct sockaddr_in); - ls->address_length = NXT_INET_ADDR_STR_LEN; - - break; - } -} - - -size_t -nxt_listen_socket_pool_min_size(nxt_listen_socket_t *ls) -{ - size_t size; - - /* - * The first nxt_sockaddr_t is intended for mandatory remote sockaddr - * and textual representaion with port. The second nxt_sockaddr_t - * is intended for local sockaddr without textual representaion which - * may be required to get specific address of connection received on - * wildcard AF_INET and AF_INET6 addresses. For AF_UNIX addresses - * the local sockaddr is not required. - */ - - switch (ls->sockaddr->u.sockaddr.sa_family) { - -#if (NXT_INET6) - - case AF_INET6: - ls->socklen = sizeof(struct sockaddr_in6); - ls->address_length = NXT_INET6_ADDR_STR_LEN; - - size = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in6) - + NXT_INET6_ADDR_STR_LEN + nxt_length(":65535"); - - if (IN6_IS_ADDR_UNSPECIFIED(&ls->sockaddr->u.sockaddr_in6.sin6_addr)) { - size += offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in6); - } - - break; - -#endif - -#if (NXT_HAVE_UNIX_DOMAIN) - - case AF_UNIX: - /* - * A remote socket is usually unbound and thus has unspecified Unix - * domain sockaddr_un which can be shortcut to 3 bytes. To handle - * a bound remote socket correctly ls->socklen should be at least - * sizeof(struct sockaddr_un), see comment in nxt_socket.h. - */ - ls->socklen = 3; - size = ls->socklen + nxt_length("unix:"); - ls->address_length = nxt_length("unix:"); - - break; - -#endif - - default: - ls->socklen = sizeof(struct sockaddr_in); - ls->address_length = NXT_INET_ADDR_STR_LEN; - - size = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in) - + NXT_INET_ADDR_STR_LEN + nxt_length(":65535"); - - if (ls->sockaddr->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY) { - size += offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in); - } - - break; - } - -#if (NXT_TLS) - - if (ls->tls) { - size += 4 * sizeof(void *) /* SSL/TLS connection */ - + sizeof(nxt_buf_mem_t) - + sizeof(nxt_work_t); /* nxt_mp_cleanup */ - } - -#endif - - return size // + sizeof(nxt_mem_pool_t) - + sizeof(nxt_conn_t) - + sizeof(nxt_log_t); -} - - -static u_char * -nxt_listen_socket_log_handler(void *ctx, u_char *pos, u_char *end) -{ - nxt_sockaddr_t *sa; - - sa = ctx; - - return nxt_sprintf(pos, end, " while creating listening socket on %*s", - (size_t) sa->length, nxt_sockaddr_start(sa)); -} diff --git a/src/nxt_listen_socket.h b/src/nxt_listen_socket.h deleted file mode 100644 index e2435b76..00000000 --- a/src/nxt_listen_socket.h +++ /dev/null @@ -1,65 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_LISTEN_SOCKET_H_INCLUDED_ -#define _NXT_LISTEN_SOCKET_H_INCLUDED_ - - -typedef struct { - /* nxt_socket_t is int. */ - nxt_socket_t socket; - int backlog; - - nxt_work_queue_t *work_queue; - nxt_work_handler_t handler; - - nxt_sockaddr_t *sockaddr; - - uint32_t count; - - uint8_t flags; - uint8_t read_after_accept; /* 1 bit */ - -#if (NXT_TLS) - uint8_t tls; /* 1 bit */ -#endif -#if (NXT_INET6 && defined IPV6_V6ONLY) - uint8_t ipv6only; /* 2 bits */ -#endif - - uint8_t socklen; - uint8_t address_length; -} nxt_listen_socket_t; - - -#if (NXT_FREEBSD || NXT_MACOSX || NXT_OPENBSD) -/* - * A backlog is limited by system-wide sysctl kern.ipc.somaxconn. - * This is supported by FreeBSD 2.2, OpenBSD 2.0, and MacOSX. - */ -#define NXT_LISTEN_BACKLOG -1 - -#else -/* - * Linux, Solaris, and NetBSD treat negative value as 0. - * 511 is a safe default. - */ -#define NXT_LISTEN_BACKLOG 511 -#endif - - -NXT_EXPORT nxt_int_t nxt_listen_socket(nxt_task_t *task, nxt_socket_t s, - int backlog); - -NXT_EXPORT nxt_int_t nxt_listen_socket_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_listen_socket_t *ls); -NXT_EXPORT nxt_int_t nxt_listen_socket_update(nxt_task_t *task, - nxt_listen_socket_t *ls, nxt_listen_socket_t *prev); -NXT_EXPORT void nxt_listen_socket_remote_size(nxt_listen_socket_t *ls); -NXT_EXPORT size_t nxt_listen_socket_pool_min_size(nxt_listen_socket_t *ls); - - -#endif /* _NXT_LISTEN_SOCKET_H_INCLUDED_ */ diff --git a/src/nxt_log.c b/src/nxt_log.c deleted file mode 100644 index 58756816..00000000 --- a/src/nxt_log.c +++ /dev/null @@ -1,119 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_uint_t nxt_debug; -nxt_uint_t nxt_trace; - - -nxt_log_t nxt_main_log = { - NXT_LOG_INFO, - 0, - nxt_log_handler, - NULL, - NULL -}; - - -nxt_str_t nxt_log_levels[6] = { - nxt_string("alert"), - nxt_string("error"), - nxt_string("warn"), - nxt_string("notice"), - nxt_string("info"), - nxt_string("debug") -}; - - -static const u_char *nxt_log_prefix; - - -void -nxt_log_start(const char *prefix) -{ - if (prefix != NULL && *prefix != '\0') { - nxt_log_prefix = (u_char *) prefix; - } -} - - -/* STUB */ -nxt_log_t * -nxt_log_set_ctx(nxt_log_t *log, nxt_log_ctx_handler_t handler, void *ctx) -{ - nxt_log_t *old; - nxt_thread_t *thr; - - thr = nxt_thread(); - old = thr->log; - - log->level = old->level; - log->handler = old->handler; - log->ctx_handler = handler; - log->ctx = ctx; - - thr->log = log; - - return old; -} - - -void nxt_cdecl -nxt_log_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) -{ - u_char *p, *end; -#if 0 - u_char *syslogmsg; -#endif - va_list args; - u_char msg[NXT_MAX_ERROR_STR]; - - p = msg; - end = msg + NXT_MAX_ERROR_STR; - - if (nxt_log_prefix != NULL) { - p = nxt_cpystrn(p, nxt_log_prefix, end - p); - *p++ = ':'; - *p++ = ' '; - } - -#if 0 - syslogmsg = p; -#endif - - p = nxt_sprintf(p, end, (log->ident != 0) ? "[%V] *%D " : "[%V] ", - &nxt_log_levels[level], log->ident); - - va_start(args, fmt); - p = nxt_vsprintf(p, end, fmt, args); - va_end(args); - - if (level != NXT_LOG_DEBUG && log->ctx_handler != NULL) { - p = log->ctx_handler(log->ctx, p, end); - } - - if (p > end - nxt_length("\n")) { - p = end - nxt_length("\n"); - } - - *p++ = '\n'; - - (void) nxt_write_console(nxt_stderr, msg, p - msg); - -#if 0 - if (level == NXT_LOG_ALERT) { - *(p - nxt_length("\n")) = '\0'; - - /* - * Syslog LOG_ALERT level is enough, because - * LOG_EMERG level broadcast a message to all users. - */ - nxt_write_syslog(LOG_ALERT, syslogmsg); - } -#endif -} diff --git a/src/nxt_log.h b/src/nxt_log.h deleted file mode 100644 index aa2fe673..00000000 --- a/src/nxt_log.h +++ /dev/null @@ -1,168 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_LOG_H_INCLUDED_ -#define _NXT_LOG_H_INCLUDED_ - - -#define NXT_LOG_ALERT 0 -#define NXT_LOG_ERR 1 -#define NXT_LOG_WARN 2 -#define NXT_LOG_NOTICE 3 -#define NXT_LOG_INFO 4 -#define NXT_LOG_DEBUG 5 - - -#define NXT_MAX_ERROR_STR 2048 - - -typedef void nxt_cdecl (*nxt_log_handler_t)(nxt_uint_t level, nxt_log_t *log, - const char *fmt, ...); -typedef u_char *(*nxt_log_ctx_handler_t)(void *ctx, u_char *pos, u_char *end); - - -struct nxt_log_s { - uint32_t level; - uint32_t ident; - nxt_log_handler_t handler; - nxt_log_ctx_handler_t ctx_handler; - void *ctx; -}; - - -NXT_EXPORT void nxt_log_start(const char *name); -NXT_EXPORT nxt_log_t *nxt_log_set_ctx(nxt_log_t *log, - nxt_log_ctx_handler_t handler, void *ctx); - -NXT_EXPORT void nxt_cdecl nxt_log_handler(nxt_uint_t level, nxt_log_t *log, - const char *fmt, ...); - - -#define nxt_log_level_enough(log, level) \ - ((log)->level >= (level)) - - -#define nxt_alert(task, ...) \ - do { \ - nxt_log_t *_log = (task)->log; \ - \ - _log->handler(NXT_LOG_ALERT, _log, __VA_ARGS__); \ - } while (0) - - -#define nxt_log(task, _level, ...) \ - do { \ - nxt_log_t *_log = (task)->log; \ - nxt_uint_t _level_ = (_level); \ - \ - if (nxt_slow_path(_log->level >= _level_)) { \ - _log->handler(_level_, _log, __VA_ARGS__); \ - } \ - } while (0) - - -#define nxt_trace(task, ...) \ - do { \ - nxt_log_t *_log = (task)->log; \ - \ - if (nxt_slow_path(_log->level >= NXT_LOG_NOTICE || nxt_trace)) { \ - _log->handler(NXT_LOG_NOTICE, _log, __VA_ARGS__); \ - } \ - } while (0) - - -#define nxt_log_alert(_log, ...) \ - do { \ - nxt_log_t *_log_ = (_log); \ - \ - _log_->handler(NXT_LOG_ALERT, _log_, __VA_ARGS__); \ - } while (0) - - -#define nxt_log_error(_level, _log, ...) \ - do { \ - nxt_log_t *_log_ = (_log); \ - nxt_uint_t _level_ = (_level); \ - \ - if (nxt_slow_path(_log_->level >= _level_)) { \ - _log_->handler(_level_, _log_, __VA_ARGS__); \ - } \ - } while (0) - - -#if (NXT_DEBUG) - -#define nxt_debug(task, ...) \ - do { \ - nxt_log_t *_log = (task)->log; \ - \ - if (nxt_slow_path(_log->level == NXT_LOG_DEBUG || nxt_debug)) { \ - _log->handler(NXT_LOG_DEBUG, _log, __VA_ARGS__); \ - } \ - } while (0) - - -#define nxt_log_debug(_log, ...) \ - do { \ - nxt_log_t *_log_ = (_log); \ - \ - if (nxt_slow_path(_log_->level == NXT_LOG_DEBUG || nxt_debug)) { \ - _log_->handler(NXT_LOG_DEBUG, _log_, __VA_ARGS__); \ - } \ - } while (0) - - -#define nxt_assert(c) \ - do { \ - if (nxt_slow_path(!(c))) { \ - nxt_thread_log_alert("%s:%d assertion failed: %s", \ - __FILE__, __LINE__, #c); \ - nxt_abort(); \ - } \ - } while (0) - -#else - -#define nxt_debug(...) - -#define nxt_log_debug(...) - -#define nxt_assert(c) - -#endif - - -#if (NXT_DEBUG_ALLOC) - -#define nxt_debug_alloc(...) \ - nxt_thread_log_debug(__VA_ARGS__) - -#else - -#define nxt_debug_alloc(...) - -#endif - - -#define nxt_main_log_alert(...) \ - nxt_log_alert(&nxt_main_log, __VA_ARGS__) - - -#define nxt_main_log_error(level, ...) \ - nxt_log_error(level, &nxt_main_log, __VA_ARGS__) - - -#define nxt_main_log_debug(...) \ - nxt_log_debug(&nxt_main_log, __VA_ARGS__) - - -NXT_EXPORT extern nxt_uint_t nxt_debug; -NXT_EXPORT extern nxt_uint_t nxt_trace; -NXT_EXPORT extern nxt_log_t nxt_main_log; -NXT_EXPORT extern nxt_str_t nxt_log_levels[]; - - -#endif /* _NXT_LOG_H_INCLUDED_ */ diff --git a/src/nxt_log_moderation.c b/src/nxt_log_moderation.c deleted file mode 100644 index 95f9cbfe..00000000 --- a/src/nxt_log_moderation.c +++ /dev/null @@ -1,97 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static void nxt_log_moderate_timer_handler(nxt_task_t *task, void *obj, - void *data); - - -nxt_bool_t -nxt_log_moderate_allow(nxt_log_moderation_t *mod) -{ - nxt_uint_t n; - nxt_time_t now; - nxt_bool_t allow, timer; - nxt_thread_t *thr; - - thr = nxt_thread(); - now = nxt_thread_time(thr); - - allow = 0; - timer = 0; - - nxt_thread_spin_lock(&mod->lock); - - n = mod->count++; - - if (now != mod->last) { - - if (n <= mod->limit) { - mod->last = now; - mod->count = 1; - allow = 1; - } - - /* "n > mod->limit" means that timer has already been set. */ - - } else { - - if (n < mod->limit) { - allow = 1; - - } else if (n == mod->limit) { - /* - * There is a race condition on 32-bit many core system - * capable to fail an operation 2^32 times per second. - * This can be fixed by storing mod->count as uint64_t. - */ - timer = 1; - mod->pid = nxt_pid; - } - } - - nxt_thread_spin_unlock(&mod->lock); - - if (timer) { - mod->timer.work_queue = &thr->engine->fast_work_queue; - mod->timer.handler = nxt_log_moderate_timer_handler; - mod->timer.log = &nxt_main_log; - mod->timer.task = &nxt_main_task; - - nxt_timer_add(thr->engine, &mod->timer, 1000); - } - - return allow; -} - - -static void -nxt_log_moderate_timer_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_bool_t msg; - nxt_timer_t *ev; - nxt_atomic_uint_t n; - nxt_log_moderation_t *mod; - - ev = obj; - mod = nxt_timer_data(ev, nxt_log_moderation_t, timer); - - nxt_thread_spin_lock(&mod->lock); - - mod->last = nxt_thread_time(task->thread); - n = mod->count; - mod->count = 0; - msg = (mod->pid == nxt_pid); - - nxt_thread_spin_unlock(&mod->lock); - - if (msg) { - nxt_log_error(mod->level, &nxt_main_log, "%s %uA times", - mod->msg, n - mod->limit); - } -} diff --git a/src/nxt_log_moderation.h b/src/nxt_log_moderation.h deleted file mode 100644 index c6033201..00000000 --- a/src/nxt_log_moderation.h +++ /dev/null @@ -1,49 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_LOG_MODERATION_H_INCLUDED_ -#define _NXT_LOG_MODERATION_H_INCLUDED_ - - -typedef struct { - uint32_t level; - uint32_t limit; - const char *msg; - nxt_thread_spinlock_t lock; - nxt_pid_t pid; - nxt_uint_t count; - nxt_time_t last; - nxt_timer_t timer; -} nxt_log_moderation_t; - - -#define NXT_LOG_MODERATION 0, -1, 0, 0, NXT_TIMER - - -#define nxt_log_alert_moderate(_mod, _log, ...) \ - do { \ - nxt_log_t *_log_ = _log; \ - \ - if (nxt_log_moderate_allow(_mod)) { \ - _log_->handler(NXT_LOG_ALERT, _log_, __VA_ARGS__); \ - } \ - } while (0) - - -#define nxt_log_moderate(_mod, _level, _log, ...) \ - do { \ - nxt_log_t *_log_ = _log; \ - \ - if (_log_->level >= (_level) && nxt_log_moderate_allow(_mod)) { \ - _log_->handler(_level, _log_, __VA_ARGS__); \ - } \ - } while (0) - - -nxt_bool_t nxt_log_moderate_allow(nxt_log_moderation_t *mod); - - -#endif /* _NXT_LOG_MODERATION_H_INCLUDED_ */ diff --git a/src/nxt_lvlhsh.c b/src/nxt_lvlhsh.c deleted file mode 100644 index 7a8b3dda..00000000 --- a/src/nxt_lvlhsh.c +++ /dev/null @@ -1,994 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * The level hash consists of hierarchical levels of arrays of pointers. - * The pointers may point to another level, a bucket, or NULL. - * The levels and buckets must be allocated in manner alike posix_memalign() - * to bookkeep additional information in pointer low bits. - * - * A level is an array of pointers. Its size is a power of 2. Levels - * may be different sizes, but on the same level the sizes are the same. - * Level sizes are specified by number of bits per level in lvlhsh->shift - * array. A hash may have up to 7 levels. There are two predefined - * shift arrays given by the first two shift array values: - * - * 1) [0, 0]: [4, 4, 4, 4, 4, 4, 4] on a 64-bit platform or - * [5, 5, 5, 5, 5, 5, 0] on a 32-bit platform, - * so default size of levels is 128 bytes. - * - * 2) [0, 10]: [10, 4, 4, 4, 4, 4, 0] on a 64-bit platform or - * [10, 5, 5, 5, 5, 0, 0] on a 32-bit platform, - * so default size of levels is 128 bytes on all levels except - * the first level. The first level is 8K or 4K on 64-bit or 32-bit - * platforms respectively. - * - * All buckets in a hash are the same size which is a power of 2. - * A bucket contains several entries stored and tested sequentially. - * The bucket size should be one or two CPU cache line size, a minimum - * allowed size is 32 bytes. A default 128-byte bucket contains 10 64-bit - * entries or 15 32-bit entries. Each entry consists of pointer to value - * data and 32-bit key. If an entry value pointer is NULL, the entry is free. - * On a 64-bit platform entry value pointers are no aligned, therefore they - * are accessed as two 32-bit integers. The rest trailing space in a bucket - * is used as pointer to next bucket and this pointer is always aligned. - * Although the level hash allows to store a lot of values in a bucket chain, - * this is non optimal way. The large data set should be stored using - * several levels. - */ - -#define nxt_lvlhsh_is_bucket(p) \ - ((uintptr_t) (p) & 1) - - -#define nxt_lvlhsh_count_inc(n) \ - n = (void *) ((uintptr_t) (n) + 2) - - -#define nxt_lvlhsh_count_dec(n) \ - n = (void *) ((uintptr_t) (n) - 2) - - -#define nxt_lvlhsh_level_size(proto, nlvl) \ - ((uintptr_t) 1 << proto->shift[nlvl]) - - -#define nxt_lvlhsh_level(lvl, mask) \ - (void **) ((uintptr_t) lvl & (~mask << 2)) - - -#define nxt_lvlhsh_level_entries(lvl, mask) \ - ((uintptr_t) lvl & (mask << 1)) - - -#define nxt_lvlhsh_store_bucket(slot, bkt) \ - slot = (void **) ((uintptr_t) bkt | 2 | 1) - - -#define nxt_lvlhsh_bucket_size(proto) \ - proto->bucket_size - - -#define nxt_lvlhsh_bucket(proto, bkt) \ - (uint32_t *) ((uintptr_t) bkt & ~(uintptr_t) proto->bucket_mask) - - -#define nxt_lvlhsh_bucket_entries(proto, bkt) \ - (((uintptr_t) bkt & (uintptr_t) proto->bucket_mask) >> 1) - - -#define nxt_lvlhsh_bucket_end(proto, bkt) \ - &bkt[proto->bucket_end] - - -#define nxt_lvlhsh_free_entry(e) \ - (!(nxt_lvlhsh_valid_entry(e))) - - -#define nxt_lvlhsh_next_bucket(proto, bkt) \ - ((void **) &bkt[proto->bucket_end]) - -#if (NXT_64BIT) - -#define nxt_lvlhsh_valid_entry(e) \ - (((e)[0] | (e)[1]) != 0) - - -#define nxt_lvlhsh_entry_value(e) \ - (void *) (((uintptr_t) (e)[1] << 32) + (e)[0]) - - -#define nxt_lvlhsh_set_entry_value(e, n) \ - (e)[0] = (uint32_t) (uintptr_t) n; \ - (e)[1] = (uint32_t) ((uintptr_t) n >> 32) - - -#define nxt_lvlhsh_entry_key(e) \ - (e)[2] - - -#define nxt_lvlhsh_set_entry_key(e, n) \ - (e)[2] = n - -#else - -#define nxt_lvlhsh_valid_entry(e) \ - ((e)[0] != 0) - - -#define nxt_lvlhsh_entry_value(e) \ - (void *) (e)[0] - - -#define nxt_lvlhsh_set_entry_value(e, n) \ - (e)[0] = (uint32_t) n - - -#define nxt_lvlhsh_entry_key(e) \ - (e)[1] - - -#define nxt_lvlhsh_set_entry_key(e, n) \ - (e)[1] = n - -#endif - - -#define NXT_LVLHSH_BUCKET_DONE ((void *) -1) - - -typedef struct { - const nxt_lvlhsh_proto_t *proto; - void *pool; - uint32_t retrieve; /* 1 bit */ -} nxt_lvlhsh_peek_t; - - -static nxt_int_t nxt_lvlhsh_level_find(nxt_lvlhsh_query_t *lhq, void **lvl, - uint32_t key, nxt_uint_t nlvl); -static nxt_int_t nxt_lvlhsh_bucket_find(nxt_lvlhsh_query_t *lhq, void **bkt); -static nxt_int_t nxt_lvlhsh_new_bucket(nxt_lvlhsh_query_t *lhq, void **slot); -static nxt_int_t nxt_lvlhsh_level_insert(nxt_lvlhsh_query_t *lhq, - void **slot, uint32_t key, nxt_uint_t nlvl); -static nxt_int_t nxt_lvlhsh_bucket_insert(nxt_lvlhsh_query_t *lhq, - void **slot, uint32_t key, nxt_int_t nlvl); -static nxt_int_t nxt_lvlhsh_convert_bucket_to_level(nxt_lvlhsh_query_t *lhq, - void **slot, nxt_uint_t nlvl, uint32_t *bucket); -static nxt_int_t nxt_lvlhsh_level_convertion_insert(nxt_lvlhsh_query_t *lhq, - void **parent, uint32_t key, nxt_uint_t nlvl); -static nxt_int_t nxt_lvlhsh_bucket_convertion_insert(nxt_lvlhsh_query_t *lhq, - void **slot, uint32_t key, nxt_int_t nlvl); -static nxt_int_t nxt_lvlhsh_free_level(nxt_lvlhsh_query_t *lhq, void **level, - nxt_uint_t size); -static nxt_int_t nxt_lvlhsh_level_delete(nxt_lvlhsh_query_t *lhq, void **slot, - uint32_t key, nxt_uint_t nlvl); -static nxt_int_t nxt_lvlhsh_bucket_delete(nxt_lvlhsh_query_t *lhq, void **bkt); -static void *nxt_lvlhsh_level_each(nxt_lvlhsh_each_t *lhe, void **level, - nxt_uint_t nlvl, nxt_uint_t shift); -static void *nxt_lvlhsh_bucket_each(nxt_lvlhsh_each_t *lhe); -static void *nxt_lvlhsh_level_peek(nxt_lvlhsh_peek_t *peek, void **level, - nxt_uint_t nlvl); -static void *nxt_lvlhsh_bucket_peek(nxt_lvlhsh_peek_t *peek, void **bkt); - - -nxt_int_t -nxt_lvlhsh_find(nxt_lvlhsh_t *lh, nxt_lvlhsh_query_t *lhq) -{ - void *slot; - - slot = lh->slot; - - if (nxt_fast_path(slot != NULL)) { - - if (nxt_lvlhsh_is_bucket(slot)) { - return nxt_lvlhsh_bucket_find(lhq, slot); - } - - return nxt_lvlhsh_level_find(lhq, slot, lhq->key_hash, 0); - } - - return NXT_DECLINED; -} - - -static nxt_int_t -nxt_lvlhsh_level_find(nxt_lvlhsh_query_t *lhq, void **lvl, uint32_t key, - nxt_uint_t nlvl) -{ - void **slot; - uintptr_t mask; - nxt_uint_t shift; - - shift = lhq->proto->shift[nlvl]; - mask = ((uintptr_t) 1 << shift) - 1; - - lvl = nxt_lvlhsh_level(lvl, mask); - slot = lvl[key & mask]; - - if (slot != NULL) { - - if (nxt_lvlhsh_is_bucket(slot)) { - return nxt_lvlhsh_bucket_find(lhq, slot); - } - - return nxt_lvlhsh_level_find(lhq, slot, key >> shift, nlvl + 1); - } - - return NXT_DECLINED; -} - - -static nxt_int_t -nxt_lvlhsh_bucket_find(nxt_lvlhsh_query_t *lhq, void **bkt) -{ - void *value; - uint32_t *bucket, *e; - nxt_uint_t n; - - do { - bucket = nxt_lvlhsh_bucket(lhq->proto, bkt); - n = nxt_lvlhsh_bucket_entries(lhq->proto, bkt); - e = bucket; - - do { - if (nxt_lvlhsh_valid_entry(e)) { - n--; - - if (nxt_lvlhsh_entry_key(e) == lhq->key_hash) { - - value = nxt_lvlhsh_entry_value(e); - - if (lhq->proto->test(lhq, value) == NXT_OK) { - lhq->value = value; - - return NXT_OK; - } - } - } - - e += NXT_LVLHSH_ENTRY_SIZE; - - } while (n != 0); - - bkt = *nxt_lvlhsh_next_bucket(lhq->proto, bucket); - - } while (bkt != NULL); - - return NXT_DECLINED; -} - - -nxt_int_t -nxt_lvlhsh_insert(nxt_lvlhsh_t *lh, nxt_lvlhsh_query_t *lhq) -{ - uint32_t key; - - if (nxt_fast_path(lh->slot != NULL)) { - - key = lhq->key_hash; - - if (nxt_lvlhsh_is_bucket(lh->slot)) { - return nxt_lvlhsh_bucket_insert(lhq, &lh->slot, key, -1); - } - - return nxt_lvlhsh_level_insert(lhq, &lh->slot, key, 0); - } - - return nxt_lvlhsh_new_bucket(lhq, &lh->slot); -} - - -static nxt_int_t -nxt_lvlhsh_new_bucket(nxt_lvlhsh_query_t *lhq, void **slot) -{ - uint32_t *bucket; - - bucket = lhq->proto->alloc(lhq->pool, nxt_lvlhsh_bucket_size(lhq->proto)); - - if (nxt_fast_path(bucket != NULL)) { - - nxt_lvlhsh_set_entry_value(bucket, lhq->value); - nxt_lvlhsh_set_entry_key(bucket, lhq->key_hash); - - *nxt_lvlhsh_next_bucket(lhq->proto, bucket) = NULL; - - nxt_lvlhsh_store_bucket(*slot, bucket); - - return NXT_OK; - } - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_lvlhsh_level_insert(nxt_lvlhsh_query_t *lhq, void **parent, uint32_t key, - nxt_uint_t nlvl) -{ - void **slot, **lvl; - nxt_int_t ret; - uintptr_t mask; - nxt_uint_t shift; - - shift = lhq->proto->shift[nlvl]; - mask = ((uintptr_t) 1 << shift) - 1; - - lvl = nxt_lvlhsh_level(*parent, mask); - slot = &lvl[key & mask]; - - if (*slot != NULL) { - key >>= shift; - - if (nxt_lvlhsh_is_bucket(*slot)) { - return nxt_lvlhsh_bucket_insert(lhq, slot, key, nlvl); - } - - return nxt_lvlhsh_level_insert(lhq, slot, key, nlvl + 1); - } - - ret = nxt_lvlhsh_new_bucket(lhq, slot); - - if (nxt_fast_path(ret == NXT_OK)) { - nxt_lvlhsh_count_inc(*parent); - } - - return ret; -} - - -static nxt_int_t -nxt_lvlhsh_bucket_insert(nxt_lvlhsh_query_t *lhq, void **slot, uint32_t key, - nxt_int_t nlvl) -{ - void **bkt, **vacant_bucket, *value; - uint32_t *bucket, *e, *vacant_entry; - nxt_int_t ret; - uintptr_t n; - const void *new_value; - const nxt_lvlhsh_proto_t *proto; - - bkt = slot; - vacant_entry = NULL; - vacant_bucket = NULL; - proto = lhq->proto; - - /* Search for duplicate entry in bucket chain. */ - - do { - bucket = nxt_lvlhsh_bucket(proto, *bkt); - n = nxt_lvlhsh_bucket_entries(proto, *bkt); - e = bucket; - - do { - if (nxt_lvlhsh_valid_entry(e)) { - - if (nxt_lvlhsh_entry_key(e) == lhq->key_hash) { - - value = nxt_lvlhsh_entry_value(e); - - if (proto->test(lhq, value) == NXT_OK) { - - new_value = lhq->value; - lhq->value = value; - - if (lhq->replace) { - nxt_lvlhsh_set_entry_value(e, new_value); - - return NXT_OK; - } - - return NXT_DECLINED; - } - } - - n--; - - } else { - /* - * Save a hole vacant position in bucket - * and continue to search for duplicate entry. - */ - if (vacant_entry == NULL) { - vacant_entry = e; - vacant_bucket = bkt; - } - } - - e += NXT_LVLHSH_ENTRY_SIZE; - - } while (n != 0); - - if (e < nxt_lvlhsh_bucket_end(proto, bucket)) { - /* - * Save a vacant position on incomplete bucket's end - * and continue to search for duplicate entry. - */ - if (vacant_entry == NULL) { - vacant_entry = e; - vacant_bucket = bkt; - } - } - - bkt = nxt_lvlhsh_next_bucket(proto, bucket); - - } while (*bkt != NULL); - - if (vacant_entry != NULL) { - nxt_lvlhsh_set_entry_value(vacant_entry, lhq->value); - nxt_lvlhsh_set_entry_key(vacant_entry, lhq->key_hash); - nxt_lvlhsh_count_inc(*vacant_bucket); - - return NXT_OK; - } - - /* All buckets are full. */ - - nlvl++; - - if (nxt_fast_path(proto->shift[nlvl] != 0)) { - - ret = nxt_lvlhsh_convert_bucket_to_level(lhq, slot, nlvl, bucket); - - if (nxt_fast_path(ret == NXT_OK)) { - return nxt_lvlhsh_level_insert(lhq, slot, key, nlvl); - } - - return ret; - } - - /* The last allowed level, only buckets may be allocated here. */ - - return nxt_lvlhsh_new_bucket(lhq, bkt); -} - - -static nxt_int_t -nxt_lvlhsh_convert_bucket_to_level(nxt_lvlhsh_query_t *lhq, void **slot, - nxt_uint_t nlvl, uint32_t *bucket) -{ - void *lvl, **level; - uint32_t *e, *end, key; - nxt_int_t ret; - nxt_uint_t i, shift, size; - nxt_lvlhsh_query_t q; - const nxt_lvlhsh_proto_t *proto; - - proto = lhq->proto; - size = nxt_lvlhsh_level_size(proto, nlvl); - - lvl = proto->alloc(lhq->pool, size * (sizeof(void *))); - - if (nxt_slow_path(lvl == NULL)) { - return NXT_ERROR; - } - - nxt_memzero(lvl, size * (sizeof(void *))); - - level = lvl; - shift = 0; - - for (i = 0; i < nlvl; i++) { - /* - * Using SIMD operations in this trivial loop with maximum - * 8 iterations may increase code size by 170 bytes. - */ - nxt_pragma_loop_disable_vectorization; - - shift += proto->shift[i]; - } - - end = nxt_lvlhsh_bucket_end(proto, bucket); - - for (e = bucket; e < end; e += NXT_LVLHSH_ENTRY_SIZE) { - - q.proto = proto; - q.pool = lhq->pool; - q.value = nxt_lvlhsh_entry_value(e); - key = nxt_lvlhsh_entry_key(e); - q.key_hash = key; - - ret = nxt_lvlhsh_level_convertion_insert(&q, &lvl, key >> shift, nlvl); - - if (nxt_slow_path(ret != NXT_OK)) { - return nxt_lvlhsh_free_level(lhq, level, size); - } - } - - *slot = lvl; - - proto->free(lhq->pool, bucket); - - return NXT_OK; -} - - -static nxt_int_t -nxt_lvlhsh_level_convertion_insert(nxt_lvlhsh_query_t *lhq, void **parent, - uint32_t key, nxt_uint_t nlvl) -{ - void **slot, **lvl; - nxt_int_t ret; - uintptr_t mask; - nxt_uint_t shift; - - shift = lhq->proto->shift[nlvl]; - mask = ((uintptr_t) 1 << shift) - 1; - - lvl = nxt_lvlhsh_level(*parent, mask); - slot = &lvl[key & mask]; - - if (*slot == NULL) { - ret = nxt_lvlhsh_new_bucket(lhq, slot); - - if (nxt_fast_path(ret == NXT_OK)) { - nxt_lvlhsh_count_inc(*parent); - } - - return ret; - } - - /* Only backets can be here. */ - - return nxt_lvlhsh_bucket_convertion_insert(lhq, slot, key >> shift, nlvl); -} - - -/* - * The special bucket insertion procedure is required because during - * convertion lhq->key contains garbage values and the test function - * cannot be called. Besides, the procedure can be simpler because - * a new entry is inserted just after occupied entries. - */ - -static nxt_int_t -nxt_lvlhsh_bucket_convertion_insert(nxt_lvlhsh_query_t *lhq, void **slot, - uint32_t key, nxt_int_t nlvl) -{ - void **bkt; - uint32_t *bucket, *e; - nxt_int_t ret; - uintptr_t n; - const nxt_lvlhsh_proto_t *proto; - - bkt = slot; - proto = lhq->proto; - - do { - bucket = nxt_lvlhsh_bucket(proto, *bkt); - n = nxt_lvlhsh_bucket_entries(proto, *bkt); - e = bucket + n * NXT_LVLHSH_ENTRY_SIZE; - - if (nxt_fast_path(e < nxt_lvlhsh_bucket_end(proto, bucket))) { - - nxt_lvlhsh_set_entry_value(e, lhq->value); - nxt_lvlhsh_set_entry_key(e, lhq->key_hash); - nxt_lvlhsh_count_inc(*bkt); - - return NXT_OK; - } - - bkt = nxt_lvlhsh_next_bucket(proto, bucket); - - } while (*bkt != NULL); - - /* All buckets are full. */ - - nlvl++; - - if (nxt_fast_path(proto->shift[nlvl] != 0)) { - - ret = nxt_lvlhsh_convert_bucket_to_level(lhq, slot, nlvl, bucket); - - if (nxt_fast_path(ret == NXT_OK)) { - return nxt_lvlhsh_level_insert(lhq, slot, key, nlvl); - } - - return ret; - } - - /* The last allowed level, only buckets may be allocated here. */ - - return nxt_lvlhsh_new_bucket(lhq, bkt); -} - - -static nxt_int_t -nxt_lvlhsh_free_level(nxt_lvlhsh_query_t *lhq, void **level, nxt_uint_t size) -{ - nxt_uint_t i; - const nxt_lvlhsh_proto_t *proto; - - proto = lhq->proto; - - for (i = 0; i < size; i++) { - - if (level[i] != NULL) { - /* - * Chained buckets are not possible here, since even - * in the worst case one bucket cannot be converted - * in two chained buckets but remains the same bucket. - */ - proto->free(lhq->pool, nxt_lvlhsh_bucket(proto, level[i])); - } - } - - proto->free(lhq->pool, level); - - return NXT_ERROR; -} - - -nxt_int_t -nxt_lvlhsh_delete(nxt_lvlhsh_t *lh, nxt_lvlhsh_query_t *lhq) -{ - if (nxt_fast_path(lh->slot != NULL)) { - - if (nxt_lvlhsh_is_bucket(lh->slot)) { - return nxt_lvlhsh_bucket_delete(lhq, &lh->slot); - } - - return nxt_lvlhsh_level_delete(lhq, &lh->slot, lhq->key_hash, 0); - } - - return NXT_DECLINED; -} - - -static nxt_int_t -nxt_lvlhsh_level_delete(nxt_lvlhsh_query_t *lhq, void **parent, uint32_t key, - nxt_uint_t nlvl) -{ - void **slot, **lvl; - uintptr_t mask; - nxt_int_t ret; - nxt_uint_t shift; - - shift = lhq->proto->shift[nlvl]; - mask = ((uintptr_t) 1 << shift) - 1; - - lvl = nxt_lvlhsh_level(*parent, mask); - slot = &lvl[key & mask]; - - if (*slot != NULL) { - - if (nxt_lvlhsh_is_bucket(*slot)) { - ret = nxt_lvlhsh_bucket_delete(lhq, slot); - - } else { - key >>= shift; - ret = nxt_lvlhsh_level_delete(lhq, slot, key, nlvl + 1); - } - - if (*slot == NULL) { - nxt_lvlhsh_count_dec(*parent); - - if (nxt_lvlhsh_level_entries(*parent, mask) == 0) { - *parent = NULL; - lhq->proto->free(lhq->pool, lvl); - } - } - - return ret; - } - - return NXT_DECLINED; -} - - -static nxt_int_t -nxt_lvlhsh_bucket_delete(nxt_lvlhsh_query_t *lhq, void **bkt) -{ - void *value; - uint32_t *bucket, *e; - uintptr_t n; - const nxt_lvlhsh_proto_t *proto; - - proto = lhq->proto; - - do { - bucket = nxt_lvlhsh_bucket(proto, *bkt); - n = nxt_lvlhsh_bucket_entries(proto, *bkt); - e = bucket; - - do { - if (nxt_lvlhsh_valid_entry(e)) { - - if (nxt_lvlhsh_entry_key(e) == lhq->key_hash) { - - value = nxt_lvlhsh_entry_value(e); - - if (proto->test(lhq, value) == NXT_OK) { - - if (nxt_lvlhsh_bucket_entries(proto, *bkt) == 1) { - *bkt = *nxt_lvlhsh_next_bucket(proto, bucket); - proto->free(lhq->pool, bucket); - - } else { - nxt_lvlhsh_count_dec(*bkt); - nxt_lvlhsh_set_entry_value(e, NULL); - } - - lhq->value = value; - - return NXT_OK; - } - } - - n--; - } - - e += NXT_LVLHSH_ENTRY_SIZE; - - } while (n != 0); - - bkt = nxt_lvlhsh_next_bucket(proto, bucket); - - } while (*bkt != NULL); - - return NXT_DECLINED; -} - - -void * -nxt_lvlhsh_each(nxt_lvlhsh_t *lh, nxt_lvlhsh_each_t *lhe) -{ - void **slot; - - if (lhe->bucket == NXT_LVLHSH_BUCKET_DONE) { - slot = lh->slot; - - if (nxt_lvlhsh_is_bucket(slot)) { - return NULL; - } - - } else { - if (nxt_slow_path(lhe->bucket == NULL)) { - - /* The first iteration only. */ - - slot = lh->slot; - - if (slot == NULL) { - return NULL; - } - - if (!nxt_lvlhsh_is_bucket(slot)) { - lhe->current = 0; - goto level; - } - - lhe->bucket = nxt_lvlhsh_bucket(lhe->proto, slot); - lhe->entries = nxt_lvlhsh_bucket_entries(lhe->proto, slot); - lhe->entry = 0; - } - - return nxt_lvlhsh_bucket_each(lhe); - } - -level: - - return nxt_lvlhsh_level_each(lhe, slot, 0, 0); -} - - -static void * -nxt_lvlhsh_level_each(nxt_lvlhsh_each_t *lhe, void **level, nxt_uint_t nlvl, - nxt_uint_t shift) -{ - void **slot, *value; - uintptr_t mask; - nxt_uint_t n, level_shift; - - level_shift = lhe->proto->shift[nlvl]; - mask = ((uintptr_t) 1 << level_shift) - 1; - - level = nxt_lvlhsh_level(level, mask); - - do { - n = (lhe->current >> shift) & mask; - slot = level[n]; - - if (slot != NULL) { - if (nxt_lvlhsh_is_bucket(slot)) { - - if (lhe->bucket != NXT_LVLHSH_BUCKET_DONE) { - - lhe->bucket = nxt_lvlhsh_bucket(lhe->proto, slot); - lhe->entries = nxt_lvlhsh_bucket_entries(lhe->proto, slot); - lhe->entry = 0; - - return nxt_lvlhsh_bucket_each(lhe); - } - - lhe->bucket = NULL; - - } else { - value = nxt_lvlhsh_level_each(lhe, slot, nlvl + 1, - shift + level_shift); - if (value != NULL) { - return value; - } - } - } - - lhe->current &= ~(mask << shift); - n = ((n + 1) & mask) << shift; - lhe->current |= n; - - } while (n != 0); - - return NULL; -} - - -static nxt_noinline void * -nxt_lvlhsh_bucket_each(nxt_lvlhsh_each_t *lhe) -{ - void *value, **next; - uint32_t *bucket; - - /* At least one valid entry must present here. */ - do { - bucket = &lhe->bucket[lhe->entry]; - lhe->entry += NXT_LVLHSH_ENTRY_SIZE; - - } while (nxt_lvlhsh_free_entry(bucket)); - - value = nxt_lvlhsh_entry_value(bucket); - - lhe->entries--; - - if (lhe->entries == 0) { - next = *nxt_lvlhsh_next_bucket(lhe->proto, lhe->bucket); - - lhe->bucket = (next == NULL) ? NXT_LVLHSH_BUCKET_DONE - : nxt_lvlhsh_bucket(lhe->proto, next); - - lhe->entries = nxt_lvlhsh_bucket_entries(lhe->proto, next); - lhe->entry = 0; - } - - return value; -} - - -void * -nxt_lvlhsh_peek(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto) -{ - void **slot; - nxt_lvlhsh_peek_t peek; - - slot = lh->slot; - - if (slot != NULL) { - - peek.proto = proto; - peek.retrieve = 0; - - if (nxt_lvlhsh_is_bucket(slot)) { - return nxt_lvlhsh_bucket_peek(&peek, &lh->slot); - } - - return nxt_lvlhsh_level_peek(&peek, &lh->slot, 0); - } - - return NULL; -} - - -static void * -nxt_lvlhsh_level_peek(nxt_lvlhsh_peek_t *peek, void **parent, nxt_uint_t nlvl) -{ - void **slot, **level, *value; - uintptr_t mask; - nxt_uint_t n, shift; - - shift = peek->proto->shift[nlvl]; - mask = ((uintptr_t) 1 << shift) - 1; - - level = nxt_lvlhsh_level(*parent, mask); - - n = 0; - - /* At least one valid level slot must present here. */ - - for ( ;; ) { - slot = &level[n]; - - if (*slot != NULL) { - - if (nxt_lvlhsh_is_bucket(*slot)) { - value = nxt_lvlhsh_bucket_peek(peek, slot); - - } else { - value = nxt_lvlhsh_level_peek(peek, slot, nlvl + 1); - } - - /* - * Checking peek->retrieve is not required here because - * there can not be empty slots during peeking. - */ - if (*slot == NULL) { - nxt_lvlhsh_count_dec(*parent); - - if (nxt_lvlhsh_level_entries(*parent, mask) == 0) { - *parent = NULL; - peek->proto->free(peek->pool, level); - } - } - - return value; - } - - n++; - } -} - - -static nxt_noinline void * -nxt_lvlhsh_bucket_peek(nxt_lvlhsh_peek_t *peek, void **bkt) -{ - void *value; - uint32_t *bucket, *entry; - const nxt_lvlhsh_proto_t *proto; - - bucket = nxt_lvlhsh_bucket(peek->proto, *bkt); - - /* At least one valid entry must present here. */ - - for (entry = bucket; - nxt_lvlhsh_free_entry(entry); - entry += NXT_LVLHSH_ENTRY_SIZE) - { - /* void */ - } - - value = nxt_lvlhsh_entry_value(entry); - - if (peek->retrieve) { - proto = peek->proto; - - if (nxt_lvlhsh_bucket_entries(proto, *bkt) == 1) { - *bkt = *nxt_lvlhsh_next_bucket(proto, bucket); - proto->free(peek->pool, bucket); - - } else { - nxt_lvlhsh_count_dec(*bkt); - nxt_lvlhsh_set_entry_value(entry, NULL); - } - } - - return value; -} - - -void * -nxt_lvlhsh_retrieve(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto, - void *pool) -{ - void **slot; - nxt_lvlhsh_peek_t peek; - - slot = lh->slot; - - if (slot != NULL) { - - peek.proto = proto; - peek.pool = pool; - peek.retrieve = 1; - - if (nxt_lvlhsh_is_bucket(slot)) { - return nxt_lvlhsh_bucket_peek(&peek, &lh->slot); - } - - return nxt_lvlhsh_level_peek(&peek, &lh->slot, 0); - } - - return NULL; -} diff --git a/src/nxt_lvlhsh.h b/src/nxt_lvlhsh.h deleted file mode 100644 index c051081c..00000000 --- a/src/nxt_lvlhsh.h +++ /dev/null @@ -1,200 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_LEVEL_HASH_H_INCLUDED_ -#define _NXT_LEVEL_HASH_H_INCLUDED_ - - -typedef struct nxt_lvlhsh_query_s nxt_lvlhsh_query_t; - -typedef nxt_int_t (*nxt_lvlhsh_test_t)(nxt_lvlhsh_query_t *lhq, void *data); -typedef void *(*nxt_lvlhsh_alloc_t)(void *ctx, size_t size); -typedef void (*nxt_lvlhsh_free_t)(void *ctx, void *p); - - -#if (NXT_64BIT) - -#define NXT_LVLHSH_DEFAULT_BUCKET_SIZE 128 -#define NXT_LVLHSH_ENTRY_SIZE 3 -#define NXT_LVLHSH_BATCH_ALLOC 16 - -/* 3 is shift of 64-bit pointer. */ -#define NXT_LVLHSH_MEMALIGN_SHIFT (NXT_MAX_MEMALIGN_SHIFT - 3) - -#else - -#define NXT_LVLHSH_DEFAULT_BUCKET_SIZE 64 -#define NXT_LVLHSH_ENTRY_SIZE 2 -#define NXT_LVLHSH_BATCH_ALLOC 8 - -/* 2 is shift of 32-bit pointer. */ -#define NXT_LVLHSH_MEMALIGN_SHIFT (NXT_MAX_MEMALIGN_SHIFT - 2) - -#endif - - -#if (NXT_LVLHSH_MEMALIGN_SHIFT < 10) -#define NXT_LVLHSH_MAX_MEMALIGN_SHIFT NXT_LVLHSH_MEMALIGN_SHIFT -#else -#define NXT_LVLHSH_MAX_MEMALIGN_SHIFT 10 -#endif - - -#define NXT_LVLHSH_BUCKET_END(bucket_size) \ - (((bucket_size) - sizeof(void *)) \ - / (NXT_LVLHSH_ENTRY_SIZE * sizeof(uint32_t)) \ - * NXT_LVLHSH_ENTRY_SIZE) - - -#define NXT_LVLHSH_BUCKET_SIZE(bucket_size) \ - NXT_LVLHSH_BUCKET_END(bucket_size), bucket_size, (bucket_size - 1) - - -#define NXT_LVLHSH_DEFAULT \ - NXT_LVLHSH_BUCKET_SIZE(NXT_LVLHSH_DEFAULT_BUCKET_SIZE), \ - { 4, 4, 4, 4, 4, 4, 4, 0 } - - -#define NXT_LVLHSH_LARGE_SLAB \ - NXT_LVLHSH_BUCKET_SIZE(NXT_LVLHSH_DEFAULT_BUCKET_SIZE), \ - { 10, 4, 4, 4, 4, 4, 4, 0 } - - -#define NXT_LVLHSH_LARGE_MEMALIGN \ - NXT_LVLHSH_BUCKET_SIZE(NXT_LVLHSH_DEFAULT_BUCKET_SIZE), \ - { NXT_LVLHSH_MAX_MEMALIGN_SHIFT, 4, 4, 4, 4, 0, 0, 0 } - - -typedef struct { - uint32_t bucket_end; - uint32_t bucket_size; - uint32_t bucket_mask; - uint8_t shift[8]; - - nxt_lvlhsh_test_t test; - nxt_lvlhsh_alloc_t alloc; - nxt_lvlhsh_free_t free; -} nxt_lvlhsh_proto_t; - - -typedef struct { - void *slot; -} nxt_lvlhsh_t; - - -struct nxt_lvlhsh_query_s { - uint32_t key_hash; - uint32_t replace; /* 1 bit */ - nxt_str_t key; - void *value; - - const nxt_lvlhsh_proto_t *proto; - void *pool; - - /* Opaque data passed for the test function. */ - void *data; -}; - - -typedef struct { - const nxt_lvlhsh_proto_t *proto; - /* - * Fields to store current bucket entry position. They cannot be - * combined in a single bucket pointer with number of entries in low - * bits, because entry positions are not aligned. A current level is - * stored as key bit path from the root. - */ - uint32_t *bucket; - uint32_t current; - uint32_t entry; - uint32_t entries; -} nxt_lvlhsh_each_t; - - -#define nxt_lvlhsh_is_empty(lh) \ - ((lh)->slot == NULL) - - -#define nxt_lvlhsh_init(lh) \ - (lh)->slot = NULL - -/* - * nxt_lvlhsh_find() finds a hash element. If the element has been - * found then it is stored in the lhq->value and nxt_lvlhsh_find() - * returns NXT_OK. Otherwise NXT_DECLINED is returned. - * - * The required nxt_lvlhsh_query_t fields: key_hash, key, proto. - */ -NXT_EXPORT nxt_int_t nxt_lvlhsh_find(nxt_lvlhsh_t *lh, nxt_lvlhsh_query_t *lhq); - -/* - * nxt_lvlhsh_insert() adds a hash element. If the element already - * presents in lvlhsh and the lhq->replace flag is zero, then lhq->value - * is updated with the old element and NXT_DECLINED is returned. - * If the element already presents in lvlhsh and the lhq->replace flag - * is non-zero, then the old element is replaced with the new element. - * lhq->value is updated with the old element, and NXT_OK is returned. - * If the element is not present in lvlhsh, then it is inserted and - * NXT_OK is returned. The lhq->value is not changed. - * On memory allocation failure NXT_ERROR is returned. - * - * The required nxt_lvlhsh_query_t fields: key_hash, key, proto, replace, value. - * The optional nxt_lvlhsh_query_t fields: pool. - */ -NXT_EXPORT nxt_int_t nxt_lvlhsh_insert(nxt_lvlhsh_t *lh, - nxt_lvlhsh_query_t *lhq); - -/* - * nxt_lvlhsh_delete() deletes a hash element. If the element has been - * found then it is removed from lvlhsh and is stored in the lhq->value, - * and NXT_OK is returned. Otherwise NXT_DECLINED is returned. - * - * The required nxt_lvlhsh_query_t fields: key_hash, key, proto. - * The optional nxt_lvlhsh_query_t fields: pool. - */ -NXT_EXPORT nxt_int_t nxt_lvlhsh_delete(nxt_lvlhsh_t *lh, - nxt_lvlhsh_query_t *lhq); - -/* - * nxt_lvlhsh_each_init() initializes iterator. - * It must be called before the first nxt_lvlhsh_each() call. - */ -#define nxt_lvlhsh_each_init(lhe, _proto) \ - do { \ - (lhe)->proto = _proto; \ - (lhe)->bucket = NULL; \ - } while (0) - -/* - * nxt_lvlhsh_each() iterates over a lvlhsh. - * It returns NULL if there is no more elements. - */ -NXT_EXPORT void *nxt_lvlhsh_each(nxt_lvlhsh_t *lh, nxt_lvlhsh_each_t *lhe); - -/* - * nxt_lvlhsh_peek() is used to iterate over a lvlhsh during the lvlhsh - * destruction. The returned hash element should be deleted from the lvlhsh, - * otherwise it will be returned again by the next nxt_lvlhsh_peek() call. - * The function returns NULL if there is no more elements in the lvlhsh. - */ -NXT_EXPORT void *nxt_lvlhsh_peek(nxt_lvlhsh_t *lh, - const nxt_lvlhsh_proto_t *proto); - -/* - * nxt_lvlhsh_retrieve() is used to iterate over a lvlhsh during the lvlhsh - * destruction. As opposed to nxt_lvlhsh_peek() the returned hash element - * is deleted from the lvlhsh. The function returns NULL if there is no - * more elements in the lvlhsh. - */ -NXT_EXPORT void *nxt_lvlhsh_retrieve(nxt_lvlhsh_t *lh, - const nxt_lvlhsh_proto_t *proto, void *pool); - - -NXT_EXPORT void *nxt_lvlhsh_alloc(void *data, size_t size); -NXT_EXPORT void nxt_lvlhsh_free(void *data, void *p); - - -#endif /* _NXT_LEVEL_HASH_H_INCLUDED_ */ diff --git a/src/nxt_macosx_sendfile.c b/src/nxt_macosx_sendfile.c deleted file mode 100644 index 2c6ea954..00000000 --- a/src/nxt_macosx_sendfile.c +++ /dev/null @@ -1,153 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* sendfile() has been introduced in MacOSX 10.5 (Leopard) */ - -#ifdef NXT_TEST_BUILD_MACOSX_SENDFILE - -ssize_t nxt_macosx_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, - size_t limit); - -static int nxt_sys_sendfile(int fd, int s, off_t offset, off_t *len, - struct sf_hdtr *hdtr, int flags) -{ - return -1; -} - -#else -#define nxt_sys_sendfile sendfile -#endif - - -ssize_t -nxt_macosx_event_conn_io_sendfile(nxt_conn_t *c, nxt_buf_t *b, size_t limit) -{ - size_t hd_size, file_size; - ssize_t n; - nxt_buf_t *fb; - nxt_err_t err; - nxt_off_t sent; - nxt_uint_t nhd, ntr; - struct iovec hd[NXT_IOBUF_MAX], tr[NXT_IOBUF_MAX]; - struct sf_hdtr hdtr, *ht; - nxt_sendbuf_coalesce_t sb; - - sb.buf = b; - sb.iobuf = hd; - sb.nmax = NXT_IOBUF_MAX; - sb.sync = 0; - sb.size = 0; - sb.limit = limit; - - nhd = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); - - if (nhd == 0 && sb.sync) { - return 0; - } - - if (sb.buf == NULL || !nxt_buf_is_file(sb.buf)) { - return nxt_event_conn_io_writev(c, hd, nhd); - } - - hd_size = sb.size; - fb = sb.buf; - - file_size = nxt_sendbuf_file_coalesce(&sb); - - if (file_size == 0) { - return nxt_event_conn_io_writev(c, hd, nhd); - } - - sb.iobuf = tr; - - ntr = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); - - /* - * Disposal of surplus kernel operations if there are no headers - * and trailers. Besides sendfile() returns EINVAL if a sf_hdtr's - * count is 0, but corresponding pointer is not NULL. - */ - - nxt_memzero(&hdtr, sizeof(struct sf_hdtr)); - ht = NULL; - - if (nhd != 0) { - ht = &hdtr; - hdtr.headers = hd; - hdtr.hdr_cnt = nhd; - } - - if (ntr != 0) { - ht = &hdtr; - hdtr.trailers = tr; - hdtr.trl_cnt = ntr; - } - - /* - * MacOSX has the same bug as old FreeBSD (http://bugs.freebsd.org/33771). - * However this bug has never been fixed and instead of this it has been - * documented as a feature in MacOSX 10.7 (Lion) sendfile(2): - * - * When a header or trailer is specified, the value of len argument - * indicates the maximum number of bytes in the header and/or file - * to be sent. It does not control the trailer; if a trailer exists, - * all of it will be sent. - */ - sent = hd_size + file_size; - - nxt_log_debug(c->socket.log, - "sendfile(%FD, %d, @%O, %O) hd:%ui tr:%ui hs:%uz", - fb->file->fd, c->socket.fd, fb->file_pos, sent, - nhd, ntr, hd_size); - - n = nxt_sys_sendfile(fb->file->fd, c->socket.fd, - fb->file_pos, &sent, ht, 0); - - err = (n == -1) ? nxt_errno : 0; - - nxt_debug(c->socket.task, "sendfile(): %d sent:%O", n, sent); - - if (n == -1) { - switch (err) { - - case NXT_EAGAIN: - c->socket.write_ready = 0; - break; - - case NXT_EINTR: - break; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "sendfile(%FD, %d, %O, %O) failed %E \"%FN\" hd:%ui tr:%ui", - fb->file->fd, c->socket.fd, fb->file_pos, sent, err, - fb->file->name, nhd, ntr); - - return NXT_ERROR; - } - - nxt_debug(c->socket.task, "sendfile() %E", err); - - return sent; - } - - if (sent == 0) { - nxt_log(c->socket.task, NXT_LOG_ERR, - "file \"%FN\" was truncated while sendfile()", fb->file->name); - - return NXT_ERROR; - } - - if (sent < (nxt_off_t) sb.size) { - c->socket.write_ready = 0; - } - - return sent; -} diff --git a/src/nxt_main.c b/src/nxt_main.c deleted file mode 100644 index 26bee873..00000000 --- a/src/nxt_main.c +++ /dev/null @@ -1,39 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -extern char **environ; - - -int nxt_cdecl -main(int argc, char **argv) -{ - nxt_int_t ret; - - if (nxt_lib_start("unit", argv, &environ) != NXT_OK) { - return 1; - } - -// nxt_main_log.level = NXT_LOG_INFO; - - nxt_main_log.handler = nxt_log_time_handler; - - ret = nxt_runtime_create(&nxt_main_task); - - if (ret != NXT_OK) { - return 1; - } - - nxt_log(&nxt_main_task, NXT_LOG_INFO, "unit " NXT_VERSION " started"); - - nxt_event_engine_start(nxt_main_task.thread->engine); - - nxt_unreachable(); - return 0; -} diff --git a/src/nxt_main.h b/src/nxt_main.h deleted file mode 100644 index aa96256e..00000000 --- a/src/nxt_main.h +++ /dev/null @@ -1,173 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_LIB_H_INCLUDED_ -#define _NXT_LIB_H_INCLUDED_ - - -#include -#include - -#define NXT_NAME "Unit" -#define NXT_SERVER NXT_NAME "/" NXT_VERSION - -typedef struct nxt_port_s nxt_port_t; -typedef struct nxt_task_s nxt_task_t; -typedef struct nxt_port_recv_msg_s nxt_port_recv_msg_t; -typedef void (*nxt_port_handler_t)(nxt_task_t *task, nxt_port_recv_msg_t *msg); -typedef struct nxt_port_handlers_s nxt_port_handlers_t; -typedef struct nxt_sig_event_s nxt_sig_event_t; -typedef struct nxt_runtime_s nxt_runtime_t; - -typedef struct nxt_thread_s nxt_thread_t; -typedef struct nxt_event_engine_s nxt_event_engine_t; -typedef struct nxt_log_s nxt_log_t; -typedef struct nxt_thread_pool_s nxt_thread_pool_t; - -typedef void (*nxt_work_handler_t)(nxt_task_t *task, void *obj, void *data); - -#include -#include -#include -#include -#include -#include - -typedef uint16_t nxt_port_id_t; - -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -typedef struct nxt_tstr_state_s nxt_tstr_state_t; -#include -#include - - -/* TODO: remove unused */ - -typedef struct nxt_fd_event_s nxt_fd_event_t; -typedef struct nxt_sockaddr_s nxt_sockaddr_t; - - -#include -#include -#include -#include - - -typedef void *(*nxt_mem_proto_alloc_t)(void *pool, size_t size); -typedef void (*nxt_mem_proto_free_t)(void *pool, void *p); - -typedef struct { - nxt_mem_proto_alloc_t alloc; - nxt_mem_proto_free_t free; -} nxt_mem_proto_t; - - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include - -typedef struct nxt_buf_s nxt_buf_t; -#include -#include -#include - -typedef struct nxt_conn_s nxt_conn_t; -#include - -#include - -#if (NXT_TLS) -#include -#endif - - -#define nxt_thread() \ - (nxt_thread_t *) nxt_thread_get_data(nxt_thread_context) - -nxt_thread_extern_data(nxt_thread_t, nxt_thread_context); - - -#include - -#include -#include - -#include -#include -#include -#include - - -typedef void (*nxt_event_conn_handler_t)(nxt_thread_t *thr, nxt_conn_t *c); -#include - -#include -#include - -#include - -#include - -#include -#include -#include - - -/* - * The envp argument must be &environ if application may - * change its process title with nxt_process_title(). - */ -NXT_EXPORT nxt_int_t nxt_lib_start(const char *app, char **argv, char ***envp); -NXT_EXPORT void nxt_lib_stop(void); - - -NXT_EXPORT extern nxt_uint_t nxt_ncpu; -NXT_EXPORT extern nxt_uint_t nxt_pagesize; -NXT_EXPORT extern nxt_task_t nxt_main_task; -NXT_EXPORT extern nxt_atomic_t nxt_task_ident; - - -#endif /* _NXT_LIB_H_INCLUDED_ */ diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c deleted file mode 100644 index 060ead41..00000000 --- a/src/nxt_main_process.c +++ /dev/null @@ -1,1730 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#if (NXT_TLS) -#include -#endif -#if (NXT_HAVE_NJS) -#include -#endif - -#include - - -typedef struct { - nxt_socket_t socket; - nxt_socket_error_t error; - u_char *start; - u_char *end; -} nxt_listening_socket_t; - - -typedef struct { - nxt_uint_t size; - nxt_conf_map_t *map; -} nxt_conf_app_map_t; - - -static nxt_int_t nxt_main_process_port_create(nxt_task_t *task, - nxt_runtime_t *rt); -static void nxt_main_process_title(nxt_task_t *task); -static void nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_main_process_signal_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_main_process_cleanup(nxt_task_t *task, nxt_process_t *process); -static void nxt_main_port_socket_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_main_port_socket_unlink_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static nxt_int_t nxt_main_listening_socket(nxt_sockaddr_t *sa, - nxt_listening_socket_t *ls); -static void nxt_main_port_modules_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static int nxt_cdecl nxt_app_lang_compare(const void *v1, const void *v2); -static void nxt_main_process_whoami_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_main_port_conf_store_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static nxt_int_t nxt_main_file_store(nxt_task_t *task, const char *tmp_name, - const char *name, u_char *buf, size_t size); -static void nxt_main_port_access_log_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); - -const nxt_sig_event_t nxt_main_process_signals[] = { - nxt_event_signal(SIGHUP, nxt_main_process_signal_handler), - nxt_event_signal(SIGINT, nxt_main_process_sigterm_handler), - nxt_event_signal(SIGQUIT, nxt_main_process_sigquit_handler), - nxt_event_signal(SIGTERM, nxt_main_process_sigterm_handler), - nxt_event_signal(SIGCHLD, nxt_main_process_sigchld_handler), - nxt_event_signal(SIGUSR1, nxt_main_process_sigusr1_handler), - nxt_event_signal_end, -}; - - -nxt_uint_t nxt_conf_ver; - -static nxt_bool_t nxt_exiting; - - -nxt_int_t -nxt_main_process_start(nxt_thread_t *thr, nxt_task_t *task, - nxt_runtime_t *rt) -{ - rt->type = NXT_PROCESS_MAIN; - - if (nxt_main_process_port_create(task, rt) != NXT_OK) { - return NXT_ERROR; - } - - nxt_main_process_title(task); - - /* - * The discovery process will send a message processed by - * nxt_main_port_modules_handler() which starts the controller - * and router processes. - */ - return nxt_process_init_start(task, nxt_discovery_process); -} - - -static nxt_conf_map_t nxt_common_app_conf[] = { - { - nxt_string("type"), - NXT_CONF_MAP_STR, - offsetof(nxt_common_app_conf_t, type), - }, - - { - nxt_string("user"), - NXT_CONF_MAP_STR, - offsetof(nxt_common_app_conf_t, user), - }, - - { - nxt_string("group"), - NXT_CONF_MAP_STR, - offsetof(nxt_common_app_conf_t, group), - }, - - { - nxt_string("stdout"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, stdout_log), - }, - - { - nxt_string("stderr"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, stderr_log), - }, - - { - nxt_string("working_directory"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, working_directory), - }, - - { - nxt_string("environment"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, environment), - }, - - { - nxt_string("isolation"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, isolation), - }, - - { - nxt_string("limits"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, limits), - }, - -}; - - -static nxt_conf_map_t nxt_common_app_limits_conf[] = { - { - nxt_string("shm"), - NXT_CONF_MAP_SIZE, - offsetof(nxt_common_app_conf_t, shm_limit), - }, - - { - nxt_string("requests"), - NXT_CONF_MAP_INT32, - offsetof(nxt_common_app_conf_t, request_limit), - }, - -}; - - -static nxt_conf_map_t nxt_external_app_conf[] = { - { - nxt_string("executable"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.external.executable), - }, - - { - nxt_string("arguments"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, u.external.arguments), - }, - -}; - - -static nxt_conf_map_t nxt_python_app_conf[] = { - { - nxt_string("home"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.python.home), - }, - - { - nxt_string("path"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, u.python.path), - }, - - { - nxt_string("protocol"), - NXT_CONF_MAP_STR, - offsetof(nxt_common_app_conf_t, u.python.protocol), - }, - - { - nxt_string("threads"), - NXT_CONF_MAP_INT32, - offsetof(nxt_common_app_conf_t, u.python.threads), - }, - - { - nxt_string("targets"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, u.python.targets), - }, - - { - nxt_string("thread_stack_size"), - NXT_CONF_MAP_INT32, - offsetof(nxt_common_app_conf_t, u.python.thread_stack_size), - }, -}; - - -static nxt_conf_map_t nxt_php_app_conf[] = { - { - nxt_string("targets"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, u.php.targets), - }, - - { - nxt_string("options"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, u.php.options), - }, -}; - - -static nxt_conf_map_t nxt_perl_app_conf[] = { - { - nxt_string("script"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.perl.script), - }, - - { - nxt_string("threads"), - NXT_CONF_MAP_INT32, - offsetof(nxt_common_app_conf_t, u.perl.threads), - }, - - { - nxt_string("thread_stack_size"), - NXT_CONF_MAP_INT32, - offsetof(nxt_common_app_conf_t, u.perl.thread_stack_size), - }, -}; - - -static nxt_conf_map_t nxt_ruby_app_conf[] = { - { - nxt_string("script"), - NXT_CONF_MAP_STR, - offsetof(nxt_common_app_conf_t, u.ruby.script), - }, - { - nxt_string("threads"), - NXT_CONF_MAP_INT32, - offsetof(nxt_common_app_conf_t, u.ruby.threads), - }, - { - nxt_string("hooks"), - NXT_CONF_MAP_STR, - offsetof(nxt_common_app_conf_t, u.ruby.hooks), - } -}; - - -static nxt_conf_map_t nxt_java_app_conf[] = { - { - nxt_string("classpath"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, u.java.classpath), - }, - { - nxt_string("webapp"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.java.webapp), - }, - { - nxt_string("options"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, u.java.options), - }, - { - nxt_string("unit_jars"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.java.unit_jars), - }, - { - nxt_string("threads"), - NXT_CONF_MAP_INT32, - offsetof(nxt_common_app_conf_t, u.java.threads), - }, - { - nxt_string("thread_stack_size"), - NXT_CONF_MAP_INT32, - offsetof(nxt_common_app_conf_t, u.java.thread_stack_size), - }, - -}; - - -static nxt_conf_map_t nxt_wasm_app_conf[] = { - { - nxt_string("module"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.wasm.module), - }, - { - nxt_string("request_handler"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.wasm.request_handler), - }, - { - nxt_string("malloc_handler"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.wasm.malloc_handler), - }, - { - nxt_string("free_handler"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.wasm.free_handler), - }, - { - nxt_string("module_init_handler"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.wasm.module_init_handler), - }, - { - nxt_string("module_end_handler"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.wasm.module_end_handler), - }, - { - nxt_string("request_init_handler"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.wasm.request_init_handler), - }, - { - nxt_string("request_end_handler"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.wasm.request_end_handler), - }, - { - nxt_string("response_end_handler"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.wasm.response_end_handler), - }, - { - nxt_string("access"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, u.wasm.access), - }, -}; - - -static nxt_conf_map_t nxt_wasm_wc_app_conf[] = { - { - nxt_string("component"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_common_app_conf_t, u.wasm_wc.component), - }, - { - nxt_string("access"), - NXT_CONF_MAP_PTR, - offsetof(nxt_common_app_conf_t, u.wasm_wc.access), - }, -}; - - -static nxt_conf_app_map_t nxt_app_maps[] = { - { nxt_nitems(nxt_external_app_conf), nxt_external_app_conf }, - { nxt_nitems(nxt_python_app_conf), nxt_python_app_conf }, - { nxt_nitems(nxt_php_app_conf), nxt_php_app_conf }, - { nxt_nitems(nxt_perl_app_conf), nxt_perl_app_conf }, - { nxt_nitems(nxt_ruby_app_conf), nxt_ruby_app_conf }, - { nxt_nitems(nxt_java_app_conf), nxt_java_app_conf }, - { nxt_nitems(nxt_wasm_app_conf), nxt_wasm_app_conf }, - { nxt_nitems(nxt_wasm_wc_app_conf), nxt_wasm_wc_app_conf }, -}; - - -static void -nxt_main_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_debug(task, "main data: %*s", - nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos); -} - - -static void -nxt_main_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - void *mem; - nxt_port_t *port; - - nxt_port_new_port_handler(task, msg); - - port = msg->u.new_port; - - if (port != NULL - && port->type == NXT_PROCESS_APP - && msg->fd[1] != -1) - { - mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t), - PROT_READ | PROT_WRITE, MAP_SHARED, msg->fd[1], 0); - if (nxt_fast_path(mem != MAP_FAILED)) { - port->queue = mem; - } - - nxt_fd_close(msg->fd[1]); - msg->fd[1] = -1; - } -} - - -static void -nxt_main_start_process_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - u_char *start, *p, ch; - size_t type_len; - nxt_int_t ret; - nxt_buf_t *b; - nxt_port_t *port; - nxt_runtime_t *rt; - nxt_process_t *process; - nxt_app_type_t idx; - nxt_conf_value_t *conf; - nxt_process_init_t *init; - nxt_common_app_conf_t *app_conf; - - rt = task->thread->runtime; - - port = rt->port_by_type[NXT_PROCESS_ROUTER]; - if (nxt_slow_path(port == NULL)) { - nxt_alert(task, "router port not found"); - goto close_fds; - } - - if (nxt_slow_path(port->pid != nxt_recv_msg_cmsg_pid(msg))) { - nxt_alert(task, "process %PI cannot start processes", - nxt_recv_msg_cmsg_pid(msg)); - - goto close_fds; - } - - process = nxt_process_new(rt); - if (nxt_slow_path(process == NULL)) { - goto close_fds; - } - - process->mem_pool = nxt_mp_create(1024, 128, 256, 32); - if (process->mem_pool == NULL) { - nxt_process_use(task, process, -1); - goto close_fds; - } - - process->parent_port = rt->port_by_type[NXT_PROCESS_MAIN]; - - init = nxt_process_init(process); - - *init = nxt_proto_process; - - b = nxt_buf_chk_make_plain(process->mem_pool, msg->buf, msg->size); - if (b == NULL) { - goto failed; - } - - nxt_debug(task, "main start prototype: %*s", b->mem.free - b->mem.pos, - b->mem.pos); - - app_conf = nxt_mp_zalloc(process->mem_pool, sizeof(nxt_common_app_conf_t)); - if (nxt_slow_path(app_conf == NULL)) { - goto failed; - } - - app_conf->shared_port_fd = msg->fd[0]; - app_conf->shared_queue_fd = msg->fd[1]; - - start = b->mem.pos; - - app_conf->name.start = start; - app_conf->name.length = nxt_strlen(start); - - init->name = (const char *) start; - - process->name = nxt_mp_alloc(process->mem_pool, app_conf->name.length - + sizeof("\"\" prototype") + 1); - - if (nxt_slow_path(process->name == NULL)) { - goto failed; - } - - p = (u_char *) process->name; - *p++ = '"'; - p = nxt_cpymem(p, init->name, app_conf->name.length); - p = nxt_cpymem(p, "\" prototype", 11); - *p = '\0'; - - app_conf->shm_limit = 100 * 1024 * 1024; - app_conf->request_limit = 0; - - start += app_conf->name.length + 1; - - conf = nxt_conf_json_parse(process->mem_pool, start, b->mem.free, NULL); - if (conf == NULL) { - nxt_alert(task, "router app configuration parsing error"); - - goto failed; - } - - rt = task->thread->runtime; - - app_conf->user.start = (u_char*)rt->user_cred.user; - app_conf->user.length = nxt_strlen(rt->user_cred.user); - - ret = nxt_conf_map_object(process->mem_pool, conf, nxt_common_app_conf, - nxt_nitems(nxt_common_app_conf), app_conf); - - if (ret != NXT_OK) { - nxt_alert(task, "failed to map common app conf received from router"); - goto failed; - } - - for (type_len = 0; type_len != app_conf->type.length; type_len++) { - ch = app_conf->type.start[type_len]; - - if (ch == ' ' || nxt_isdigit(ch)) { - break; - } - } - - idx = nxt_app_parse_type(app_conf->type.start, type_len); - - if (nxt_slow_path(idx >= nxt_nitems(nxt_app_maps))) { - nxt_alert(task, "invalid app type %d received from router", (int) idx); - goto failed; - } - - ret = nxt_conf_map_object(process->mem_pool, conf, nxt_app_maps[idx].map, - nxt_app_maps[idx].size, app_conf); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "failed to map app conf received from router"); - goto failed; - } - - if (app_conf->limits != NULL) { - ret = nxt_conf_map_object(process->mem_pool, app_conf->limits, - nxt_common_app_limits_conf, - nxt_nitems(nxt_common_app_limits_conf), - app_conf); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "failed to map app limits received from router"); - goto failed; - } - } - - app_conf->self = conf; - - process->stream = msg->port_msg.stream; - process->data.app = app_conf; - - ret = nxt_process_start(task, process); - if (nxt_fast_path(ret == NXT_OK || ret == NXT_AGAIN)) { - - /* Close shared port fds only in main process. */ - if (ret == NXT_OK) { - nxt_fd_close(app_conf->shared_port_fd); - nxt_fd_close(app_conf->shared_queue_fd); - } - - /* Avoid fds close in caller. */ - msg->fd[0] = -1; - msg->fd[1] = -1; - - return; - } - -failed: - - nxt_process_use(task, process, -1); - - port = nxt_runtime_port_find(rt, msg->port_msg.pid, - msg->port_msg.reply_port); - - if (nxt_fast_path(port != NULL)) { - nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, - -1, msg->port_msg.stream, 0, NULL); - } - -close_fds: - - nxt_fd_close(msg->fd[0]); - msg->fd[0] = -1; - - nxt_fd_close(msg->fd[1]); - msg->fd[1] = -1; -} - - -static void -nxt_main_process_created_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_port_t *port; - nxt_process_t *process; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - port = nxt_runtime_port_find(rt, msg->port_msg.pid, - msg->port_msg.reply_port); - if (nxt_slow_path(port == NULL)) { - return; - } - - process = port->process; - - nxt_assert(process != NULL); - nxt_assert(process->state == NXT_PROCESS_STATE_CREATING); - -#if (NXT_HAVE_LINUX_NS && NXT_HAVE_CLONE_NEWUSER) - if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) { - if (nxt_slow_path(nxt_clone_credential_map(task, process->pid, - process->user_cred, - &process->isolation.clone) - != NXT_OK)) - { - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, - -1, msg->port_msg.stream, 0, NULL); - return; - } - } - -#endif - - process->state = NXT_PROCESS_STATE_CREATED; - - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST, - -1, msg->port_msg.stream, 0, NULL); -} - - -static nxt_port_handlers_t nxt_main_process_port_handlers = { - .data = nxt_main_data_handler, - .new_port = nxt_main_new_port_handler, - .process_created = nxt_main_process_created_handler, - .process_ready = nxt_port_process_ready_handler, - .whoami = nxt_main_process_whoami_handler, - .remove_pid = nxt_port_remove_pid_handler, - .start_process = nxt_main_start_process_handler, - .socket = nxt_main_port_socket_handler, - .socket_unlink = nxt_main_port_socket_unlink_handler, - .modules = nxt_main_port_modules_handler, - .conf_store = nxt_main_port_conf_store_handler, -#if (NXT_TLS) - .cert_get = nxt_cert_store_get_handler, - .cert_delete = nxt_cert_store_delete_handler, -#endif -#if (NXT_HAVE_NJS) - .script_get = nxt_script_store_get_handler, - .script_delete = nxt_script_store_delete_handler, -#endif - .access_log = nxt_main_port_access_log_handler, - .rpc_ready = nxt_port_rpc_handler, - .rpc_error = nxt_port_rpc_handler, -}; - - -static void -nxt_main_process_whoami_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_buf_t *buf; - nxt_pid_t pid, ppid; - nxt_port_t *port; - nxt_runtime_t *rt; - nxt_process_t *pprocess; - - nxt_assert(msg->port_msg.reply_port == 0); - - if (nxt_slow_path(msg->buf == NULL - || nxt_buf_used_size(msg->buf) != sizeof(nxt_pid_t))) - { - nxt_alert(task, "whoami: buffer is NULL or unexpected size"); - goto fail; - } - - nxt_memcpy(&ppid, msg->buf->mem.pos, sizeof(nxt_pid_t)); - - rt = task->thread->runtime; - - pprocess = nxt_runtime_process_find(rt, ppid); - if (nxt_slow_path(pprocess == NULL)) { - nxt_alert(task, "whoami: parent process %PI not found", ppid); - goto fail; - } - - pid = nxt_recv_msg_cmsg_pid(msg); - - nxt_debug(task, "whoami: from %PI, parent %PI, fd %d", pid, ppid, - msg->fd[0]); - - if (msg->fd[0] != -1) { - port = nxt_runtime_process_port_create(task, rt, pid, 0, - NXT_PROCESS_APP); - if (nxt_slow_path(port == NULL)) { - goto fail; - } - - nxt_fd_nonblocking(task, msg->fd[0]); - - port->pair[0] = -1; - port->pair[1] = msg->fd[0]; - msg->fd[0] = -1; - - port->max_size = 16 * 1024; - port->max_share = 64 * 1024; - port->socket.task = task; - - nxt_port_write_enable(task, port); - - } else { - port = nxt_runtime_port_find(rt, pid, 0); - if (nxt_slow_path(port == NULL)) { - goto fail; - } - } - - if (ppid != nxt_pid) { - nxt_queue_insert_tail(&pprocess->children, &port->process->link); - } - - buf = nxt_buf_mem_alloc(task->thread->engine->mem_pool, - sizeof(nxt_pid_t), 0); - if (nxt_slow_path(buf == NULL)) { - goto fail; - } - - buf->mem.free = nxt_cpymem(buf->mem.free, &pid, sizeof(nxt_pid_t)); - - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST, -1, - msg->port_msg.stream, 0, buf); - -fail: - - if (msg->fd[0] != -1) { - nxt_fd_close(msg->fd[0]); - } -} - - -static nxt_int_t -nxt_main_process_port_create(nxt_task_t *task, nxt_runtime_t *rt) -{ - nxt_int_t ret; - nxt_port_t *port; - nxt_process_t *process; - - port = nxt_runtime_process_port_create(task, rt, nxt_pid, 0, - NXT_PROCESS_MAIN); - if (nxt_slow_path(port == NULL)) { - return NXT_ERROR; - } - - process = port->process; - - ret = nxt_port_socket_init(task, port, 0); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_use(task, port, -1); - return ret; - } - - /* - * A main process port. A write port is not closed - * since it should be inherited by processes. - */ - nxt_port_enable(task, port, &nxt_main_process_port_handlers); - - process->state = NXT_PROCESS_STATE_READY; - - return NXT_OK; -} - - -static void -nxt_main_process_title(nxt_task_t *task) -{ - u_char *p, *end; - nxt_uint_t i; - u_char title[2048]; - - end = title + sizeof(title) - 1; - - p = nxt_sprintf(title, end, "unit: main v" NXT_VERSION " [%s", - nxt_process_argv[0]); - - for (i = 1; nxt_process_argv[i] != NULL; i++) { - p = nxt_sprintf(p, end, " %s", nxt_process_argv[i]); - } - - if (p < end) { - *p++ = ']'; - } - - *p = '\0'; - - nxt_process_title(task, "%s", title); -} - - -static void -nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_debug(task, "sigterm handler signo:%d (%s)", - (int) (uintptr_t) obj, data); - - /* TODO: fast exit. */ - - nxt_exiting = 1; - - nxt_runtime_quit(task, 0); -} - - -static void -nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_debug(task, "sigquit handler signo:%d (%s)", - (int) (uintptr_t) obj, data); - - /* TODO: graceful exit. */ - - nxt_exiting = 1; - - nxt_runtime_quit(task, 0); -} - - -static void -nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_mp_t *mp; - nxt_int_t ret; - nxt_uint_t n; - nxt_port_t *port; - nxt_file_t *file, *new_file; - nxt_array_t *new_files; - nxt_runtime_t *rt; - - nxt_log(task, NXT_LOG_NOTICE, "signal %d (%s) received, %s", - (int) (uintptr_t) obj, data, "log files rotation"); - - rt = task->thread->runtime; - - port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - if (nxt_fast_path(port != NULL)) { - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_ACCESS_LOG, - -1, 0, 0, NULL); - } - - mp = nxt_mp_create(1024, 128, 256, 32); - if (mp == NULL) { - return; - } - - n = nxt_list_nelts(rt->log_files); - - new_files = nxt_array_create(mp, n, sizeof(nxt_file_t)); - if (new_files == NULL) { - nxt_mp_destroy(mp); - return; - } - - nxt_list_each(file, rt->log_files) { - - /* This allocation cannot fail. */ - new_file = nxt_array_add(new_files); - - new_file->name = file->name; - new_file->fd = NXT_FILE_INVALID; - new_file->log_level = NXT_LOG_ALERT; - - ret = nxt_file_open(task, new_file, O_WRONLY | O_APPEND, O_CREAT, - NXT_FILE_OWNER_ACCESS); - - if (ret != NXT_OK) { - goto fail; - } - - } nxt_list_loop; - - new_file = new_files->elts; - - ret = nxt_file_stderr(&new_file[0]); - - if (ret == NXT_OK) { - n = 0; - - nxt_list_each(file, rt->log_files) { - - nxt_port_change_log_file(task, rt, n, new_file[n].fd); - /* - * The old log file descriptor must be closed at the moment - * when no other threads use it. dup2() allows to use the - * old file descriptor for new log file. This change is - * performed atomically in the kernel. - */ - (void) nxt_file_redirect(file, new_file[n].fd); - - n++; - - } nxt_list_loop; - - nxt_mp_destroy(mp); - return; - } - -fail: - - new_file = new_files->elts; - n = new_files->nelts; - - while (n != 0) { - if (new_file->fd != NXT_FILE_INVALID) { - nxt_file_close(task, new_file); - } - - new_file++; - n--; - } - - nxt_mp_destroy(mp); -} - - -static void -nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, void *data) -{ - int status; - nxt_int_t ret; - nxt_err_t err; - nxt_pid_t pid; - nxt_port_t *port; - nxt_queue_t children; - nxt_runtime_t *rt; - nxt_process_t *process, *child; - nxt_process_init_t init; - - nxt_debug(task, "sigchld handler signo:%d (%s)", - (int) (uintptr_t) obj, data); - - rt = task->thread->runtime; - - for ( ;; ) { - pid = waitpid(-1, &status, WNOHANG); - - if (pid == -1) { - - switch (err = nxt_errno) { - - case NXT_ECHILD: - return; - - case NXT_EINTR: - continue; - - default: - nxt_alert(task, "waitpid() failed: %E", err); - return; - } - } - - nxt_debug(task, "waitpid(): %PI", pid); - - if (pid == 0) { - return; - } - - if (WTERMSIG(status)) { -#ifdef WCOREDUMP - nxt_alert(task, "process %PI exited on signal %d%s", - pid, WTERMSIG(status), - WCOREDUMP(status) ? " (core dumped)" : ""); -#else - nxt_alert(task, "process %PI exited on signal %d", - pid, WTERMSIG(status)); -#endif - - } else { - nxt_trace(task, "process %PI exited with code %d", - pid, WEXITSTATUS(status)); - } - - process = nxt_runtime_process_find(rt, pid); - - if (process != NULL) { - nxt_main_process_cleanup(task, process); - - if (process->state == NXT_PROCESS_STATE_READY) { - process->stream = 0; - } - - nxt_queue_init(&children); - - if (!nxt_queue_is_empty(&process->children)) { - nxt_queue_add(&children, &process->children); - - nxt_queue_init(&process->children); - - nxt_queue_each(child, &children, nxt_process_t, link) { - port = nxt_process_port_first(child); - - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, - -1, 0, 0, NULL); - } nxt_queue_loop; - } - - if (nxt_exiting) { - nxt_process_close_ports(task, process); - - nxt_queue_each(child, &children, nxt_process_t, link) { - nxt_queue_remove(&child->link); - child->link.next = NULL; - - nxt_process_close_ports(task, child); - } nxt_queue_loop; - - if (rt->nprocesses <= 1) { - nxt_runtime_quit(task, 0); - - return; - } - - continue; - } - - nxt_port_remove_notify_others(task, process); - - nxt_queue_each(child, &children, nxt_process_t, link) { - nxt_port_remove_notify_others(task, child); - - nxt_queue_remove(&child->link); - child->link.next = NULL; - - nxt_process_close_ports(task, child); - } nxt_queue_loop; - - init = *(nxt_process_init_t *) nxt_process_init(process); - - nxt_process_close_ports(task, process); - - if (init.restart) { - ret = nxt_process_init_start(task, init); - if (nxt_slow_path(ret == NXT_ERROR)) { - nxt_alert(task, "failed to restart %s", init.name); - } - } - } - } -} - - -static void -nxt_main_process_signal_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_trace(task, "signal signo:%d (%s) received, ignored", - (int) (uintptr_t) obj, data); -} - - -static void -nxt_main_process_cleanup(nxt_task_t *task, nxt_process_t *process) -{ - if (process->isolation.cleanup != NULL) { - process->isolation.cleanup(task, process); - } - - if (process->isolation.cgroup_cleanup != NULL) { - process->isolation.cgroup_cleanup(task, process); - } -} - - -static void -nxt_main_port_socket_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - size_t size; - nxt_int_t ret; - nxt_buf_t *b, *out; - nxt_port_t *port; - nxt_sockaddr_t *sa; - nxt_port_msg_type_t type; - nxt_listening_socket_t ls; - u_char message[2048]; - - port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, - msg->port_msg.reply_port); - if (nxt_slow_path(port == NULL)) { - return; - } - - if (nxt_slow_path(port->type != NXT_PROCESS_ROUTER)) { - nxt_alert(task, "process %PI cannot create listener sockets", - msg->port_msg.pid); - - return; - } - - b = msg->buf; - sa = (nxt_sockaddr_t *) b->mem.pos; - - /* TODO check b size and make plain */ - - ls.socket = -1; - ls.error = NXT_SOCKET_ERROR_SYSTEM; - ls.start = message; - ls.end = message + sizeof(message); - - nxt_debug(task, "listening socket \"%*s\"", - (size_t) sa->length, nxt_sockaddr_start(sa)); - - ret = nxt_main_listening_socket(sa, &ls); - - if (ret == NXT_OK) { - nxt_debug(task, "socket(\"%*s\"): %d", - (size_t) sa->length, nxt_sockaddr_start(sa), ls.socket); - - out = NULL; - - type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD; - - } else { - size = ls.end - ls.start; - - nxt_alert(task, "%*s", size, ls.start); - - out = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, - size + 1); - if (nxt_fast_path(out != NULL)) { - *out->mem.free++ = (uint8_t) ls.error; - - out->mem.free = nxt_cpymem(out->mem.free, ls.start, size); - } - - type = NXT_PORT_MSG_RPC_ERROR; - } - - nxt_port_socket_write(task, port, type, ls.socket, msg->port_msg.stream, - 0, out); -} - - -static nxt_int_t -nxt_main_listening_socket(nxt_sockaddr_t *sa, nxt_listening_socket_t *ls) -{ - nxt_err_t err; - nxt_socket_t s; - - const socklen_t length = sizeof(int); - static const int enable = 1; - - s = socket(sa->u.sockaddr.sa_family, sa->type, 0); - - if (nxt_slow_path(s == -1)) { - err = nxt_errno; - -#if (NXT_INET6) - - if (err == EAFNOSUPPORT && sa->u.sockaddr.sa_family == AF_INET6) { - ls->error = NXT_SOCKET_ERROR_NOINET6; - } - -#endif - - ls->end = nxt_sprintf(ls->start, ls->end, - "socket(\\\"%*s\\\") failed %E", - (size_t) sa->length, nxt_sockaddr_start(sa), err); - - return NXT_ERROR; - } - - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &enable, length) != 0) { - ls->end = nxt_sprintf(ls->start, ls->end, - "setsockopt(\\\"%*s\\\", SO_REUSEADDR) failed %E", - (size_t) sa->length, nxt_sockaddr_start(sa), - nxt_errno); - goto fail; - } - -#if (NXT_INET6) - - if (sa->u.sockaddr.sa_family == AF_INET6) { - - if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &enable, length) != 0) { - ls->end = nxt_sprintf(ls->start, ls->end, - "setsockopt(\\\"%*s\\\", IPV6_V6ONLY) failed %E", - (size_t) sa->length, nxt_sockaddr_start(sa), - nxt_errno); - goto fail; - } - } - -#endif - - if (bind(s, &sa->u.sockaddr, sa->socklen) != 0) { - err = nxt_errno; - -#if (NXT_HAVE_UNIX_DOMAIN) - - if (sa->u.sockaddr.sa_family == AF_UNIX) { - switch (err) { - - case EACCES: - ls->error = NXT_SOCKET_ERROR_ACCESS; - break; - - case ENOENT: - case ENOTDIR: - ls->error = NXT_SOCKET_ERROR_PATH; - break; - } - - } else -#endif - { - switch (err) { - - case EACCES: - ls->error = NXT_SOCKET_ERROR_PORT; - break; - - case EADDRINUSE: - ls->error = NXT_SOCKET_ERROR_INUSE; - break; - - case EADDRNOTAVAIL: - ls->error = NXT_SOCKET_ERROR_NOADDR; - break; - } - } - - ls->end = nxt_sprintf(ls->start, ls->end, "bind(\\\"%*s\\\") failed %E", - (size_t) sa->length, nxt_sockaddr_start(sa), err); - goto fail; - } - -#if (NXT_HAVE_UNIX_DOMAIN) - - if (sa->u.sockaddr.sa_family == AF_UNIX - && sa->u.sockaddr_un.sun_path[0] != '\0') - { - char *filename; - mode_t access; - nxt_thread_t *thr; - - filename = sa->u.sockaddr_un.sun_path; - access = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - - if (chmod(filename, access) != 0) { - ls->end = nxt_sprintf(ls->start, ls->end, - "chmod(\\\"%s\\\") failed %E", - filename, nxt_errno); - goto fail; - } - - thr = nxt_thread(); - nxt_runtime_listen_socket_add(thr->runtime, sa); - } - -#endif - - ls->socket = s; - - return NXT_OK; - -fail: - - (void) close(s); - - return NXT_ERROR; -} - - -static void -nxt_main_port_socket_unlink_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ -#if (NXT_HAVE_UNIX_DOMAIN) - size_t i; - nxt_buf_t *b; - const char *filename; - nxt_runtime_t *rt; - nxt_sockaddr_t *sa; - nxt_listen_socket_t *ls; - - b = msg->buf; - sa = (nxt_sockaddr_t *) b->mem.pos; - - filename = sa->u.sockaddr_un.sun_path; - unlink(filename); - - rt = task->thread->runtime; - - for (i = 0; i < rt->listen_sockets->nelts; i++) { - const char *name; - - ls = (nxt_listen_socket_t *) rt->listen_sockets->elts + i; - sa = ls->sockaddr; - - if (sa->u.sockaddr.sa_family != AF_UNIX - || sa->u.sockaddr_un.sun_path[0] == '\0') - { - continue; - } - - name = sa->u.sockaddr_un.sun_path; - if (strcmp(name, filename) != 0) { - continue; - } - - nxt_array_remove(rt->listen_sockets, ls); - break; - } -#endif -} - - -static nxt_conf_map_t nxt_app_lang_module_map[] = { - { - nxt_string("type"), - NXT_CONF_MAP_INT, - offsetof(nxt_app_lang_module_t, type), - }, - - { - nxt_string("version"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_app_lang_module_t, version), - }, - - { - nxt_string("file"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_app_lang_module_t, file), - }, -}; - - -static nxt_conf_map_t nxt_app_lang_mounts_map[] = { - { - nxt_string("src"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_fs_mount_t, src), - }, - { - nxt_string("dst"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_fs_mount_t, dst), - }, - { - nxt_string("name"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_fs_mount_t, name), - }, - { - nxt_string("type"), - NXT_CONF_MAP_INT, - offsetof(nxt_fs_mount_t, type), - }, - { - nxt_string("flags"), - NXT_CONF_MAP_INT, - offsetof(nxt_fs_mount_t, flags), - }, - { - nxt_string("data"), - NXT_CONF_MAP_CSTRZ, - offsetof(nxt_fs_mount_t, data), - }, -}; - - -static void -nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - uint32_t index, jindex, nmounts; - nxt_mp_t *mp; - nxt_int_t ret; - nxt_buf_t *b; - nxt_port_t *port; - nxt_runtime_t *rt; - nxt_fs_mount_t *mnt; - nxt_conf_value_t *conf, *root, *value, *mounts; - nxt_app_lang_module_t *lang; - - static nxt_str_t root_path = nxt_string("/"); - static nxt_str_t mounts_name = nxt_string("mounts"); - - rt = task->thread->runtime; - - if (msg->port_msg.pid != rt->port_by_type[NXT_PROCESS_DISCOVERY]->pid) { - nxt_alert(task, "process %PI cannot send modules", msg->port_msg.pid); - return; - } - - if (nxt_exiting) { - nxt_debug(task, "ignoring discovered modules, exiting"); - return; - } - - port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, - msg->port_msg.reply_port); - - if (nxt_fast_path(port != NULL)) { - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1, - msg->port_msg.stream, 0, NULL); - } - - b = msg->buf; - - if (b == NULL) { - return; - } - - mp = nxt_mp_create(1024, 128, 256, 32); - if (mp == NULL) { - return; - } - - b = nxt_buf_chk_make_plain(mp, b, msg->size); - - if (b == NULL) { - return; - } - - nxt_debug(task, "application languages: \"%*s\"", - b->mem.free - b->mem.pos, b->mem.pos); - - conf = nxt_conf_json_parse(mp, b->mem.pos, b->mem.free, NULL); - if (conf == NULL) { - goto fail; - } - - root = nxt_conf_get_path(conf, &root_path); - if (root == NULL) { - goto fail; - } - - for (index = 0; /* void */ ; index++) { - value = nxt_conf_get_array_element(root, index); - if (value == NULL) { - break; - } - - lang = nxt_array_zero_add(rt->languages); - if (lang == NULL) { - goto fail; - } - - lang->module = NULL; - - ret = nxt_conf_map_object(rt->mem_pool, value, nxt_app_lang_module_map, - nxt_nitems(nxt_app_lang_module_map), lang); - - if (ret != NXT_OK) { - goto fail; - } - - mounts = nxt_conf_get_object_member(value, &mounts_name, NULL); - if (mounts == NULL) { - nxt_alert(task, "missing mounts from discovery message."); - goto fail; - } - - if (nxt_conf_type(mounts) != NXT_CONF_ARRAY) { - nxt_alert(task, "invalid mounts type from discovery message."); - goto fail; - } - - nmounts = nxt_conf_array_elements_count(mounts); - - lang->mounts = nxt_array_create(rt->mem_pool, nmounts, - sizeof(nxt_fs_mount_t)); - - if (lang->mounts == NULL) { - goto fail; - } - - for (jindex = 0; /* */; jindex++) { - value = nxt_conf_get_array_element(mounts, jindex); - if (value == NULL) { - break; - } - - mnt = nxt_array_zero_add(lang->mounts); - if (mnt == NULL) { - goto fail; - } - - mnt->builtin = 1; - mnt->deps = 1; - - ret = nxt_conf_map_object(rt->mem_pool, value, - nxt_app_lang_mounts_map, - nxt_nitems(nxt_app_lang_mounts_map), mnt); - - if (ret != NXT_OK) { - goto fail; - } - } - - nxt_debug(task, "lang %d %s \"%s\" (%d mounts)", - lang->type, lang->version, lang->file, lang->mounts->nelts); - } - - qsort(rt->languages->elts, rt->languages->nelts, - sizeof(nxt_app_lang_module_t), nxt_app_lang_compare); - -fail: - - nxt_mp_destroy(mp); - - ret = nxt_process_init_start(task, nxt_controller_process); - if (ret == NXT_OK) { - ret = nxt_process_init_start(task, nxt_router_process); - } - - if (nxt_slow_path(ret == NXT_ERROR)) { - nxt_exiting = 1; - - nxt_runtime_quit(task, 1); - } -} - - -static int nxt_cdecl -nxt_app_lang_compare(const void *v1, const void *v2) -{ - int n; - const nxt_app_lang_module_t *lang1, *lang2; - - lang1 = v1; - lang2 = v2; - - n = lang1->type - lang2->type; - - if (n != 0) { - return n; - } - - n = nxt_strverscmp(lang1->version, lang2->version); - - /* Negate result to move higher versions to the beginning. */ - - return -n; -} - - -static void -nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - void *p; - size_t n, size; - nxt_int_t ret; - nxt_port_t *ctl_port; - nxt_runtime_t *rt; - u_char ver[NXT_INT_T_LEN]; - - rt = task->thread->runtime; - - ctl_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; - - if (nxt_slow_path(msg->port_msg.pid != ctl_port->pid)) { - nxt_alert(task, "process %PI cannot store conf", msg->port_msg.pid); - return; - } - - p = MAP_FAILED; - - /* - * Ancient compilers like gcc 4.8.5 on CentOS 7 wants 'size' to be - * initialized in 'cleanup' section. - */ - size = 0; - - if (nxt_slow_path(msg->fd[0] == -1)) { - nxt_alert(task, "conf_store_handler: invalid shm fd"); - goto error; - } - - if (nxt_buf_mem_used_size(&msg->buf->mem) != sizeof(size_t)) { - nxt_alert(task, "conf_store_handler: unexpected buffer size (%d)", - (int) nxt_buf_mem_used_size(&msg->buf->mem)); - goto error; - } - - nxt_memcpy(&size, msg->buf->mem.pos, sizeof(size_t)); - - p = nxt_mem_mmap(NULL, size, PROT_READ, MAP_SHARED, msg->fd[0], 0); - - nxt_fd_close(msg->fd[0]); - msg->fd[0] = -1; - - if (nxt_slow_path(p == MAP_FAILED)) { - goto error; - } - - nxt_debug(task, "conf_store_handler(%uz): %*s", size, size, p); - - if (nxt_conf_ver != NXT_VERNUM) { - n = nxt_sprintf(ver, ver + NXT_INT_T_LEN, "%d", NXT_VERNUM) - ver; - - ret = nxt_main_file_store(task, rt->ver_tmp, rt->ver, ver, n); - if (nxt_slow_path(ret != NXT_OK)) { - goto error; - } - - nxt_conf_ver = NXT_VERNUM; - } - - ret = nxt_main_file_store(task, rt->conf_tmp, rt->conf, p, size); - - if (nxt_fast_path(ret == NXT_OK)) { - goto cleanup; - } - -error: - - nxt_alert(task, "failed to store current configuration"); - -cleanup: - - if (p != MAP_FAILED) { - nxt_mem_munmap(p, size); - } - - if (msg->fd[0] != -1) { - nxt_fd_close(msg->fd[0]); - msg->fd[0] = -1; - } -} - - -static nxt_int_t -nxt_main_file_store(nxt_task_t *task, const char *tmp_name, const char *name, - u_char *buf, size_t size) -{ - ssize_t n; - nxt_int_t ret; - nxt_file_t file; - - nxt_memzero(&file, sizeof(nxt_file_t)); - - file.name = (nxt_file_name_t *) name; - - ret = nxt_file_open(task, &file, NXT_FILE_WRONLY, NXT_FILE_TRUNCATE, - NXT_FILE_OWNER_ACCESS); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - n = nxt_file_write(&file, buf, size, 0); - - nxt_file_close(task, &file); - - if (nxt_slow_path(n != (ssize_t) size)) { - (void) nxt_file_delete(file.name); - return NXT_ERROR; - } - - return nxt_file_rename(file.name, (nxt_file_name_t *) name); -} - - -static void -nxt_main_port_access_log_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - u_char *path; - nxt_int_t ret; - nxt_file_t file; - nxt_port_t *port; - nxt_port_msg_type_t type; - - nxt_debug(task, "opening access log file"); - - path = msg->buf->mem.pos; - - nxt_memzero(&file, sizeof(nxt_file_t)); - - file.name = (nxt_file_name_t *) path; - file.log_level = NXT_LOG_ERR; - - ret = nxt_file_open(task, &file, O_WRONLY | O_APPEND, O_CREAT, - NXT_FILE_OWNER_ACCESS); - - type = (ret == NXT_OK) ? NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD - : NXT_PORT_MSG_RPC_ERROR; - - port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, - msg->port_msg.reply_port); - - if (nxt_fast_path(port != NULL)) { - (void) nxt_port_socket_write(task, port, type, file.fd, - msg->port_msg.stream, 0, NULL); - } -} diff --git a/src/nxt_main_process.h b/src/nxt_main_process.h deleted file mode 100644 index ef083d63..00000000 --- a/src/nxt_main_process.h +++ /dev/null @@ -1,37 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_MAIN_PROCESS_H_INCLUDED_ -#define _NXT_MAIN_PROCESS_H_INCLUDED_ - - -typedef enum { - NXT_SOCKET_ERROR_SYSTEM = 0, - NXT_SOCKET_ERROR_NOINET6, - NXT_SOCKET_ERROR_PORT, - NXT_SOCKET_ERROR_INUSE, - NXT_SOCKET_ERROR_NOADDR, - NXT_SOCKET_ERROR_ACCESS, - NXT_SOCKET_ERROR_PATH, -} nxt_socket_error_t; - - -nxt_int_t nxt_main_process_start(nxt_thread_t *thr, nxt_task_t *task, - nxt_runtime_t *runtime); - - -NXT_EXPORT extern nxt_uint_t nxt_conf_ver; -NXT_EXPORT extern const nxt_process_init_t nxt_discovery_process; -NXT_EXPORT extern const nxt_process_init_t nxt_controller_process; -NXT_EXPORT extern const nxt_process_init_t nxt_router_process; -NXT_EXPORT extern const nxt_process_init_t nxt_proto_process; -NXT_EXPORT extern const nxt_process_init_t nxt_app_process; - -extern const nxt_sig_event_t nxt_main_process_signals[]; -extern const nxt_sig_event_t nxt_process_signals[]; - - -#endif /* _NXT_MAIN_PROCESS_H_INCLUDED_ */ diff --git a/src/nxt_malloc.c b/src/nxt_malloc.c deleted file mode 100644 index 5ea7322f..00000000 --- a/src/nxt_malloc.c +++ /dev/null @@ -1,229 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static nxt_log_moderation_t nxt_malloc_log_moderation = { - NXT_LOG_ALERT, 2, "memory allocation failed", NXT_LOG_MODERATION -}; - - -static nxt_log_t * -nxt_malloc_log(void) -{ - nxt_thread_t *thr; - - thr = nxt_thread(); - - if (thr != NULL && thr->log != NULL) { - return thr->log; - } - - return &nxt_main_log; -} - - -void * -nxt_malloc(size_t size) -{ - void *p; - - p = malloc(size); - - if (nxt_fast_path(p != NULL)) { - nxt_log_debug(nxt_malloc_log(), "malloc(%uz): %p", size, p); - - } else { - nxt_log_alert_moderate(&nxt_malloc_log_moderation, nxt_malloc_log(), - "malloc(%uz) failed %E", size, nxt_errno); - } - - return p; -} - - -void * -nxt_zalloc(size_t size) -{ - void *p; - - p = nxt_malloc(size); - - if (nxt_fast_path(p != NULL)) { - nxt_memzero(p, size); - } - - return p; -} - - -void * -nxt_realloc(void *p, size_t size) -{ - void *n; - uintptr_t ptr; - - /* - * Workaround for a warning on GCC 12 about using "p" pointer in debug log - * after realloc(). - */ - ptr = (uintptr_t) p; - - n = realloc(p, size); - - if (nxt_fast_path(n != NULL)) { - nxt_log_debug(nxt_malloc_log(), "realloc(%p, %uz): %p", ptr, size, n); - - } else { - nxt_log_alert_moderate(&nxt_malloc_log_moderation, nxt_malloc_log(), - "realloc(%p, %uz) failed %E", - ptr, size, nxt_errno); - } - - return n; -} - - -/* nxt_lvlhsh_* functions moved here to avoid references from nxt_lvlhsh.c. */ - -void * -nxt_lvlhsh_alloc(void *data, size_t size) -{ - return nxt_memalign(size, size); -} - - -void -nxt_lvlhsh_free(void *data, void *p) -{ - nxt_free(p); -} - - -#if (NXT_DEBUG) - -void -nxt_free(void *p) -{ - nxt_log_debug(nxt_malloc_log(), "free(%p)", p); - - free(p); -} - - -#endif - - -#if (NXT_HAVE_POSIX_MEMALIGN) - -/* - * posix_memalign() presents in Linux glibc 2.1.91, FreeBSD 7.0, - * Solaris 11, MacOSX 10.6 (Snow Leopard), NetBSD 5.0. - */ - -void * -nxt_memalign(size_t alignment, size_t size) -{ - void *p; - nxt_err_t err; - - err = posix_memalign(&p, alignment, size); - - if (nxt_fast_path(err == 0)) { - nxt_thread_log_debug("posix_memalign(%uz, %uz): %p", - alignment, size, p); - return p; - } - - nxt_log_alert_moderate(&nxt_malloc_log_moderation, nxt_malloc_log(), - "posix_memalign(%uz, %uz) failed %E", - alignment, size, err); - return NULL; -} - -#elif (NXT_HAVE_MEMALIGN) - -/* memalign() presents in Solaris, HP-UX. */ - -void * -nxt_memalign(size_t alignment, size_t size) -{ - void *p; - - p = memalign(alignment, size); - - if (nxt_fast_path(p != NULL)) { - nxt_thread_log_debug("memalign(%uz, %uz): %p", - alignment, size, p); - return p; - } - - nxt_log_alert_moderate(&nxt_malloc_log_moderation, nxt_malloc_log(), - "memalign(%uz, %uz) failed %E", - alignment, size, nxt_errno); - return NULL; -} - -#elif (NXT_FREEBSD) - -/* - * FreeBSD prior to 7.0 lacks posix_memalign(), but if a requested size - * is lesser than or equal to 4K, then phkmalloc aligns the size to the - * next highest power of 2 and allocates memory with the same alignment. - * Allocations larger than 2K are always aligned to 4K. - */ - -void * -nxt_memalign(size_t alignment, size_t size) -{ - size_t aligned_size; - u_char *p; - nxt_err_t err; - - if (nxt_slow_path((alignment - 1) & alignment) != 0) { - /* Alignment must be a power of 2. */ - err = NXT_EINVAL; - goto fail; - } - - if (nxt_slow_path(alignment > 4096)) { - err = NXT_EOPNOTSUPP; - goto fail; - } - - if (nxt_fast_path(size <= 2048)) { - aligned_size = nxt_max(size, alignment); - - } else { - /* Align to 4096. */ - aligned_size = size; - } - - p = malloc(aligned_size); - - if (nxt_fast_path(p != NULL)) { - nxt_thread_log_debug("nxt_memalign(%uz, %uz): %p", alignment, size, p); - - } else { - nxt_log_alert_moderate(&nxt_malloc_log_moderation, nxt_malloc_log(), - "malloc(%uz) failed %E", size, nxt_errno); - } - - return p; - -fail: - - nxt_thread_log_alert("nxt_memalign(%uz, %uz) failed %E", - alignment, size, err); - return NULL; -} - -#else - -#error no memalign() implementation. - -#endif diff --git a/src/nxt_malloc.h b/src/nxt_malloc.h deleted file mode 100644 index fd5493a5..00000000 --- a/src/nxt_malloc.h +++ /dev/null @@ -1,126 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_MALLOC_H_INCLUDED_ -#define _NXT_UNIX_MALLOC_H_INCLUDED_ - - -NXT_EXPORT void *nxt_malloc(size_t size) - NXT_MALLOC_LIKE; -NXT_EXPORT void *nxt_zalloc(size_t size) - NXT_MALLOC_LIKE; -NXT_EXPORT void *nxt_realloc(void *p, size_t size) - NXT_MALLOC_LIKE; -NXT_EXPORT void *nxt_memalign(size_t alignment, size_t size) - NXT_MALLOC_LIKE; - - -#if (NXT_DEBUG) - -NXT_EXPORT void nxt_free(void *p); - -#else - -#define nxt_free(p) \ - free(p) - -#endif - - -#if (NXT_HAVE_MALLOC_USABLE_SIZE) - -/* - * Due to allocation strategies malloc() allocators may allocate more - * memory than is requested, so malloc_usable_size() allows to use all - * allocated memory. It is helpful for socket buffers or unaligned disk - * file I/O. However, they may be suboptimal for aligned disk file I/O. - */ - -#if (NXT_LINUX) - -/* - * Linux glibc stores bookkeeping information together with allocated - * memory itself. Size of the bookkeeping information is 12 or 24 bytes - * on 32-bit and 64-bit platforms respectively. Due to alignment there - * are usually 4 or 8 spare bytes respectively. However, if allocation - * is larger than about 128K, spare size may be up to one page: glibc aligns - * sum of allocation and bookkeeping size to a page. So if requirement - * of the large allocation size is not strict it is better to allocate - * with small cutback and then to adjust size with malloc_usable_size(). - * Glibc malloc_usable_size() is fast operation. - */ - -#define nxt_malloc_usable_size(p, size) \ - size = malloc_usable_size(p) - -#define nxt_malloc_cutback(cutback, size) \ - size = ((cutback) && size > 127 * 1024) ? size - 32 : size - -#elif (NXT_FREEBSD) - -/* - * FreeBSD prior to 7.0 (phkmalloc) aligns sizes to - * 16 - 2048 a power of two - * 2049 - ... aligned to 4K - * - * FreeBSD 7.0 (jemalloc) aligns sizes to: - * 2 - 8 a power of two - * 9 - 512 aligned to 16 - * 513 - 2048 a power of two, i.e. aligned to 1K - * 2049 - 1M aligned to 4K - * 1M- ... aligned to 1M - * See table in src/lib/libc/stdlib/malloc.c - * - * FreeBSD 7.0 malloc_usable_size() is fast for allocations, which - * are lesser than 1M. Larger allocations require mutex acquiring. - */ - -#define nxt_malloc_usable_size(p, size) \ - size = malloc_usable_size(p) - -#define nxt_malloc_cutback(cutback, size) - -#endif - -#elif (NXT_HAVE_MALLOC_GOOD_SIZE) - -/* - * MacOSX aligns sizes to - * 16 - 496 aligned to 16, 32-bit - * 16 - 992 aligned to 16, 64-bit - * 497/993 - 15K aligned to 512, if lesser than 1G RAM - * 497/993 - 127K aligned to 512, otherwise - * 15K/127K- ... aligned to 4K - * - * malloc_good_size() is faster than malloc_size() - */ - -#define nxt_malloc_usable_size(p, size) \ - size = malloc_good_size(size) - -#define nxt_malloc_cutback(cutback, size) - -#else - -#define nxt_malloc_usable_size(p, size) - -#define nxt_malloc_cutback(cutback, size) - -#endif - - -#if (NXT_HAVE_POSIX_MEMALIGN || NXT_HAVE_MEMALIGN) -#define NXT_MAX_MEMALIGN_SHIFT 32 - -#elif (NXT_FREEBSD) -#define NXT_MAX_MEMALIGN_SHIFT 12 - -#else -#define NXT_MAX_MEMALIGN_SHIFT 3 -#endif - - -#endif /* _NXT_UNIX_MALLOC_H_INCLUDED_ */ diff --git a/src/nxt_mem_map.c b/src/nxt_mem_map.c deleted file mode 100644 index f9caf54f..00000000 --- a/src/nxt_mem_map.c +++ /dev/null @@ -1,40 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -void * -nxt_mem_mmap(void *addr, size_t len, nxt_uint_t protection, nxt_uint_t flags, - nxt_fd_t fd, nxt_off_t offset) -{ - void *p; - - p = mmap(addr, len, protection, flags, fd, offset); - - if (nxt_fast_path(p != MAP_FAILED)) { - nxt_thread_log_debug("mmap(%p, %uz, %uxi, %uxi, %FD, %O): %p", - addr, len, protection, flags, fd, offset, p); - - } else { - nxt_thread_log_alert("mmap(%p, %uz, %ui, %ui, %FD, %O) failed %E", - addr, len, protection, flags, fd, offset, nxt_errno); - } - - return p; -} - - -void -nxt_mem_munmap(void *addr, size_t len) -{ - if (nxt_fast_path(munmap(addr, len) == 0)) { - nxt_thread_log_debug("munmap(%p, %uz)", addr, len); - - } else { - nxt_thread_log_alert("munmap(%p, %uz) failed %E", addr, len, nxt_errno); - } -} diff --git a/src/nxt_mem_map.h b/src/nxt_mem_map.h deleted file mode 100644 index e529aff8..00000000 --- a/src/nxt_mem_map.h +++ /dev/null @@ -1,62 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_MEM_MAP_H_INCLUDED_ -#define _NXT_UNIX_MEM_MAP_H_INCLUDED_ - - -#define NXT_MEM_MAP_FAILED MAP_FAILED - - -#define NXT_MEM_MAP_READ PROT_READ -#define NXT_MEM_MAP_WRITE PROT_WRITE - - -#if (NXT_HAVE_MAP_ANONYMOUS) -#define NXT_MEM_MAP_ANON MAP_ANONYMOUS -#else -#define NXT_MEM_MAP_ANON MAP_ANON -#endif - -#define NXT_MEM_MAP_SHARED (MAP_SHARED | NXT_MEM_MAP_ANON) - - -#if (NXT_HAVE_MAP_POPULATE) -/* - * Linux MAP_POPULATE reads ahead and wires pages. - * (MAP_POPULATE | MAP_NONBLOCK) wires only resident pages - * without read ahead but it does not work since Linux 2.6.23. - */ -#define NXT_MEM_MAP_PREFAULT MAP_POPULATE - -#elif (NXT_HAVE_MAP_PREFAULT_READ) -/* FreeBSD MAP_PREFAULT_READ wires resident pages without read ahead. */ -#define NXT_MEM_MAP_PREFAULT MAP_PREFAULT_READ - -#else -#define NXT_MEM_MAP_PREFAULT 0 -#endif - -#define NXT_MEM_MAP_FILE (MAP_SHARED | NXT_MEM_MAP_PREFAULT) - - -#define nxt_mem_map_file_ctx_t(ctx) - - -#define nxt_mem_map(addr, ctx, len, protection, flags, fd, offset) \ - nxt_mem_mmap(addr, len, protection, flags, fd, offset) - - -#define nxt_mem_unmap(addr, ctx, len) \ - nxt_mem_munmap(addr, len) - - -NXT_EXPORT void *nxt_mem_mmap(void *addr, size_t len, nxt_uint_t protection, - nxt_uint_t flags, nxt_fd_t fd, nxt_off_t offset); -NXT_EXPORT void nxt_mem_munmap(void *addr, size_t len); - - -#endif /* _NXT_UNIX_MEM_MAP_H_INCLUDED_ */ diff --git a/src/nxt_mem_zone.c b/src/nxt_mem_zone.c deleted file mode 100644 index a3ba3700..00000000 --- a/src/nxt_mem_zone.c +++ /dev/null @@ -1,948 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -#define NXT_MEM_ZONE_PAGE_FREE 0 -/* - * A page was never allocated before so it should be filled with - * junk on the first time allocation if memory debugging is enabled. - */ -#define NXT_MEM_ZONE_PAGE_FRESH 1 - -/* An entire page is currently used, no chunks inside the page. */ -#define NXT_MEM_ZONE_PAGE_USED 2 - - -typedef struct nxt_mem_zone_page_s nxt_mem_zone_page_t; - -struct nxt_mem_zone_page_s { - /* - * A size of page chunks if value is greater than or equal to 16. - * Otherwise it is used to mark page state: NXT_MEM_ZONE_PAGE_FREE, - * NXT_MEM_ZONE_PAGE_FRESH, and NXT_MEM_ZONE_PAGE_USED. - */ - uint16_t size; - - /* A number of free chunks of a chunked page. */ - uint16_t chunks; - - union { - /* A chunk bitmap if a number of chunks is lesser than 32. */ - uint8_t map[4]; - /* - * The count is a number of successive occupied pages in the first - * page. In the next occupied pages and in all free pages the count - * is zero, because a number of successive free pages is stored in - * free block size resided in beginning of the first free page. - */ - uint32_t count; - } u; - - /* Used for slot list of pages with free chunks. */ - nxt_mem_zone_page_t *next; - - /* - * Used to link of all pages including free, chunked and occupied - * pages to coalesce free pages. - */ - nxt_queue_link_t link; -}; - - -typedef struct { - uint32_t size; - uint32_t chunks; - uint32_t start; - uint32_t map_size; - nxt_mem_zone_page_t *pages; -} nxt_mem_zone_slot_t; - - -typedef struct { - NXT_RBTREE_NODE (node); - uint32_t size; -} nxt_mem_zone_free_block_t; - - -struct nxt_mem_zone_s { - nxt_thread_spinlock_t lock; - nxt_mem_zone_page_t *pages; - nxt_mem_zone_page_t sentinel_page; - nxt_rbtree_t free_pages; - - uint32_t page_size_shift; - uint32_t page_size_mask; - uint32_t max_chunk_size; - uint32_t small_bitmap_min_size; - - u_char *start; - u_char *end; - - nxt_mem_zone_slot_t slots[]; -}; - - -#define nxt_mem_zone_page_addr(zone, page) \ - (void *) (zone->start + ((page - zone->pages) << zone->page_size_shift)) - - -#define nxt_mem_zone_addr_page(zone, addr) \ - &zone->pages[((u_char *) addr - zone->start) >> zone->page_size_shift] - - -#define nxt_mem_zone_page_is_free(page) \ - (page->size < NXT_MEM_ZONE_PAGE_USED) - - -#define nxt_mem_zone_page_is_chunked(page) \ - (page->size >= 16) - - -#define nxt_mem_zone_page_bitmap(zone, slot) \ - (slot->size < zone->small_bitmap_min_size) - - -#define nxt_mem_zone_set_chunk_free(map, chunk) \ - map[chunk / 8] &= ~(0x80 >> (chunk & 7)) - - -#define nxt_mem_zone_chunk_is_free(map, chunk) \ - ((map[chunk / 8] & (0x80 >> (chunk & 7))) == 0) - - -#define nxt_mem_zone_fresh_junk(p, size) \ - nxt_memset((p), 0xA5, size) - - -#define nxt_mem_zone_free_junk(p, size) \ - nxt_memset((p), 0x5A, size) - - -static uint32_t nxt_mem_zone_pages(u_char *start, size_t zone_size, - nxt_uint_t page_size); -static void *nxt_mem_zone_slots_init(nxt_mem_zone_t *zone, - nxt_uint_t page_size); -static void nxt_mem_zone_slot_init(nxt_mem_zone_slot_t *slot, - nxt_uint_t page_size); -static intptr_t nxt_mem_zone_rbtree_compare(nxt_rbtree_node_t *node1, - nxt_rbtree_node_t *node2); -static void *nxt_mem_zone_alloc_small(nxt_mem_zone_t *zone, - nxt_mem_zone_slot_t *slot, size_t size); -static nxt_uint_t nxt_mem_zone_alloc_chunk(uint8_t *map, nxt_uint_t offset, - nxt_uint_t size); -static void *nxt_mem_zone_alloc_large(nxt_mem_zone_t *zone, size_t alignment, - size_t size); -static nxt_mem_zone_page_t *nxt_mem_zone_alloc_pages(nxt_mem_zone_t *zone, - size_t alignment, uint32_t pages); -static nxt_mem_zone_free_block_t * - nxt_mem_zone_find_free_block(nxt_mem_zone_t *zone, nxt_rbtree_node_t *node, - uint32_t alignment, uint32_t pages); -static const char *nxt_mem_zone_free_chunk(nxt_mem_zone_t *zone, - nxt_mem_zone_page_t *page, void *p); -static void nxt_mem_zone_free_pages(nxt_mem_zone_t *zone, - nxt_mem_zone_page_t *page, nxt_uint_t count); - - -static nxt_log_moderation_t nxt_mem_zone_log_moderation = { - NXT_LOG_ALERT, 2, "mem_zone_alloc() failed, not enough memory", - NXT_LOG_MODERATION -}; - - -nxt_mem_zone_t * -nxt_mem_zone_init(u_char *start, size_t zone_size, nxt_uint_t page_size) -{ - uint32_t pages; - nxt_uint_t n; - nxt_mem_zone_t *zone; - nxt_mem_zone_page_t *page; - nxt_mem_zone_free_block_t *block; - - if (nxt_slow_path((page_size & (page_size - 1)) != 0)) { - nxt_thread_log_alert("mem zone page size must be a power of 2"); - return NULL; - } - - pages = nxt_mem_zone_pages(start, zone_size, page_size); - if (pages == 0) { - return NULL; - } - - zone = (nxt_mem_zone_t *) start; - - /* The function returns address after all slots. */ - page = nxt_mem_zone_slots_init(zone, page_size); - - zone->pages = page; - - for (n = 0; n < pages; n++) { - page[n].size = NXT_MEM_ZONE_PAGE_FRESH; - } - - /* - * A special sentinel page entry marked as used does not correspond - * to a real page. The entry simplifies neighbour queue nodes check - * in nxt_mem_zone_free_pages(). - */ - zone->sentinel_page.size = NXT_MEM_ZONE_PAGE_USED; - nxt_queue_sentinel(&zone->sentinel_page.link); - nxt_queue_insert_after(&zone->sentinel_page.link, &page->link); - - /* rbtree of free pages. */ - - nxt_rbtree_init(&zone->free_pages, nxt_mem_zone_rbtree_compare); - - block = (nxt_mem_zone_free_block_t *) zone->start; - block->size = pages; - - nxt_rbtree_insert(&zone->free_pages, &block->node); - - return zone; -} - - -static uint32_t -nxt_mem_zone_pages(u_char *start, size_t zone_size, nxt_uint_t page_size) -{ - u_char *end; - size_t reserved; - nxt_uint_t n, pages, size, chunks, last; - nxt_mem_zone_t *zone; - - /* - * Find all maximum chunk sizes which zone page can be split on - * with minimum 16-byte step. - */ - last = page_size / 16; - n = 0; - size = 32; - - do { - chunks = page_size / size; - - if (last != chunks) { - last = chunks; - n++; - } - - size += 16; - - } while (chunks > 1); - - /* - * Find number of usable zone pages except zone bookkeeping data, - * slots, and pages entries. - */ - reserved = sizeof(nxt_mem_zone_t) + (n * sizeof(nxt_mem_zone_slot_t)); - - end = nxt_trunc_ptr(start + zone_size, page_size); - zone_size = end - start; - - pages = (zone_size - reserved) / (page_size + sizeof(nxt_mem_zone_page_t)); - - if (reserved > zone_size || pages == 0) { - nxt_thread_log_alert("mem zone size is too small: %uz", zone_size); - return 0; - } - - reserved += pages * sizeof(nxt_mem_zone_page_t); - nxt_memzero(start, reserved); - - zone = (nxt_mem_zone_t *) start; - - zone->start = nxt_align_ptr(start + reserved, page_size); - zone->end = end; - - nxt_thread_log_debug("mem zone pages: %uD, unused:%z", pages, - end - (zone->start + pages * page_size)); - - /* - * If a chunk size is lesser than zone->small_bitmap_min_size - * bytes, a page's chunk bitmap is larger than 32 bits and the - * bimap is placed at the start of the page. - */ - zone->small_bitmap_min_size = page_size / 32; - - zone->page_size_mask = page_size - 1; - zone->max_chunk_size = page_size / 2; - - n = zone->max_chunk_size; - - do { - zone->page_size_shift++; - n /= 2; - } while (n != 0); - - return (uint32_t) pages; -} - - -static void * -nxt_mem_zone_slots_init(nxt_mem_zone_t *zone, nxt_uint_t page_size) -{ - nxt_uint_t n, size, chunks; - nxt_mem_zone_slot_t *slot; - - slot = zone->slots; - - slot[0].chunks = page_size / 16; - slot[0].size = 16; - - n = 0; - size = 32; - - for ( ;; ) { - chunks = page_size / size; - - if (slot[n].chunks != chunks) { - - nxt_mem_zone_slot_init(&slot[n], page_size); - - nxt_thread_log_debug( - "mem zone size:%uD chunks:%uD start:%uD map:%uD", - slot[n].size, slot[n].chunks + 1, - slot[n].start, slot[n].map_size); - - n++; - - if (chunks == 1) { - return &slot[n]; - } - } - - slot[n].chunks = chunks; - slot[n].size = size; - size += 16; - } -} - - -static void -nxt_mem_zone_slot_init(nxt_mem_zone_slot_t *slot, nxt_uint_t page_size) -{ - /* - * Calculate number of bytes required to store a chunk bitmap - * and align it to 4 bytes. - */ - slot->map_size = nxt_align_size(((slot->chunks + 7) / 8), 4); - - /* If chunk size is not a multiple of zone page size, there - * is surplus space which can be used for the chunk's bitmap. - */ - slot->start = page_size - slot->chunks * slot->size; - - /* slot->chunks should be one less than actual number of chunks. */ - slot->chunks--; - - if (slot->map_size > 4) { - /* A page's chunks bitmap is placed at the start of the page. */ - - if (slot->start < slot->map_size) { - /* - * There is no surplus space or the space is too - * small for chunks bitmap, so use the first chunks. - */ - if (slot->size < slot->map_size) { - /* The first chunks are occupied by bitmap. */ - slot->chunks -= slot->map_size / slot->size; - slot->start = nxt_align_size(slot->map_size, 16); - - } else { - /* The first chunk is occupied by bitmap. */ - slot->chunks--; - slot->start = slot->size; - } - } - } -} - - -/* - * Round up to the next highest power of 2. The algorithm is - * described in "Bit Twiddling Hacks" by Sean Eron Anderson. - */ - -nxt_inline uint32_t -nxt_next_highest_power_of_two(uint32_t n) -{ - n--; - n |= n >> 1; - n |= n >> 2; - n |= n >> 4; - n |= n >> 8; - n |= n >> 16; - n++; - - return n; -} - - -static intptr_t -nxt_mem_zone_rbtree_compare(nxt_rbtree_node_t *node1, nxt_rbtree_node_t *node2) -{ - u_char *start1, *end1, *start2, *end2; - uint32_t n, size, size1, size2; - nxt_mem_zone_free_block_t *block1, *block2; - - block1 = (nxt_mem_zone_free_block_t *) node1; - block2 = (nxt_mem_zone_free_block_t *) node2; - - size1 = block1->size; - size2 = block2->size; - - /* - * This subtractions do not overflow if number of pages of a free - * block is below 2^31-1. This allows to use blocks up to 128G if - * a zone page size is just 64 bytes. - */ - n = size1 - size2; - - if (n != 0) { - return n; - } - - /* - * Sort equally sized blocks by their capability to allocate memory with - * alignment equal to the size rounded the previous higest power of 2. - */ - - /* Round the size to the previous higest power of two. */ - size = nxt_next_highest_power_of_two(size1) >> 1; - - /* Align the blocks' start and end to the rounded size. */ - start1 = nxt_align_ptr(block1, size); - end1 = nxt_trunc_ptr((u_char *) block1 + size1, size); - - start2 = nxt_align_ptr(block2, size); - end2 = nxt_trunc_ptr((u_char *) block2 + size2, size); - - return (end1 - start1) - (end2 - start2); -} - - -void * -nxt_mem_zone_zalloc(nxt_mem_zone_t *zone, size_t size) -{ - void *p; - - p = nxt_mem_zone_align(zone, 1, size); - - if (nxt_fast_path(p != NULL)) { - nxt_memzero(p, size); - } - - return p; -} - - -void * -nxt_mem_zone_align(nxt_mem_zone_t *zone, size_t alignment, size_t size) -{ - void *p; - nxt_mem_zone_slot_t *slot; - - if (nxt_slow_path((alignment - 1) & alignment) != 0) { - /* Alignment must be a power of 2. */ - return NULL; - } - - if (size <= zone->max_chunk_size && alignment <= zone->max_chunk_size) { - /* All chunks are aligned to 16. */ - - if (alignment > 16) { - /* - * Chunks which size is power of 2 are aligned to the size. - * So allocation size should be increased to the next highest - * power of two. This can waste memory, but a main consumer - * of aligned allocations is lvlhsh which anyway allocates - * memory with alignment equal to size. - */ - size = nxt_next_highest_power_of_two(size); - size = nxt_max(size, alignment); - } - - /* - * Find a zone slot with appropriate chunk size. - * This operation can be performed without holding lock. - */ - for (slot = zone->slots; slot->size < size; slot++) { /* void */ } - - nxt_thread_log_debug("mem zone alloc: @%uz:%uz chunk:%uD", - alignment, size, slot->size); - - nxt_thread_spin_lock(&zone->lock); - - p = nxt_mem_zone_alloc_small(zone, slot, size); - - } else { - - nxt_thread_log_debug("mem zone alloc: @%uz:%uz", alignment, size); - - nxt_thread_spin_lock(&zone->lock); - - p = nxt_mem_zone_alloc_large(zone, alignment, size); - } - - nxt_thread_spin_unlock(&zone->lock); - - if (nxt_fast_path(p != NULL)) { - nxt_thread_log_debug("mem zone alloc: %p", p); - - } else { - nxt_log_alert_moderate(&nxt_mem_zone_log_moderation, nxt_thread_log(), - "nxt_mem_zone_alloc(%uz, %uz) failed, not enough memory", - alignment, size); - } - - return p; -} - - -static void * -nxt_mem_zone_alloc_small(nxt_mem_zone_t *zone, nxt_mem_zone_slot_t *slot, - size_t size) -{ - u_char *p; - uint8_t *map; - nxt_mem_zone_page_t *page; - - page = slot->pages; - - if (nxt_fast_path(page != NULL)) { - - p = nxt_mem_zone_page_addr(zone, page); - - if (nxt_mem_zone_page_bitmap(zone, slot)) { - /* A page's chunks bitmap is placed at the start of the page. */ - map = p; - - } else { - map = page->u.map; - } - - p += nxt_mem_zone_alloc_chunk(map, slot->start, slot->size); - - page->chunks--; - - if (page->chunks == 0) { - /* - * Remove full page from the zone slot list of pages with - * free chunks. - */ - slot->pages = page->next; -#if (NXT_DEBUG) - page->next = NULL; -#endif - } - - return p; - } - - page = nxt_mem_zone_alloc_pages(zone, 1, 1); - - if (nxt_fast_path(page != NULL)) { - - slot->pages = page; - - page->size = slot->size; - /* slot->chunks are already one less. */ - page->chunks = slot->chunks; - page->u.count = 0; - page->next = NULL; - - p = nxt_mem_zone_page_addr(zone, page); - - if (nxt_mem_zone_page_bitmap(zone, slot)) { - /* A page's chunks bitmap is placed at the start of the page. */ - map = p; - nxt_memzero(map, slot->map_size); - - } else { - map = page->u.map; - } - - /* Mark the first chunk as busy. */ - map[0] = 0x80; - - return p + slot->start; - } - - return NULL; -} - - -static nxt_uint_t -nxt_mem_zone_alloc_chunk(uint8_t *map, nxt_uint_t offset, nxt_uint_t size) -{ - uint8_t mask; - nxt_uint_t n; - - n = 0; - - /* The page must have at least one free chunk. */ - - for ( ;; ) { - /* The bitmap is always aligned to uint32_t. */ - - if (*(uint32_t *) &map[n] != 0xFFFFFFFF) { - - do { - if (map[n] != 0xFF) { - - mask = 0x80; - - do { - if ((map[n] & mask) == 0) { - /* The free chunk is found. */ - map[n] |= mask; - return offset; - } - - offset += size; - mask >>= 1; - - } while (mask != 0); - - } else { - /* Fast-forward: all 8 chunks are occupied. */ - offset += size * 8; - } - - n++; - - } while (n % 4 != 0); - - } else { - /* Fast-forward: all 32 chunks are occupied. */ - offset += size * 32; - n += 4; - } - } -} - - -static void * -nxt_mem_zone_alloc_large(nxt_mem_zone_t *zone, size_t alignment, size_t size) -{ - uint32_t pages; - nxt_mem_zone_page_t *page; - - pages = (size + zone->page_size_mask) >> zone->page_size_shift; - - page = nxt_mem_zone_alloc_pages(zone, alignment, pages); - - if (nxt_fast_path(page != NULL)) { - return nxt_mem_zone_page_addr(zone, page); - } - - return NULL; -} - - -static nxt_mem_zone_page_t * -nxt_mem_zone_alloc_pages(nxt_mem_zone_t *zone, size_t alignment, uint32_t pages) -{ - u_char *p; - size_t prev_size; - uint32_t prev_pages, node_pages, next_pages; - nxt_uint_t n; - nxt_mem_zone_page_t *prev_page, *page, *next_page; - nxt_mem_zone_free_block_t *block, *next_block; - - block = nxt_mem_zone_find_free_block(zone, - nxt_rbtree_root(&zone->free_pages), - alignment, pages); - - if (nxt_slow_path(block == NULL)) { - return NULL; - } - - node_pages = block->size; - - nxt_rbtree_delete(&zone->free_pages, &block->node); - - p = nxt_align_ptr(block, alignment); - page = nxt_mem_zone_addr_page(zone, p); - - prev_size = p - (u_char *) block; - - if (prev_size != 0) { - prev_pages = prev_size >> zone->page_size_shift; - node_pages -= prev_pages; - - block->size = prev_pages; - nxt_rbtree_insert(&zone->free_pages, &block->node); - - prev_page = nxt_mem_zone_addr_page(zone, block); - nxt_queue_insert_after(&prev_page->link, &page->link); - } - - next_pages = node_pages - pages; - - if (next_pages != 0) { - next_page = &page[pages]; - next_block = nxt_mem_zone_page_addr(zone, next_page); - next_block->size = next_pages; - - nxt_rbtree_insert(&zone->free_pages, &next_block->node); - nxt_queue_insert_after(&page->link, &next_page->link); - } - - /* Go through pages after all rbtree operations to not trash CPU cache. */ - - page[0].u.count = pages; - - for (n = 0; n < pages; n++) { - - if (page[n].size == NXT_MEM_ZONE_PAGE_FRESH) { - nxt_mem_zone_fresh_junk(nxt_mem_zone_page_addr(zone, &page[n]), - zone->page_size_mask + 1); - } - - page[n].size = NXT_MEM_ZONE_PAGE_USED; - } - - return page; -} - - -/* - * Free blocks are sorted by size and then if the sizes are equal - * by aligned allocation capabilty. The former criterion is just - * comparison with a requested size and it can be used for iteractive - * search. The later criterion cannot be tested only by the requested - * size and alignment, so recursive in-order tree traversal is required - * to find a suitable free block. nxt_mem_zone_find_free_block() uses - * only recursive in-order tree traversal because anyway the slowest part - * of the algorithm are CPU cache misses. Besides the last tail recursive - * call may be optimized by compiler into iteractive search. - */ - -static nxt_mem_zone_free_block_t * -nxt_mem_zone_find_free_block(nxt_mem_zone_t *zone, nxt_rbtree_node_t *node, - uint32_t alignment, uint32_t pages) -{ - u_char *aligned, *end; - nxt_mem_zone_free_block_t *block, *free_block; - - if (node == nxt_rbtree_sentinel(&zone->free_pages)) { - return NULL; - } - - block = (nxt_mem_zone_free_block_t *) node; - - if (pages <= block->size) { - - free_block = nxt_mem_zone_find_free_block(zone, block->node.left, - alignment, pages); - if (free_block != NULL) { - return free_block; - } - - aligned = nxt_align_ptr(block, alignment); - - if (pages == block->size) { - if (aligned == (u_char *) block) { - /* Exact match. */ - return block; - } - - } else { /* pages < block->size */ - aligned += pages << zone->page_size_shift; - end = nxt_pointer_to(block, block->size << zone->page_size_shift); - - if (aligned <= end) { - return block; - } - } - } - - return nxt_mem_zone_find_free_block(zone, block->node.right, - alignment, pages); -} - - -void -nxt_mem_zone_free(nxt_mem_zone_t *zone, void *p) -{ - nxt_uint_t count; - const char *err; - nxt_mem_zone_page_t *page; - - nxt_thread_log_debug("mem zone free: %p", p); - - if (nxt_fast_path(zone->start <= (u_char *) p - && (u_char *) p < zone->end)) - { - page = nxt_mem_zone_addr_page(zone, p); - - nxt_thread_spin_lock(&zone->lock); - - if (nxt_mem_zone_page_is_chunked(page)) { - err = nxt_mem_zone_free_chunk(zone, page, p); - - } else if (nxt_slow_path(nxt_mem_zone_page_is_free(page))) { - err = "page is already free"; - - } else if (nxt_slow_path((uintptr_t) p & zone->page_size_mask) != 0) { - err = "invalid pointer to chunk"; - - } else { - count = page->u.count; - - if (nxt_fast_path(count != 0)) { - nxt_mem_zone_free_junk(p, count * zone->page_size_mask + 1); - nxt_mem_zone_free_pages(zone, page, count); - err = NULL; - - } else { - /* Not the first allocated page. */ - err = "pointer to wrong page"; - } - } - - nxt_thread_spin_unlock(&zone->lock); - - } else { - err = "pointer is out of zone"; - } - - if (nxt_slow_path(err != NULL)) { - nxt_thread_log_alert("nxt_mem_zone_free(%p): %s", p, err); - } -} - - -static const char * -nxt_mem_zone_free_chunk(nxt_mem_zone_t *zone, nxt_mem_zone_page_t *page, - void *p) -{ - u_char *map; - uint32_t size, offset, chunk; - nxt_mem_zone_page_t *pg, **ppg; - nxt_mem_zone_slot_t *slot; - - size = page->size; - - /* Find a zone slot with appropriate chunk size. */ - for (slot = zone->slots; slot->size < size; slot++) { /* void */ } - - offset = (uintptr_t) p & zone->page_size_mask; - offset -= slot->start; - - chunk = offset / size; - - if (nxt_slow_path(offset != chunk * size)) { - return "pointer to wrong chunk"; - } - - if (nxt_mem_zone_page_bitmap(zone, slot)) { - /* A page's chunks bitmap is placed at the start of the page. */ - map = (u_char *) ((uintptr_t) p & ~((uintptr_t) zone->page_size_mask)); - - } else { - map = page->u.map; - } - - if (nxt_mem_zone_chunk_is_free(map, chunk)) { - return "chunk is already free"; - } - - nxt_mem_zone_set_chunk_free(map, chunk); - - nxt_mem_zone_free_junk(p, page->size); - - if (page->chunks == 0) { - page->chunks = 1; - - /* Add the page to the head of slot list of pages with free chunks. */ - page->next = slot->pages; - slot->pages = page; - - } else if (page->chunks != slot->chunks) { - page->chunks++; - - } else { - - if (map != page->u.map) { - nxt_mem_zone_free_junk(map, slot->map_size); - } - - /* - * All chunks are free, remove the page from the slot list of pages - * with free chunks and add the page to the free pages tree. - */ - ppg = &slot->pages; - - for (pg = slot->pages; pg != NULL; pg = pg->next) { - - if (pg == page) { - *ppg = page->next; - break; - } - - ppg = &pg->next; - } - - nxt_mem_zone_free_pages(zone, page, 1); - } - - return NULL; -} - - -static void -nxt_mem_zone_free_pages(nxt_mem_zone_t *zone, nxt_mem_zone_page_t *page, - nxt_uint_t count) -{ - nxt_mem_zone_page_t *prev_page, *next_page; - nxt_mem_zone_free_block_t *block, *prev_block, *next_block; - - page->size = NXT_MEM_ZONE_PAGE_FREE; - page->chunks = 0; - page->u.count = 0; - page->next = NULL; - - nxt_memzero(&page[1], (count - 1) * sizeof(nxt_mem_zone_page_t)); - - next_page = nxt_queue_link_data(page->link.next, nxt_mem_zone_page_t, link); - - if (nxt_mem_zone_page_is_free(next_page)) { - - /* Coalesce with the next free pages. */ - - nxt_queue_remove(&next_page->link); - nxt_memzero(next_page, sizeof(nxt_mem_zone_page_t)); - - next_block = nxt_mem_zone_page_addr(zone, next_page); - count += next_block->size; - nxt_rbtree_delete(&zone->free_pages, &next_block->node); - } - - prev_page = nxt_queue_link_data(page->link.prev, nxt_mem_zone_page_t, link); - - if (nxt_mem_zone_page_is_free(prev_page)) { - - /* Coalesce with the previous free pages. */ - - nxt_queue_remove(&page->link); - - prev_block = nxt_mem_zone_page_addr(zone, prev_page); - count += prev_block->size; - nxt_rbtree_delete(&zone->free_pages, &prev_block->node); - - prev_block->size = count; - nxt_rbtree_insert(&zone->free_pages, &prev_block->node); - - return; - } - - block = nxt_mem_zone_page_addr(zone, page); - block->size = count; - nxt_rbtree_insert(&zone->free_pages, &block->node); -} diff --git a/src/nxt_mem_zone.h b/src/nxt_mem_zone.h deleted file mode 100644 index 89d73ca2..00000000 --- a/src/nxt_mem_zone.h +++ /dev/null @@ -1,28 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_MEM_ZONE_H_INCLUDED_ -#define _NXT_MEM_ZONE_H_INCLUDED_ - - -typedef struct nxt_mem_zone_s nxt_mem_zone_t; - - -NXT_EXPORT nxt_mem_zone_t *nxt_mem_zone_init(u_char *start, size_t zone_size, - nxt_uint_t page_size); - -#define nxt_mem_zone_alloc(zone, size) \ - nxt_mem_zone_align((zone), 1, (size)) - -NXT_EXPORT void *nxt_mem_zone_align(nxt_mem_zone_t *zone, size_t alignment, - size_t size) - NXT_MALLOC_LIKE; -NXT_EXPORT void *nxt_mem_zone_zalloc(nxt_mem_zone_t *zone, size_t size) - NXT_MALLOC_LIKE; -NXT_EXPORT void nxt_mem_zone_free(nxt_mem_zone_t *zone, void *p); - - -#endif /* _NXT_MEM_ZONE_H_INCLUDED_ */ diff --git a/src/nxt_mp.c b/src/nxt_mp.c deleted file mode 100644 index 2bd8cdee..00000000 --- a/src/nxt_mp.c +++ /dev/null @@ -1,1075 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * A memory pool allocates memory in clusters of specified size and aligned - * to page_alignment. A cluster is divided on pages of specified size. Page - * size must be a power of 2. A page can be used entirely or can be divided - * on chunks of equal size. Chunk size must be a power of 2. Non-freeable - * memory is also allocated from pages. A cluster can contains a mix of pages - * with different chunk sizes and non-freeable pages. Cluster size must be - * a multiple of page size and may be not a power of 2. Allocations greater - * than page are allocated outside clusters. Start addresses and sizes of - * the clusters and large allocations are stored in rbtree blocks to find - * them on free operations. The rbtree nodes are sorted by start addresses. - * The rbtree is also used to destroy memory pool. - */ - - -typedef struct { - /* - * Used to link - * *) pages with free chunks in pool chunk pages lists, - * *) pages with free space for non-freeable allocations, - * *) free pages in clusters. - */ - nxt_queue_link_t link; - - union { - /* Chunk bitmap. There can be no more than 32 chunks in a page. */ - uint32_t map; - - /* Size of taken non-freeable space. */ - uint32_t taken; - } u; - - /* - * Size of chunks or page shifted by pool->chunk_size_shift. Zero means - * that page is free, 0xFF means page with non-freeable allocations. - */ - uint8_t size; - - /* Number of free chunks of a chunked page. */ - uint8_t chunks; - - /* - * Number of allocation fails due to free space insufficiency - * in non-freeable page. - */ - uint8_t fails; - - /* - * Page number in page cluster. - * There can be no more than 256 pages in a cluster. - */ - uint8_t number; -} nxt_mp_page_t; - - -/* - * Some malloc implementations (e.g. jemalloc) allocates large enough - * blocks (e.g. greater than 4K) with 4K alignment. So if a block - * descriptor will be allocated together with the block it will take - * excessive 4K memory. So it is better to allocate the block descriptor - * apart. - */ - -typedef enum { - /* Block of cluster. The block is allocated apart of the cluster. */ - NXT_MP_CLUSTER_BLOCK = 0, - /* - * Block of large allocation. - * The block is allocated apart of the allocation. - */ - NXT_MP_DISCRETE_BLOCK, - /* - * Block of large allocation. - * The block is allocated just after of the allocation. - */ - NXT_MP_EMBEDDED_BLOCK, -} nxt_mp_block_type_t; - - -typedef struct { - NXT_RBTREE_NODE (node); - nxt_mp_block_type_t type:8; - uint8_t freeable; - - /* Block size must be less than 4G. */ - uint32_t size; - - u_char *start; - nxt_mp_page_t pages[]; -} nxt_mp_block_t; - - -struct nxt_mp_s { - /* rbtree of nxt_mp_block_t. */ - nxt_rbtree_t blocks; - - uint8_t chunk_size_shift; - uint8_t page_size_shift; - uint32_t page_size; - uint32_t page_alignment; - uint32_t cluster_size; - uint32_t retain; - -#if (NXT_DEBUG) - nxt_pid_t pid; - nxt_tid_t tid; -#endif - - nxt_work_t *cleanup; - - /* Lists of nxt_mp_page_t. */ - nxt_queue_t free_pages; - nxt_queue_t nget_pages; - nxt_queue_t get_pages; - nxt_queue_t chunk_pages[]; -}; - - -#define nxt_mp_chunk_get_free(map) \ - (__builtin_ffs(map) - 1) - - -#define nxt_mp_chunk_is_free(map, chunk) \ - ((map & (1 << chunk)) != 0) - - -#define nxt_mp_chunk_set_busy(map, chunk) \ - map &= ~(1 << chunk) - - -#define nxt_mp_chunk_set_free(map, chunk) \ - map |= (1 << chunk) - - -#define nxt_mp_free_junk(p, size) \ - memset((p), 0x5A, size) - - -#if !(NXT_DEBUG_MEMORY) -static void *nxt_mp_alloc_small(nxt_mp_t *mp, size_t size); -static void *nxt_mp_get_small(nxt_mp_t *mp, nxt_queue_t *pages, size_t size); -static nxt_mp_page_t *nxt_mp_alloc_page(nxt_mp_t *mp); -static nxt_mp_block_t *nxt_mp_alloc_cluster(nxt_mp_t *mp); -#endif -static void *nxt_mp_alloc_large(nxt_mp_t *mp, size_t alignment, size_t size, - nxt_bool_t freeable); -static intptr_t nxt_mp_rbtree_compare(nxt_rbtree_node_t *node1, - nxt_rbtree_node_t *node2); -static nxt_mp_block_t *nxt_mp_find_block(nxt_rbtree_t *tree, const u_char *p); -static const char *nxt_mp_chunk_free(nxt_mp_t *mp, nxt_mp_block_t *cluster, - u_char *p); - - -#if (NXT_HAVE_BUILTIN_CLZ) - -#define nxt_lg2(value) \ - (31 - __builtin_clz(value)) - -#else - -static const int nxt_lg2_tab64[64] = { - 63, 0, 58, 1, 59, 47, 53, 2, - 60, 39, 48, 27, 54, 33, 42, 3, - 61, 51, 37, 40, 49, 18, 28, 20, - 55, 30, 34, 11, 43, 14, 22, 4, - 62, 57, 46, 52, 38, 26, 32, 41, - 50, 36, 17, 19, 29, 10, 13, 21, - 56, 45, 25, 31, 35, 16, 9, 12, - 44, 24, 15, 8, 23, 7, 6, 5 -}; - -static const uint64_t nxt_lg2_magic = 0x07EDD5E59A4E28C2ULL; - -static int -nxt_lg2(uint64_t v) -{ - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v |= v >> 32; - return nxt_lg2_tab64[ ((v - (v >> 1)) * nxt_lg2_magic) >> 58 ]; -} - -#endif - - -#if (NXT_DEBUG) - -nxt_inline void -nxt_mp_thread_assert(nxt_mp_t *mp) -{ - nxt_tid_t tid; - nxt_thread_t *thread; - - thread = nxt_thread(); - tid = nxt_thread_tid(thread); - - if (nxt_fast_path(mp->tid == tid)) { - return; - } - - if (nxt_slow_path(nxt_pid != mp->pid)) { - mp->pid = nxt_pid; - mp->tid = tid; - - return; - } - - nxt_log_alert(thread->log, "mem_pool locked by thread %PT", mp->tid); - nxt_abort(); -} - -#else - -#define nxt_mp_thread_assert(mp) - -#endif - - -void -nxt_mp_thread_adopt(nxt_mp_t *mp) -{ -#if (NXT_DEBUG) - mp->pid = nxt_pid; - mp->tid = nxt_thread_tid(nxt_thread()); -#endif -} - - -nxt_mp_t * -nxt_mp_create(size_t cluster_size, size_t page_alignment, size_t page_size, - size_t min_chunk_size) -{ - nxt_mp_t *mp; - uint32_t pages, chunk_size_shift, page_size_shift; - nxt_queue_t *chunk_pages; - - chunk_size_shift = nxt_lg2(min_chunk_size); - page_size_shift = nxt_lg2(page_size); - - pages = page_size_shift - chunk_size_shift; - - mp = nxt_zalloc(sizeof(nxt_mp_t) + pages * sizeof(nxt_queue_t)); - - if (nxt_fast_path(mp != NULL)) { - mp->retain = 1; - mp->chunk_size_shift = chunk_size_shift; - mp->page_size_shift = page_size_shift; - mp->page_size = page_size; - mp->page_alignment = nxt_max(page_alignment, NXT_MAX_ALIGNMENT); - mp->cluster_size = cluster_size; - - chunk_pages = mp->chunk_pages; - - while (pages != 0) { - nxt_queue_init(chunk_pages); - chunk_pages++; - pages--; - } - - nxt_queue_init(&mp->free_pages); - nxt_queue_init(&mp->nget_pages); - nxt_queue_init(&mp->get_pages); - - nxt_rbtree_init(&mp->blocks, nxt_mp_rbtree_compare); - } - - nxt_debug_alloc("mp %p create(%uz, %uz, %uz, %uz)", mp, cluster_size, - page_alignment, page_size, min_chunk_size); - - return mp; -} - - -void -nxt_mp_retain(nxt_mp_t *mp) -{ - mp->retain++; - - nxt_thread_log_debug("mp %p retain: %uD", mp, mp->retain); -} - - -void -nxt_mp_release(nxt_mp_t *mp) -{ - mp->retain--; - - nxt_thread_log_debug("mp %p release: %uD", mp, mp->retain); - - if (mp->retain == 0) { - nxt_mp_destroy(mp); - } -} - - -void -nxt_mp_destroy(nxt_mp_t *mp) -{ - void *p; - nxt_work_t *work, *next_work; - nxt_mp_block_t *block; - nxt_rbtree_node_t *node, *next; - - nxt_debug_alloc("mp %p destroy", mp); - - nxt_mp_thread_assert(mp); - - while (mp->cleanup != NULL) { - work = mp->cleanup; - next_work = work->next; - - work->handler(work->task, work->obj, work->data); - - mp->cleanup = next_work; - } - - next = nxt_rbtree_root(&mp->blocks); - - while (next != nxt_rbtree_sentinel(&mp->blocks)) { - - node = nxt_rbtree_destroy_next(&mp->blocks, &next); - block = (nxt_mp_block_t *) node; - - p = block->start; - - if (block->type != NXT_MP_EMBEDDED_BLOCK) { - nxt_free(block); - } - - nxt_free(p); - } - - nxt_free(mp); -} - - -nxt_bool_t -nxt_mp_test_sizes(size_t cluster_size, size_t page_alignment, size_t page_size, - size_t min_chunk_size) -{ - nxt_bool_t valid; - - /* Alignment and sizes must be a power of 2. */ - - valid = nxt_expect(1, (nxt_is_power_of_two(page_alignment) - && nxt_is_power_of_two(page_size) - && nxt_is_power_of_two(min_chunk_size))); - if (!valid) { - return 0; - } - - page_alignment = nxt_max(page_alignment, NXT_MAX_ALIGNMENT); - - valid = nxt_expect(1, (page_size >= 64 - && page_size >= page_alignment - && page_size >= min_chunk_size - && min_chunk_size * 32 >= page_size - && cluster_size >= page_size - && cluster_size / page_size <= 256 - && cluster_size % page_size == 0)); - if (!valid) { - return 0; - } - - return 1; -} - - -nxt_bool_t -nxt_mp_is_empty(nxt_mp_t *mp) -{ - return (nxt_rbtree_is_empty(&mp->blocks) - && nxt_queue_is_empty(&mp->free_pages)); -} - - -void * -nxt_mp_alloc(nxt_mp_t *mp, size_t size) -{ - void *p; - -#if !(NXT_DEBUG_MEMORY) - - if (size <= mp->page_size) { - p = nxt_mp_alloc_small(mp, size); - - } else { - p = nxt_mp_alloc_large(mp, NXT_MAX_ALIGNMENT, size, 1); - } - -#else - - p = nxt_mp_alloc_large(mp, NXT_MAX_ALIGNMENT, size, 1); - -#endif - - nxt_debug_alloc("mp %p alloc(%uz): %p", mp, size, p); - - return p; -} - - -void * -nxt_mp_zalloc(nxt_mp_t *mp, size_t size) -{ - void *p; - - p = nxt_mp_alloc(mp, size); - - if (nxt_fast_path(p != NULL)) { - memset(p, 0, size); - } - - return p; -} - - -void * -nxt_mp_align(nxt_mp_t *mp, size_t alignment, size_t size) -{ - void *p; - - /* Alignment must be a power of 2. */ - - if (nxt_fast_path(nxt_is_power_of_two(alignment))) { - -#if !(NXT_DEBUG_MEMORY) - - size_t aligned_size; - - aligned_size = nxt_max(size, alignment); - - if (aligned_size <= mp->page_size && alignment <= mp->page_alignment) { - p = nxt_mp_alloc_small(mp, aligned_size); - - } else { - p = nxt_mp_alloc_large(mp, alignment, size, 1); - } - -#else - - p = nxt_mp_alloc_large(mp, alignment, size, 1); - -#endif - - } else { - p = NULL; - } - - nxt_debug_alloc("mp %p align(@%uz:%uz): %p", mp, alignment, size, p); - - return p; -} - - -void * -nxt_mp_zalign(nxt_mp_t *mp, size_t alignment, size_t size) -{ - void *p; - - p = nxt_mp_align(mp, alignment, size); - - if (nxt_fast_path(p != NULL)) { - memset(p, 0, size); - } - - return p; -} - - -nxt_inline nxt_uint_t -nxt_mp_chunk_pages_index(nxt_mp_t *mp, size_t size) -{ - nxt_int_t n, index; - - index = 0; - - if (size > 1) { - n = nxt_lg2(size - 1) + 1 - mp->chunk_size_shift; - - if (n > 0) { - index = n; - } - } - - return index; -} - - -#if !(NXT_DEBUG_MEMORY) - -nxt_inline u_char * -nxt_mp_page_addr(nxt_mp_t *mp, nxt_mp_page_t *page) -{ - size_t page_offset; - nxt_mp_block_t *block; - - page_offset = page->number * sizeof(nxt_mp_page_t) - + offsetof(nxt_mp_block_t, pages); - - block = (nxt_mp_block_t *) ((u_char *) page - page_offset); - - return block->start + (page->number << mp->page_size_shift); -} - - -static void * -nxt_mp_alloc_small(nxt_mp_t *mp, size_t size) -{ - u_char *p; - nxt_uint_t n, index; - nxt_queue_t *chunk_pages; - nxt_mp_page_t *page; - nxt_queue_link_t *link; - - nxt_mp_thread_assert(mp); - - p = NULL; - - if (size <= mp->page_size / 2) { - - index = nxt_mp_chunk_pages_index(mp, size); - chunk_pages = &mp->chunk_pages[index]; - - if (nxt_fast_path(!nxt_queue_is_empty(chunk_pages))) { - - link = nxt_queue_first(chunk_pages); - page = nxt_queue_link_data(link, nxt_mp_page_t, link); - - p = nxt_mp_page_addr(mp, page); - - n = nxt_mp_chunk_get_free(page->u.map); - nxt_mp_chunk_set_busy(page->u.map, n); - - p += ((n << index) << mp->chunk_size_shift); - - page->chunks--; - - if (page->chunks == 0) { - /* - * Remove full page from the pool chunk pages list - * of pages with free chunks. - */ - nxt_queue_remove(&page->link); - } - - } else { - page = nxt_mp_alloc_page(mp); - - if (nxt_fast_path(page != NULL)) { - page->size = (1 << index); - - n = mp->page_size_shift - (index + mp->chunk_size_shift); - page->chunks = (1 << n) - 1; - - nxt_queue_insert_head(chunk_pages, &page->link); - - /* Mark the first chunk as busy. */ - page->u.map = 0xFFFFFFFE; - - p = nxt_mp_page_addr(mp, page); - } - } - - } else { - page = nxt_mp_alloc_page(mp); - - if (nxt_fast_path(page != NULL)) { - page->size = mp->page_size >> mp->chunk_size_shift; - - p = nxt_mp_page_addr(mp, page); - } - } - - nxt_debug_alloc("mp %p chunk:%uz alloc: %p", mp, - page->size << mp->chunk_size_shift, p); - - return p; -} - - -static void * -nxt_mp_get_small(nxt_mp_t *mp, nxt_queue_t *pages, size_t size) -{ - u_char *p; - uint32_t available; - nxt_mp_page_t *page; - nxt_queue_link_t *link, *next; - - nxt_mp_thread_assert(mp); - - for (link = nxt_queue_first(pages); - link != nxt_queue_tail(pages); - link = next) - { - next = nxt_queue_next(link); - page = nxt_queue_link_data(link, nxt_mp_page_t, link); - - available = mp->page_size - page->u.taken; - - if (size <= available) { - goto found; - } - - if (available == 0 || page->fails++ > 100) { - nxt_queue_remove(link); - } - } - - page = nxt_mp_alloc_page(mp); - - if (nxt_slow_path(page == NULL)) { - return page; - } - - nxt_queue_insert_head(pages, &page->link); - - page->size = 0xFF; - page->u.taken = 0; - -found: - - p = nxt_mp_page_addr(mp, page); - - p += page->u.taken; - page->u.taken += size; - - return p; -} - - -static nxt_mp_page_t * -nxt_mp_alloc_page(nxt_mp_t *mp) -{ - nxt_mp_page_t *page; - nxt_mp_block_t *cluster; - nxt_queue_link_t *link; - - if (nxt_queue_is_empty(&mp->free_pages)) { - cluster = nxt_mp_alloc_cluster(mp); - if (nxt_slow_path(cluster == NULL)) { - return NULL; - } - } - - link = nxt_queue_first(&mp->free_pages); - nxt_queue_remove(link); - - page = nxt_queue_link_data(link, nxt_mp_page_t, link); - - return page; -} - - -static nxt_mp_block_t * -nxt_mp_alloc_cluster(nxt_mp_t *mp) -{ - nxt_uint_t n; - nxt_mp_block_t *cluster; - - n = mp->cluster_size >> mp->page_size_shift; - - cluster = nxt_zalloc(sizeof(nxt_mp_block_t) + n * sizeof(nxt_mp_page_t)); - - if (nxt_slow_path(cluster == NULL)) { - return NULL; - } - - /* NXT_MP_CLUSTER_BLOCK type is zero. */ - - cluster->size = mp->cluster_size; - - cluster->start = nxt_memalign(mp->page_alignment, mp->cluster_size); - if (nxt_slow_path(cluster->start == NULL)) { - nxt_free(cluster); - return NULL; - } - - n--; - cluster->pages[n].number = n; - nxt_queue_insert_head(&mp->free_pages, &cluster->pages[n].link); - - while (n != 0) { - n--; - cluster->pages[n].number = n; - nxt_queue_insert_before(&cluster->pages[n + 1].link, - &cluster->pages[n].link); - } - - nxt_rbtree_insert(&mp->blocks, &cluster->node); - - return cluster; -} - -#endif - - -static void * -nxt_mp_alloc_large(nxt_mp_t *mp, size_t alignment, size_t size, - nxt_bool_t freeable) -{ - u_char *p; - size_t aligned_size; - uint8_t type; - nxt_mp_block_t *block; - - nxt_mp_thread_assert(mp); - - /* Allocation must be less than 4G. */ - if (nxt_slow_path(size >= 0xFFFFFFFF)) { - return NULL; - } - - if (nxt_is_power_of_two(size)) { - block = nxt_malloc(sizeof(nxt_mp_block_t)); - if (nxt_slow_path(block == NULL)) { - return NULL; - } - - p = nxt_memalign(alignment, size); - if (nxt_slow_path(p == NULL)) { - nxt_free(block); - return NULL; - } - - type = NXT_MP_DISCRETE_BLOCK; - - } else { - aligned_size = nxt_align_size(size, sizeof(uintptr_t)); - - p = nxt_memalign(alignment, aligned_size + sizeof(nxt_mp_block_t)); - if (nxt_slow_path(p == NULL)) { - return NULL; - } - - block = (nxt_mp_block_t *) (p + aligned_size); - type = NXT_MP_EMBEDDED_BLOCK; - } - - block->type = type; - block->freeable = freeable; - block->size = size; - block->start = p; - - nxt_rbtree_insert(&mp->blocks, &block->node); - - return p; -} - - -static intptr_t -nxt_mp_rbtree_compare(nxt_rbtree_node_t *node1, nxt_rbtree_node_t *node2) -{ - nxt_mp_block_t *block1, *block2; - - block1 = (nxt_mp_block_t *) node1; - block2 = (nxt_mp_block_t *) node2; - - /* - * Shifting is necessary to prevent overflow of intptr_t when block1->start - * is much greater than block2->start or vice versa. - * - * It is safe to drop one bit since there cannot be adjacent addresses - * because of alignments and allocation sizes. Effectively this reduces - * the absolute values to fit into the magnitude of intptr_t. - */ - return ((uintptr_t) block1->start >> 1) - ((uintptr_t) block2->start >> 1); -} - - -void -nxt_mp_free(nxt_mp_t *mp, void *p) -{ - const char *err; - nxt_mp_block_t *block; - - nxt_mp_thread_assert(mp); - - nxt_debug_alloc("mp %p free(%p)", mp, p); - - block = nxt_mp_find_block(&mp->blocks, p); - - if (nxt_fast_path(block != NULL)) { - - if (block->type == NXT_MP_CLUSTER_BLOCK) { - err = nxt_mp_chunk_free(mp, block, p); - - if (nxt_fast_path(err == NULL)) { - return; - } - - } else if (nxt_fast_path(p == block->start)) { - - if (block->freeable) { - nxt_rbtree_delete(&mp->blocks, &block->node); - - if (block->type == NXT_MP_DISCRETE_BLOCK) { - nxt_free(block); - } - - nxt_free(p); - - return; - } - - err = "freed pointer points to non-freeable block: %p"; - - } else { - err = "freed pointer points to middle of block: %p"; - } - - } else { - err = "freed pointer is out of pool: %p"; - } - - nxt_thread_log_alert(err, p); -} - - -static nxt_mp_block_t * -nxt_mp_find_block(nxt_rbtree_t *tree, const u_char *p) -{ - nxt_mp_block_t *block; - nxt_rbtree_node_t *node, *sentinel; - - node = nxt_rbtree_root(tree); - sentinel = nxt_rbtree_sentinel(tree); - - while (node != sentinel) { - - block = (nxt_mp_block_t *) node; - - if (p < block->start) { - node = node->left; - - } else if (p >= block->start + block->size) { - node = node->right; - - } else { - return block; - } - } - - return NULL; -} - - -static const char * -nxt_mp_chunk_free(nxt_mp_t *mp, nxt_mp_block_t *cluster, u_char *p) -{ - u_char *start; - uintptr_t offset; - nxt_uint_t n, size, chunk; - nxt_queue_t *chunk_pages; - nxt_mp_page_t *page; - - n = (p - cluster->start) >> mp->page_size_shift; - start = cluster->start + (n << mp->page_size_shift); - - page = &cluster->pages[n]; - - if (nxt_slow_path(page->size == 0)) { - return "freed pointer points to already free page: %p"; - } - - if (nxt_slow_path(page->size == 0xFF)) { - return "freed pointer points to non-freeable page: %p"; - } - - size = page->size << mp->chunk_size_shift; - - if (size != mp->page_size) { - - offset = (uintptr_t) (p - start) & (mp->page_size - 1); - chunk = offset / size; - - if (nxt_slow_path(offset != chunk * size)) { - return "freed pointer points to wrong chunk: %p"; - } - - if (nxt_slow_path(nxt_mp_chunk_is_free(page->u.map, chunk))) { - return "freed pointer points to already free chunk: %p"; - } - - nxt_mp_chunk_set_free(page->u.map, chunk); - - if (page->u.map != 0xFFFFFFFF) { - page->chunks++; - - if (page->chunks == 1) { - /* - * Add the page to the head of pool chunk pages list - * of pages with free chunks. - */ - n = nxt_mp_chunk_pages_index(mp, size); - chunk_pages = &mp->chunk_pages[n]; - - nxt_queue_insert_head(chunk_pages, &page->link); - } - - nxt_mp_free_junk(p, size); - - return NULL; - - } else { - /* - * All chunks are free, remove the page from pool - * chunk pages list of pages with free chunks. - */ - nxt_queue_remove(&page->link); - } - - } else if (nxt_slow_path(p != start)) { - return "invalid pointer to chunk: %p"; - } - - /* Add the free page to the pool's free pages tree. */ - - page->size = 0; - nxt_queue_insert_head(&mp->free_pages, &page->link); - - nxt_mp_free_junk(p, size); - - /* Test if all pages in the cluster are free. */ - - n = mp->cluster_size >> mp->page_size_shift; - page = cluster->pages; - - do { - if (page->size != 0) { - return NULL; - } - - page++; - n--; - } while (n != 0); - - /* Free cluster. */ - - n = mp->cluster_size >> mp->page_size_shift; - page = cluster->pages; - - do { - nxt_queue_remove(&page->link); - page++; - n--; - } while (n != 0); - - nxt_rbtree_delete(&mp->blocks, &cluster->node); - - p = cluster->start; - - nxt_free(cluster); - nxt_free(p); - - return NULL; -} - - -void * -nxt_mp_nget(nxt_mp_t *mp, size_t size) -{ - void *p; - -#if !(NXT_DEBUG_MEMORY) - - if (size <= mp->page_size) { - p = nxt_mp_get_small(mp, &mp->nget_pages, size); - - } else { - p = nxt_mp_alloc_large(mp, NXT_MAX_ALIGNMENT, size, 0); - } - -#else - - p = nxt_mp_alloc_large(mp, NXT_MAX_ALIGNMENT, size, 0); - -#endif - - nxt_debug_alloc("mp %p nget(%uz): %p", mp, size, p); - - return p; -} - - -void * -nxt_mp_get(nxt_mp_t *mp, size_t size) -{ - void *p; - -#if !(NXT_DEBUG_MEMORY) - - if (size <= mp->page_size) { - size = nxt_max(size, NXT_MAX_ALIGNMENT); - p = nxt_mp_get_small(mp, &mp->get_pages, size); - - } else { - p = nxt_mp_alloc_large(mp, NXT_MAX_ALIGNMENT, size, 0); - } - -#else - - p = nxt_mp_alloc_large(mp, NXT_MAX_ALIGNMENT, size, 0); - -#endif - - nxt_debug_alloc("mp %p get(%uz): %p", mp, size, p); - - return p; -} - - -void * -nxt_mp_zget(nxt_mp_t *mp, size_t size) -{ - void *p; - - p = nxt_mp_get(mp, size); - - if (nxt_fast_path(p != NULL)) { - memset(p, 0, size); - } - - return p; -} - - -nxt_int_t -nxt_mp_cleanup(nxt_mp_t *mp, nxt_work_handler_t handler, - nxt_task_t *task, void *obj, void *data) -{ - nxt_work_t *work; - - work = nxt_mp_get(mp, sizeof(nxt_work_t)); - - if (nxt_slow_path(work == NULL)) { - return NXT_ERROR; - } - - work->next = mp->cleanup; - work->handler = handler; - work->task = task; - work->obj = obj; - work->data = data; - - mp->cleanup = work; - - return NXT_OK; -} - - -void * -nxt_mp_lvlhsh_alloc(void *pool, size_t size) -{ - return nxt_mp_align(pool, size, size); -} - - -void -nxt_mp_lvlhsh_free(void *pool, void *p) -{ - nxt_mp_free(pool, p); -} diff --git a/src/nxt_mp.h b/src/nxt_mp.h deleted file mode 100644 index a5aaabd1..00000000 --- a/src/nxt_mp.h +++ /dev/null @@ -1,119 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_MP_H_INCLUDED_ -#define _NXT_MP_H_INCLUDED_ - - -/* - * Memory pool keeps track of all allocations so they can be freed at once - * on pool destruction. A memory pool is not thread safe, so only one thread - * must work with the pool. If an allocation should be passed to another - * thread, it should be allocated with nxt_mp_retain() and then should be - * freed with nxt_mp_release(). These functions updates pool retention - * counter. Memory pools decrease number of malloc() and free() calls and - * thus reduces thread contention on locks in malloc library. Memory pools - * allow to make both freeable and non-freeable allocations. The freeable - * memory is allocated in fixed size chunks to decrease memory fragmentaiton - * on reallocations. The non-freeable memory is intended to allocate - * structures and other items which should be available until memory pool - * destruction. Due to allocation strategy described in nxt_mp.c memory pools - * may also improve data cache locality. - */ - -typedef struct nxt_mp_s nxt_mp_t; - - -/* - * nxt_mp_create() creates a memory pool and sets the pool's retention - * counter to 1. - */ -NXT_EXPORT nxt_mp_t *nxt_mp_create(size_t cluster_size, size_t page_alignment, - size_t page_size, size_t min_chunk_size) - NXT_MALLOC_LIKE; - -/* - * nxt_mp_destroy() destroys memory pool in spite of the pool's retention - * counter. - */ -NXT_EXPORT void nxt_mp_destroy(nxt_mp_t *mp); - -/* - * nxt_mp_retain() increases memory pool retention counter. - */ -NXT_EXPORT void nxt_mp_retain(nxt_mp_t *mp); - -/* - * nxt_mp_release() decreases memory pool retention counter. - * If the counter becomes zero the pool is destroyed. - */ -NXT_EXPORT void nxt_mp_release(nxt_mp_t *mp); - -/* nxt_mp_test_sizes() tests validity of memory pool parameters. */ -NXT_EXPORT nxt_bool_t nxt_mp_test_sizes(size_t cluster_size, - size_t page_alignment, size_t page_size, size_t min_chunk_size); - -/* nxt_mp_is_empty() tests that pool is empty. */ -NXT_EXPORT nxt_bool_t nxt_mp_is_empty(nxt_mp_t *mp); - - -/* - * nxt_mp_alloc() returns aligned freeable memory. - * The alignment is sutiable to allocate structures. - */ -NXT_EXPORT void *nxt_mp_alloc(nxt_mp_t *mp, size_t size) - NXT_MALLOC_LIKE; - - -/* - * nxt_mp_zalloc() returns zeroed aligned freeable memory. - * The alignment is sutiable to allocate structures. - */ -NXT_EXPORT void *nxt_mp_zalloc(nxt_mp_t *mp, size_t size) - NXT_MALLOC_LIKE; - -/* nxt_mp_align() returns aligned freeable memory. */ -NXT_EXPORT void *nxt_mp_align(nxt_mp_t *mp, size_t alignment, size_t size) - NXT_MALLOC_LIKE; - -/* nxt_mp_zalign() returns zeroed aligned freeable memory. */ -NXT_EXPORT void *nxt_mp_zalign(nxt_mp_t *mp, size_t alignment, size_t size) - NXT_MALLOC_LIKE; - -/* nxt_mp_free() frees freeable memory. */ -NXT_EXPORT void nxt_mp_free(nxt_mp_t *mp, void *p); - - -/* nxt_mp_nget() returns non-aligned non-freeable memory. */ -NXT_EXPORT void *nxt_mp_nget(nxt_mp_t *mp, size_t size) - NXT_MALLOC_LIKE; - -/* - * nxt_mp_get() returns aligned non-freeable memory. - * The alignment is sutiable to allocate structures. - */ -NXT_EXPORT void *nxt_mp_get(nxt_mp_t *mp, size_t size) - NXT_MALLOC_LIKE; - -/* - * nxt_mp_zget() returns zeroed aligned non-freeable memory. - * The alignment is sutiable to allocate structures. - */ -NXT_EXPORT void *nxt_mp_zget(nxt_mp_t *mp, size_t size) - NXT_MALLOC_LIKE; - - -NXT_EXPORT nxt_int_t nxt_mp_cleanup(nxt_mp_t *mp, nxt_work_handler_t handler, - nxt_task_t *task, void *obj, void *data); - - -NXT_EXPORT void nxt_mp_thread_adopt(nxt_mp_t *mp); - - -NXT_EXPORT void *nxt_mp_lvlhsh_alloc(void *pool, size_t size); -NXT_EXPORT void nxt_mp_lvlhsh_free(void *pool, void *p); - -#endif /* _NXT_MP_H_INCLUDED_ */ diff --git a/src/nxt_murmur_hash.c b/src/nxt_murmur_hash.c deleted file mode 100644 index 56bf2d4b..00000000 --- a/src/nxt_murmur_hash.c +++ /dev/null @@ -1,86 +0,0 @@ - -/* - * The code is based on the code by Austin Appleby, - * released to the public domain. - */ - -#include - - -uint32_t -nxt_murmur_hash2(const void *data, size_t len) -{ - uint32_t h, k; - const u_char *p; - const uint32_t m = 0x5BD1E995; - - p = data; - h = 0 ^ (uint32_t) len; - - while (len >= 4) { - k = p[0]; - k |= p[1] << 8; - k |= p[2] << 16; - k |= p[3] << 24; - - k *= m; - k ^= k >> 24; - k *= m; - - h *= m; - h ^= k; - - p += 4; - len -= 4; - } - - switch (len) { - case 3: - h ^= p[2] << 16; - /* Fall through. */ - case 2: - h ^= p[1] << 8; - /* Fall through. */ - case 1: - h ^= p[0]; - h *= m; - } - - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} - - -/* The MurmurHash2 for fixed 4 byte length. */ - -uint32_t -nxt_murmur_hash2_uint32(const void *data) -{ - uint32_t h, k; - const u_char *p; - const uint32_t m = 0x5BD1E995; - - p = data; - - k = p[0]; - k |= p[1] << 8; - k |= p[2] << 16; - k |= p[3] << 24; - - k *= m; - k ^= k >> 24; - k *= m; - - h = 0 ^ 4; - h *= m; - h ^= k; - - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} diff --git a/src/nxt_murmur_hash.h b/src/nxt_murmur_hash.h deleted file mode 100644 index 289dc5b0..00000000 --- a/src/nxt_murmur_hash.h +++ /dev/null @@ -1,15 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_MURMUR_HASH_H_INCLUDED_ -#define _NXT_MURMUR_HASH_H_INCLUDED_ - - -NXT_EXPORT uint32_t nxt_murmur_hash2(const void *data, size_t len); -NXT_EXPORT uint32_t nxt_murmur_hash2_uint32(const void *data); - - -#endif /* _NXT_MURMUR_HASH_H_INCLUDED_ */ diff --git a/src/nxt_nncq.h b/src/nxt_nncq.h deleted file mode 100644 index 6c9ab326..00000000 --- a/src/nxt_nncq.h +++ /dev/null @@ -1,162 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_NNCQ_H_INCLUDED_ -#define _NXT_NNCQ_H_INCLUDED_ - - -/* Numeric Naive Circular Queue */ - -#define NXT_NNCQ_SIZE 16384 - -typedef uint32_t nxt_nncq_atomic_t; -typedef uint16_t nxt_nncq_cycle_t; - -typedef struct { - nxt_nncq_atomic_t head; - nxt_nncq_atomic_t entries[NXT_NNCQ_SIZE]; - nxt_nncq_atomic_t tail; -} nxt_nncq_t; - - -static inline nxt_nncq_atomic_t -nxt_nncq_head(nxt_nncq_t const volatile *q) -{ - return q->head; -} - - -static inline nxt_nncq_atomic_t -nxt_nncq_tail(nxt_nncq_t const volatile *q) -{ - return q->tail; -} - - -static inline void -nxt_nncq_tail_cmp_inc(nxt_nncq_t volatile *q, nxt_nncq_atomic_t t) -{ - nxt_atomic_cmp_set(&q->tail, t, t + 1); -} - - -static inline nxt_nncq_atomic_t -nxt_nncq_index(nxt_nncq_t const volatile *q, nxt_nncq_atomic_t i) -{ - return i % NXT_NNCQ_SIZE; -} - - -static inline nxt_nncq_atomic_t -nxt_nncq_map(nxt_nncq_t const volatile *q, nxt_nncq_atomic_t i) -{ - return i % NXT_NNCQ_SIZE; -} - - -static inline nxt_nncq_cycle_t -nxt_nncq_cycle(nxt_nncq_t const volatile *q, nxt_nncq_atomic_t i) -{ - return i / NXT_NNCQ_SIZE; -} - - -static inline nxt_nncq_cycle_t -nxt_nncq_next_cycle(nxt_nncq_t const volatile *q, nxt_nncq_cycle_t i) -{ - return i + 1; -} - - -static inline nxt_nncq_atomic_t -nxt_nncq_new_entry(nxt_nncq_t const volatile *q, nxt_nncq_cycle_t cycle, - nxt_nncq_atomic_t i) -{ - return cycle * NXT_NNCQ_SIZE + (i % NXT_NNCQ_SIZE); -} - - -static inline nxt_nncq_atomic_t -nxt_nncq_empty(nxt_nncq_t const volatile *q) -{ - return NXT_NNCQ_SIZE; -} - - -static inline void -nxt_nncq_init(nxt_nncq_t volatile *q) -{ - q->head = NXT_NNCQ_SIZE; - nxt_memzero((void *) q->entries, NXT_NNCQ_SIZE * sizeof(nxt_nncq_atomic_t)); - q->tail = NXT_NNCQ_SIZE; -} - - -static inline void -nxt_nncq_enqueue(nxt_nncq_t volatile *q, nxt_nncq_atomic_t val) -{ - nxt_nncq_cycle_t e_cycle, t_cycle; - nxt_nncq_atomic_t n, t, e, j; - - for ( ;; ) { - t = nxt_nncq_tail(q); - j = nxt_nncq_map(q, t); - e = q->entries[j]; - - e_cycle = nxt_nncq_cycle(q, e); - t_cycle = nxt_nncq_cycle(q, t); - - if (e_cycle == t_cycle) { - nxt_nncq_tail_cmp_inc(q, t); - continue; - } - - if (nxt_nncq_next_cycle(q, e_cycle) != t_cycle) { - continue; - } - - n = nxt_nncq_new_entry(q, t_cycle, val); - - if (nxt_atomic_cmp_set(&q->entries[j], e, n)) { - break; - } - } - - nxt_nncq_tail_cmp_inc(q, t); -} - - -static inline nxt_nncq_atomic_t -nxt_nncq_dequeue(nxt_nncq_t volatile *q) -{ - nxt_nncq_cycle_t e_cycle, h_cycle; - nxt_nncq_atomic_t h, j, e; - - for ( ;; ) { - h = nxt_nncq_head(q); - j = nxt_nncq_map(q, h); - e = q->entries[j]; - - e_cycle = nxt_nncq_cycle(q, e); - h_cycle = nxt_nncq_cycle(q, h); - - if (e_cycle != h_cycle) { - if (nxt_nncq_next_cycle(q, e_cycle) == h_cycle) { - return nxt_nncq_empty(q); - } - - continue; - } - - if (nxt_atomic_cmp_set(&q->head, h, h + 1)) { - break; - } - } - - return nxt_nncq_index(q, e); -} - - -#endif /* _NXT_NNCQ_H_INCLUDED_ */ diff --git a/src/nxt_nvbcq.h b/src/nxt_nvbcq.h deleted file mode 100644 index e164615b..00000000 --- a/src/nxt_nvbcq.h +++ /dev/null @@ -1,146 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_NVBCQ_H_INCLUDED_ -#define _NXT_NVBCQ_H_INCLUDED_ - - -/* Numeric VBart Circular Queue */ - -#define NXT_NVBCQ_SIZE 16384 - -typedef uint32_t nxt_nvbcq_atomic_t; - -struct nxt_nvbcq_s { - nxt_nvbcq_atomic_t head; - nxt_nvbcq_atomic_t entries[NXT_NVBCQ_SIZE]; - nxt_nvbcq_atomic_t tail; -}; - -typedef struct nxt_nvbcq_s nxt_nvbcq_t; - - -static inline nxt_nvbcq_atomic_t -nxt_nvbcq_head(nxt_nvbcq_t const volatile *q) -{ - return q->head; -} - - -static inline nxt_nvbcq_atomic_t -nxt_nvbcq_tail(nxt_nvbcq_t const volatile *q) -{ - return q->tail; -} - - -static inline void -nxt_nvbcq_tail_cmp_inc(nxt_nvbcq_t volatile *q, nxt_nvbcq_atomic_t t) -{ - nxt_atomic_cmp_set(&q->tail, t, t + 1); -} - - -static inline nxt_nvbcq_atomic_t -nxt_nvbcq_index(nxt_nvbcq_t const volatile *q, nxt_nvbcq_atomic_t i) -{ - return i % NXT_NVBCQ_SIZE; -} - - -static inline nxt_nvbcq_atomic_t -nxt_nvbcq_map(nxt_nvbcq_t const volatile *q, nxt_nvbcq_atomic_t i) -{ - return i % NXT_NVBCQ_SIZE; -} - - -static inline nxt_nvbcq_atomic_t -nxt_nvbcq_empty(nxt_nvbcq_t const volatile *q) -{ - return NXT_NVBCQ_SIZE; -} - - -static inline void -nxt_nvbcq_init(nxt_nvbcq_t volatile *q) -{ - nxt_nvbcq_atomic_t i; - - q->head = 0; - - for (i = 0; i < NXT_NVBCQ_SIZE; i++) { - q->entries[i] = NXT_NVBCQ_SIZE; - } - - q->tail = NXT_NVBCQ_SIZE; -} - - -static inline void -nxt_nvbcq_enqueue(nxt_nvbcq_t volatile *q, nxt_nvbcq_atomic_t val) -{ - nxt_nvbcq_atomic_t t, h, i; - - t = nxt_nvbcq_tail(q); - h = t - NXT_NVBCQ_SIZE; - - for ( ;; ) { - i = nxt_nvbcq_map(q, t); - - if (q->entries[i] == NXT_NVBCQ_SIZE - && nxt_atomic_cmp_set(&q->entries[i], NXT_NVBCQ_SIZE, val)) - { - nxt_nvbcq_tail_cmp_inc(q, t); - return; - } - - if ((t - h) == NXT_NVBCQ_SIZE) { - h = nxt_nvbcq_head(q); - - if ((t - h) == NXT_NVBCQ_SIZE) { - return; - } - } - - t++; - } -} - - -static inline nxt_nvbcq_atomic_t -nxt_nvbcq_dequeue(nxt_nvbcq_t volatile *q) -{ - nxt_nvbcq_atomic_t h, t, i, e; - - h = nxt_nvbcq_head(q); - t = h + NXT_NVBCQ_SIZE; - - for ( ;; ) { - i = nxt_nvbcq_map(q, h); - e = q->entries[i]; - - if (e < NXT_NVBCQ_SIZE - && nxt_atomic_cmp_set(&q->entries[i], e, NXT_NVBCQ_SIZE)) - { - nxt_atomic_cmp_set(&q->head, h, h + 1); - - return e; - } - - if ((t - h) == NXT_NVBCQ_SIZE) { - t = nxt_nvbcq_tail(q); - - if ((t - h) == NXT_NVBCQ_SIZE) { - return NXT_NVBCQ_SIZE; - } - } - - h++; - } -} - - -#endif /* _NXT_NVBCQ_H_INCLUDED_ */ diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c deleted file mode 100644 index 8f66f45b..00000000 --- a/src/nxt_openssl.c +++ /dev/null @@ -1,1817 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include - -#define OPENSSL_SUPPRESS_DEPRECATED - -#include -#include -#include -#include -#include -#include -#include - - -typedef struct { - SSL *session; - nxt_conn_t *conn; - - int ssl_error; - uint8_t times; /* 2 bits */ - uint8_t handshake; /* 1 bit */ - - nxt_tls_conf_t *conf; - nxt_buf_mem_t buffer; -} nxt_openssl_conn_t; - - -struct nxt_tls_ticket_s { - u_char name[16]; - u_char hmac_key[32]; - u_char aes_key[32]; - uint8_t size; -}; - - -struct nxt_tls_tickets_s { - nxt_uint_t count; - nxt_tls_ticket_t tickets[]; -}; - - -typedef enum { - NXT_OPENSSL_HANDSHAKE = 0, - NXT_OPENSSL_READ, - NXT_OPENSSL_WRITE, - NXT_OPENSSL_SHUTDOWN, -} nxt_openssl_io_t; - - -static nxt_int_t nxt_openssl_library_init(nxt_task_t *task); -static void nxt_openssl_library_free(nxt_task_t *task); -#if OPENSSL_VERSION_NUMBER < 0x10100004L -static nxt_int_t nxt_openssl_locks_init(void); -static void nxt_openssl_lock(int mode, int type, const char *file, int line); -static unsigned long nxt_openssl_thread_id(void); -static void nxt_openssl_locks_free(void); -#endif -static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp, - nxt_tls_init_t *tls_init, nxt_bool_t last); -static nxt_int_t nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, - nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t single); -#if (NXT_HAVE_OPENSSL_CONF_CMD) -static nxt_int_t nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, - nxt_conf_value_t *value, nxt_mp_t *mp); -#endif -#if (NXT_HAVE_OPENSSL_TLSEXT) -static nxt_int_t nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, - nxt_tls_init_t *tls_init, nxt_mp_t *mp); -static int nxt_tls_ticket_key_callback(SSL *s, unsigned char *name, - unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc); -#endif -static void nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, - time_t timeout); -static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, - nxt_tls_conf_t *conf, nxt_mp_t *mp); -static nxt_int_t nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, - void *data); -static nxt_int_t nxt_openssl_bundle_hash_insert(nxt_task_t *task, - nxt_lvlhsh_t *lvlhsh, nxt_tls_bundle_hash_item_t *item, nxt_mp_t * mp); -static nxt_int_t nxt_openssl_servername(SSL *s, int *ad, void *arg); -static nxt_tls_bundle_conf_t *nxt_openssl_find_ctx(nxt_tls_conf_t *conf, - nxt_str_t *sn); -static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); -static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, - nxt_conn_t *c); -static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data); -static ssize_t nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); -static ssize_t nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb); -static ssize_t nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, - void *buf, size_t size); -static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, - void *data); -static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, - int ret, nxt_err_t sys_err, nxt_openssl_io_t io); -static void nxt_openssl_conn_io_shutdown_timeout(nxt_task_t *task, void *obj, - void *data); -static void nxt_cdecl nxt_openssl_conn_error(nxt_task_t *task, - nxt_err_t err, const char *fmt, ...); -static nxt_uint_t nxt_openssl_log_error_level(nxt_err_t err); - - -const nxt_tls_lib_t nxt_openssl_lib = { - .library_init = nxt_openssl_library_init, - .library_free = nxt_openssl_library_free, - - .server_init = nxt_openssl_server_init, - .server_free = nxt_openssl_server_free, -}; - - -static nxt_conn_io_t nxt_openssl_conn_io = { - .read = nxt_conn_io_read, - .recvbuf = nxt_openssl_conn_io_recvbuf, - - .write = nxt_conn_io_write, - .sendbuf = nxt_openssl_conn_io_sendbuf, - - .shutdown = nxt_openssl_conn_io_shutdown, -}; - - -static long nxt_openssl_version; -static int nxt_openssl_connection_index; - - -static nxt_int_t -nxt_openssl_library_init(nxt_task_t *task) -{ - int index; - - if (nxt_fast_path(nxt_openssl_version != 0)) { - return NXT_OK; - } - -#if OPENSSL_VERSION_NUMBER >= 0x10100003L - - OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); - -#else - { - nxt_int_t ret; - - SSL_load_error_strings(); - - OPENSSL_config(NULL); - - /* - * SSL_library_init(3): - * - * SSL_library_init() always returns "1", - * so it is safe to discard the return value. - */ - (void) SSL_library_init(); - - ret = nxt_openssl_locks_init(); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - } - -#endif - - nxt_openssl_version = SSLeay(); - - nxt_log(task, NXT_LOG_INFO, "%s, %xl", - SSLeay_version(SSLEAY_VERSION), nxt_openssl_version); - -#ifndef SSL_OP_NO_COMPRESSION - { - /* - * Disable gzip compression in OpenSSL prior to 1.0.0 - * version, this saves about 522K per connection. - */ - int n; - STACK_OF(SSL_COMP) *ssl_comp_methods; - - ssl_comp_methods = SSL_COMP_get_compression_methods(); - - for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) { - (void) sk_SSL_COMP_pop(ssl_comp_methods); - } - } -#endif - - index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); - - if (index == -1) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "SSL_get_ex_new_index() failed"); - return NXT_ERROR; - } - - nxt_openssl_connection_index = index; - - return NXT_OK; -} - - -#if OPENSSL_VERSION_NUMBER >= 0x10100003L - -static void -nxt_openssl_library_free(nxt_task_t *task) -{ -} - -#else - -static nxt_thread_mutex_t *nxt_openssl_locks; - -static nxt_int_t -nxt_openssl_locks_init(void) -{ - int i, n; - nxt_int_t ret; - - n = CRYPTO_num_locks(); - - nxt_openssl_locks = OPENSSL_malloc(n * sizeof(nxt_thread_mutex_t)); - if (nxt_slow_path(nxt_openssl_locks == NULL)) { - return NXT_ERROR; - } - - for (i = 0; i < n; i++) { - ret = nxt_thread_mutex_create(&nxt_openssl_locks[i]); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - } - - CRYPTO_set_locking_callback(nxt_openssl_lock); - - CRYPTO_set_id_callback(nxt_openssl_thread_id); - - return NXT_OK; -} - - -static void -nxt_openssl_lock(int mode, int type, const char *file, int line) -{ - nxt_thread_mutex_t *lock; - - lock = &nxt_openssl_locks[type]; - - if ((mode & CRYPTO_LOCK) != 0) { - (void) nxt_thread_mutex_lock(lock); - - } else { - (void) nxt_thread_mutex_unlock(lock); - } -} - - -static u_long -nxt_openssl_thread_id(void) -{ - return (u_long) nxt_thread_handle(); -} - - -static void -nxt_openssl_library_free(nxt_task_t *task) -{ - nxt_openssl_locks_free(); -} - - -static void -nxt_openssl_locks_free(void) -{ - int i, n; - - n = CRYPTO_num_locks(); - - CRYPTO_set_locking_callback(NULL); - - for (i = 0; i < n; i++) { - nxt_thread_mutex_destroy(&nxt_openssl_locks[i]); - } - - OPENSSL_free(nxt_openssl_locks); -} - -#endif - - -static nxt_int_t -nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp, - nxt_tls_init_t *tls_init, nxt_bool_t last) -{ - SSL_CTX *ctx; - const char *ca_certificate; - nxt_tls_conf_t *conf; - STACK_OF(X509_NAME) *list; - nxt_tls_bundle_conf_t *bundle; - - ctx = SSL_CTX_new(SSLv23_server_method()); - if (ctx == NULL) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_new() failed"); - return NXT_ERROR; - } - - conf = tls_init->conf; - - bundle = conf->bundle; - nxt_assert(bundle != NULL); - - bundle->ctx = ctx; - -#ifdef SSL_OP_NO_RENEGOTIATION - /* Renegration is not currently supported. */ - SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); -#endif - -#ifdef SSL_OP_NO_COMPRESSION - /* - * Disable gzip compression in OpenSSL 1.0.0, - * this saves about 522K per connection. - */ - SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); -#endif - -#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF - /* Request SSL_ERROR_ZERO_RETURN on EOF. */ - SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF); -#endif - -#ifdef SSL_MODE_RELEASE_BUFFERS - - if (nxt_openssl_version >= 10001078) { - /* - * Allow to release read and write buffers in OpenSSL 1.0.0, - * this saves about 34K per idle connection. It is not safe - * before OpenSSL 1.0.1h (CVE-2010-5298). - */ - SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); - } - -#endif - - if (nxt_openssl_chain_file(task, ctx, conf, mp, - last && bundle->next == NULL) - != NXT_OK) - { - goto fail; - } -/* - key = conf->certificate_key; - - if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "SSL_CTX_use_PrivateKey_file(\"%s\") failed", - key); - goto fail; - } -*/ - - if (conf->ciphers) { /* else use system crypto policy */ - if (SSL_CTX_set_cipher_list(ctx, conf->ciphers) == 0) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "SSL_CTX_set_cipher_list(\"%s\") failed", - conf->ciphers); - goto fail; - } - } - -#if (NXT_HAVE_OPENSSL_CONF_CMD) - if (tls_init->conf_cmds != NULL - && nxt_ssl_conf_commands(task, ctx, tls_init->conf_cmds, mp) != NXT_OK) - { - goto fail; - } -#endif - - nxt_ssl_session_cache(ctx, tls_init->cache_size, tls_init->timeout); - -#if (NXT_HAVE_OPENSSL_TLSEXT) - if (nxt_tls_ticket_keys(task, ctx, tls_init, mp) != NXT_OK) { - goto fail; - } -#endif - - SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - - if (conf->ca_certificate != NULL) { - - /* TODO: verify callback */ - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); - - /* TODO: verify depth */ - SSL_CTX_set_verify_depth(ctx, 1); - - ca_certificate = conf->ca_certificate; - - if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "SSL_CTX_load_verify_locations(\"%s\") failed", - ca_certificate); - goto fail; - } - - list = SSL_load_client_CA_file(ca_certificate); - - if (list == NULL) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "SSL_load_client_CA_file(\"%s\") failed", - ca_certificate); - goto fail; - } - - /* - * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and - * 0.9.8 versions always leaves an error in the error queue. - */ - ERR_clear_error(); - - SSL_CTX_set_client_CA_list(ctx, list); - } - - if (last) { - conf->conn_init = nxt_openssl_conn_init; - - if (bundle->next != NULL) { - SSL_CTX_set_tlsext_servername_callback(ctx, nxt_openssl_servername); - } - } - - return NXT_OK; - -fail: - - SSL_CTX_free(ctx); - -#if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ - && OPENSSL_VERSION_NUMBER < 0x1010101fL) - RAND_keep_random_devices_open(0); -#endif - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf, - nxt_mp_t *mp, nxt_bool_t single) -{ - BIO *bio; - X509 *cert, *ca; - long reason; - EVP_PKEY *key; - nxt_int_t ret; - nxt_tls_bundle_conf_t *bundle; - - ret = NXT_ERROR; - cert = NULL; - - bio = BIO_new(BIO_s_fd()); - if (bio == NULL) { - goto end; - } - - bundle = conf->bundle; - - BIO_set_fd(bio, bundle->chain_file, BIO_CLOSE); - - cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); - if (cert == NULL) { - goto end; - } - - if (SSL_CTX_use_certificate(ctx, cert) != 1) { - goto end; - } - - if (!single && nxt_openssl_cert_get_names(task, cert, conf, mp) != NXT_OK) { - goto clean; - } - - for ( ;; ) { - ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); - - if (ca == NULL) { - reason = ERR_GET_REASON(ERR_peek_last_error()); - if (reason != PEM_R_NO_START_LINE) { - goto end; - } - - ERR_clear_error(); - break; - } - - /* - * Note that ca isn't freed if it was successfully added to the chain, - * while the main certificate needs a X509_free() call, since - * its reference count is increased by SSL_CTX_use_certificate(). - */ -#ifdef SSL_CTX_add0_chain_cert - if (SSL_CTX_add0_chain_cert(ctx, ca) != 1) { -#else - if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) { -#endif - X509_free(ca); - goto end; - } - } - - if (BIO_reset(bio) != 0) { - goto end; - } - - key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - if (key == NULL) { - goto end; - } - - if (SSL_CTX_use_PrivateKey(ctx, key) == 1) { - ret = NXT_OK; - } - - EVP_PKEY_free(key); - -end: - - if (ret != NXT_OK) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "nxt_openssl_chain_file() failed"); - } - -clean: - - BIO_free(bio); - X509_free(cert); - - return ret; -} - - -#if (NXT_HAVE_OPENSSL_CONF_CMD) - -static nxt_int_t -nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, nxt_conf_value_t *conf, - nxt_mp_t *mp) -{ - int ret; - char *zcmd, *zvalue; - uint32_t index; - nxt_str_t cmd, value; - SSL_CONF_CTX *cctx; - nxt_conf_value_t *member; - - cctx = SSL_CONF_CTX_new(); - if (nxt_slow_path(cctx == NULL)) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "SSL_CONF_CTX_new() failed"); - return NXT_ERROR; - } - - SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE - | SSL_CONF_FLAG_SERVER - | SSL_CONF_FLAG_CERTIFICATE - | SSL_CONF_FLAG_SHOW_ERRORS); - - SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); - - index = 0; - - for ( ;; ) { - member = nxt_conf_next_object_member(conf, &cmd, &index); - if (nxt_slow_path(member == NULL)) { - break; - } - - nxt_conf_get_string(member, &value); - - zcmd = nxt_str_cstrz(mp, &cmd); - zvalue = nxt_str_cstrz(mp, &value); - - if (nxt_slow_path(zcmd == NULL || zvalue == NULL)) { - goto fail; - } - - ret = SSL_CONF_cmd(cctx, zcmd, zvalue); - if (ret == -2) { - nxt_openssl_log_error(task, NXT_LOG_ERR, - "unknown command \"%s\" in " - "\"conf_commands\" option", zcmd); - goto fail; - } - - if (ret <= 0) { - nxt_openssl_log_error(task, NXT_LOG_ERR, - "invalid value \"%s\" for command \"%s\" " - "in \"conf_commands\" option", - zvalue, zcmd); - goto fail; - } - - nxt_debug(task, "SSL_CONF_cmd(\"%s\", \"%s\")", zcmd, zvalue); - } - - if (SSL_CONF_CTX_finish(cctx) != 1) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "SSL_CONF_finish() failed"); - goto fail; - } - - SSL_CONF_CTX_free(cctx); - - return NXT_OK; - -fail: - - SSL_CONF_CTX_free(cctx); - - return NXT_ERROR; -} - -#endif - -#if (NXT_HAVE_OPENSSL_TLSEXT) - -static nxt_int_t -nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_init_t *tls_init, - nxt_mp_t *mp) -{ - size_t len; - uint32_t i; - nxt_str_t value; - nxt_uint_t count; - nxt_conf_value_t *member, *tickets_conf; - nxt_tls_ticket_t *ticket; - nxt_tls_tickets_t *tickets; - u_char buf[80]; - - tickets_conf = tls_init->tickets_conf; - - if (tickets_conf == NULL) { - goto no_ticket; - } - - if (nxt_conf_type(tickets_conf) == NXT_CONF_BOOLEAN) { - if (nxt_conf_get_boolean(tickets_conf) == 0) { - goto no_ticket; - } - - return NXT_OK; - } - - count = nxt_conf_array_elements_count_or_1(tickets_conf); - - if (count == 0) { - goto no_ticket; - } - -#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB - - tickets = nxt_mp_get(mp, sizeof(nxt_tls_tickets_t) - + count * sizeof(nxt_tls_ticket_t)); - if (nxt_slow_path(tickets == NULL)) { - return NXT_ERROR; - } - - tickets->count = count; - tls_init->conf->tickets = tickets; - i = 0; - - do { - ticket = &tickets->tickets[i]; - - i++; - - member = nxt_conf_get_array_element_or_itself(tickets_conf, count - i); - if (member == NULL) { - break; - } - - nxt_conf_get_string(member, &value); - - len = nxt_base64_decode(buf, value.start, value.length); - - nxt_memcpy(ticket->name, buf, 16); - - if (len == 48) { - nxt_memcpy(ticket->aes_key, buf + 16, 16); - nxt_memcpy(ticket->hmac_key, buf + 32, 16); - ticket->size = 16; - - } else { - nxt_memcpy(ticket->hmac_key, buf + 16, 32); - nxt_memcpy(ticket->aes_key, buf + 48, 32); - ticket->size = 32; - } - - } while (i < count); - - if (SSL_CTX_set_tlsext_ticket_key_cb(ctx, nxt_tls_ticket_key_callback) - == 0) - { - nxt_openssl_log_error(task, NXT_LOG_ALERT, - "Unit was built with Session Tickets support, however, " - "now it is linked dynamically to an OpenSSL library " - "which has no tlsext support, therefore Session Tickets " - "are not available"); - - return NXT_ERROR; - } - - return NXT_OK; - -#else - nxt_alert(task, "Setting custom session ticket keys is not supported with " - "this version of OpenSSL library"); - - return NXT_ERROR; - -#endif - -no_ticket: - - SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); - - return NXT_OK; -} - - -#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB - -static int -nxt_tls_ticket_key_callback(SSL *s, unsigned char *name, unsigned char *iv, - EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc) -{ - nxt_uint_t i; - nxt_conn_t *c; - const EVP_MD *digest; - const EVP_CIPHER *cipher; - nxt_tls_ticket_t *ticket; - nxt_openssl_conn_t *tls; - - c = SSL_get_ex_data(s, nxt_openssl_connection_index); - - if (nxt_slow_path(c == NULL)) { - nxt_thread_log_alert("SSL_get_ex_data() failed"); - return -1; - } - - tls = c->u.tls; - ticket = tls->conf->tickets->tickets; - - i = 0; - - if (enc == 1) { - /* encrypt session ticket */ - - nxt_debug(c->socket.task, "TLS session ticket encrypt"); - - cipher = (ticket[0].size == 16) ? EVP_aes_128_cbc() : EVP_aes_256_cbc(); - - if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) { - nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, - "RAND_bytes() failed"); - return -1; - } - - nxt_memcpy(name, ticket[0].name, 16); - - if (EVP_EncryptInit_ex(ectx, cipher, NULL, ticket[0].aes_key, iv) != 1) - { - nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, - "EVP_EncryptInit_ex() failed"); - return -1; - } - - } else { - /* decrypt session ticket */ - - do { - if (memcmp(name, ticket[i].name, 16) == 0) { - goto found; - } - - } while (++i < tls->conf->tickets->count); - - nxt_debug(c->socket.task, "TLS session ticket decrypt, key not found"); - - return 0; - - found: - - nxt_debug(c->socket.task, - "TLS session ticket decrypt, key number: \"%d\"", i); - - enc = (i == 0) ? 1 : 2 /* renew */; - - cipher = (ticket[i].size == 16) ? EVP_aes_128_cbc() : EVP_aes_256_cbc(); - - if (EVP_DecryptInit_ex(ectx, cipher, NULL, ticket[i].aes_key, iv) != 1) - { - nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, - "EVP_DecryptInit_ex() failed"); - return -1; - } - } - -#ifdef OPENSSL_NO_SHA256 - digest = EVP_sha1(); -#else - digest = EVP_sha256(); -#endif - - if (HMAC_Init_ex(hctx, ticket[i].hmac_key, ticket[i].size, digest, NULL) - != 1) - { - nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, - "HMAC_Init_ex() failed"); - return -1; - } - - return enc; -} - -#endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */ - -#endif /* NXT_HAVE_OPENSSL_TLSEXT */ - - -static void -nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, time_t timeout) -{ - if (cache_size == 0) { - SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); - return; - } - - SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); - - SSL_CTX_sess_set_cache_size(ctx, cache_size); - - SSL_CTX_set_timeout(ctx, (long) timeout); -} - - -static nxt_uint_t -nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf, - nxt_mp_t *mp) -{ - int len; - nxt_str_t domain, str; - X509_NAME *x509_name; - nxt_uint_t i, n; - GENERAL_NAME *name; - nxt_tls_bundle_conf_t *bundle; - STACK_OF(GENERAL_NAME) *alt_names; - nxt_tls_bundle_hash_item_t *item; - - bundle = conf->bundle; - - alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - - if (alt_names != NULL) { - n = sk_GENERAL_NAME_num(alt_names); - - for (i = 0; i != n; i++) { - name = sk_GENERAL_NAME_value(alt_names, i); - - if (name->type != GEN_DNS) { - continue; - } - - str.length = ASN1_STRING_length(name->d.dNSName); -#if OPENSSL_VERSION_NUMBER > 0x10100000L - str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); -#else - str.start = ASN1_STRING_data(name->d.dNSName); -#endif - - domain.start = nxt_mp_nget(mp, str.length); - if (nxt_slow_path(domain.start == NULL)) { - goto fail; - } - - domain.length = str.length; - nxt_memcpy_lowcase(domain.start, str.start, str.length); - - item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); - if (nxt_slow_path(item == NULL)) { - goto fail; - } - - item->name = domain; - item->bundle = bundle; - - if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, - item, mp) - == NXT_ERROR) - { - goto fail; - } - } - - sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); - - } else { - x509_name = X509_get_subject_name(cert); - len = X509_NAME_get_text_by_NID(x509_name, NID_commonName, - NULL, 0); - if (len <= 0) { - nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither " - "Subject Alternative Name nor Common Name", &bundle->name); - return NXT_OK; - } - - domain.start = nxt_mp_nget(mp, len + 1); - if (nxt_slow_path(domain.start == NULL)) { - return NXT_ERROR; - } - - domain.length = X509_NAME_get_text_by_NID(x509_name, NID_commonName, - (char *) domain.start, - len + 1); - nxt_memcpy_lowcase(domain.start, domain.start, domain.length); - - item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); - if (nxt_slow_path(item == NULL)) { - return NXT_ERROR; - } - - item->name = domain; - item->bundle = bundle; - - if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, item, - mp) - == NXT_ERROR) - { - return NXT_ERROR; - } - } - - return NXT_OK; - -fail: - - sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); - - return NXT_ERROR; -} - - -static const nxt_lvlhsh_proto_t nxt_openssl_bundle_hash_proto - nxt_aligned(64) = -{ - NXT_LVLHSH_DEFAULT, - nxt_openssl_bundle_hash_test, - nxt_mp_lvlhsh_alloc, - nxt_mp_lvlhsh_free, -}; - - -static nxt_int_t -nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_tls_bundle_hash_item_t *item; - - item = data; - - return nxt_strstr_eq(&lhq->key, &item->name) ? NXT_OK : NXT_DECLINED; -} - - -static nxt_int_t -nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, - nxt_tls_bundle_hash_item_t *item, nxt_mp_t *mp) -{ - nxt_str_t str; - nxt_int_t ret; - nxt_lvlhsh_query_t lhq; - nxt_tls_bundle_hash_item_t *old; - - str = item->name; - - if (item->name.start[0] == '*') { - item->name.start++; - item->name.length--; - - if (item->name.length == 0 || item->name.start[0] != '.') { - nxt_log(task, NXT_LOG_WARN, "ignored invalid name \"%V\" " - "in certificate \"%V\": missing \".\" " - "after wildcard symbol", &str, &item->bundle->name); - return NXT_OK; - } - } - - lhq.pool = mp; - lhq.key = item->name; - lhq.value = item; - lhq.proto = &nxt_openssl_bundle_hash_proto; - lhq.replace = 0; - lhq.key_hash = nxt_murmur_hash2(item->name.start, item->name.length); - - ret = nxt_lvlhsh_insert(lvlhsh, &lhq); - if (nxt_fast_path(ret == NXT_OK)) { - nxt_debug(task, "name \"%V\" for certificate \"%V\" is inserted", - &str, &item->bundle->name); - return NXT_OK; - } - - if (nxt_fast_path(ret == NXT_DECLINED)) { - old = lhq.value; - if (old->bundle != item->bundle) { - nxt_log(task, NXT_LOG_WARN, "ignored duplicate name \"%V\" " - "in certificate \"%V\", identical name appears in \"%V\"", - &str, &old->bundle->name, &item->bundle->name); - - old->bundle = item->bundle; - } - - return NXT_OK; - } - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_openssl_servername(SSL *s, int *ad, void *arg) -{ - nxt_str_t str; - nxt_uint_t i; - nxt_conn_t *c; - const char *servername; - nxt_tls_conf_t *conf; - nxt_openssl_conn_t *tls; - nxt_tls_bundle_conf_t *bundle; - - c = SSL_get_ex_data(s, nxt_openssl_connection_index); - - if (nxt_slow_path(c == NULL)) { - nxt_thread_log_alert("SSL_get_ex_data() failed"); - return SSL_TLSEXT_ERR_ALERT_FATAL; - } - - servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); - - if (servername == NULL) { - nxt_debug(c->socket.task, "SSL_get_servername(): NULL"); - goto done; - } - - str.length = nxt_strlen(servername); - if (str.length == 0) { - nxt_debug(c->socket.task, "SSL_get_servername(): \"\" is empty"); - goto done; - } - - if (servername[0] == '.') { - nxt_debug(c->socket.task, "ignored the server name \"%s\": " - "leading \".\"", servername); - goto done; - } - - nxt_debug(c->socket.task, "tls with servername \"%s\"", servername); - - str.start = nxt_mp_nget(c->mem_pool, str.length); - if (nxt_slow_path(str.start == NULL)) { - return SSL_TLSEXT_ERR_ALERT_FATAL; - } - - nxt_memcpy_lowcase(str.start, (const u_char *) servername, str.length); - - tls = c->u.tls; - conf = tls->conf; - - bundle = nxt_openssl_find_ctx(conf, &str); - - if (bundle == NULL) { - for (i = 1; i < str.length; i++) { - if (str.start[i] == '.') { - str.start += i; - str.length -= i; - - bundle = nxt_openssl_find_ctx(conf, &str); - break; - } - } - } - - if (bundle != NULL) { - nxt_debug(c->socket.task, "new tls context found for \"%V\": \"%V\" " - "(old: \"%V\")", &str, &bundle->name, - &conf->bundle->name); - - if (bundle != conf->bundle) { - if (SSL_set_SSL_CTX(s, bundle->ctx) == NULL) { - nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, - "SSL_set_SSL_CTX() failed"); - - return SSL_TLSEXT_ERR_ALERT_FATAL; - } - } - } - -done: - - return SSL_TLSEXT_ERR_OK; -} - - -static nxt_tls_bundle_conf_t * -nxt_openssl_find_ctx(nxt_tls_conf_t *conf, nxt_str_t *sn) -{ - nxt_int_t ret; - nxt_lvlhsh_query_t lhq; - nxt_tls_bundle_hash_item_t *item; - - lhq.key_hash = nxt_murmur_hash2(sn->start, sn->length); - lhq.key = *sn; - lhq.proto = &nxt_openssl_bundle_hash_proto; - - ret = nxt_lvlhsh_find(&conf->bundle_hash, &lhq); - if (ret != NXT_OK) { - return NULL; - } - - item = lhq.value; - - return item->bundle; -} - - -static void -nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf) -{ - nxt_tls_bundle_conf_t *bundle; - - bundle = conf->bundle; - nxt_assert(bundle != NULL); - - do { - SSL_CTX_free(bundle->ctx); - bundle = bundle->next; - } while (bundle != NULL); - - if (conf->tickets) { - nxt_memzero(conf->tickets->tickets, - conf->tickets->count * sizeof(nxt_tls_ticket_t)); - } - -#if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ - && OPENSSL_VERSION_NUMBER < 0x1010101fL) - RAND_keep_random_devices_open(0); -#endif -} - - -static void -nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) -{ - int ret; - SSL *s; - SSL_CTX *ctx; - nxt_openssl_conn_t *tls; - - nxt_log_debug(c->socket.log, "openssl conn init"); - - tls = nxt_mp_zget(c->mem_pool, sizeof(nxt_openssl_conn_t)); - if (tls == NULL) { - goto fail; - } - - c->u.tls = tls; - nxt_buf_mem_set_size(&tls->buffer, conf->buffer_size); - - ctx = conf->bundle->ctx; - - s = SSL_new(ctx); - if (s == NULL) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_new() failed"); - goto fail; - } - - tls->session = s; - /* To pass TLS config to the nxt_openssl_servername() callback. */ - tls->conf = conf; - tls->conn = c; - - ret = SSL_set_fd(s, c->socket.fd); - - if (ret == 0) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_fd(%d) failed", - c->socket.fd); - goto fail; - } - - SSL_set_accept_state(s); - - if (SSL_set_ex_data(s, nxt_openssl_connection_index, c) == 0) { - nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_ex_data() failed"); - goto fail; - } - - c->io = &nxt_openssl_conn_io; - c->sendfile = NXT_CONN_SENDFILE_OFF; - - nxt_openssl_conn_handshake(task, c, c->socket.data); - - return; - -fail: - - nxt_work_queue_add(c->read_work_queue, c->read_state->error_handler, - task, c, c->socket.data); -} - - -nxt_inline void -nxt_openssl_conn_free(nxt_task_t *task, nxt_conn_t *c) -{ - nxt_openssl_conn_t *tls; - - nxt_debug(task, "openssl conn free"); - - tls = c->u.tls; - - if (tls != NULL) { - c->u.tls = NULL; - nxt_free(tls->buffer.start); - SSL_free(tls->session); - } -} - - -static void -nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data) -{ - int ret; - nxt_int_t n; - nxt_err_t err; - nxt_conn_t *c; - nxt_work_queue_t *wq; - nxt_work_handler_t handler; - nxt_openssl_conn_t *tls; - const nxt_conn_state_t *state; - - c = obj; - - nxt_debug(task, "openssl conn handshake fd:%d", c->socket.fd); - - if (c->socket.error != 0) { - return; - } - - tls = c->u.tls; - - if (tls == NULL) { - return; - } - - nxt_debug(task, "openssl conn handshake: %d times", tls->times); - - /* "tls->times == 1" is suitable to run SSL_do_handshake() in job. */ - - ret = SSL_do_handshake(tls->session); - - err = (ret <= 0) ? nxt_socket_errno : 0; - - nxt_thread_time_debug_update(task->thread); - - nxt_debug(task, "SSL_do_handshake(%d): %d err:%d", c->socket.fd, ret, err); - - state = (c->read_state != NULL) ? c->read_state : c->write_state; - - if (ret > 0) { - /* ret == 1, the handshake was successfully completed. */ - tls->handshake = 1; - - if (c->read_state != NULL) { - if (state->io_read_handler != NULL || c->read != NULL) { - nxt_conn_read(task->thread->engine, c); - return; - } - - } else { - if (c->write != NULL) { - nxt_conn_write(task->thread->engine, c); - return; - } - } - - handler = state->ready_handler; - - } else { - c->socket.read_handler = nxt_openssl_conn_handshake; - c->socket.write_handler = nxt_openssl_conn_handshake; - - n = nxt_openssl_conn_test_error(task, c, ret, err, - NXT_OPENSSL_HANDSHAKE); - switch (n) { - - case NXT_AGAIN: - if (tls->ssl_error == SSL_ERROR_WANT_READ && tls->times < 2) { - tls->times++; - } - - return; - - case 0: - handler = state->close_handler; - break; - - default: - case NXT_ERROR: - nxt_openssl_conn_error(task, err, "SSL_do_handshake(%d) failed", - c->socket.fd); - - handler = state->error_handler; - break; - } - } - - wq = (c->read_state != NULL) ? c->read_work_queue : c->write_work_queue; - - nxt_work_queue_add(wq, handler, task, c, data); -} - - -static ssize_t -nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b) -{ - int ret; - size_t size; - nxt_int_t n; - nxt_err_t err; - nxt_openssl_conn_t *tls; - - tls = c->u.tls; - size = b->mem.end - b->mem.free; - - ret = SSL_read(tls->session, b->mem.free, size); - - err = (ret <= 0) ? nxt_socket_errno : 0; - - nxt_debug(c->socket.task, "SSL_read(%d, %p, %uz): %d err:%d", - c->socket.fd, b->mem.free, size, ret, err); - - if (ret > 0) { - return ret; - } - - n = nxt_openssl_conn_test_error(c->socket.task, c, ret, err, - NXT_OPENSSL_READ); - if (n == NXT_ERROR) { - nxt_openssl_conn_error(c->socket.task, err, - "SSL_read(%d, %p, %uz) failed", - c->socket.fd, b->mem.free, size); - } - - return n; -} - - -static ssize_t -nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb) -{ - nxt_uint_t niov; - struct iovec iov; - - niov = nxt_sendbuf_mem_coalesce0(task, sb, &iov, 1); - - if (niov == 0 && sb->sync) { - return 0; - } - - return nxt_openssl_conn_io_send(task, sb, iov.iov_base, iov.iov_len); -} - - -static ssize_t -nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf, - size_t size) -{ - int ret; - nxt_err_t err; - nxt_int_t n; - nxt_conn_t *c; - nxt_openssl_conn_t *tls; - - tls = sb->tls; - - ret = SSL_write(tls->session, buf, size); - - err = (ret <= 0) ? nxt_socket_errno : 0; - - nxt_debug(task, "SSL_write(%d, %p, %uz): %d err:%d", - sb->socket, buf, size, ret, err); - - if (ret > 0) { - return ret; - } - - c = tls->conn; - c->socket.write_ready = sb->ready; - - n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_WRITE); - - sb->ready = c->socket.write_ready; - - if (n == NXT_ERROR) { - sb->error = c->socket.error; - nxt_openssl_conn_error(task, err, "SSL_write(%d, %p, %uz) failed", - sb->socket, buf, size); - } - - return n; -} - - -static void -nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) -{ - int ret, mode; - SSL *s; - nxt_err_t err; - nxt_int_t n; - nxt_bool_t quiet, once; - nxt_conn_t *c; - nxt_openssl_conn_t *tls; - nxt_work_handler_t handler; - - c = obj; - - nxt_debug(task, "openssl conn shutdown fd:%d", c->socket.fd); - - c->read_state = NULL; - tls = c->u.tls; - - if (tls == NULL) { - return; - } - - s = tls->session; - - if (s == NULL || !tls->handshake) { - handler = c->write_state->ready_handler; - goto done; - } - - mode = SSL_get_shutdown(s); - - if (c->socket.timedout || c->socket.error != 0) { - quiet = 1; - - } else if (c->socket.closed && !(mode & SSL_RECEIVED_SHUTDOWN)) { - quiet = 1; - - } else { - quiet = 0; - } - - SSL_set_quiet_shutdown(s, quiet); - - if (tls->conf->no_wait_shutdown) { - mode |= SSL_RECEIVED_SHUTDOWN; - } - - once = 1; - - for ( ;; ) { - SSL_set_shutdown(s, mode); - - ret = SSL_shutdown(s); - - err = (ret <= 0) ? nxt_socket_errno : 0; - - nxt_debug(task, "SSL_shutdown(%d, %d, %b): %d err:%d", - c->socket.fd, mode, quiet, ret, err); - - if (ret > 0) { - /* ret == 1, the shutdown was successfully completed. */ - handler = c->write_state->ready_handler; - goto done; - } - - if (ret == 0) { - /* - * If SSL_shutdown() returns 0 then it should be called - * again. The second SSL_shutdown() call should return - * -1/SSL_ERROR_WANT_READ or -1/SSL_ERROR_WANT_WRITE. - * OpenSSL prior to 0.9.8m version however never returns - * -1 at all. Fortunately, OpenSSL preserves internally - * correct status available via SSL_get_error(-1). - */ - if (once) { - once = 0; - mode = SSL_get_shutdown(s); - continue; - } - - ret = -1; - } - - /* ret == -1 */ - - break; - } - - c->socket.read_handler = nxt_openssl_conn_io_shutdown; - c->socket.write_handler = nxt_openssl_conn_io_shutdown; - c->socket.error_handler = c->write_state->error_handler; - - n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_SHUTDOWN); - - switch (n) { - - case 0: - handler = c->write_state->close_handler; - break; - - case NXT_AGAIN: - c->write_timer.handler = nxt_openssl_conn_io_shutdown_timeout; - nxt_timer_add(task->thread->engine, &c->write_timer, 5000); - return; - - default: - case NXT_ERROR: - nxt_openssl_conn_error(task, err, "SSL_shutdown(%d) failed", - c->socket.fd); - handler = c->write_state->error_handler; - } - -done: - - nxt_openssl_conn_free(task, c); - - nxt_work_queue_add(c->write_work_queue, handler, task, c, data); -} - - -static nxt_int_t -nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, int ret, - nxt_err_t sys_err, nxt_openssl_io_t io) -{ - u_long lib_err; - nxt_openssl_conn_t *tls; - - tls = c->u.tls; - - tls->ssl_error = SSL_get_error(tls->session, ret); - - nxt_debug(task, "SSL_get_error(): %d", tls->ssl_error); - - switch (tls->ssl_error) { - - case SSL_ERROR_WANT_READ: - c->socket.read_ready = 0; - - if (io != NXT_OPENSSL_READ) { - nxt_fd_event_block_write(task->thread->engine, &c->socket); - - if (nxt_fd_event_is_disabled(c->socket.read)) { - nxt_fd_event_enable_read(task->thread->engine, &c->socket); - } - } - - return NXT_AGAIN; - - case SSL_ERROR_WANT_WRITE: - c->socket.write_ready = 0; - - if (io != NXT_OPENSSL_WRITE) { - nxt_fd_event_block_read(task->thread->engine, &c->socket); - - if (nxt_fd_event_is_disabled(c->socket.write)) { - nxt_fd_event_enable_write(task->thread->engine, &c->socket); - } - } - - return NXT_AGAIN; - - case SSL_ERROR_SYSCALL: - lib_err = ERR_peek_error(); - - nxt_debug(task, "ERR_peek_error(): %l", lib_err); - - if (sys_err != 0 || lib_err != 0) { - c->socket.error = sys_err; - return NXT_ERROR; - } - - /* A connection was just closed. */ - c->socket.closed = 1; - return 0; - - case SSL_ERROR_ZERO_RETURN: - /* A "close notify" alert. */ - return 0; - - default: /* SSL_ERROR_SSL, etc. */ - c->socket.error = 1000; /* Nonexistent errno code. */ - return NXT_ERROR; - } -} - - -static void -nxt_openssl_conn_io_shutdown_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - - timer = obj; - - nxt_debug(task, "openssl conn shutdown timeout"); - - c = nxt_write_timer_conn(timer); - - c->socket.timedout = 1; - nxt_openssl_conn_io_shutdown(task, c, NULL); -} - - -static void nxt_cdecl -nxt_openssl_conn_error(nxt_task_t *task, nxt_err_t err, const char *fmt, ...) -{ - u_char *p, *end; - va_list args; - nxt_uint_t level; - u_char msg[NXT_MAX_ERROR_STR]; - - level = nxt_openssl_log_error_level(err); - - if (nxt_log_level_enough(task->log, level)) { - - end = msg + sizeof(msg); - - va_start(args, fmt); - p = nxt_vsprintf(msg, end, fmt, args); - va_end(args); - - if (err != 0) { - p = nxt_sprintf(p, end, " %E", err); - } - - p = nxt_openssl_copy_error(p, end); - - nxt_log(task, level, "%*s", p - msg, msg); - - } else { - ERR_clear_error(); - } -} - - -static nxt_uint_t -nxt_openssl_log_error_level(nxt_err_t err) -{ - switch (ERR_GET_REASON(ERR_peek_error())) { - - case 0: - return nxt_socket_error_level(err); - - case SSL_R_BAD_CHANGE_CIPHER_SPEC: /* 103 */ - case SSL_R_BLOCK_CIPHER_PAD_IS_WRONG: /* 129 */ - case SSL_R_DIGEST_CHECK_FAILED: /* 149 */ - case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST: /* 151 */ - case SSL_R_EXCESSIVE_MESSAGE_SIZE: /* 152 */ - case SSL_R_LENGTH_MISMATCH: /* 159 */ -#ifdef SSL_R_NO_CIPHERS_PASSED - case SSL_R_NO_CIPHERS_PASSED: /* 182 */ -#endif - case SSL_R_NO_CIPHERS_SPECIFIED: /* 183 */ - case SSL_R_NO_COMPRESSION_SPECIFIED: /* 187 */ - case SSL_R_NO_SHARED_CIPHER: /* 193 */ - case SSL_R_RECORD_LENGTH_MISMATCH: /* 213 */ -#ifdef SSL_R_PARSE_TLSEXT - case SSL_R_PARSE_TLSEXT: /* 227 */ -#endif - case SSL_R_UNEXPECTED_MESSAGE: /* 244 */ - case SSL_R_UNEXPECTED_RECORD: /* 245 */ - case SSL_R_UNKNOWN_ALERT_TYPE: /* 246 */ - case SSL_R_UNKNOWN_PROTOCOL: /* 252 */ - case SSL_R_WRONG_VERSION_NUMBER: /* 267 */ - case SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC: /* 281 */ -#ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG - case SSL_R_RENEGOTIATE_EXT_TOO_LONG: /* 335 */ - case SSL_R_RENEGOTIATION_ENCODING_ERR: /* 336 */ - case SSL_R_RENEGOTIATION_MISMATCH: /* 337 */ -#endif -#ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED - case SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED: /* 338 */ -#endif -#ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING - case SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING: /* 345 */ -#endif - case 1000:/* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ - case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE: /* 1010 */ - case SSL_R_SSLV3_ALERT_BAD_RECORD_MAC: /* 1020 */ - case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: /* 1021 */ - case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW: /* 1022 */ - case SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE: /* 1030 */ - case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE: /* 1040 */ - case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER: /* 1047 */ - break; - - case SSL_R_SSLV3_ALERT_NO_CERTIFICATE: /* 1041 */ - case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: /* 1042 */ - case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE: /* 1043 */ - case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: /* 1044 */ - case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: /* 1045 */ - case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: /* 1046 */ - case SSL_R_TLSV1_ALERT_UNKNOWN_CA: /* 1048 */ - case SSL_R_TLSV1_ALERT_ACCESS_DENIED: /* 1049 */ - case SSL_R_TLSV1_ALERT_DECODE_ERROR: /* 1050 */ - case SSL_R_TLSV1_ALERT_DECRYPT_ERROR: /* 1051 */ - case SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION: /* 1060 */ - case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION: /* 1070 */ - case SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY: /* 1071 */ - case SSL_R_TLSV1_ALERT_INTERNAL_ERROR: /* 1080 */ - case SSL_R_TLSV1_ALERT_USER_CANCELLED: /* 1090 */ - case SSL_R_TLSV1_ALERT_NO_RENEGOTIATION: /* 1100 */ - return NXT_LOG_ERR; - - default: - return NXT_LOG_ALERT; - } - - return NXT_LOG_INFO; -} - - -void nxt_cdecl -nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level, const char *fmt, ...) -{ - u_char *p, *end; - va_list args; - u_char msg[NXT_MAX_ERROR_STR]; - - end = msg + sizeof(msg); - - va_start(args, fmt); - p = nxt_vsprintf(msg, end, fmt, args); - va_end(args); - - p = nxt_openssl_copy_error(p, end); - - nxt_log(task, level, "%*s", p - msg, msg); -} - - -u_char * -nxt_openssl_copy_error(u_char *p, u_char *end) -{ - int flags; - u_long err; - nxt_bool_t clear; - const char *data, *delimiter; - - err = ERR_peek_error(); - if (err == 0) { - return p; - } - - /* Log the most relevant error message ... */ - data = ERR_reason_error_string(err); - - p = nxt_sprintf(p, end, " (%d: %s) (OpenSSL: ", ERR_GET_REASON(err), data); - - /* - * ... followed by all queued cumbersome OpenSSL error messages - * and drain the error queue. - */ - delimiter = ""; - clear = 0; - - for ( ;; ) { -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - err = ERR_get_error_all(NULL, NULL, NULL, &data, &flags); -#else - err = ERR_get_error_line_data(NULL, NULL, &data, &flags); -#endif - if (err == 0) { - break; - } - - p = nxt_sprintf(p, end, "%s", delimiter); - - ERR_error_string_n(err, (char *) p, end - p); - - while (p < end && *p != '\0') { - p++; - } - - if ((flags & ERR_TXT_STRING) != 0) { - p = nxt_sprintf(p, end, ":%s", data); - } - - clear |= ((flags & ERR_TXT_MALLOCED) != 0); - - delimiter = "; "; - } - - /* Deallocate additional data. */ - - if (clear) { - ERR_clear_error(); - } - - if (p < end) { - *p++ = ')'; - } - - return p; -} diff --git a/src/nxt_parse.c b/src/nxt_parse.c deleted file mode 100644 index e60bab4c..00000000 --- a/src/nxt_parse.c +++ /dev/null @@ -1,348 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * nxt_int_parse() returns size_t value >= 0 on success, - * -1 on failure, and -2 on overflow. - */ - -nxt_int_t -nxt_int_parse(const u_char *p, size_t length) -{ - u_char c; - nxt_uint_t val; - - static const nxt_uint_t cutoff = NXT_INT_T_MAX / 10; - static const nxt_uint_t cutlim = NXT_INT_T_MAX % 10; - - if (nxt_fast_path(length != 0)) { - - val = 0; - - do { - c = *p++; - - /* Values below '0' become >= 208. */ - c = c - '0'; - - if (nxt_slow_path(c > 9)) { - return -1; - } - - if (nxt_slow_path(val >= cutoff && (val > cutoff || c > cutlim))) { - /* An overflow. */ - return -2; - } - - val = val * 10 + c; - - length--; - - } while (length != 0); - - return val; - } - - return -1; -} - - -/* - * nxt_size_t_parse() returns size_t value >= 0 on success, - * -1 on failure, and -2 on overflow. - */ - -ssize_t -nxt_size_t_parse(const u_char *p, size_t length) -{ - u_char c; - size_t val; - - static const size_t cutoff = NXT_SIZE_T_MAX / 10; - static const size_t cutlim = NXT_SIZE_T_MAX % 10; - - if (nxt_fast_path(length != 0)) { - - val = 0; - - do { - c = *p++; - - /* Values below '0' become >= 208. */ - c = c - '0'; - - if (nxt_slow_path(c > 9)) { - return -1; - } - - if (nxt_slow_path(val >= cutoff && (val > cutoff || c > cutlim))) { - /* An overflow. */ - return -2; - } - - val = val * 10 + c; - - length--; - - } while (length != 0); - - return val; - } - - return -1; -} - - -/* - * nxt_size_parse() parses size string with optional K or M units and - * returns size_t value >= 0 on success, -1 on failure, and -2 on overflow. - */ - -ssize_t -nxt_size_parse(const u_char *p, size_t length) -{ - u_char unit; - ssize_t val, max; - nxt_uint_t shift; - - if (nxt_fast_path(length != 0)) { - - length--; - - /* Upper case. */ - unit = p[length] & ~0x20; - - switch (unit) { - - case 'G': - max = NXT_SIZE_T_MAX >> 30; - shift = 30; - break; - - case 'M': - max = NXT_SIZE_T_MAX >> 20; - shift = 20; - break; - - case 'K': - max = NXT_SIZE_T_MAX >> 10; - shift = 10; - break; - - default: - return nxt_size_t_parse(p, length + 1); - } - - val = nxt_size_t_parse(p, length); - - if (nxt_fast_path(val >= 0)) { - - if (nxt_slow_path(val > max)) { - /* An overflow. */ - return -2; - } - - val <<= shift; - } - - return val; - } - - return -1; -} - - -/* - * nxt_off_t_parse() returns nxt_off_t value >= 0 on success, - * -1 on failure, and -2 on overflow. - */ - -nxt_off_t -nxt_off_t_parse(const u_char *p, size_t length) -{ - u_char c; - nxt_uoff_t val; - - static const nxt_uoff_t cutoff = NXT_OFF_T_MAX / 10; - static const nxt_uoff_t cutlim = NXT_OFF_T_MAX % 10; - - if (nxt_fast_path(length != 0)) { - - val = 0; - - do { - c = *p++; - - /* Values below '0' become >= 208. */ - c = c - '0'; - - if (nxt_slow_path(c > 9)) { - return -1; - } - - if (nxt_slow_path(val >= cutoff && (val > cutoff || c > cutlim))) { - /* An overflow. */ - return -2; - } - - val = val * 10 + c; - - length--; - - } while (length != 0); - - return val; - } - - return -1; -} - - -/* - * nxt_str_int_parse() returns nxt_int_t value >= 0 on success, - * -1 on failure, and -2 on overflow and also updates the 's' argument. - */ - -nxt_int_t -nxt_str_int_parse(nxt_str_t *s) -{ - u_char c, *p; - size_t length; - nxt_uint_t val; - - static const nxt_uint_t cutoff = NXT_INT_T_MAX / 10; - static const nxt_uint_t cutlim = NXT_INT_T_MAX % 10; - - length = s->length; - - if (nxt_slow_path(length == 0)) { - return -1; - } - - p = s->start; - val = 0; - - do { - c = *p; - - /* Values below '0' become >= 208. */ - c = c - '0'; - - if (c > 9) { - break; - } - - if (nxt_slow_path(val >= cutoff && (val > cutoff || c > cutlim))) { - /* An overflow. */ - return -2; - } - - val = val * 10 + c; - - p++; - length--; - - } while (length != 0); - - s->length = length; - s->start = p; - - return val; -} - - -/* - * nxt_number_parse() returns a double value >= 0 and updates the start - * argument on success, or returns -1 on failure or -2 on overflow. - */ - -double -nxt_number_parse(const u_char **start, const u_char *end) -{ - u_char c; - nxt_bool_t overflow; - nxt_uint_t integral, frac, power; - const u_char *p; - - static const nxt_uint_t cutoff = NXT_INT_T_MAX / 10; - static const nxt_uint_t cutlim = NXT_INT_T_MAX % 10; - - p = *start; - integral = 0; - - while (p < end) { - c = *p; - - if (c == '.') { - goto dot; - } - - /* Values below '0' become >= 208. */ - c = c - '0'; - - if (c > 9) { - break; - } - - overflow = nxt_expect(0, (integral >= cutoff - && (integral > cutoff || c > cutlim))); - - if (overflow) { - return -2; - } - - integral = integral * 10 + c; - - p++; - } - - if (nxt_fast_path(p != *start)) { - *start = p; - return integral; - } - - /* No value. */ - return -1; - -dot: - - if (nxt_slow_path(p == *start)) { - /* No leading digit before dot. */ - return -1; - } - - frac = 0; - power = 1; - - for (p++; p < end; p++) { - c = *p; - - /* Values below '0' become >= 208. */ - c = c - '0'; - - if (c > 9) { - break; - } - - overflow = nxt_expect(0, (frac >= cutoff && (frac > cutoff - || c > cutlim)) - || power > cutoff); - - if (overflow) { - return -2; - } - - frac = frac * 10 + c; - power *= 10; - } - - *start = p; - - return integral + (double) frac / power; -} diff --git a/src/nxt_parse.h b/src/nxt_parse.h deleted file mode 100644 index 0643af1e..00000000 --- a/src/nxt_parse.h +++ /dev/null @@ -1,25 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PARSE_H_INCLUDED_ -#define _NXT_PARSE_H_INCLUDED_ - - -NXT_EXPORT nxt_int_t nxt_int_parse(const u_char *p, size_t len); -NXT_EXPORT ssize_t nxt_size_t_parse(const u_char *p, size_t len); -NXT_EXPORT ssize_t nxt_size_parse(const u_char *p, size_t len); -NXT_EXPORT nxt_off_t nxt_off_t_parse(const u_char *p, size_t len); - -NXT_EXPORT nxt_int_t nxt_str_int_parse(nxt_str_t *s); - -NXT_EXPORT double nxt_number_parse(const u_char **start, const u_char *end); - -NXT_EXPORT nxt_time_t nxt_time_parse(const u_char *p, size_t len); -NXT_EXPORT nxt_int_t nxt_term_parse(const u_char *p, size_t len, - nxt_bool_t seconds); - - -#endif /* _NXT_PARSE_H_INCLUDED_ */ diff --git a/src/nxt_pcre.c b/src/nxt_pcre.c deleted file mode 100644 index 737fc7cf..00000000 --- a/src/nxt_pcre.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) Axel Duch - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -struct nxt_regex_s { - pcre *code; - pcre_extra *extra; - nxt_str_t pattern; -}; - -struct nxt_regex_match_s { - int ovecsize; - int ovec[]; -}; - - -static void *nxt_pcre_malloc(size_t size); -static void nxt_pcre_free(void *p); - -static nxt_mp_t *nxt_pcre_mp; - - -nxt_regex_t * -nxt_regex_compile(nxt_mp_t *mp, nxt_str_t *source, nxt_regex_err_t *err) -{ - int erroffset; - char *pattern; - void *saved_malloc, *saved_free; - nxt_regex_t *re; - - err->offset = source->length; - - re = nxt_mp_get(mp, sizeof(nxt_regex_t) + source->length + 1); - if (nxt_slow_path(re == NULL)) { - err->msg = "memory allocation failed"; - return NULL; - } - - pattern = nxt_pointer_to(re, sizeof(nxt_regex_t)); - - nxt_memcpy(pattern, source->start, source->length); - pattern[source->length] = '\0'; - - re->pattern.length = source->length; - re->pattern.start = (u_char *) pattern; - - saved_malloc = pcre_malloc; - saved_free = pcre_free; - - pcre_malloc = nxt_pcre_malloc; - pcre_free = nxt_pcre_free; - nxt_pcre_mp = mp; - - re->code = pcre_compile(pattern, 0, &err->msg, &erroffset, NULL); - if (nxt_fast_path(re->code != NULL)) { -#if 0 - re->extra = pcre_study(re->code, PCRE_STUDY_JIT_COMPILE, &err->msg); - if (nxt_slow_path(re->extra == NULL && err->msg != NULL)) { - nxt_log_warn(thr->log, "pcre_study(%V) failed: %s", source, err->msg); - } -#else - re->extra = NULL; -#endif - - } else { - err->offset = erroffset; - re = NULL; - } - - pcre_malloc = saved_malloc; - pcre_free = saved_free; - - return re; -} - - -static void* -nxt_pcre_malloc(size_t size) -{ - if (nxt_slow_path(nxt_pcre_mp == NULL)) { - nxt_thread_log_alert("pcre_malloc(%uz) called without memory pool", - size); - return NULL; - } - - nxt_thread_log_debug("pcre_malloc(%uz), pool %p", size, nxt_pcre_mp); - - return nxt_mp_get(nxt_pcre_mp, size); -} - - -static void -nxt_pcre_free(void *p) -{ -} - - -nxt_regex_match_t * -nxt_regex_match_create(nxt_mp_t *mp, size_t size) -{ - nxt_regex_match_t *match; - - match = nxt_mp_get(mp, sizeof(nxt_regex_match_t) + sizeof(int) * size); - if (nxt_fast_path(match != NULL)) { - match->ovecsize = size; - } - - return match; -} - - -nxt_int_t -nxt_regex_match(nxt_regex_t *re, u_char *subject, size_t length, - nxt_regex_match_t *match) -{ - int ret; - - ret = pcre_exec(re->code, re->extra, (const char *) subject, length, 0, 0, - match->ovec, match->ovecsize); - if (nxt_slow_path(ret < PCRE_ERROR_NOMATCH)) { - nxt_thread_log_error(NXT_LOG_ERR, - "pcre_exec() failed: %d on \"%*s\" using \"%V\"", - ret, length, subject, &re->pattern); - - return NXT_ERROR; - } - - return (ret != PCRE_ERROR_NOMATCH); -} diff --git a/src/nxt_pcre2.c b/src/nxt_pcre2.c deleted file mode 100644 index cb51062c..00000000 --- a/src/nxt_pcre2.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) Axel Duch - * Copyright (C) NGINX, Inc. - */ - -#include -#include - -#define PCRE2_CODE_UNIT_WIDTH 8 -#include - - -static void *nxt_pcre2_malloc(PCRE2_SIZE size, void *memory_data); -static void nxt_pcre2_free(void *p, void *memory_data); - - -struct nxt_regex_s { - pcre2_code *code; - nxt_str_t pattern; -}; - - -nxt_regex_t * -nxt_regex_compile(nxt_mp_t *mp, nxt_str_t *source, nxt_regex_err_t *err) -{ - int errcode; - nxt_int_t ret; - PCRE2_SIZE erroffset; - nxt_regex_t *re; - pcre2_general_context *general_ctx; - pcre2_compile_context *compile_ctx; - - static const u_char alloc_error[] = "memory allocation failed"; - - general_ctx = pcre2_general_context_create(nxt_pcre2_malloc, - nxt_pcre2_free, mp); - if (nxt_slow_path(general_ctx == NULL)) { - goto alloc_fail; - } - - compile_ctx = pcre2_compile_context_create(general_ctx); - if (nxt_slow_path(compile_ctx == NULL)) { - goto alloc_fail; - } - - re = nxt_mp_get(mp, sizeof(nxt_regex_t)); - if (nxt_slow_path(re == NULL)) { - goto alloc_fail; - } - - if (nxt_slow_path(nxt_str_dup(mp, &re->pattern, source) == NULL)) { - goto alloc_fail; - } - - re->code = pcre2_compile((PCRE2_SPTR) source->start, source->length, 0, - &errcode, &erroffset, compile_ctx); - if (nxt_slow_path(re->code == NULL)) { - err->offset = erroffset; - - ret = pcre2_get_error_message(errcode, (PCRE2_UCHAR *) err->msg, - ERR_BUF_SIZE); - if (ret < 0) { - (void) nxt_sprintf(err->msg, err->msg + ERR_BUF_SIZE, - "compilation failed with unknown " - "error code: %d%Z", errcode); - } - - return NULL; - } - -#if 0 - errcode = pcre2_jit_compile(re, PCRE2_JIT_COMPLETE); - if (nxt_slow_path(errcode != 0 && errcode != PCRE2_ERROR_JIT_BADOPTION)) { - ret = pcre2_get_error_message(errcode, (PCRE2_UCHAR *) err->msg, - ERR_BUF_SIZE); - if (ret < 0) { - (void) nxt_sprintf(err->msg, err->msg + ERR_BUF_SIZE, - "JIT compilation failed with unknown " - "error code: %d%Z", errcode); - } - - return NULL; - } -#endif - - return re; - -alloc_fail: - - err->offset = source->length; - nxt_memcpy(err->msg, alloc_error, sizeof(alloc_error)); - - return NULL; -} - - -static void * -nxt_pcre2_malloc(PCRE2_SIZE size, void *mp) -{ - return nxt_mp_get(mp, size); -} - - -static void -nxt_pcre2_free(void *p, void *mp) -{ -} - - -nxt_regex_match_t * -nxt_regex_match_create(nxt_mp_t *mp, size_t size) -{ - nxt_regex_match_t *match; - pcre2_general_context *ctx; - - ctx = pcre2_general_context_create(nxt_pcre2_malloc, nxt_pcre2_free, mp); - if (nxt_slow_path(ctx == NULL)) { - nxt_thread_log_alert("pcre2_general_context_create() failed"); - return NULL; - } - - match = pcre2_match_data_create(size, ctx); - if (nxt_slow_path(match == NULL)) { - nxt_thread_log_alert("pcre2_match_data_create(%uz) failed", size); - return NULL; - } - - return match; -} - - -nxt_int_t -nxt_regex_match(nxt_regex_t *re, u_char *subject, size_t length, - nxt_regex_match_t *match) -{ - nxt_int_t ret; - PCRE2_UCHAR errptr[ERR_BUF_SIZE]; - - ret = pcre2_match(re->code, (PCRE2_SPTR) subject, length, 0, 0, match, - NULL); - - if (nxt_slow_path(ret < PCRE2_ERROR_NOMATCH)) { - - if (pcre2_get_error_message(ret, errptr, ERR_BUF_SIZE) < 0) { - nxt_thread_log_error(NXT_LOG_ERR, - "pcre2_match() failed: %d on \"%*s\" " - "using \"%V\"", ret, length, subject, - &re->pattern); - - } else { - nxt_thread_log_error(NXT_LOG_ERR, - "pcre2_match() failed: %s (%d) on \"%*s\" " - "using \"%V\"", errptr, ret, length, subject, - &re->pattern); - } - - return NXT_ERROR; - } - - return (ret != PCRE2_ERROR_NOMATCH); -} diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c deleted file mode 100644 index 77117533..00000000 --- a/src/nxt_php_sapi.c +++ /dev/null @@ -1,1641 +0,0 @@ -/* - * Copyright (C) Max Romanov - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - -#include "php.h" -#include "SAPI.h" -#include "php_main.h" -#include "php_variables.h" -#include "ext/standard/php_standard.h" - -#include -#include -#include -#include -#include - - -#if (PHP_VERSION_ID >= 50400) -#define NXT_HAVE_PHP_IGNORE_CWD 1 -#endif - -#if (PHP_VERSION_ID >= 70100) -#define NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 1 -#else -#define NXT_HAVE_PHP_INTERRUPTS 1 -#endif - -#if (PHP_VERSION_ID >= 70000) -#define NXT_PHP7 1 -#endif -#if (PHP_VERSION_ID >= 80000) -#define NXT_PHP8 1 -#endif - -/* PHP 8 */ -#ifndef TSRMLS_CC -#define TSRMLS_CC -#define TSRMLS_DC -#define TSRMLS_D void -#define TSRMLS_C -#endif - - -typedef struct { - nxt_str_t root; - nxt_str_t index; - nxt_str_t script_name; - nxt_str_t script_dirname; - nxt_str_t script_filename; -} nxt_php_target_t; - - -typedef struct { - char *cookie; - nxt_str_t *root; - nxt_str_t *index; - nxt_str_t path_info; - nxt_str_t script_name; - nxt_str_t script_filename; - nxt_str_t script_dirname; - nxt_unit_request_info_t *req; - - uint8_t chdir; /* 1 bit */ -} nxt_php_run_ctx_t; - - -#if NXT_PHP8 -typedef int (*nxt_php_disable_t)(const char *p, size_t size); -#elif NXT_PHP7 -typedef int (*nxt_php_disable_t)(char *p, size_t size); -#else -typedef int (*nxt_php_disable_t)(char *p, uint TSRMLS_DC); -#endif - -#if (PHP_VERSION_ID < 70200) -typedef void (*zif_handler)(INTERNAL_FUNCTION_PARAMETERS); -#endif - - -static nxt_int_t nxt_php_setup(nxt_task_t *task, nxt_process_t *process, - nxt_common_app_conf_t *conf); -static nxt_int_t nxt_php_start(nxt_task_t *task, nxt_process_data_t *data); -static nxt_int_t nxt_php_set_target(nxt_task_t *task, nxt_php_target_t *target, - nxt_conf_value_t *conf); -static nxt_int_t nxt_php_set_ini_path(nxt_task_t *task, nxt_str_t *path, - char *workdir); -static void nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options, - int type); -static nxt_int_t nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, - int type); -#ifdef NXT_PHP8 -static void nxt_php_disable_functions(nxt_str_t *str); -#endif -static void nxt_php_disable(nxt_task_t *task, const char *type, - nxt_str_t *value, char **ptr, nxt_php_disable_t disable); - -static nxt_int_t nxt_php_dirname(const nxt_str_t *file, nxt_str_t *dir); -static void nxt_php_str_trim_trail(nxt_str_t *str, u_char t); -static void nxt_php_str_trim_lead(nxt_str_t *str, u_char t); -nxt_inline u_char *nxt_realpath(const void *c); - -static nxt_int_t nxt_php_do_301(nxt_unit_request_info_t *req); -static nxt_int_t nxt_php_handle_fs_err(nxt_unit_request_info_t *req); - -static void nxt_php_request_handler(nxt_unit_request_info_t *req); -static void nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx, - nxt_unit_request_t *r); -#if (PHP_VERSION_ID < 70400) -static void nxt_zend_stream_init_fp(zend_file_handle *handle, FILE *fp, - const char *filename); -#endif -static void nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r); -nxt_inline void nxt_php_vcwd_chdir(nxt_unit_request_info_t *req, u_char *dir); - -static int nxt_php_startup(sapi_module_struct *sapi_module); -static int nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC); -static void *nxt_php_hash_str_find_ptr(const HashTable *ht, - const nxt_str_t *str); -static char *nxt_php_read_cookies(TSRMLS_D); -static void nxt_php_set_sptr(nxt_unit_request_info_t *req, const char *name, - nxt_unit_sptr_t *v, uint32_t len, zval *track_vars_array TSRMLS_DC); -nxt_inline void nxt_php_set_str(nxt_unit_request_info_t *req, const char *name, - nxt_str_t *s, zval *track_vars_array TSRMLS_DC); -static void nxt_php_set_cstr(nxt_unit_request_info_t *req, const char *name, - const char *str, uint32_t len, zval *track_vars_array TSRMLS_DC); -static void nxt_php_register_variables(zval *track_vars_array TSRMLS_DC); -#if NXT_PHP8 -static void nxt_php_log_message(const char *message, int syslog_type_int); -#else -#ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE -static void nxt_php_log_message(char *message, int syslog_type_int); -#else -static void nxt_php_log_message(char *message TSRMLS_DC); -#endif -#endif - -#ifdef NXT_PHP7 -static size_t nxt_php_unbuffered_write(const char *str, - size_t str_length TSRMLS_DC); -static size_t nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC); -#else -static int nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC); -static int nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC); -#endif - - -#ifdef NXT_PHP7 -#if (PHP_VERSION_ID < 70200) -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_fastcgi_finish_request, 0, 0, - _IS_BOOL, NULL, 0) -#else -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_fastcgi_finish_request, 0, 0, - _IS_BOOL, 0) -#endif -#else /* PHP5 */ -ZEND_BEGIN_ARG_INFO_EX(arginfo_fastcgi_finish_request, 0, 0, 0) -#endif -ZEND_END_ARG_INFO() - -ZEND_FUNCTION(fastcgi_finish_request); - -PHP_MINIT_FUNCTION(nxt_php_ext); -ZEND_NAMED_FUNCTION(nxt_php_chdir); - - -static const zend_function_entry nxt_php_ext_functions[] = { - ZEND_FE(fastcgi_finish_request, arginfo_fastcgi_finish_request) - ZEND_FE_END -}; - - -zif_handler nxt_php_chdir_handler; -zend_auto_global *nxt_php_server_ag; - - -static zend_module_entry nxt_php_unit_module = { - STANDARD_MODULE_HEADER, - "unit", - nxt_php_ext_functions, /* function table */ - PHP_MINIT(nxt_php_ext), /* initialization */ - NULL, /* shutdown */ - NULL, /* request initialization */ - NULL, /* request shutdown */ - NULL, /* information */ - NXT_VERSION, - STANDARD_MODULE_PROPERTIES -}; - - -PHP_MINIT_FUNCTION(nxt_php_ext) -{ - zend_function *func; - - static const nxt_str_t chdir = nxt_string("chdir"); - - func = nxt_php_hash_str_find_ptr(CG(function_table), &chdir); - if (nxt_slow_path(func == NULL)) { - return FAILURE; - } - - nxt_php_chdir_handler = func->internal_function.handler; - func->internal_function.handler = nxt_php_chdir; - - return SUCCESS; -} - - -ZEND_NAMED_FUNCTION(nxt_php_chdir) -{ - nxt_php_run_ctx_t *ctx; - - ctx = SG(server_context); - - if (nxt_fast_path(ctx != NULL)) { - ctx->chdir = 1; - } - - nxt_php_chdir_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); -} - - -PHP_FUNCTION(fastcgi_finish_request) -{ - zend_auto_global *ag; - nxt_php_run_ctx_t *ctx; - - if (nxt_slow_path(zend_parse_parameters_none() == FAILURE)) { -#ifdef NXT_PHP8 - RETURN_THROWS(); -#else - return; -#endif - } - - ctx = SG(server_context); - - if (nxt_slow_path(ctx == NULL || ctx->req == NULL)) { - RETURN_FALSE; - } - -#ifdef NXT_PHP7 - php_output_end_all(); - php_header(); -#else -#ifdef PHP_OUTPUT_NEWAPI - php_output_end_all(TSRMLS_C); -#else - php_end_ob_buffers(1 TSRMLS_CC); -#endif - - php_header(TSRMLS_C); -#endif - - ag = nxt_php_server_ag; - - if (ag->armed) { -#ifdef NXT_PHP7 - ag->armed = ag->auto_global_callback(ag->name); -#else - ag->armed = ag->auto_global_callback(ag->name, ag->name_len TSRMLS_CC); -#endif - } - - nxt_unit_request_done(ctx->req, NXT_UNIT_OK); - ctx->req = NULL; - - PG(connection_status) = PHP_CONNECTION_ABORTED; -#ifdef NXT_PHP7 - php_output_set_status(PHP_OUTPUT_DISABLED); -#else -#ifdef PHP_OUTPUT_NEWAPI - php_output_set_status(PHP_OUTPUT_DISABLED TSRMLS_CC); -#else - php_output_set_status(0 TSRMLS_CC); -#endif -#endif - - RETURN_TRUE; -} - - -static sapi_module_struct nxt_php_sapi_module = -{ - (char *) "cli-server", - (char *) "unit", - - nxt_php_startup, /* startup */ - php_module_shutdown_wrapper, /* shutdown */ - - NULL, /* activate */ - NULL, /* deactivate */ - - nxt_php_unbuffered_write, /* unbuffered write */ - NULL, /* flush */ - NULL, /* get uid */ - NULL, /* getenv */ - - php_error, /* error handler */ - - NULL, /* header handler */ - nxt_php_send_headers, /* send headers handler */ - NULL, /* send header handler */ - - nxt_php_read_post, /* read POST data */ - nxt_php_read_cookies, /* read Cookies */ - - nxt_php_register_variables, /* register server variables */ - nxt_php_log_message, /* log message */ - NULL, /* get request time */ - NULL, /* terminate process */ - - NULL, /* php_ini_path_override */ -#ifdef NXT_HAVE_PHP_INTERRUPTS - NULL, /* block_interruptions */ - NULL, /* unblock_interruptions */ -#endif - NULL, /* default_post_reader */ - NULL, /* treat_data */ - NULL, /* executable_location */ - - 0, /* php_ini_ignore */ -#ifdef NXT_HAVE_PHP_IGNORE_CWD - 1, /* php_ini_ignore_cwd */ -#endif - NULL, /* get_fd */ - - NULL, /* force_http_10 */ - - NULL, /* get_target_uid */ - NULL, /* get_target_gid */ - - NULL, /* input_filter */ - - NULL, /* ini_defaults */ - 0, /* phpinfo_as_text */ - - NULL, /* ini_entries */ - NULL, /* additional_functions */ - NULL /* input_filter_init */ -}; - - -static uint32_t compat[] = { - NXT_VERNUM, NXT_DEBUG, -}; - - -NXT_EXPORT nxt_app_module_t nxt_app_module = { - sizeof(compat), - compat, - nxt_string("php"), - PHP_VERSION, - NULL, - 0, - nxt_php_setup, - nxt_php_start, -}; - - -static nxt_php_target_t *nxt_php_targets; -static nxt_int_t nxt_php_last_target = -1; - -static nxt_unit_ctx_t *nxt_php_unit_ctx; -#if defined(ZTS) && (PHP_VERSION_ID < 70400) -static void ***tsrm_ls; -#endif - - -static nxt_int_t -nxt_php_setup(nxt_task_t *task, nxt_process_t *process, - nxt_common_app_conf_t *conf) -{ - nxt_str_t ini_path; - nxt_int_t ret; - nxt_conf_value_t *value; - nxt_php_app_conf_t *c; - - static nxt_str_t file_str = nxt_string("file"); - static nxt_str_t user_str = nxt_string("user"); - static nxt_str_t admin_str = nxt_string("admin"); - - c = &conf->u.php; - -#ifdef ZTS - -#if (PHP_VERSION_ID >= 70400) - php_tsrm_startup(); -#else - tsrm_startup(1, 1, 0, NULL); - tsrm_ls = ts_resource(0); -#endif - -#endif - -#if defined(NXT_PHP7) && defined(ZEND_SIGNALS) - -#if (NXT_ZEND_SIGNAL_STARTUP) - zend_signal_startup(); -#elif defined(ZTS) -#error PHP is built with thread safety and broken signals. -#endif - -#endif - - sapi_startup(&nxt_php_sapi_module); - - if (c->options != NULL) { - value = nxt_conf_get_object_member(c->options, &file_str, NULL); - - if (value != NULL) { - nxt_conf_get_string(value, &ini_path); - - ret = nxt_php_set_ini_path(task, &ini_path, - conf->working_directory); - - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - } - - if (nxt_slow_path(nxt_php_startup(&nxt_php_sapi_module) == FAILURE)) { - nxt_alert(task, "failed to initialize SAPI module and extension"); - return NXT_ERROR; - } - - if (c->options != NULL) { - value = nxt_conf_get_object_member(c->options, &admin_str, NULL); - nxt_php_set_options(task, value, ZEND_INI_SYSTEM); - - value = nxt_conf_get_object_member(c->options, &user_str, NULL); - nxt_php_set_options(task, value, ZEND_INI_USER); - } - -#ifdef NXT_PHP7 - nxt_php_server_ag = zend_hash_str_find_ptr(CG(auto_globals), "_SERVER", - nxt_length("_SERVER")); -#else - zend_hash_quick_find(CG(auto_globals), "_SERVER", sizeof("_SERVER"), - zend_hash_func("_SERVER", sizeof("_SERVER")), - (void **) &nxt_php_server_ag); -#endif - if (nxt_slow_path(nxt_php_server_ag == NULL)) { - nxt_alert(task, "failed to find $_SERVER auto global"); - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_php_start(nxt_task_t *task, nxt_process_data_t *data) -{ - uint32_t next; - nxt_int_t ret; - nxt_str_t name; - nxt_uint_t n; - nxt_unit_ctx_t *unit_ctx; - nxt_unit_init_t php_init; - nxt_conf_value_t *value; - nxt_php_app_conf_t *c; - nxt_common_app_conf_t *conf; - - conf = data->app; - c = &conf->u.php; - - n = (c->targets != NULL) ? nxt_conf_object_members_count(c->targets) : 1; - - nxt_php_targets = nxt_zalloc(sizeof(nxt_php_target_t) * n); - if (nxt_slow_path(nxt_php_targets == NULL)) { - return NXT_ERROR; - } - - if (c->targets != NULL) { - next = 0; - - for (n = 0; /* void */; n++) { - value = nxt_conf_next_object_member(c->targets, &name, &next); - if (value == NULL) { - break; - } - - ret = nxt_php_set_target(task, &nxt_php_targets[n], value); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - - } else { - ret = nxt_php_set_target(task, &nxt_php_targets[0], conf->self); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - - ret = nxt_unit_default_init(task, &php_init, conf); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "nxt_unit_default_init() failed"); - return ret; - } - - php_init.callbacks.request_handler = nxt_php_request_handler; - - unit_ctx = nxt_unit_init(&php_init); - if (nxt_slow_path(unit_ctx == NULL)) { - return NXT_ERROR; - } - - nxt_php_unit_ctx = unit_ctx; - - nxt_unit_run(nxt_php_unit_ctx); - nxt_unit_done(nxt_php_unit_ctx); - - exit(0); - - return NXT_OK; -} - - -static nxt_int_t -nxt_php_set_target(nxt_task_t *task, nxt_php_target_t *target, - nxt_conf_value_t *conf) -{ - u_char *tmp, *p; - nxt_str_t str; - nxt_int_t ret; - nxt_conf_value_t *value; - - static nxt_str_t root_str = nxt_string("root"); - static nxt_str_t script_str = nxt_string("script"); - static nxt_str_t index_str = nxt_string("index"); - - value = nxt_conf_get_object_member(conf, &root_str, NULL); - - nxt_conf_get_string(value, &str); - - tmp = nxt_malloc(str.length + 1); - if (nxt_slow_path(tmp == NULL)) { - return NXT_ERROR; - } - - p = tmp; - - p = nxt_cpymem(p, str.start, str.length); - *p = '\0'; - - p = nxt_realpath(tmp); - if (nxt_slow_path(p == NULL)) { - nxt_alert(task, "root realpath(%s) failed %E", tmp, nxt_errno); - return NXT_ERROR; - } - - nxt_free(tmp); - - target->root.length = nxt_strlen(p); - target->root.start = p; - - nxt_php_str_trim_trail(&target->root, '/'); - - value = nxt_conf_get_object_member(conf, &script_str, NULL); - - if (value != NULL) { - nxt_conf_get_string(value, &str); - - nxt_php_str_trim_lead(&str, '/'); - - tmp = nxt_malloc(target->root.length + 1 + str.length + 1); - if (nxt_slow_path(tmp == NULL)) { - return NXT_ERROR; - } - - p = tmp; - - p = nxt_cpymem(p, target->root.start, target->root.length); - *p++ = '/'; - - p = nxt_cpymem(p, str.start, str.length); - *p = '\0'; - - p = nxt_realpath(tmp); - if (nxt_slow_path(p == NULL)) { - nxt_alert(task, "script realpath(%s) failed %E", tmp, nxt_errno); - return NXT_ERROR; - } - - nxt_free(tmp); - - target->script_filename.length = nxt_strlen(p); - target->script_filename.start = p; - - if (!nxt_str_start(&target->script_filename, - target->root.start, target->root.length)) - { - nxt_alert(task, "script is not under php root"); - return NXT_ERROR; - } - - ret = nxt_php_dirname(&target->script_filename, - &target->script_dirname); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - target->script_name.length = target->script_filename.length - - target->root.length; - target->script_name.start = target->script_filename.start - + target->root.length; - - } else { - value = nxt_conf_get_object_member(conf, &index_str, NULL); - - if (value != NULL) { - nxt_conf_get_string(value, &str); - - tmp = nxt_malloc(str.length); - if (nxt_slow_path(tmp == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy(tmp, str.start, str.length); - - target->index.length = str.length; - target->index.start = tmp; - - } else { - nxt_str_set(&target->index, "index.php"); - } - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_php_set_ini_path(nxt_task_t *task, nxt_str_t *ini_path, char *workdir) -{ - size_t wdlen; - u_char *p, *start; - - if (ini_path->start[0] == '/' || workdir == NULL) { - p = nxt_malloc(ini_path->length + 1); - if (nxt_slow_path(p == NULL)) { - return NXT_ERROR; - } - - start = p; - - } else { - wdlen = nxt_strlen(workdir); - - p = nxt_malloc(wdlen + ini_path->length + 2); - if (nxt_slow_path(p == NULL)) { - return NXT_ERROR; - } - - start = p; - - p = nxt_cpymem(p, workdir, wdlen); - - if (workdir[wdlen - 1] != '/') { - *p++ = '/'; - } - } - - p = nxt_cpymem(p, ini_path->start, ini_path->length); - *p = '\0'; - - nxt_php_sapi_module.php_ini_path_override = (char *) start; - - return NXT_OK; -} - - -static void -nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options, int type) -{ - uint32_t next; - nxt_str_t name, value; - nxt_conf_value_t *value_obj; - - if (options != NULL) { - next = 0; - - for ( ;; ) { - value_obj = nxt_conf_next_object_member(options, &name, &next); - if (value_obj == NULL) { - break; - } - - nxt_conf_get_string(value_obj, &value); - - if (nxt_php_alter_option(&name, &value, type) != NXT_OK) { - nxt_log(task, NXT_LOG_ERR, - "setting PHP option \"%V: %V\" failed", &name, &value); - continue; - } - - if (nxt_str_eq(&name, "disable_functions", 17)) { -#ifdef NXT_PHP8 - nxt_php_disable_functions(&value); -#else - nxt_php_disable(task, "function", &value, - &PG(disable_functions), - zend_disable_function); -#endif - continue; - } - - if (nxt_str_eq(&name, "disable_classes", 15)) { - nxt_php_disable(task, "class", &value, - &PG(disable_classes), - zend_disable_class); - continue; - } - } - } -} - - -#ifdef NXT_PHP7 - -static nxt_int_t -nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, int type) -{ - zend_string *zs; - zend_ini_entry *ini_entry; - - ini_entry = nxt_php_hash_str_find_ptr(EG(ini_directives), name); - if (nxt_slow_path(ini_entry == NULL)) { - return NXT_ERROR; - } - - /* PHP exits on memory allocation errors. */ - zs = zend_string_init((char *) value->start, value->length, 1); - - if (ini_entry->on_modify - && ini_entry->on_modify(ini_entry, zs, ini_entry->mh_arg1, - ini_entry->mh_arg2, ini_entry->mh_arg3, - ZEND_INI_STAGE_ACTIVATE) - != SUCCESS) - { - zend_string_release(zs); - return NXT_ERROR; - } - - ini_entry->value = zs; - ini_entry->modifiable = type; - - return NXT_OK; -} - -#else /* PHP 5. */ - -static nxt_int_t -nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, int type) -{ - char *cstr; - zend_ini_entry *ini_entry; - - ini_entry = nxt_php_hash_str_find_ptr(EG(ini_directives), name); - if (nxt_slow_path(ini_entry == NULL)) { - return NXT_ERROR; - } - - cstr = nxt_malloc(value->length + 1); - if (nxt_slow_path(cstr == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy(cstr, value->start, value->length); - cstr[value->length] = '\0'; - - if (ini_entry->on_modify - && ini_entry->on_modify(ini_entry, cstr, value->length, - ini_entry->mh_arg1, ini_entry->mh_arg2, - ini_entry->mh_arg3, ZEND_INI_STAGE_ACTIVATE - TSRMLS_CC) - != SUCCESS) - { - nxt_free(cstr); - return NXT_ERROR; - } - - ini_entry->value = cstr; - ini_entry->value_length = value->length; - ini_entry->modifiable = type; - - return NXT_OK; -} - -#endif - - -#ifdef NXT_PHP8 - -static void -nxt_php_disable_functions(nxt_str_t *str) -{ - char *p; - - p = nxt_malloc(str->length + 1); - if (nxt_slow_path(p == NULL)) { - return; - } - - nxt_memcpy(p, str->start, str->length); - p[str->length] = '\0'; - - zend_disable_functions(p); - - nxt_free(p); -} - -#endif - - -static void -nxt_php_disable(nxt_task_t *task, const char *type, nxt_str_t *value, - char **ptr, nxt_php_disable_t disable) -{ - char c, *p, *start; - - p = nxt_malloc(value->length + 1); - if (nxt_slow_path(p == NULL)) { - return; - } - - /* - * PHP frees this memory on module shutdown. - * See core_globals_dtor() for details. - */ - *ptr = p; - - nxt_memcpy(p, value->start, value->length); - p[value->length] = '\0'; - - start = p; - - do { - c = *p; - - if (c == ' ' || c == ',' || c == '\0') { - - if (p != start) { - *p = '\0'; - -#ifdef NXT_PHP7 - if (disable(start, p - start) -#else - if (disable(start, p - start TSRMLS_CC) -#endif - != SUCCESS) - { - nxt_log(task, NXT_LOG_ERR, - "PHP: failed to disable \"%s\": no such %s", - start, type); - } - } - - start = p + 1; - } - - p++; - - } while (c != '\0'); -} - - -static nxt_int_t -nxt_php_dirname(const nxt_str_t *file, nxt_str_t *dir) -{ - size_t length; - - if (file->length == 0 || file->start[0] != '/') { - nxt_unit_alert(NULL, "php_dirname: invalid file name " - "(not starts from '/')"); - return NXT_ERROR; - } - - length = file->length; - - while (file->start[length - 1] != '/') { - length--; - } - - dir->length = length; - dir->start = nxt_malloc(length + 1); - if (nxt_slow_path(dir->start == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy(dir->start, file->start, length); - - dir->start[length] = '\0'; - - return NXT_OK; -} - - -static void -nxt_php_str_trim_trail(nxt_str_t *str, u_char t) -{ - while (str->length > 0 && str->start[str->length - 1] == t) { - str->length--; - } - - str->start[str->length] = '\0'; -} - - -static void -nxt_php_str_trim_lead(nxt_str_t *str, u_char t) -{ - while (str->length > 0 && str->start[0] == t) { - str->length--; - str->start++; - } -} - - -nxt_inline u_char * -nxt_realpath(const void *c) -{ - return (u_char *) realpath(c, NULL); -} - - -static nxt_int_t -nxt_php_do_301(nxt_unit_request_info_t *req) -{ - char *p, *url, *port; - uint32_t size; - const char *proto; - nxt_unit_request_t *r; - - r = req->request; - - url = nxt_malloc(sizeof("https://") - 1 - + r->server_name_length - + r->local_port_length + 1 - + r->path_length + 1 - + r->query_length + 1 - + 1); - if (nxt_slow_path(url == NULL)) { - return NXT_UNIT_ERROR; - } - - proto = r->tls ? "https://" : "http://"; - p = nxt_cpymem(url, proto, strlen(proto)); - p = nxt_cpymem(p, nxt_unit_sptr_get(&r->server_name), - r->server_name_length); - - port = nxt_unit_sptr_get(&r->local_port); - if (r->local_port_length > 0 - && !(r->tls && strcmp(port, "443") == 0) - && !(!r->tls && strcmp(port, "80") == 0)) - { - *p++ = ':'; - p = nxt_cpymem(p, port, r->local_port_length); - } - - p = nxt_cpymem(p, nxt_unit_sptr_get(&r->path), r->path_length); - *p++ = '/'; - - if (r->query_length > 0) { - *p++ = '?'; - p = nxt_cpymem(p, nxt_unit_sptr_get(&r->query), r->query_length); - } - - *p = '\0'; - - size = p - url; - - nxt_unit_response_init(req, NXT_HTTP_MOVED_PERMANENTLY, 1, - nxt_length("Location") + size); - nxt_unit_response_add_field(req, "Location", nxt_length("Location"), - url, size); - - nxt_free(url); - - return NXT_UNIT_OK; -} - - -static nxt_int_t -nxt_php_handle_fs_err(nxt_unit_request_info_t *req) -{ - switch (nxt_errno) { - case ELOOP: - case EACCES: - case ENFILE: - return nxt_unit_response_init(req, NXT_HTTP_FORBIDDEN, 0, 0); - case ENOENT: - case ENOTDIR: - case ENAMETOOLONG: - return nxt_unit_response_init(req, NXT_HTTP_NOT_FOUND, 0, 0); - } - - return NXT_UNIT_ERROR; -} - - -static void -nxt_php_request_handler(nxt_unit_request_info_t *req) -{ - nxt_php_target_t *target; - nxt_php_run_ctx_t ctx; - nxt_unit_request_t *r; - - r = req->request; - target = &nxt_php_targets[r->app_target]; - - nxt_memzero(&ctx, sizeof(ctx)); - - ctx.req = req; - ctx.root = &target->root; - ctx.index = &target->index; - - if (target->script_filename.length == 0) { - nxt_php_dynamic_request(&ctx, r); - return; - } - - ctx.script_filename = target->script_filename; - ctx.script_dirname = target->script_dirname; - ctx.script_name = target->script_name; - - ctx.chdir = (r->app_target != nxt_php_last_target); - - nxt_php_execute(&ctx, r); - - nxt_php_last_target = ctx.chdir ? -1 : r->app_target; -} - - -static void -nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r) -{ - u_char *p; - nxt_str_t path, script_name; - nxt_int_t ret; - - path.length = r->path_length; - path.start = nxt_unit_sptr_get(&r->path); - - nxt_str_null(&script_name); - - ctx->path_info.start = memmem(path.start, path.length, ".php/", - strlen(".php/")); - if (ctx->path_info.start != NULL) { - ctx->path_info.start += 4; - path.length = ctx->path_info.start - path.start; - - ctx->path_info.length = r->path_length - path.length; - - } else if (path.start[path.length - 1] == '/') { - script_name = *ctx->index; - - } else if (path.length < 4 - || memcmp(path.start + (path.length - 4), ".php", 4) != 0) - { - char tpath[PATH_MAX]; - nxt_int_t ec; - struct stat sb; - - ec = NXT_UNIT_ERROR; - - if (ctx->root->length + path.length + 1 > PATH_MAX) { - nxt_unit_request_done(ctx->req, ec); - - return; - } - - p = nxt_cpymem(tpath, ctx->root->start, ctx->root->length); - p = nxt_cpymem(p, path.start, path.length); - *p = '\0'; - - ret = stat(tpath, &sb); - if (ret == 0 && S_ISDIR(sb.st_mode)) { - ec = nxt_php_do_301(ctx->req); - } else if (ret == -1) { - ec = nxt_php_handle_fs_err(ctx->req); - } - - nxt_unit_request_done(ctx->req, ec); - - return; - } - - ctx->script_filename.length = ctx->root->length - + path.length - + script_name.length; - - p = nxt_malloc(ctx->script_filename.length + 1); - if (nxt_slow_path(p == NULL)) { - nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR); - - return; - } - - ctx->script_filename.start = p; - - ctx->script_name.length = path.length + script_name.length; - ctx->script_name.start = p + ctx->root->length; - - p = nxt_cpymem(p, ctx->root->start, ctx->root->length); - p = nxt_cpymem(p, path.start, path.length); - - if (script_name.length > 0) { - p = nxt_cpymem(p, script_name.start, script_name.length); - } - - *p = '\0'; - - ctx->chdir = 1; - - ret = nxt_php_dirname(&ctx->script_filename, &ctx->script_dirname); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR); - nxt_free(ctx->script_filename.start); - - return; - } - - nxt_php_execute(ctx, r); - - nxt_free(ctx->script_filename.start); - nxt_free(ctx->script_dirname.start); - - nxt_php_last_target = -1; -} - - -#if (PHP_VERSION_ID < 70400) -static void -nxt_zend_stream_init_fp(zend_file_handle *handle, FILE *fp, - const char *filename) -{ - nxt_memzero(handle, sizeof(zend_file_handle)); - handle->type = ZEND_HANDLE_FP; - handle->handle.fp = fp; - handle->filename = filename; -} -#else -#define nxt_zend_stream_init_fp zend_stream_init_fp -#endif - - -static void -nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r) -{ - FILE *fp; -#if (PHP_VERSION_ID < 50600) - void *read_post; -#endif - const char *filename; - nxt_unit_field_t *f; - zend_file_handle file_handle; - - filename = (const char *) ctx->script_filename.start; - - nxt_unit_req_debug(ctx->req, "PHP execute script %s", filename); - - fp = fopen(filename, "re"); - if (fp == NULL) { - nxt_int_t ec; - - nxt_unit_req_debug(ctx->req, "PHP fopen(\"%s\") failed", filename); - - ec = nxt_php_handle_fs_err(ctx->req); - nxt_unit_request_done(ctx->req, ec); - return; - } - - SG(server_context) = ctx; - SG(options) |= SAPI_OPTION_NO_CHDIR; - SG(request_info).request_uri = nxt_unit_sptr_get(&r->target); - SG(request_info).request_method = nxt_unit_sptr_get(&r->method); - - SG(request_info).proto_num = 1001; - - SG(request_info).query_string = r->query.offset - ? nxt_unit_sptr_get(&r->query) : NULL; - SG(request_info).content_length = r->content_length; - - if (r->content_type_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->content_type_field; - - SG(request_info).content_type = nxt_unit_sptr_get(&f->value); - } - - if (r->cookie_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->cookie_field; - - ctx->cookie = nxt_unit_sptr_get(&f->value); - } - - if (r->authorization_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->authorization_field; - -#ifdef NXT_PHP7 - php_handle_auth_data(nxt_unit_sptr_get(&f->value)); -#else - php_handle_auth_data(nxt_unit_sptr_get(&f->value) TSRMLS_CC); -#endif - - } else { - SG(request_info).auth_digest = NULL; - SG(request_info).auth_user = NULL; - SG(request_info).auth_password = NULL; - } - - SG(sapi_headers).http_response_code = 200; - - SG(request_info).path_translated = NULL; - -#ifdef NXT_PHP7 - if (nxt_slow_path(php_request_startup() == FAILURE)) { -#else - if (nxt_slow_path(php_request_startup(TSRMLS_C) == FAILURE)) { -#endif - nxt_unit_req_debug(ctx->req, "php_request_startup() failed"); - - nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR); - fclose(fp); - - return; - } - - if (ctx->chdir) { - ctx->chdir = 0; - nxt_php_vcwd_chdir(ctx->req, ctx->script_dirname.start); - } - - nxt_zend_stream_init_fp(&file_handle, fp, filename); - - php_execute_script(&file_handle TSRMLS_CC); - -#if (PHP_VERSION_ID >= 80100) - zend_destroy_file_handle(&file_handle); -#endif - - /* Prevention of consuming possible unread request body. */ -#if (PHP_VERSION_ID < 50600) - read_post = sapi_module.read_post; - sapi_module.read_post = NULL; -#else - SG(post_read) = 1; -#endif - - php_request_shutdown(NULL); - - if (ctx->req != NULL) { - nxt_unit_request_done(ctx->req, NXT_UNIT_OK); - } - -#if (PHP_VERSION_ID < 50600) - sapi_module.read_post = read_post; -#endif -} - - -nxt_inline void -nxt_php_vcwd_chdir(nxt_unit_request_info_t *req, u_char *dir) -{ - if (nxt_slow_path(VCWD_CHDIR((char *) dir) != 0)) { - nxt_unit_req_alert(req, "VCWD_CHDIR(%s) failed (%d: %s)", - dir, errno, strerror(errno)); - } -} - - -static int -nxt_php_startup(sapi_module_struct *sapi_module) -{ -#if (PHP_VERSION_ID < 80200) - return php_module_startup(sapi_module, &nxt_php_unit_module, 1); -#else - return php_module_startup(sapi_module, &nxt_php_unit_module); -#endif -} - - -#ifdef NXT_PHP7 -static size_t -nxt_php_unbuffered_write(const char *str, size_t str_length TSRMLS_DC) -#else -static int -nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC) -#endif -{ - int rc; - nxt_php_run_ctx_t *ctx; - - ctx = SG(server_context); - - rc = nxt_unit_response_write(ctx->req, str, str_length); - if (nxt_fast_path(rc == NXT_UNIT_OK)) { - return str_length; - } - - php_handle_aborted_connection(); - return 0; -} - - -static int -nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) -{ - int rc, fields_count; - char *colon, *value; - uint16_t status; - uint32_t resp_size; - nxt_php_run_ctx_t *ctx; - sapi_header_struct *h; - zend_llist_position zpos; - nxt_unit_request_info_t *req; - - ctx = SG(server_context); - req = ctx->req; - - nxt_unit_req_debug(req, "nxt_php_send_headers"); - - if (SG(request_info).no_headers == 1) { - rc = nxt_unit_response_init(req, 200, 0, 0); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return SAPI_HEADER_SEND_FAILED; - } - - return SAPI_HEADER_SENT_SUCCESSFULLY; - } - - resp_size = 0; - fields_count = zend_llist_count(&sapi_headers->headers); - - for (h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos); - h; - h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos)) - { - resp_size += h->header_len; - } - - status = SG(sapi_headers).http_response_code; - - rc = nxt_unit_response_init(req, status, fields_count, resp_size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return SAPI_HEADER_SEND_FAILED; - } - - for (h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos); - h; - h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos)) - { - colon = memchr(h->header, ':', h->header_len); - if (nxt_slow_path(colon == NULL)) { - nxt_unit_req_warn(req, "colon not found in header '%.*s'", - (int) h->header_len, h->header); - continue; - } - - value = colon + 1; - while(isspace(*value)) { - value++; - } - - nxt_unit_response_add_field(req, h->header, colon - h->header, - value, - h->header_len - (value - h->header)); - } - - rc = nxt_unit_response_send(req); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_req_debug(req, "failed to send response"); - - return SAPI_HEADER_SEND_FAILED; - } - - return SAPI_HEADER_SENT_SUCCESSFULLY; -} - - -#ifdef NXT_PHP7 -static size_t -nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC) -#else -static int -nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC) -#endif -{ - nxt_php_run_ctx_t *ctx; - - ctx = SG(server_context); - - nxt_unit_req_debug(ctx->req, "nxt_php_read_post %d", (int) count_bytes); - - return nxt_unit_request_read(ctx->req, buffer, count_bytes); -} - - -static char * -nxt_php_read_cookies(TSRMLS_D) -{ - nxt_php_run_ctx_t *ctx; - - ctx = SG(server_context); - - nxt_unit_req_debug(ctx->req, "nxt_php_read_cookies"); - - return ctx->cookie; -} - - -static void -nxt_php_register_variables(zval *track_vars_array TSRMLS_DC) -{ - const char *name; - nxt_unit_field_t *f, *f_end; - nxt_php_run_ctx_t *ctx; - nxt_unit_request_t *r; - nxt_unit_request_info_t *req; - - ctx = SG(server_context); - - req = ctx->req; - r = req->request; - - nxt_unit_req_debug(req, "nxt_php_register_variables"); - - php_register_variable_safe((char *) "SERVER_SOFTWARE", - (char *) nxt_server.start, - nxt_server.length, track_vars_array TSRMLS_CC); - - nxt_php_set_sptr(req, "SERVER_PROTOCOL", &r->version, r->version_length, - track_vars_array TSRMLS_CC); - - /* - * 'PHP_SELF' - * The filename of the currently executing script, relative to the document - * root. For instance, $_SERVER['PHP_SELF'] in a script at the address - * http://example.com/foo/bar.php would be /foo/bar.php. The __FILE__ - * constant contains the full path and filename of the current (i.e. - * included) file. If PHP is running as a command-line processor this - * variable contains the script name since PHP 4.3.0. Previously it was not - * available. - */ - - if (ctx->path_info.length != 0) { - nxt_php_set_sptr(req, "PHP_SELF", &r->path, r->path_length, - track_vars_array TSRMLS_CC); - - nxt_php_set_str(req, "PATH_INFO", &ctx->path_info, - track_vars_array TSRMLS_CC); - - } else { - nxt_php_set_str(req, "PHP_SELF", &ctx->script_name, - track_vars_array TSRMLS_CC); - } - - /* - * 'SCRIPT_NAME' - * Contains the current script's path. This is useful for pages which need - * to point to themselves. The __FILE__ constant contains the full path and - * filename of the current (i.e. included) file. - */ - - nxt_php_set_str(req, "SCRIPT_NAME", &ctx->script_name, - track_vars_array TSRMLS_CC); - - /* - * 'SCRIPT_FILENAME' - * The absolute pathname of the currently executing script. - */ - - nxt_php_set_str(req, "SCRIPT_FILENAME", &ctx->script_filename, - track_vars_array TSRMLS_CC); - - /* - * 'DOCUMENT_ROOT' - * The document root directory under which the current script is executing, - * as defined in the server's configuration file. - */ - - nxt_php_set_str(req, "DOCUMENT_ROOT", ctx->root, - track_vars_array TSRMLS_CC); - - nxt_php_set_sptr(req, "REQUEST_METHOD", &r->method, r->method_length, - track_vars_array TSRMLS_CC); - nxt_php_set_sptr(req, "REQUEST_URI", &r->target, r->target_length, - track_vars_array TSRMLS_CC); - nxt_php_set_sptr(req, "QUERY_STRING", &r->query, r->query_length, - track_vars_array TSRMLS_CC); - - nxt_php_set_sptr(req, "REMOTE_ADDR", &r->remote, r->remote_length, - track_vars_array TSRMLS_CC); - nxt_php_set_sptr(req, "SERVER_ADDR", &r->local_addr, r->local_addr_length, - track_vars_array TSRMLS_CC); - - nxt_php_set_sptr(req, "SERVER_NAME", &r->server_name, r->server_name_length, - track_vars_array TSRMLS_CC); - nxt_php_set_cstr(req, "SERVER_PORT", "80", 2, track_vars_array TSRMLS_CC); - - if (r->tls) { - nxt_php_set_cstr(req, "HTTPS", "on", 2, track_vars_array TSRMLS_CC); - } - - f_end = r->fields + r->fields_count; - for (f = r->fields; f < f_end; f++) { - name = nxt_unit_sptr_get(&f->name); - - nxt_php_set_sptr(req, name, &f->value, f->value_length, - track_vars_array TSRMLS_CC); - } - - if (r->content_length_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->content_length_field; - - nxt_php_set_sptr(req, "CONTENT_LENGTH", &f->value, f->value_length, - track_vars_array TSRMLS_CC); - } - - if (r->content_type_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->content_type_field; - - nxt_php_set_sptr(req, "CONTENT_TYPE", &f->value, f->value_length, - track_vars_array TSRMLS_CC); - } -} - - -static void -nxt_php_set_sptr(nxt_unit_request_info_t *req, const char *name, - nxt_unit_sptr_t *v, uint32_t len, zval *track_vars_array TSRMLS_DC) -{ - char *str; -#if NXT_PHP7 - size_t new_len; -#else - unsigned int new_len; -#endif - - str = nxt_unit_sptr_get(v); - - nxt_unit_req_debug(req, "php: register %s='%.*s'", name, (int) len, str); - - if (sapi_module.input_filter(PARSE_SERVER, (char *) name, &str, len, - &new_len TSRMLS_CC)) - { - php_register_variable_safe((char *) name, str, new_len, - track_vars_array TSRMLS_CC); - } -} - - -nxt_inline void -nxt_php_set_str(nxt_unit_request_info_t *req, const char *name, - nxt_str_t *s, zval *track_vars_array TSRMLS_DC) -{ - nxt_php_set_cstr(req, name, (char *) s->start, s->length, - track_vars_array TSRMLS_CC); -} - - -#ifdef NXT_PHP7 - -static void * -nxt_php_hash_str_find_ptr(const HashTable *ht, const nxt_str_t *str) -{ - return zend_hash_str_find_ptr(ht, (const char *) str->start, str->length); -} - -#else - -static void * -nxt_php_hash_str_find_ptr(const HashTable *ht, const nxt_str_t *str) -{ - int ret; - void *entry; - char buf[256]; - - if (nxt_slow_path(str->length >= (sizeof(buf) - 1))) { - return NULL; - } - - nxt_memcpy(buf, str->start, str->length); - buf[str->length] = '\0'; - - ret = zend_hash_find(ht, buf, str->length + 1, &entry); - if (nxt_fast_path(ret == SUCCESS)) { - return entry; - } - - return NULL; -} - -#endif - - -static void -nxt_php_set_cstr(nxt_unit_request_info_t *req, const char *name, - const char *cstr, uint32_t len, zval *track_vars_array TSRMLS_DC) -{ - if (nxt_slow_path(cstr == NULL)) { - return; - } - - nxt_unit_req_debug(req, "php: register %s='%.*s'", name, (int) len, cstr); - - php_register_variable_safe((char *) name, (char *) cstr, len, - track_vars_array TSRMLS_CC); -} - - -#if NXT_PHP8 -static void -nxt_php_log_message(const char *message, int syslog_type_int) -#else -#ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE -static void -nxt_php_log_message(char *message, int syslog_type_int) -#else -static void -nxt_php_log_message(char *message TSRMLS_DC) -#endif -#endif -{ - nxt_php_run_ctx_t *ctx; - - ctx = SG(server_context); - - if (ctx != NULL) { - nxt_unit_req_log(ctx->req, NXT_UNIT_LOG_NOTICE, - "php message: %s", message); - - } else { - nxt_unit_log(nxt_php_unit_ctx, NXT_UNIT_LOG_NOTICE, - "php message: %s", message); - } -} diff --git a/src/nxt_polarssl.c b/src/nxt_polarssl.c deleted file mode 100644 index 4a814473..00000000 --- a/src/nxt_polarssl.c +++ /dev/null @@ -1,118 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - * Copyright (C) Igor Sysoev - */ - -#include -#include -#include -#include -#include - - -typedef struct { - ssl_context ssl; - x509_cert certificate; - rsa_context key; -} nxt_polarssl_ctx_t; - - -static nxt_int_t nxt_polarssl_server_init(nxt_ssltls_conf_t *conf); -static void nxt_polarssl_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf, - nxt_event_conn_t *c); -static void nxt_polarssl_log_error(nxt_uint_t level, nxt_log_t *log, int err, - const char *fmt, ...); - - -nxt_ssltls_lib_t nxt_polarssl_lib = { - nxt_polarssl_server_init, - NULL, -}; - - -static nxt_int_t -nxt_polarssl_server_init(nxt_ssltls_conf_t *conf) -{ - int n; - nxt_thread_t *thr; - nxt_polarssl_ctx_t *ctx; - - thr = nxt_thread(); - - /* TODO: mem_pool */ - - ctx = nxt_zalloc(sizeof(nxt_polarssl_ctx_t)); - if (ctx == NULL) { - return NXT_ERROR; - } - - n = ssl_init(&ctx->ssl); - if (n != 0) { - nxt_polarssl_log_error(NXT_LOG_ALERT, thr->log, n, "ssl_init() failed"); - return NXT_ERROR; - } - - ssl_set_endpoint(&ctx->ssl, SSL_IS_SERVER ); - - conf->ctx = ctx; - conf->conn_init = nxt_polarssl_conn_init; - - n = x509parse_crtfile(&ctx->certificate, conf->certificate); - if (n != 0) { - nxt_polarssl_log_error(NXT_LOG_ALERT, thr->log, n, - "x509parse_crt(\"%V\") failed", - &conf->certificate); - goto fail; - } - - rsa_init(&ctx->key, RSA_PKCS_V15, 0); - - n = x509parse_keyfile(&ctx->key, conf->certificate_key, NULL); - if (n != 0) { - nxt_polarssl_log_error(NXT_LOG_ALERT, thr->log, n, - "x509parse_key(\"%V\") failed", - &conf->certificate_key); - goto fail; - } - - ssl_set_own_cert(&ctx->ssl, &ctx->certificate, &ctx->key); - - /* TODO: ciphers */ - - /* TODO: ca_certificate */ - - return NXT_OK; - -fail: - - return NXT_ERROR; -} - - -static void -nxt_polarssl_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf, - nxt_event_conn_t *c) -{ -} - - -static void -nxt_polarssl_log_error(nxt_uint_t level, nxt_log_t *log, int err, - const char *fmt, ...) -{ - va_list args; - u_char *p, *end, msg[NXT_MAX_ERROR_STR]; - - end = msg + NXT_MAX_ERROR_STR; - - va_start(args, fmt); - p = nxt_vsprintf(msg, end, fmt, args); - va_end(args); - - p = nxt_sprintf(p, end, " (%d: ", err); - - error_strerror(err, (char *) msg, p - msg); - - nxt_log_error(level, log, "%*s)", p - msg, msg); -} diff --git a/src/nxt_poll_engine.c b/src/nxt_poll_engine.c deleted file mode 100644 index f514e0a9..00000000 --- a/src/nxt_poll_engine.c +++ /dev/null @@ -1,694 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -#define NXT_POLL_ADD 0 -#define NXT_POLL_CHANGE 1 -#define NXT_POLL_DELETE 2 - - -typedef struct { - /* - * A file descriptor is stored in hash entry to allow - * nxt_poll_fd_hash_test() to not dereference a pointer to - * nxt_fd_event_t which may be invalid if the file descriptor has - * been already closed and the nxt_fd_event_t's memory has been freed. - */ - nxt_socket_t fd; - - uint32_t index; - void *event; -} nxt_poll_hash_entry_t; - - -static nxt_int_t nxt_poll_create(nxt_event_engine_t *engine, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_poll_free(nxt_event_engine_t *engine); -static void nxt_poll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static void nxt_poll_disable(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static nxt_bool_t nxt_poll_close(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_poll_enable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_poll_enable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_poll_disable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_poll_disable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_poll_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static void nxt_poll_block_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_poll_oneshot_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_poll_oneshot_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_poll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, - nxt_uint_t op, nxt_uint_t events); -static nxt_int_t nxt_poll_commit_changes(nxt_event_engine_t *engine); -static nxt_int_t nxt_poll_set_add(nxt_event_engine_t *engine, - nxt_fd_event_t *ev, int events); -static nxt_int_t nxt_poll_set_change(nxt_event_engine_t *engine, - nxt_fd_t fd, int events); -static nxt_int_t nxt_poll_set_delete(nxt_event_engine_t *engine, nxt_fd_t fd); -static void nxt_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); -static nxt_poll_hash_entry_t *nxt_poll_fd_hash_get(nxt_event_engine_t *engine, - nxt_fd_t fd); -static nxt_int_t nxt_poll_fd_hash_test(nxt_lvlhsh_query_t *lhq, void *data); -static void nxt_poll_fd_hash_destroy(nxt_event_engine_t *engine, - nxt_lvlhsh_t *lh); - - -const nxt_event_interface_t nxt_poll_engine = { - "poll", - nxt_poll_create, - nxt_poll_free, - nxt_poll_enable, - nxt_poll_disable, - nxt_poll_disable, - nxt_poll_close, - nxt_poll_enable_read, - nxt_poll_enable_write, - nxt_poll_disable_read, - nxt_poll_disable_write, - nxt_poll_block_read, - nxt_poll_block_write, - nxt_poll_oneshot_read, - nxt_poll_oneshot_write, - nxt_poll_enable_read, - NULL, - NULL, - NULL, - NULL, - nxt_poll, - - &nxt_unix_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static const nxt_lvlhsh_proto_t nxt_poll_fd_hash_proto nxt_aligned(64) = -{ - NXT_LVLHSH_LARGE_MEMALIGN, - nxt_poll_fd_hash_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -static nxt_int_t -nxt_poll_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - engine->u.poll.mchanges = mchanges; - - engine->u.poll.changes = nxt_malloc(sizeof(nxt_poll_change_t) * mchanges); - - if (engine->u.poll.changes != NULL) { - return NXT_OK; - } - - return NXT_ERROR; -} - - -static void -nxt_poll_free(nxt_event_engine_t *engine) -{ - nxt_debug(&engine->task, "poll free"); - - nxt_free(engine->u.poll.set); - nxt_free(engine->u.poll.changes); - nxt_poll_fd_hash_destroy(engine, &engine->u.poll.fd_hash); - - nxt_memzero(&engine->u.poll, sizeof(nxt_poll_engine_t)); -} - - -static void -nxt_poll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_ACTIVE; - ev->write = NXT_EVENT_ACTIVE; - - nxt_poll_change(engine, ev, NXT_POLL_ADD, POLLIN | POLLOUT); -} - - -static void -nxt_poll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE && ev->write != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_poll_change(engine, ev, NXT_POLL_DELETE, 0); - } -} - - -static nxt_bool_t -nxt_poll_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_poll_disable(engine, ev); - - return ev->changing; -} - - -static void -nxt_poll_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - ev->read = NXT_EVENT_ACTIVE; - - if (ev->write == NXT_EVENT_INACTIVE) { - op = NXT_POLL_ADD; - events = POLLIN; - - } else { - op = NXT_POLL_CHANGE; - events = POLLIN | POLLOUT; - } - - nxt_poll_change(engine, ev, op, events); -} - - -static void -nxt_poll_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - ev->write = NXT_EVENT_ACTIVE; - - if (ev->read == NXT_EVENT_INACTIVE) { - op = NXT_POLL_ADD; - events = POLLOUT; - - } else { - op = NXT_POLL_CHANGE; - events = POLLIN | POLLOUT; - } - - nxt_poll_change(engine, ev, op, events); -} - - -static void -nxt_poll_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write == NXT_EVENT_INACTIVE) { - op = NXT_POLL_DELETE; - events = 0; - - } else { - op = NXT_POLL_CHANGE; - events = POLLOUT; - } - - nxt_poll_change(engine, ev, op, events); -} - - -static void -nxt_poll_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read == NXT_EVENT_INACTIVE) { - op = NXT_POLL_DELETE; - events = 0; - - } else { - op = NXT_POLL_CHANGE; - events = POLLIN; - } - - nxt_poll_change(engine, ev, op, events); -} - - -static void -nxt_poll_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - nxt_poll_disable_read(engine, ev); - } -} - - -static void -nxt_poll_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - nxt_poll_disable_write(engine, ev); - } -} - - -static void -nxt_poll_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op; - - op = (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) ? - NXT_POLL_ADD : NXT_POLL_CHANGE; - - ev->read = NXT_EVENT_ONESHOT; - ev->write = NXT_EVENT_INACTIVE; - - nxt_poll_change(engine, ev, op, POLLIN); -} - - -static void -nxt_poll_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op; - - op = (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) ? - NXT_POLL_ADD : NXT_POLL_CHANGE; - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_ONESHOT; - - nxt_poll_change(engine, ev, op, POLLOUT); -} - - -/* - * poll changes are batched to improve instruction and data cache - * locality of several lvlhsh operations followed by poll() call. - */ - -static void -nxt_poll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, nxt_uint_t op, - nxt_uint_t events) -{ - nxt_poll_change_t *change; - - nxt_debug(ev->task, "poll change: fd:%d op:%d ev:%XD", ev->fd, op, events); - - if (engine->u.poll.nchanges >= engine->u.poll.mchanges) { - (void) nxt_poll_commit_changes(engine); - } - - ev->changing = 1; - - change = &engine->u.poll.changes[engine->u.poll.nchanges++]; - change->op = op; - change->events = events; - change->event = ev; -} - - -static nxt_int_t -nxt_poll_commit_changes(nxt_event_engine_t *engine) -{ - nxt_int_t ret, retval; - nxt_fd_event_t *ev; - nxt_poll_change_t *change, *end; - - nxt_debug(&engine->task, "poll changes:%ui", engine->u.poll.nchanges); - - retval = NXT_OK; - change = engine->u.poll.changes; - end = change + engine->u.poll.nchanges; - - do { - ev = change->event; - ev->changing = 0; - - switch (change->op) { - - case NXT_POLL_ADD: - ret = nxt_poll_set_add(engine, ev, change->events); - - if (nxt_fast_path(ret == NXT_OK)) { - goto next; - } - - break; - - case NXT_POLL_CHANGE: - ret = nxt_poll_set_change(engine, ev->fd, change->events); - - if (nxt_fast_path(ret == NXT_OK)) { - goto next; - } - - break; - - case NXT_POLL_DELETE: - ret = nxt_poll_set_delete(engine, ev->fd); - - if (nxt_fast_path(ret == NXT_OK)) { - goto next; - } - - break; - } - - nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler, - ev->task, ev, ev->data); - - retval = NXT_ERROR; - - next: - - change++; - - } while (change < end); - - engine->u.poll.nchanges = 0; - - return retval; -} - - -static nxt_int_t -nxt_poll_set_add(nxt_event_engine_t *engine, nxt_fd_event_t *ev, int events) -{ - nxt_int_t ret; - nxt_uint_t max_nfds; - struct pollfd *pfd; - nxt_lvlhsh_query_t lhq; - nxt_poll_hash_entry_t *phe; - - nxt_debug(&engine->task, "poll add event: fd:%d ev:%04Xi", ev->fd, events); - - if (engine->u.poll.nfds >= engine->u.poll.max_nfds) { - max_nfds = engine->u.poll.max_nfds + 512; /* 4K */ - - pfd = nxt_realloc(engine->u.poll.set, sizeof(struct pollfd) * max_nfds); - if (nxt_slow_path(pfd == NULL)) { - return NXT_ERROR; - } - - engine->u.poll.set = pfd; - engine->u.poll.max_nfds = max_nfds; - } - - phe = nxt_malloc(sizeof(nxt_poll_hash_entry_t)); - if (nxt_slow_path(phe == NULL)) { - return NXT_ERROR; - } - - phe->fd = ev->fd; - phe->index = engine->u.poll.nfds; - phe->event = ev; - - pfd = &engine->u.poll.set[engine->u.poll.nfds++]; - pfd->fd = ev->fd; - pfd->events = events; - pfd->revents = 0; - - lhq.key_hash = nxt_murmur_hash2(&ev->fd, sizeof(nxt_fd_t)); - lhq.replace = 0; - lhq.value = phe; - lhq.proto = &nxt_poll_fd_hash_proto; - lhq.data = engine; - - ret = nxt_lvlhsh_insert(&engine->u.poll.fd_hash, &lhq); - - if (nxt_fast_path(ret == NXT_OK)) { - return NXT_OK; - } - - nxt_free(phe); - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_poll_set_change(nxt_event_engine_t *engine, nxt_fd_t fd, int events) -{ - nxt_poll_hash_entry_t *phe; - - nxt_debug(&engine->task, "poll change event: fd:%d ev:%04Xi", - fd, events); - - phe = nxt_poll_fd_hash_get(engine, fd); - - if (nxt_fast_path(phe != NULL)) { - engine->u.poll.set[phe->index].events = events; - return NXT_OK; - } - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_poll_set_delete(nxt_event_engine_t *engine, nxt_fd_t fd) -{ - nxt_int_t ret; - nxt_uint_t index, nfds; - nxt_lvlhsh_query_t lhq; - nxt_poll_hash_entry_t *phe; - - nxt_debug(&engine->task, "poll delete event: fd:%d", fd); - - lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); - lhq.proto = &nxt_poll_fd_hash_proto; - lhq.data = engine; - - ret = nxt_lvlhsh_delete(&engine->u.poll.fd_hash, &lhq); - - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - phe = lhq.value; - - index = phe->index; - engine->u.poll.nfds--; - nfds = engine->u.poll.nfds; - - if (index != nfds) { - engine->u.poll.set[index] = engine->u.poll.set[nfds]; - - phe = nxt_poll_fd_hash_get(engine, engine->u.poll.set[nfds].fd); - - phe->index = index; - } - - nxt_free(lhq.value); - - return NXT_OK; -} - - -static void -nxt_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) -{ - int nevents; - nxt_fd_t fd; - nxt_err_t err; - nxt_bool_t error; - nxt_uint_t i, events, level; - struct pollfd *pfd; - nxt_fd_event_t *ev; - nxt_poll_hash_entry_t *phe; - - if (engine->u.poll.nchanges != 0) { - if (nxt_poll_commit_changes(engine) != NXT_OK) { - /* Error handlers have been enqueued on failure. */ - timeout = 0; - } - } - - nxt_debug(&engine->task, "poll() events:%ui timeout:%M", - engine->u.poll.nfds, timeout); - - nevents = poll(engine->u.poll.set, engine->u.poll.nfds, timeout); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(engine->task.thread); - - nxt_debug(&engine->task, "poll(): %d", nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - nxt_log(&engine->task, level, "poll() failed %E", err); - return; - } - - for (i = 0; i < engine->u.poll.nfds && nevents != 0; i++) { - - pfd = &engine->u.poll.set[i]; - events = pfd->revents; - - if (events == 0) { - continue; - } - - fd = pfd->fd; - - phe = nxt_poll_fd_hash_get(engine, fd); - - if (nxt_slow_path(phe == NULL)) { - nxt_alert(&engine->task, - "poll() returned invalid fd:%d ev:%04Xd rev:%04uXi", - fd, pfd->events, events); - - /* Mark the poll entry to ignore it by the kernel. */ - pfd->fd = -1; - goto next; - } - - ev = phe->event; - - nxt_debug(ev->task, "poll: fd:%d ev:%04uXi rd:%d wr:%d", - fd, events, ev->read, ev->write); - - if (nxt_slow_path((events & POLLNVAL) != 0)) { - nxt_alert(ev->task, "poll() error fd:%d ev:%04Xd rev:%04uXi", - fd, pfd->events, events); - - /* Mark the poll entry to ignore it by the kernel. */ - pfd->fd = -1; - - nxt_work_queue_add(&engine->fast_work_queue, - ev->error_handler, ev->task, ev, ev->data); - goto next; - } - - /* - * On a socket's remote end close: - * - * Linux, FreeBSD, and Solaris set POLLIN; - * MacOSX sets POLLIN and POLLHUP; - * NetBSD sets POLLIN, and poll(2) claims this explicitly: - * - * If the remote end of a socket is closed, poll() - * returns a POLLIN event, rather than a POLLHUP. - * - * On error: - * - * Linux sets POLLHUP and POLLERR only; - * FreeBSD adds POLLHUP to POLLIN or POLLOUT, although poll(2) - * claims the opposite: - * - * Note that POLLHUP and POLLOUT should never be - * present in the revents bitmask at the same time. - * - * Solaris and NetBSD do not add POLLHUP or POLLERR; - * MacOSX sets POLLHUP only. - * - * If an implementation sets POLLERR or POLLHUP only without POLLIN - * or POLLOUT, the "error" variable enqueues only one active handler. - */ - - error = (((events & (POLLERR | POLLHUP)) != 0) - && ((events & (POLLIN | POLLOUT)) == 0)); - - if ((events & POLLIN) || (error && ev->read_handler != NULL)) { - error = 0; - ev->read_ready = 1; - - if (ev->read == NXT_EVENT_ONESHOT) { - ev->read = NXT_EVENT_INACTIVE; - nxt_poll_change(engine, ev, NXT_POLL_DELETE, 0); - } - - nxt_work_queue_add(ev->read_work_queue, ev->read_handler, - ev->task, ev, ev->data); - } - - if ((events & POLLOUT) || (error && ev->write_handler != NULL)) { - ev->write_ready = 1; - - if (ev->write == NXT_EVENT_ONESHOT) { - ev->write = NXT_EVENT_INACTIVE; - nxt_poll_change(engine, ev, NXT_POLL_DELETE, 0); - } - - nxt_work_queue_add(ev->write_work_queue, ev->write_handler, - ev->task, ev, ev->data); - } - - next: - - nevents--; - } -} - - -static nxt_poll_hash_entry_t * -nxt_poll_fd_hash_get(nxt_event_engine_t *engine, nxt_fd_t fd) -{ - nxt_lvlhsh_query_t lhq; - nxt_poll_hash_entry_t *phe; - - lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); - lhq.proto = &nxt_poll_fd_hash_proto; - lhq.data = engine; - - if (nxt_lvlhsh_find(&engine->u.poll.fd_hash, &lhq) == NXT_OK) { - phe = lhq.value; - return phe; - } - - nxt_alert(&engine->task, "fd %d not found in hash", fd); - - return NULL; -} - - -static nxt_int_t -nxt_poll_fd_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_event_engine_t *engine; - nxt_poll_hash_entry_t *phe; - - phe = data; - - /* nxt_murmur_hash2() is unique for 4 bytes. */ - - engine = lhq->data; - - if (nxt_fast_path(phe->fd == engine->u.poll.set[phe->index].fd)) { - return NXT_OK; - } - - nxt_alert(&engine->task, "fd %d in hash mismatches fd %d in poll set", - phe->fd, engine->u.poll.set[phe->index].fd); - - return NXT_DECLINED; -} - - -static void -nxt_poll_fd_hash_destroy(nxt_event_engine_t *engine, nxt_lvlhsh_t *lh) -{ - nxt_poll_hash_entry_t *phe; - - for ( ;; ) { - phe = nxt_lvlhsh_retrieve(lh, &nxt_poll_fd_hash_proto, NULL); - - if (phe == NULL) { - return; - } - - nxt_free(phe); - } -} diff --git a/src/nxt_pollset_engine.c b/src/nxt_pollset_engine.c deleted file mode 100644 index e2c1a2d0..00000000 --- a/src/nxt_pollset_engine.c +++ /dev/null @@ -1,645 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * pollset has been introduced in AIX 5L 5.3. - * - * pollset_create() returns a pollset_t descriptor which is not - * a file descriptor, so it cannot be added to another pollset. - * The first pollset_create() call returns 0. - */ - - -#define NXT_POLLSET_ADD 0 -#define NXT_POLLSET_UPDATE 1 -#define NXT_POLLSET_CHANGE 2 -#define NXT_POLLSET_DELETE 3 - - -static nxt_int_t nxt_pollset_create(nxt_event_engine_t *engine, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_pollset_free(nxt_event_engine_t *engine); -static void nxt_pollset_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static void nxt_pollset_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static nxt_bool_t nxt_pollset_close(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_pollset_enable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_pollset_enable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_pollset_disable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_pollset_disable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_pollset_block_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_pollset_block_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_pollset_oneshot_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_pollset_oneshot_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_pollset_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, - nxt_uint_t op, nxt_uint_t events); -static nxt_int_t nxt_pollset_commit_changes(nxt_event_engine_t *engine); -static void nxt_pollset_change_error(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_pollset_remove(nxt_event_engine_t *engine, nxt_fd_t fd); -static nxt_int_t nxt_pollset_write(nxt_event_engine_t *engine, - struct poll_ctl *ctl, int n); -static void nxt_pollset_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); - - -const nxt_event_interface_t nxt_pollset_engine = { - "pollset", - nxt_pollset_create, - nxt_pollset_free, - nxt_pollset_enable, - nxt_pollset_disable, - nxt_pollset_disable, - nxt_pollset_close, - nxt_pollset_enable_read, - nxt_pollset_enable_write, - nxt_pollset_disable_read, - nxt_pollset_disable_write, - nxt_pollset_block_read, - nxt_pollset_block_write, - nxt_pollset_oneshot_read, - nxt_pollset_oneshot_write, - nxt_pollset_enable_read, - NULL, - NULL, - NULL, - NULL, - nxt_pollset_poll, - - &nxt_unix_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static nxt_int_t -nxt_pollset_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - void *changes; - - engine->u.pollset.ps = -1; - engine->u.pollset.mchanges = mchanges; - engine->u.pollset.mevents = mevents; - - changes = nxt_malloc(sizeof(nxt_pollset_change_t) * mchanges); - if (changes == NULL) { - goto fail; - } - - engine->u.pollset.changes = changes; - - /* - * NXT_POLLSET_CHANGE requires two struct poll_ctl's - * for PS_DELETE and subsequent PS_ADD. - */ - changes = nxt_malloc(2 * sizeof(struct poll_ctl) * mchanges); - if (changes == NULL) { - goto fail; - } - - engine->u.pollset.write_changes = changes; - - engine->u.pollset.events = nxt_malloc(sizeof(struct pollfd) * mevents); - if (engine->u.pollset.events == NULL) { - goto fail; - } - - engine->u.pollset.ps = pollset_create(-1); - - if (engine->u.pollset.ps == -1) { - nxt_alert(&engine->task, "pollset_create() failed %E", nxt_errno); - goto fail; - } - - nxt_debug(&engine->task, "pollset_create(): %d", engine->u.pollset.ps); - - return NXT_OK; - -fail: - - nxt_pollset_free(engine); - - return NXT_ERROR; -} - - -static void -nxt_pollset_free(nxt_event_engine_t *engine) -{ - pollset_t ps; - - ps = engine->u.pollset.ps; - - nxt_debug(&engine->task, "pollset %d free", ps); - - if (ps != -1 && pollset_destroy(ps) != 0) { - nxt_alert(&engine->task, "pollset_destroy(%d) failed %E", - ps, nxt_errno); - } - - nxt_free(engine->u.pollset.events); - nxt_free(engine->u.pollset.write_changes); - nxt_free(engine->u.pollset.changes); - nxt_fd_event_hash_destroy(&engine->u.pollset.fd_hash); - - nxt_memzero(&engine->u.pollset, sizeof(nxt_pollset_engine_t)); -} - - -static void -nxt_pollset_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_ACTIVE; - ev->write = NXT_EVENT_ACTIVE; - - nxt_pollset_change(engine, ev, NXT_POLLSET_ADD, POLLIN | POLLOUT); -} - - -static void -nxt_pollset_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_pollset_change(engine, ev, NXT_POLLSET_DELETE, 0); - } -} - - -/* - * A closed descriptor must be deleted from a pollset, otherwise next - * pollset_poll() will return POLLNVAL on it. However, pollset_ctl() - * allows to delete the already closed file descriptor from the pollset - * using PS_DELETE, so the removal can be batched, pollset_ctl(2): - * - * After a file descriptor is added to a pollset, the file descriptor will - * not be removed until a pollset_ctl call with the cmd of PS_DELETE is - * executed. The file descriptor remains in the pollset even if the file - * descriptor is closed. A pollset_poll operation on a pollset containing - * a closed file descriptor returns a POLLNVAL event for that file - * descriptor. If the file descriptor is later allocated to a new object, - * the new object will be polled on future pollset_poll calls. - */ - -static nxt_bool_t -nxt_pollset_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_pollset_disable(engine, ev); - - return ev->changing; -} - - -static void -nxt_pollset_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - if (ev->read != NXT_EVENT_BLOCKED) { - - events = POLLIN; - - if (ev->write == NXT_EVENT_INACTIVE) { - op = NXT_POLLSET_ADD; - - } else if (ev->write == NXT_EVENT_BLOCKED) { - ev->write = NXT_EVENT_INACTIVE; - op = NXT_POLLSET_CHANGE; - - } else { - op = NXT_POLLSET_UPDATE; - events = POLLIN | POLLOUT; - } - - nxt_pollset_change(engine, ev, op, events); - } - - ev->read = NXT_EVENT_ACTIVE; -} - - -static void -nxt_pollset_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - if (ev->write != NXT_EVENT_BLOCKED) { - - events = POLLOUT; - - if (ev->read == NXT_EVENT_INACTIVE) { - op = NXT_POLLSET_ADD; - - } else if (ev->read == NXT_EVENT_BLOCKED) { - ev->read = NXT_EVENT_INACTIVE; - op = NXT_POLLSET_CHANGE; - - } else { - op = NXT_POLLSET_UPDATE; - events = POLLIN | POLLOUT; - } - - nxt_pollset_change(engine, ev, op, events); - } - - ev->write = NXT_EVENT_ACTIVE; -} - - -static void -nxt_pollset_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write <= NXT_EVENT_BLOCKED) { - ev->write = NXT_EVENT_INACTIVE; - op = NXT_POLLSET_DELETE; - events = POLLREMOVE; - - } else { - op = NXT_POLLSET_CHANGE; - events = POLLOUT; - } - - nxt_pollset_change(engine, ev, op, events); -} - - -static void -nxt_pollset_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_uint_t op, events; - - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read <= NXT_EVENT_BLOCKED) { - ev->read = NXT_EVENT_INACTIVE; - op = NXT_POLLSET_DELETE; - events = POLLREMOVE; - - } else { - op = NXT_POLLSET_CHANGE; - events = POLLIN; - } - - nxt_pollset_change(engine, ev, op, events); -} - - -static void -nxt_pollset_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_pollset_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_pollset_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_pollset_enable_read(engine, ev); - - ev->read = NXT_EVENT_ONESHOT; -} - - -static void -nxt_pollset_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_pollset_enable_write(engine, ev); - - ev->write = NXT_EVENT_ONESHOT; -} - - -/* - * PS_ADD adds only a new file descriptor to a pollset. - * PS_DELETE removes a file descriptor from a pollset. - * - * PS_MOD can add a new file descriptor or modify events for a file - * descriptor which is already in a pollset. However, modified events - * are always ORed, so to delete an event for a file descriptor, - * the file descriptor must be removed using PS_DELETE and then - * added again without the event. - */ - -static void -nxt_pollset_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, - nxt_uint_t op, nxt_uint_t events) -{ - nxt_pollset_change_t *change; - - nxt_debug(ev->task, "pollset %d change fd:%d op:%ui ev:%04Xi", - engine->u.pollset.ps, ev->fd, op, events); - - if (engine->u.pollset.nchanges >= engine->u.pollset.mchanges) { - (void) nxt_pollset_commit_changes(engine); - } - - ev->changing = 1; - - change = &engine->u.pollset.changes[engine->u.pollset.nchanges++]; - change->op = op; - change->cmd = (op == NXT_POLLSET_DELETE) ? PS_DELETE : PS_MOD; - change->events = events; - change->event = ev; -} - - -static nxt_int_t -nxt_pollset_commit_changes(nxt_event_engine_t *engine) -{ - size_t n; - nxt_int_t ret, retval; - nxt_fd_event_t *ev; - struct poll_ctl *ctl, *write_changes; - nxt_pollset_change_t *change, *end; - - nxt_debug(&engine->task, "pollset %d changes:%ui", - engine->u.pollset.ps, engine->u.pollset.nchanges); - - retval = NXT_OK; - n = 0; - write_changes = engine->u.pollset.write_changes; - change = engine->u.pollset.changes; - end = change + engine->u.pollset.nchanges; - - do { - ev = change->event; - ev->changing = 0; - - nxt_debug(&engine->task, "pollset fd:%d op:%d ev:%04Xd", - ev->fd, change->op, change->events); - - if (change->op == NXT_POLLSET_CHANGE) { - ctl = &write_changes[n++]; - ctl->cmd = PS_DELETE; - ctl->events = 0; - ctl->fd = ev->fd; - } - - ctl = &write_changes[n++]; - ctl->cmd = change->cmd; - ctl->events = change->events; - ctl->fd = ev->fd; - - change++; - - } while (change < end); - - change = engine->u.pollset.changes; - end = change + engine->u.pollset.nchanges; - - ret = nxt_pollset_write(engine, write_changes, n); - - if (nxt_slow_path(ret != NXT_OK)) { - - do { - nxt_pollset_change_error(engine, change->event); - change++; - } while (change < end); - - engine->u.pollset.nchanges = 0; - - return NXT_ERROR; - } - - do { - ev = change->event; - - if (change->op == NXT_POLLSET_ADD) { - ret = nxt_fd_event_hash_add(&engine->u.pollset.fd_hash, ev->fd, ev); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_pollset_change_error(engine, ev); - retval = NXT_ERROR; - } - - } else if (change->op == NXT_POLLSET_DELETE) { - nxt_fd_event_hash_delete(&engine->task, &engine->u.pollset.fd_hash, - ev->fd, 0); - } - - /* Nothing to do for NXT_POLLSET_UPDATE and NXT_POLLSET_CHANGE. */ - - change++; - - } while (change < end); - - engine->u.pollset.nchanges = 0; - - return retval; -} - - -static void -nxt_pollset_change_error(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler, - ev->task, ev, ev->data); - - nxt_fd_event_hash_delete(&engine->task, &engine->u.pollset.fd_hash, - ev->fd, 1); - - nxt_pollset_remove(engine, ev->fd); -} - - -static void -nxt_pollset_remove(nxt_event_engine_t *engine, nxt_fd_t fd) -{ - int n; - struct pollfd pfd; - struct poll_ctl ctl; - - pfd.fd = fd; - pfd.events = 0; - pfd.revents = 0; - - n = pollset_query(engine->u.pollset.ps, &pfd); - - nxt_debug(&engine->task, "pollset_query(%d, %d): %d", - engine->u.pollset.ps, fd, n); - - if (n == 0) { - /* The file descriptor is not in the pollset. */ - return; - } - - if (n == -1) { - nxt_alert(&engine->task, "pollset_query(%d, %d) failed %E", - engine->u.pollset.ps, fd, nxt_errno); - /* Fall through. */ - } - - /* n == 1: The file descriptor is in the pollset. */ - - nxt_debug(&engine->task, "pollset %d remove fd:%d", - engine->u.pollset.ps, fd); - - ctl.cmd = PS_DELETE; - ctl.events = 0; - ctl.fd = fd; - - nxt_pollset_write(engine, &ctl, 1); -} - - -static nxt_int_t -nxt_pollset_write(nxt_event_engine_t *engine, struct poll_ctl *ctl, int n) -{ - pollset_t ps; - - ps = engine->u.pollset.ps; - - nxt_debug(&engine->task, "pollset_ctl(%d) changes:%d", ps, n); - - nxt_set_errno(0); - - n = pollset_ctl(ps, ctl, n); - - if (nxt_fast_path(n == 0)) { - return NXT_OK; - } - - nxt_alert(&engine->task, "pollset_ctl(%d) failed: %d %E", ps, n, nxt_errno); - - return NXT_ERROR; -} - - -static void -nxt_pollset_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) -{ - int nevents; - nxt_fd_t fd; - nxt_int_t i; - nxt_err_t err; - nxt_uint_t events, level; - struct pollfd *pfd; - nxt_fd_event_t *ev; - - if (engine->u.pollset.nchanges != 0) { - if (nxt_pollset_commit_changes(engine) != NXT_OK) { - /* Error handlers have been enqueued on failure. */ - timeout = 0; - } - } - - nxt_debug(&engine->task, "pollset_poll(%d) timeout:%M", - engine->u.pollset.ps, timeout); - - nevents = pollset_poll(engine->u.pollset.ps, engine->u.pollset.events, - engine->u.pollset.mevents, timeout); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(engine->task.thread); - - nxt_debug(&engine->task, "pollset_poll(%d): %d", - engine->u.pollset.ps, nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - - nxt_log(&engine->task, level, "pollset_poll(%d) failed %E", - engine->u.pollset.ps, err); - - return; - } - - for (i = 0; i < nevents; i++) { - - pfd = &engine->u.pollset.events[i]; - fd = pfd->fd; - events = pfd->revents; - - ev = nxt_fd_event_hash_get(&engine->task, &engine->u.pollset.fd_hash, - fd); - - if (nxt_slow_path(ev == NULL)) { - nxt_alert(&engine->task, - "pollset_poll(%d) returned invalid " - "fd:%d ev:%04Xd rev:%04uXi", - engine->u.pollset.ps, fd, pfd->events, events); - - nxt_pollset_remove(engine, fd); - continue; - } - - nxt_debug(ev->task, "pollset: fd:%d ev:%04uXi", fd, events); - - if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { - nxt_alert(ev->task, - "pollset_poll(%d) error fd:%d ev:%04Xd rev:%04uXi", - engine->u.pollset.ps, fd, pfd->events, events); - - nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler, - ev->task, ev, ev->data); - continue; - } - - if (events & POLLIN) { - ev->read_ready = 1; - - if (ev->read != NXT_EVENT_BLOCKED) { - nxt_work_queue_add(ev->read_work_queue, ev->read_handler, - ev->task, ev, ev->data); - } - - if (ev->read == NXT_EVENT_BLOCKED - || ev->read == NXT_EVENT_ONESHOT) - { - nxt_pollset_disable_read(engine, ev); - } - } - - if (events & POLLOUT) { - ev->write_ready = 1; - - if (ev->write != NXT_EVENT_BLOCKED) { - nxt_work_queue_add(ev->write_work_queue, ev->write_handler, - ev->task, ev, ev->data); - } - - if (ev->write == NXT_EVENT_BLOCKED - || ev->write == NXT_EVENT_ONESHOT) - { - nxt_pollset_disable_write(engine, ev); - } - } - } -} diff --git a/src/nxt_port.c b/src/nxt_port.c deleted file mode 100644 index b9964df4..00000000 --- a/src/nxt_port.c +++ /dev/null @@ -1,631 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include -#include - - -static void nxt_port_remove_pid(nxt_task_t *task, nxt_port_recv_msg_t *msg, - nxt_pid_t pid); -static void nxt_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); - -static nxt_atomic_uint_t nxt_port_last_id = 1; - - -static void -nxt_port_mp_cleanup(nxt_task_t *task, void *obj, void *data) -{ - nxt_mp_t *mp; - nxt_port_t *port; - - port = obj; - mp = data; - - nxt_assert(port->pair[0] == -1); - nxt_assert(port->pair[1] == -1); - - nxt_assert(port->use_count == 0); - nxt_assert(port->app_link.next == NULL); - nxt_assert(port->idle_link.next == NULL); - - nxt_assert(nxt_queue_is_empty(&port->messages)); - nxt_assert(nxt_lvlhsh_is_empty(&port->rpc_streams)); - nxt_assert(nxt_lvlhsh_is_empty(&port->rpc_peers)); - - nxt_thread_mutex_destroy(&port->write_mutex); - - nxt_mp_free(mp, port); -} - - -nxt_port_t * -nxt_port_new(nxt_task_t *task, nxt_port_id_t id, nxt_pid_t pid, - nxt_process_type_t type) -{ - nxt_mp_t *mp; - nxt_port_t *port; - - mp = nxt_mp_create(1024, 128, 256, 32); - - if (nxt_slow_path(mp == NULL)) { - return NULL; - } - - port = nxt_mp_zalloc(mp, sizeof(nxt_port_t)); - - if (nxt_fast_path(port != NULL)) { - port->id = id; - port->pid = pid; - port->type = type; - port->mem_pool = mp; - port->use_count = 1; - - nxt_mp_cleanup(mp, nxt_port_mp_cleanup, task, port, mp); - - nxt_queue_init(&port->messages); - nxt_thread_mutex_create(&port->write_mutex); - - port->queue_fd = -1; - - } else { - nxt_mp_destroy(mp); - } - - nxt_thread_log_debug("port %p %d:%d new, type %d", port, pid, id, type); - - return port; -} - - -void -nxt_port_close(nxt_task_t *task, nxt_port_t *port) -{ - size_t size; - - nxt_debug(task, "port %p %d:%d close, type %d", port, port->pid, - port->id, port->type); - - if (port->pair[0] != -1) { - nxt_port_rpc_close(task, port); - - nxt_fd_close(port->pair[0]); - port->pair[0] = -1; - } - - if (port->pair[1] != -1) { - nxt_fd_close(port->pair[1]); - port->pair[1] = -1; - - if (port->app != NULL) { - nxt_router_app_port_close(task, port); - } - } - - if (port->queue_fd != -1) { - nxt_fd_close(port->queue_fd); - port->queue_fd = -1; - } - - if (port->queue != NULL) { - size = (port->id == (nxt_port_id_t) -1) ? sizeof(nxt_app_queue_t) - : sizeof(nxt_port_queue_t); - nxt_mem_munmap(port->queue, size); - - port->queue = NULL; - } -} - - -static void -nxt_port_release(nxt_task_t *task, nxt_port_t *port) -{ - nxt_debug(task, "port %p %d:%d release, type %d", port, port->pid, - port->id, port->type); - - port->app = NULL; - - if (port->link.next != NULL) { - nxt_assert(port->process != NULL); - - nxt_process_port_remove(port); - - nxt_process_use(task, port->process, -1); - } - - nxt_mp_release(port->mem_pool); -} - - -nxt_port_id_t -nxt_port_get_next_id(void) -{ - return nxt_atomic_fetch_add(&nxt_port_last_id, 1); -} - - -void -nxt_port_reset_next_id(void) -{ - nxt_port_last_id = 1; -} - - -void -nxt_port_enable(nxt_task_t *task, nxt_port_t *port, - const nxt_port_handlers_t *handlers) -{ - port->pid = nxt_pid; - port->handler = nxt_port_handler; - port->data = (nxt_port_handler_t *) (handlers); - - nxt_port_read_enable(task, port); -} - - -static void -nxt_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_port_handler_t *handlers; - - if (nxt_fast_path(msg->port_msg.type < NXT_PORT_MSG_MAX)) { - - nxt_debug(task, "port %d: message type:%uD fds:%d,%d", - msg->port->socket.fd, msg->port_msg.type, - msg->fd[0], msg->fd[1]); - - handlers = msg->port->data; - handlers[msg->port_msg.type](task, msg); - - return; - } - - nxt_alert(task, "port %d: unknown message type:%uD", - msg->port->socket.fd, msg->port_msg.type); -} - - -void -nxt_port_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_runtime_quit(task, 0); -} - - -/* TODO join with process_ready and move to nxt_main_process.c */ -nxt_inline void -nxt_port_send_new_port(nxt_task_t *task, nxt_runtime_t *rt, - nxt_port_t *new_port, uint32_t stream) -{ - nxt_port_t *port; - nxt_process_t *process; - - nxt_debug(task, "new port %d for process %PI", - new_port->pair[1], new_port->pid); - - nxt_runtime_process_each(rt, process) { - - if (process->pid == new_port->pid || process->pid == nxt_pid) { - continue; - } - - port = nxt_process_port_first(process); - - if (nxt_proc_send_matrix[port->type][new_port->type]) { - (void) nxt_port_send_port(task, port, new_port, stream); - } - - } nxt_runtime_process_loop; -} - - -nxt_int_t -nxt_port_send_port(nxt_task_t *task, nxt_port_t *port, nxt_port_t *new_port, - uint32_t stream) -{ - nxt_buf_t *b; - nxt_port_msg_new_port_t *msg; - - b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, - sizeof(nxt_port_data_t)); - if (nxt_slow_path(b == NULL)) { - return NXT_ERROR; - } - - nxt_debug(task, "send port %FD to process %PI", - new_port->pair[1], port->pid); - - b->mem.free += sizeof(nxt_port_msg_new_port_t); - msg = (nxt_port_msg_new_port_t *) b->mem.pos; - - msg->id = new_port->id; - msg->pid = new_port->pid; - msg->max_size = port->max_size; - msg->max_share = port->max_share; - msg->type = new_port->type; - - return nxt_port_socket_write2(task, port, NXT_PORT_MSG_NEW_PORT, - new_port->pair[1], new_port->queue_fd, - stream, 0, b); -} - - -void -nxt_port_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_port_t *port; - nxt_runtime_t *rt; - nxt_port_msg_new_port_t *new_port_msg; - - rt = task->thread->runtime; - - new_port_msg = (nxt_port_msg_new_port_t *) msg->buf->mem.pos; - - /* TODO check b size and make plain */ - - nxt_debug(task, "new port %d received for process %PI:%d", - msg->fd[0], new_port_msg->pid, new_port_msg->id); - - port = nxt_runtime_port_find(rt, new_port_msg->pid, new_port_msg->id); - if (port != NULL) { - nxt_debug(task, "port %PI:%d already exists", new_port_msg->pid, - new_port_msg->id); - - msg->u.new_port = port; - - nxt_fd_close(msg->fd[0]); - msg->fd[0] = -1; - return; - } - - port = nxt_runtime_process_port_create(task, rt, new_port_msg->pid, - new_port_msg->id, - new_port_msg->type); - if (nxt_slow_path(port == NULL)) { - return; - } - - nxt_fd_nonblocking(task, msg->fd[0]); - - port->pair[0] = -1; - port->pair[1] = msg->fd[0]; - port->max_size = new_port_msg->max_size; - port->max_share = new_port_msg->max_share; - - port->socket.task = task; - - nxt_port_write_enable(task, port); - - msg->u.new_port = port; -} - -/* TODO move to nxt_main_process.c */ -void -nxt_port_process_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_port_t *port; - nxt_process_t *process; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - process = nxt_runtime_process_find(rt, msg->port_msg.pid); - if (nxt_slow_path(process == NULL)) { - return; - } - - nxt_assert(process->state != NXT_PROCESS_STATE_READY); - - process->state = NXT_PROCESS_STATE_READY; - - nxt_assert(!nxt_queue_is_empty(&process->ports)); - - port = nxt_process_port_first(process); - - nxt_debug(task, "process %PI ready", msg->port_msg.pid); - - if (msg->fd[0] != -1) { - port->queue_fd = msg->fd[0]; - port->queue = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t), - PROT_READ | PROT_WRITE, MAP_SHARED, - msg->fd[0], 0); - } - - nxt_port_send_new_port(task, rt, port, msg->port_msg.stream); -} - - -void -nxt_port_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_runtime_t *rt; - nxt_process_t *process; - - rt = task->thread->runtime; - - if (nxt_slow_path(msg->fd[0] == -1)) { - nxt_log(task, NXT_LOG_WARN, "invalid fd passed with mmap message"); - - return; - } - - process = nxt_runtime_process_find(rt, msg->port_msg.pid); - if (nxt_slow_path(process == NULL)) { - nxt_log(task, NXT_LOG_WARN, "failed to get process #%PI", - msg->port_msg.pid); - - goto fail_close; - } - - nxt_port_incoming_port_mmap(task, process, msg->fd[0]); - -fail_close: - - nxt_fd_close(msg->fd[0]); -} - - -void -nxt_port_change_log_file(nxt_task_t *task, nxt_runtime_t *rt, nxt_uint_t slot, - nxt_fd_t fd) -{ - nxt_buf_t *b; - nxt_port_t *port; - nxt_process_t *process; - - nxt_debug(task, "change log file #%ui fd:%FD", slot, fd); - - nxt_runtime_process_each(rt, process) { - - if (nxt_pid == process->pid) { - continue; - } - - port = nxt_process_port_first(process); - - b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, - sizeof(nxt_uint_t), 0); - if (nxt_slow_path(b == NULL)) { - continue; - } - - b->mem.free = nxt_cpymem(b->mem.free, &slot, sizeof(nxt_uint_t)); - - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_CHANGE_FILE, - fd, 0, 0, b); - - } nxt_runtime_process_loop; -} - - -void -nxt_port_change_log_file_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_buf_t *b; - nxt_uint_t slot; - nxt_file_t *log_file; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - b = msg->buf; - slot = *(nxt_uint_t *) b->mem.pos; - - log_file = nxt_list_elt(rt->log_files, slot); - - nxt_debug(task, "change log file %FD:%FD", msg->fd[0], log_file->fd); - - /* - * The old log file descriptor must be closed at the moment when no - * other threads use it. dup2() allows to use the old file descriptor - * for new log file. This change is performed atomically in the kernel. - */ - if (nxt_file_redirect(log_file, msg->fd[0]) == NXT_OK) { - if (slot == 0) { - (void) nxt_file_stderr(log_file); - } - } -} - - -void -nxt_port_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - size_t dump_size; - nxt_buf_t *b; - - b = msg->buf; - dump_size = b->mem.free - b->mem.pos; - - if (dump_size > 300) { - dump_size = 300; - } - - nxt_debug(task, "data: %*s", dump_size, b->mem.pos); -} - - -void -nxt_port_remove_notify_others(nxt_task_t *task, nxt_process_t *process) -{ - nxt_pid_t pid; - nxt_buf_t *buf; - nxt_port_t *port; - nxt_runtime_t *rt; - nxt_process_t *p; - nxt_process_type_t ptype; - - pid = process->pid; - - ptype = nxt_process_type(process); - - rt = task->thread->runtime; - - nxt_runtime_process_each(rt, p) { - - if (p->pid == nxt_pid - || p->pid == pid - || nxt_queue_is_empty(&p->ports)) - { - continue; - } - - port = nxt_process_port_first(p); - - if (nxt_proc_remove_notify_matrix[ptype][port->type] == 0) { - continue; - } - - buf = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, - sizeof(pid)); - - if (nxt_slow_path(buf == NULL)) { - continue; - } - - buf->mem.free = nxt_cpymem(buf->mem.free, &pid, sizeof(pid)); - - nxt_port_socket_write(task, port, NXT_PORT_MSG_REMOVE_PID, -1, - process->stream, 0, buf); - - } nxt_runtime_process_loop; -} - - -void -nxt_port_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_pid_t pid; - nxt_buf_t *buf; - - buf = msg->buf; - - nxt_assert(nxt_buf_used_size(buf) == sizeof(pid)); - - nxt_memcpy(&pid, buf->mem.pos, sizeof(nxt_pid_t)); - - nxt_port_remove_pid(task, msg, pid); -} - - -static void -nxt_port_remove_pid(nxt_task_t *task, nxt_port_recv_msg_t *msg, - nxt_pid_t pid) -{ - nxt_runtime_t *rt; - nxt_process_t *process; - - msg->u.removed_pid = pid; - - nxt_debug(task, "port remove pid %PI handler", pid); - - rt = task->thread->runtime; - - nxt_port_rpc_remove_peer(task, msg->port, pid); - - process = nxt_runtime_process_find(rt, pid); - - if (process) { - nxt_process_close_ports(task, process); - } -} - - -void -nxt_port_empty_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_debug(task, "port empty handler"); -} - - -typedef struct { - nxt_work_t work; - nxt_port_t *port; - nxt_port_post_handler_t handler; -} nxt_port_work_t; - - -static void -nxt_port_post_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_port_t *port; - nxt_port_work_t *pw; - nxt_port_post_handler_t handler; - - pw = obj; - port = pw->port; - handler = pw->handler; - - nxt_free(pw); - - handler(task, port, data); - - nxt_port_use(task, port, -1); -} - - -nxt_int_t -nxt_port_post(nxt_task_t *task, nxt_port_t *port, - nxt_port_post_handler_t handler, void *data) -{ - nxt_port_work_t *pw; - - if (task->thread->engine == port->engine) { - handler(task, port, data); - - return NXT_OK; - } - - pw = nxt_zalloc(sizeof(nxt_port_work_t)); - - if (nxt_slow_path(pw == NULL)) { - return NXT_ERROR; - } - - nxt_atomic_fetch_add(&port->use_count, 1); - - pw->work.handler = nxt_port_post_handler; - pw->work.task = &port->engine->task; - pw->work.obj = pw; - pw->work.data = data; - - pw->port = port; - pw->handler = handler; - - nxt_event_engine_post(port->engine, &pw->work); - - return NXT_OK; -} - - -static void -nxt_port_release_handler(nxt_task_t *task, nxt_port_t *port, void *data) -{ - /* no op */ -} - - -void -nxt_port_use(nxt_task_t *task, nxt_port_t *port, int i) -{ - int c; - - c = nxt_atomic_fetch_add(&port->use_count, i); - - if (i < 0 && c == -i) { - - if (port->engine == NULL || task->thread->engine == port->engine) { - nxt_port_release(task, port); - - return; - } - - nxt_port_post(task, port, nxt_port_release_handler, NULL); - } -} diff --git a/src/nxt_port.h b/src/nxt_port.h deleted file mode 100644 index 772fb41a..00000000 --- a/src/nxt_port.h +++ /dev/null @@ -1,376 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PORT_H_INCLUDED_ -#define _NXT_PORT_H_INCLUDED_ - - -struct nxt_port_handlers_s { - /* RPC responses. */ - nxt_port_handler_t rpc_ready; - nxt_port_handler_t rpc_error; - - /* Main process RPC requests. */ - nxt_port_handler_t start_process; - nxt_port_handler_t socket; - nxt_port_handler_t socket_unlink; - nxt_port_handler_t modules; - nxt_port_handler_t conf_store; - nxt_port_handler_t cert_get; - nxt_port_handler_t cert_delete; - nxt_port_handler_t script_get; - nxt_port_handler_t script_delete; - nxt_port_handler_t access_log; - - /* File descriptor exchange. */ - nxt_port_handler_t change_file; - nxt_port_handler_t new_port; - nxt_port_handler_t get_port; - nxt_port_handler_t port_ack; - nxt_port_handler_t mmap; - nxt_port_handler_t get_mmap; - - /* New process */ - nxt_port_handler_t process_created; - nxt_port_handler_t process_ready; - nxt_port_handler_t whoami; - - /* Process exit/crash notification. */ - nxt_port_handler_t remove_pid; - - /* Stop process command. */ - nxt_port_handler_t quit; - - /* Request headers. */ - nxt_port_handler_t req_headers; - nxt_port_handler_t req_headers_ack; - nxt_port_handler_t req_body; - - /* Websocket frame. */ - nxt_port_handler_t websocket_frame; - - /* Various data. */ - nxt_port_handler_t data; - nxt_port_handler_t app_restart; - - /* Status report. */ - nxt_port_handler_t status; - - nxt_port_handler_t oosm; - nxt_port_handler_t shm_ack; - nxt_port_handler_t read_queue; - nxt_port_handler_t read_socket; -}; - - -#define nxt_port_handler_idx(name) \ - ( offsetof(nxt_port_handlers_t, name) / sizeof(nxt_port_handler_t) ) - -#define nxt_msg_last(handler) \ - (handler | NXT_PORT_MSG_LAST) - -typedef enum { - NXT_PORT_MSG_LAST = 0x100, - NXT_PORT_MSG_CLOSE_FD = 0x200, - NXT_PORT_MSG_SYNC = 0x400, - - NXT_PORT_MSG_MASK = 0xFF, - - _NXT_PORT_MSG_RPC_READY = nxt_port_handler_idx(rpc_ready), - _NXT_PORT_MSG_RPC_ERROR = nxt_port_handler_idx(rpc_error), - - _NXT_PORT_MSG_START_PROCESS = nxt_port_handler_idx(start_process), - _NXT_PORT_MSG_SOCKET = nxt_port_handler_idx(socket), - _NXT_PORT_MSG_SOCKET_UNLINK = nxt_port_handler_idx(socket_unlink), - _NXT_PORT_MSG_MODULES = nxt_port_handler_idx(modules), - _NXT_PORT_MSG_CONF_STORE = nxt_port_handler_idx(conf_store), - _NXT_PORT_MSG_CERT_GET = nxt_port_handler_idx(cert_get), - _NXT_PORT_MSG_CERT_DELETE = nxt_port_handler_idx(cert_delete), - _NXT_PORT_MSG_SCRIPT_GET = nxt_port_handler_idx(script_get), - _NXT_PORT_MSG_SCRIPT_DELETE = nxt_port_handler_idx(script_delete), - _NXT_PORT_MSG_ACCESS_LOG = nxt_port_handler_idx(access_log), - - _NXT_PORT_MSG_CHANGE_FILE = nxt_port_handler_idx(change_file), - _NXT_PORT_MSG_NEW_PORT = nxt_port_handler_idx(new_port), - _NXT_PORT_MSG_GET_PORT = nxt_port_handler_idx(get_port), - _NXT_PORT_MSG_PORT_ACK = nxt_port_handler_idx(port_ack), - _NXT_PORT_MSG_MMAP = nxt_port_handler_idx(mmap), - _NXT_PORT_MSG_GET_MMAP = nxt_port_handler_idx(get_mmap), - - _NXT_PORT_MSG_PROCESS_CREATED = nxt_port_handler_idx(process_created), - _NXT_PORT_MSG_PROCESS_READY = nxt_port_handler_idx(process_ready), - _NXT_PORT_MSG_WHOAMI = nxt_port_handler_idx(whoami), - _NXT_PORT_MSG_REMOVE_PID = nxt_port_handler_idx(remove_pid), - _NXT_PORT_MSG_QUIT = nxt_port_handler_idx(quit), - - _NXT_PORT_MSG_REQ_HEADERS = nxt_port_handler_idx(req_headers), - _NXT_PORT_MSG_REQ_HEADERS_ACK = nxt_port_handler_idx(req_headers_ack), - _NXT_PORT_MSG_REQ_BODY = nxt_port_handler_idx(req_body), - _NXT_PORT_MSG_WEBSOCKET = nxt_port_handler_idx(websocket_frame), - - _NXT_PORT_MSG_DATA = nxt_port_handler_idx(data), - _NXT_PORT_MSG_APP_RESTART = nxt_port_handler_idx(app_restart), - _NXT_PORT_MSG_STATUS = nxt_port_handler_idx(status), - - _NXT_PORT_MSG_OOSM = nxt_port_handler_idx(oosm), - _NXT_PORT_MSG_SHM_ACK = nxt_port_handler_idx(shm_ack), - _NXT_PORT_MSG_READ_QUEUE = nxt_port_handler_idx(read_queue), - _NXT_PORT_MSG_READ_SOCKET = nxt_port_handler_idx(read_socket), - - NXT_PORT_MSG_MAX = sizeof(nxt_port_handlers_t) - / sizeof(nxt_port_handler_t), - - NXT_PORT_MSG_RPC_READY = _NXT_PORT_MSG_RPC_READY, - NXT_PORT_MSG_RPC_READY_LAST = nxt_msg_last(_NXT_PORT_MSG_RPC_READY), - NXT_PORT_MSG_RPC_ERROR = nxt_msg_last(_NXT_PORT_MSG_RPC_ERROR), - NXT_PORT_MSG_START_PROCESS = nxt_msg_last(_NXT_PORT_MSG_START_PROCESS), - NXT_PORT_MSG_SOCKET = nxt_msg_last(_NXT_PORT_MSG_SOCKET), - NXT_PORT_MSG_SOCKET_UNLINK = nxt_msg_last(_NXT_PORT_MSG_SOCKET_UNLINK), - NXT_PORT_MSG_MODULES = nxt_msg_last(_NXT_PORT_MSG_MODULES), - NXT_PORT_MSG_CONF_STORE = nxt_msg_last(_NXT_PORT_MSG_CONF_STORE), - NXT_PORT_MSG_CERT_GET = nxt_msg_last(_NXT_PORT_MSG_CERT_GET), - NXT_PORT_MSG_CERT_DELETE = nxt_msg_last(_NXT_PORT_MSG_CERT_DELETE), - NXT_PORT_MSG_SCRIPT_GET = nxt_msg_last(_NXT_PORT_MSG_SCRIPT_GET), - NXT_PORT_MSG_SCRIPT_DELETE = nxt_msg_last(_NXT_PORT_MSG_SCRIPT_DELETE), - NXT_PORT_MSG_ACCESS_LOG = nxt_msg_last(_NXT_PORT_MSG_ACCESS_LOG), - NXT_PORT_MSG_CHANGE_FILE = nxt_msg_last(_NXT_PORT_MSG_CHANGE_FILE), - NXT_PORT_MSG_NEW_PORT = nxt_msg_last(_NXT_PORT_MSG_NEW_PORT), - NXT_PORT_MSG_GET_PORT = nxt_msg_last(_NXT_PORT_MSG_GET_PORT), - NXT_PORT_MSG_PORT_ACK = nxt_msg_last(_NXT_PORT_MSG_PORT_ACK), - NXT_PORT_MSG_MMAP = nxt_msg_last(_NXT_PORT_MSG_MMAP) - | NXT_PORT_MSG_SYNC, - NXT_PORT_MSG_GET_MMAP = nxt_msg_last(_NXT_PORT_MSG_GET_MMAP), - - NXT_PORT_MSG_PROCESS_CREATED = nxt_msg_last(_NXT_PORT_MSG_PROCESS_CREATED), - NXT_PORT_MSG_PROCESS_READY = nxt_msg_last(_NXT_PORT_MSG_PROCESS_READY), - NXT_PORT_MSG_WHOAMI = nxt_msg_last(_NXT_PORT_MSG_WHOAMI), - NXT_PORT_MSG_QUIT = nxt_msg_last(_NXT_PORT_MSG_QUIT), - NXT_PORT_MSG_REMOVE_PID = nxt_msg_last(_NXT_PORT_MSG_REMOVE_PID), - - NXT_PORT_MSG_REQ_HEADERS = _NXT_PORT_MSG_REQ_HEADERS, - NXT_PORT_MSG_REQ_BODY = _NXT_PORT_MSG_REQ_BODY, - NXT_PORT_MSG_WEBSOCKET = _NXT_PORT_MSG_WEBSOCKET, - NXT_PORT_MSG_WEBSOCKET_LAST = nxt_msg_last(_NXT_PORT_MSG_WEBSOCKET), - - NXT_PORT_MSG_DATA = _NXT_PORT_MSG_DATA, - NXT_PORT_MSG_DATA_LAST = nxt_msg_last(_NXT_PORT_MSG_DATA), - NXT_PORT_MSG_APP_RESTART = nxt_msg_last(_NXT_PORT_MSG_APP_RESTART), - NXT_PORT_MSG_STATUS = nxt_msg_last(_NXT_PORT_MSG_STATUS), - - NXT_PORT_MSG_OOSM = nxt_msg_last(_NXT_PORT_MSG_OOSM), - NXT_PORT_MSG_SHM_ACK = nxt_msg_last(_NXT_PORT_MSG_SHM_ACK), - NXT_PORT_MSG_READ_QUEUE = _NXT_PORT_MSG_READ_QUEUE, - NXT_PORT_MSG_READ_SOCKET = _NXT_PORT_MSG_READ_SOCKET, -} nxt_port_msg_type_t; - - -/* Passed as a first iov chunk. */ -typedef struct { - uint32_t stream; - - nxt_pid_t pid; /* not used on Linux and FreeBSD */ - - nxt_port_id_t reply_port; - - uint8_t type; - - /* Last message for this stream. */ - uint8_t last; /* 1 bit */ - - /* Message data send using mmap, next chunk is a nxt_port_mmap_msg_t. */ - uint8_t mmap; /* 1 bit */ - - /* Non-First fragment in fragmented message sequence. */ - uint8_t nf; /* 1 bit */ - - /* More Fragments followed. */ - uint8_t mf; /* 1 bit */ -} nxt_port_msg_t; - - -typedef struct { - nxt_queue_link_t link; - nxt_buf_t *buf; - size_t share; - nxt_fd_t fd[2]; - nxt_port_msg_t port_msg; - uint8_t close_fd; /* 1 bit */ - uint8_t allocated; /* 1 bit */ -} nxt_port_send_msg_t; - -#if (NXT_HAVE_UCRED) || (NXT_HAVE_MSGHDR_CMSGCRED) -#define NXT_USE_CMSG_PID 1 -#endif - -struct nxt_port_recv_msg_s { - nxt_fd_t fd[2]; - nxt_buf_t *buf; - nxt_port_t *port; - nxt_port_msg_t port_msg; - size_t size; -#if (NXT_USE_CMSG_PID) - nxt_pid_t cmsg_pid; -#endif - nxt_bool_t cancelled; - union { - nxt_port_t *new_port; - nxt_pid_t removed_pid; - void *data; - } u; -}; - - -#if (NXT_USE_CMSG_PID) -#define nxt_recv_msg_cmsg_pid(msg) ((msg)->cmsg_pid) -#define nxt_recv_msg_cmsg_pid_ref(msg) (&(msg)->cmsg_pid) -#else -#define nxt_recv_msg_cmsg_pid(msg) ((msg)->port_msg.pid) -#define nxt_recv_msg_cmsg_pid_ref(msg) (NULL) -#endif - -typedef struct nxt_app_s nxt_app_t; - -struct nxt_port_s { - nxt_fd_event_t socket; - - nxt_queue_link_t link; /* for nxt_process_t.ports */ - nxt_process_t *process; - - nxt_queue_link_t app_link; /* for nxt_app_t.ports */ - nxt_app_t *app; - nxt_port_t *main_app_port; - - nxt_queue_link_t idle_link; /* for nxt_app_t.idle_ports */ - nxt_msec_t idle_start; - - nxt_queue_t messages; /* of nxt_port_send_msg_t */ - nxt_thread_mutex_t write_mutex; - - /* Maximum size of message part. */ - uint32_t max_size; - /* Maximum interleave of message parts. */ - uint32_t max_share; - - uint32_t active_websockets; - uint32_t active_requests; - - nxt_port_handler_t handler; - nxt_port_handler_t *data; - - nxt_mp_t *mem_pool; - nxt_event_engine_t *engine; - - nxt_buf_t *free_bufs; - nxt_socket_t pair[2]; - - nxt_port_id_t id; - nxt_pid_t pid; - - nxt_lvlhsh_t rpc_streams; /* stream to nxt_port_rpc_reg_t */ - nxt_lvlhsh_t rpc_peers; /* peer to queue of nxt_port_rpc_reg_t */ - - nxt_lvlhsh_t frags; - - nxt_atomic_t use_count; - - nxt_process_type_t type; - - nxt_fd_t queue_fd; - void *queue; - - void *socket_msg; - int from_socket; -}; - - -typedef struct { - nxt_port_id_t id; - nxt_pid_t pid; - size_t max_size; - size_t max_share; - nxt_process_type_t type:8; -} nxt_port_msg_new_port_t; - - -typedef struct { - nxt_port_id_t id; - nxt_pid_t pid; -} nxt_port_msg_get_port_t; - - -typedef struct { - uint32_t id; -} nxt_port_msg_get_mmap_t; - - -/* - * nxt_port_data_t size is allocation size - * which enables effective reuse of memory pool cache. - */ -typedef union { - nxt_buf_t buf; - nxt_port_msg_new_port_t new_port; -} nxt_port_data_t; - - -typedef void (*nxt_port_post_handler_t)(nxt_task_t *task, nxt_port_t *port, - void *data); - -nxt_port_t *nxt_port_new(nxt_task_t *task, nxt_port_id_t id, nxt_pid_t pid, - nxt_process_type_t type); - -nxt_port_id_t nxt_port_get_next_id(void); -void nxt_port_reset_next_id(void); - -nxt_int_t nxt_port_socket_init(nxt_task_t *task, nxt_port_t *port, - size_t max_size); -void nxt_port_destroy(nxt_port_t *port); -void nxt_port_close(nxt_task_t *task, nxt_port_t *port); -void nxt_port_write_enable(nxt_task_t *task, nxt_port_t *port); -void nxt_port_write_close(nxt_port_t *port); -void nxt_port_read_enable(nxt_task_t *task, nxt_port_t *port); -void nxt_port_read_close(nxt_port_t *port); -nxt_int_t nxt_port_socket_write2(nxt_task_t *task, nxt_port_t *port, - nxt_uint_t type, nxt_fd_t fd, nxt_fd_t fd2, uint32_t stream, - nxt_port_id_t reply_port, nxt_buf_t *b); - -nxt_inline nxt_int_t -nxt_port_socket_write(nxt_task_t *task, nxt_port_t *port, - nxt_uint_t type, nxt_fd_t fd, uint32_t stream, nxt_port_id_t reply_port, - nxt_buf_t *b) -{ - return nxt_port_socket_write2(task, port, type, fd, -1, stream, reply_port, - b); -} - -void nxt_port_enable(nxt_task_t *task, nxt_port_t *port, - const nxt_port_handlers_t *handlers); -nxt_int_t nxt_port_send_port(nxt_task_t *task, nxt_port_t *port, - nxt_port_t *new_port, uint32_t stream); -void nxt_port_change_log_file(nxt_task_t *task, nxt_runtime_t *rt, - nxt_uint_t slot, nxt_fd_t fd); -void nxt_port_remove_notify_others(nxt_task_t *task, nxt_process_t *process); - -void nxt_port_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -void nxt_port_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -void nxt_port_process_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -void nxt_port_change_log_file_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -void nxt_port_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -void nxt_port_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -void nxt_port_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -void nxt_port_empty_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); - -nxt_int_t nxt_port_post(nxt_task_t *task, nxt_port_t *port, - nxt_port_post_handler_t handler, void *data); -void nxt_port_use(nxt_task_t *task, nxt_port_t *port, int i); - -nxt_inline void nxt_port_inc_use(nxt_port_t *port) -{ - nxt_atomic_fetch_add(&port->use_count, 1); -} - -#endif /* _NXT_PORT_H_INCLUDED_ */ diff --git a/src/nxt_port_hash.c b/src/nxt_port_hash.c deleted file mode 100644 index b23acfb2..00000000 --- a/src/nxt_port_hash.c +++ /dev/null @@ -1,142 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -#include - - -// Explicitly using 32 bit types to avoid possible alignment. -typedef struct { - int32_t pid; - uint32_t port_id; -} nxt_pid_port_id_t; - - -static nxt_int_t -nxt_port_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_port_t *port; - nxt_pid_port_id_t *pid_port_id; - - port = data; - pid_port_id = (nxt_pid_port_id_t *) lhq->key.start; - - if (lhq->key.length == sizeof(nxt_pid_port_id_t) - && pid_port_id->pid == port->pid - && pid_port_id->port_id == port->id) - { - return NXT_OK; - } - - return NXT_DECLINED; -} - -static const nxt_lvlhsh_proto_t lvlhsh_ports_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_port_hash_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -nxt_port_t * -nxt_port_hash_retrieve(nxt_lvlhsh_t *port_hash) -{ - return nxt_lvlhsh_retrieve(port_hash, &lvlhsh_ports_proto, NULL); -} - - -nxt_inline void -nxt_port_hash_lhq(nxt_lvlhsh_query_t *lhq, nxt_pid_port_id_t *pid_port) -{ - lhq->key_hash = nxt_murmur_hash2(pid_port, sizeof(nxt_pid_port_id_t)); - lhq->key.length = sizeof(nxt_pid_port_id_t); - lhq->key.start = (u_char *) pid_port; - lhq->proto = &lvlhsh_ports_proto; - lhq->pool = NULL; -} - - -nxt_int_t -nxt_port_hash_add(nxt_lvlhsh_t *port_hash, nxt_port_t *port) -{ - nxt_int_t res; - nxt_pid_port_id_t pid_port; - nxt_lvlhsh_query_t lhq; - - pid_port.pid = port->pid; - pid_port.port_id = port->id; - - nxt_port_hash_lhq(&lhq, &pid_port); - lhq.replace = 0; - lhq.value = port; - - res = nxt_lvlhsh_insert(port_hash, &lhq); - - switch (res) { - - case NXT_OK: - break; - - default: - nxt_thread_log_error(NXT_LOG_WARN, "port #%d for pid %PI add failed", - port->id, port->pid); - break; - } - - return res; -} - - -nxt_int_t -nxt_port_hash_remove(nxt_lvlhsh_t *port_hash, nxt_port_t *port) -{ - nxt_int_t res; - nxt_pid_port_id_t pid_port; - nxt_lvlhsh_query_t lhq; - - pid_port.pid = port->pid; - pid_port.port_id = port->id; - - nxt_port_hash_lhq(&lhq, &pid_port); - - res = nxt_lvlhsh_delete(port_hash, &lhq); - - switch (res) { - - case NXT_OK: - break; - - default: - nxt_thread_log_error(NXT_LOG_WARN, "port #%d for pid %PI remove failed", - port->id, port->pid); - break; - } - - return res; -} - - -nxt_port_t * -nxt_port_hash_find(nxt_lvlhsh_t *port_hash, nxt_pid_t pid, - nxt_port_id_t port_id) -{ - nxt_pid_port_id_t pid_port; - nxt_lvlhsh_query_t lhq; - - pid_port.pid = pid; - pid_port.port_id = port_id; - - nxt_port_hash_lhq(&lhq, &pid_port); - - if (nxt_lvlhsh_find(port_hash, &lhq) == NXT_OK) { - nxt_thread_log_debug("process port (%PI, %d) found", pid, port_id); - return lhq.value; - } - - nxt_thread_log_debug("process port (%PI, %d) not found", pid, port_id); - - return NULL; -} diff --git a/src/nxt_port_hash.h b/src/nxt_port_hash.h deleted file mode 100644 index c975cab7..00000000 --- a/src/nxt_port_hash.h +++ /dev/null @@ -1,24 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PORT_HASH_H_INCLUDED_ -#define _NXT_PORT_HASH_H_INCLUDED_ - - -#include - - -nxt_int_t nxt_port_hash_add(nxt_lvlhsh_t *port_hash, nxt_port_t *port); - -nxt_int_t nxt_port_hash_remove(nxt_lvlhsh_t *port_hash, nxt_port_t *port); - -nxt_port_t *nxt_port_hash_find(nxt_lvlhsh_t *port_hash, nxt_pid_t pid, - nxt_port_id_t port_id); - -nxt_port_t *nxt_port_hash_retrieve(nxt_lvlhsh_t *port_hash); - - -#endif /* _NXT_PORT_HASH_H_INCLIDED_ */ diff --git a/src/nxt_port_memory.c b/src/nxt_port_memory.c deleted file mode 100644 index 0a4a6c53..00000000 --- a/src/nxt_port_memory.c +++ /dev/null @@ -1,882 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -#include - -#if (NXT_HAVE_MEMFD_CREATE) - -#include -#include -#include - -#endif - -#include - - -static void nxt_port_broadcast_shm_ack(nxt_task_t *task, nxt_port_t *port, - void *data); - - -nxt_inline void -nxt_port_mmap_handler_use(nxt_port_mmap_handler_t *mmap_handler, int i) -{ - int c; - - c = nxt_atomic_fetch_add(&mmap_handler->use_count, i); - - if (i < 0 && c == -i) { - if (mmap_handler->hdr != NULL) { - nxt_mem_munmap(mmap_handler->hdr, PORT_MMAP_SIZE); - mmap_handler->hdr = NULL; - } - - if (mmap_handler->fd != -1) { - nxt_fd_close(mmap_handler->fd); - } - - nxt_free(mmap_handler); - } -} - - -static nxt_port_mmap_t * -nxt_port_mmap_at(nxt_port_mmaps_t *port_mmaps, uint32_t i) -{ - uint32_t cap; - - cap = port_mmaps->cap; - - if (cap == 0) { - cap = i + 1; - } - - while (i + 1 > cap) { - - if (cap < 16) { - cap = cap * 2; - - } else { - cap = cap + cap / 2; - } - } - - if (cap != port_mmaps->cap) { - - port_mmaps->elts = nxt_realloc(port_mmaps->elts, - cap * sizeof(nxt_port_mmap_t)); - if (nxt_slow_path(port_mmaps->elts == NULL)) { - return NULL; - } - - nxt_memzero(port_mmaps->elts + port_mmaps->cap, - sizeof(nxt_port_mmap_t) * (cap - port_mmaps->cap)); - - port_mmaps->cap = cap; - } - - if (i + 1 > port_mmaps->size) { - port_mmaps->size = i + 1; - } - - return port_mmaps->elts + i; -} - - -void -nxt_port_mmaps_destroy(nxt_port_mmaps_t *port_mmaps, nxt_bool_t free_elts) -{ - uint32_t i; - nxt_port_mmap_t *port_mmap; - - if (port_mmaps == NULL) { - return; - } - - port_mmap = port_mmaps->elts; - - for (i = 0; i < port_mmaps->size; i++) { - nxt_port_mmap_handler_use(port_mmap[i].mmap_handler, -1); - } - - port_mmaps->size = 0; - - if (free_elts != 0) { - nxt_free(port_mmaps->elts); - } -} - - -#define nxt_port_mmap_free_junk(p, size) \ - memset((p), 0xA5, size) - - -static void -nxt_port_mmap_buf_completion(nxt_task_t *task, void *obj, void *data) -{ - u_char *p; - nxt_mp_t *mp; - nxt_buf_t *b, *next; - nxt_process_t *process; - nxt_chunk_id_t c; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - if (nxt_buf_ts_handle(task, obj, data)) { - return; - } - - b = obj; - - nxt_assert(data == b->parent); - - mmap_handler = data; - -complete_buf: - - hdr = mmap_handler->hdr; - - if (nxt_slow_path(hdr->src_pid != nxt_pid && hdr->dst_pid != nxt_pid)) { - nxt_debug(task, "mmap buf completion: mmap for other process pair " - "%PI->%PI", hdr->src_pid, hdr->dst_pid); - - goto release_buf; - } - - if (b->is_port_mmap_sent && b->mem.pos > b->mem.start) { - /* - * Chunks until b->mem.pos has been sent to other side, - * let's release rest (if any). - */ - p = b->mem.pos - 1; - c = nxt_port_mmap_chunk_id(hdr, p) + 1; - p = nxt_port_mmap_chunk_start(hdr, c); - - } else { - p = b->mem.start; - c = nxt_port_mmap_chunk_id(hdr, p); - } - - nxt_port_mmap_free_junk(p, b->mem.end - p); - - nxt_debug(task, "mmap buf completion: %p [%p,%uz] (sent=%d), " - "%PI->%PI,%d,%d", b, b->mem.start, b->mem.end - b->mem.start, - b->is_port_mmap_sent, hdr->src_pid, hdr->dst_pid, hdr->id, c); - - while (p < b->mem.end) { - nxt_port_mmap_set_chunk_free(hdr->free_map, c); - - p += PORT_MMAP_CHUNK_SIZE; - c++; - } - - if (hdr->dst_pid == nxt_pid - && nxt_atomic_cmp_set(&hdr->oosm, 1, 0)) - { - process = nxt_runtime_process_find(task->thread->runtime, hdr->src_pid); - - nxt_process_broadcast_shm_ack(task, process); - } - -release_buf: - - nxt_port_mmap_handler_use(mmap_handler, -1); - - next = b->next; - mp = b->data; - - nxt_mp_free(mp, b); - nxt_mp_release(mp); - - if (next != NULL) { - b = next; - mmap_handler = b->parent; - - goto complete_buf; - } -} - - -nxt_port_mmap_handler_t * -nxt_port_incoming_port_mmap(nxt_task_t *task, nxt_process_t *process, - nxt_fd_t fd) -{ - void *mem; - struct stat mmap_stat; - nxt_port_mmap_t *port_mmap; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - nxt_debug(task, "got new mmap fd #%FD from process %PI", - fd, process->pid); - - port_mmap = NULL; - - if (fstat(fd, &mmap_stat) == -1) { - nxt_log(task, NXT_LOG_WARN, "fstat(%FD) failed %E", fd, nxt_errno); - - return NULL; - } - - mem = nxt_mem_mmap(NULL, mmap_stat.st_size, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - - if (nxt_slow_path(mem == MAP_FAILED)) { - nxt_log(task, NXT_LOG_WARN, "mmap() failed %E", nxt_errno); - - return NULL; - } - - hdr = mem; - - if (nxt_slow_path(hdr->src_pid != process->pid - || hdr->dst_pid != nxt_pid)) - { - nxt_log(task, NXT_LOG_WARN, "unexpected pid in mmap header detected: " - "%PI != %PI or %PI != %PI", hdr->src_pid, process->pid, - hdr->dst_pid, nxt_pid); - - nxt_mem_munmap(mem, PORT_MMAP_SIZE); - - return NULL; - } - - mmap_handler = nxt_zalloc(sizeof(nxt_port_mmap_handler_t)); - if (nxt_slow_path(mmap_handler == NULL)) { - nxt_log(task, NXT_LOG_WARN, "failed to allocate mmap_handler"); - - nxt_mem_munmap(mem, PORT_MMAP_SIZE); - - return NULL; - } - - mmap_handler->hdr = hdr; - mmap_handler->fd = -1; - - nxt_thread_mutex_lock(&process->incoming.mutex); - - port_mmap = nxt_port_mmap_at(&process->incoming, hdr->id); - if (nxt_slow_path(port_mmap == NULL)) { - nxt_log(task, NXT_LOG_WARN, "failed to add mmap to incoming array"); - - nxt_mem_munmap(mem, PORT_MMAP_SIZE); - - nxt_free(mmap_handler); - mmap_handler = NULL; - - goto fail; - } - - port_mmap->mmap_handler = mmap_handler; - nxt_port_mmap_handler_use(mmap_handler, 1); - - hdr->sent_over = 0xFFFFu; - -fail: - - nxt_thread_mutex_unlock(&process->incoming.mutex); - - return mmap_handler; -} - - -static nxt_port_mmap_handler_t * -nxt_port_new_port_mmap(nxt_task_t *task, nxt_port_mmaps_t *mmaps, - nxt_bool_t tracking, nxt_int_t n) -{ - void *mem; - nxt_fd_t fd; - nxt_int_t i; - nxt_free_map_t *free_map; - nxt_port_mmap_t *port_mmap; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - mmap_handler = nxt_zalloc(sizeof(nxt_port_mmap_handler_t)); - if (nxt_slow_path(mmap_handler == NULL)) { - nxt_alert(task, "failed to allocate mmap_handler"); - - return NULL; - } - - port_mmap = nxt_port_mmap_at(mmaps, mmaps->size); - if (nxt_slow_path(port_mmap == NULL)) { - nxt_alert(task, "failed to add port mmap to mmaps array"); - - nxt_free(mmap_handler); - return NULL; - } - - fd = nxt_shm_open(task, PORT_MMAP_SIZE); - if (nxt_slow_path(fd == -1)) { - goto remove_fail; - } - - mem = nxt_mem_mmap(NULL, PORT_MMAP_SIZE, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - - if (nxt_slow_path(mem == MAP_FAILED)) { - nxt_fd_close(fd); - goto remove_fail; - } - - mmap_handler->hdr = mem; - mmap_handler->fd = fd; - port_mmap->mmap_handler = mmap_handler; - nxt_port_mmap_handler_use(mmap_handler, 1); - - /* Init segment header. */ - hdr = mmap_handler->hdr; - - nxt_memset(hdr->free_map, 0xFFU, sizeof(hdr->free_map)); - nxt_memset(hdr->free_tracking_map, 0xFFU, sizeof(hdr->free_tracking_map)); - - hdr->id = mmaps->size - 1; - hdr->src_pid = nxt_pid; - hdr->sent_over = 0xFFFFu; - - /* Mark first chunk as busy */ - free_map = tracking ? hdr->free_tracking_map : hdr->free_map; - - for (i = 0; i < n; i++) { - nxt_port_mmap_set_chunk_busy(free_map, i); - } - - /* Mark as busy chunk followed the last available chunk. */ - nxt_port_mmap_set_chunk_busy(hdr->free_map, PORT_MMAP_CHUNK_COUNT); - nxt_port_mmap_set_chunk_busy(hdr->free_tracking_map, PORT_MMAP_CHUNK_COUNT); - - nxt_log(task, NXT_LOG_DEBUG, "new mmap #%D created for %PI -> ...", - hdr->id, nxt_pid); - - return mmap_handler; - -remove_fail: - - nxt_free(mmap_handler); - - mmaps->size--; - - return NULL; -} - - -nxt_int_t -nxt_shm_open(nxt_task_t *task, size_t size) -{ - nxt_fd_t fd; - -#if (NXT_HAVE_MEMFD_CREATE || NXT_HAVE_SHM_OPEN) - - u_char *p, name[64]; - - p = nxt_sprintf(name, name + sizeof(name), NXT_SHM_PREFIX "unit.%PI.%uxD", - nxt_pid, nxt_random(&task->thread->random)); - *p = '\0'; - -#endif - -#if (NXT_HAVE_MEMFD_CREATE) - - fd = syscall(SYS_memfd_create, name, MFD_CLOEXEC); - - if (nxt_slow_path(fd == -1)) { - nxt_alert(task, "memfd_create(%s) failed %E", name, nxt_errno); - - return -1; - } - - nxt_debug(task, "memfd_create(%s): %FD", name, fd); - -#elif (NXT_HAVE_SHM_OPEN_ANON) - - fd = shm_open(SHM_ANON, O_RDWR, S_IRUSR | S_IWUSR); - - if (nxt_slow_path(fd == -1)) { - nxt_alert(task, "shm_open(SHM_ANON) failed %E", nxt_errno); - - return -1; - } - - nxt_debug(task, "shm_open(SHM_ANON): %FD", fd); - -#elif (NXT_HAVE_SHM_OPEN) - - /* Just in case. */ - shm_unlink((char *) name); - - fd = shm_open((char *) name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); - - if (nxt_slow_path(fd == -1)) { - nxt_alert(task, "shm_open(%s) failed %E", name, nxt_errno); - - return -1; - } - - nxt_debug(task, "shm_open(%s): %FD", name, fd); - - if (nxt_slow_path(shm_unlink((char *) name) == -1)) { - nxt_log(task, NXT_LOG_WARN, "shm_unlink(%s) failed %E", name, - nxt_errno); - } - -#else - -#error No working shared memory implementation. - -#endif - - if (nxt_slow_path(ftruncate(fd, size) == -1)) { - nxt_alert(task, "ftruncate() failed %E", nxt_errno); - - nxt_fd_close(fd); - - return -1; - } - - return fd; -} - - -static nxt_port_mmap_handler_t * -nxt_port_mmap_get(nxt_task_t *task, nxt_port_mmaps_t *mmaps, nxt_chunk_id_t *c, - nxt_int_t n, nxt_bool_t tracking) -{ - nxt_int_t i, res, nchunks; - nxt_free_map_t *free_map; - nxt_port_mmap_t *port_mmap; - nxt_port_mmap_t *end_port_mmap; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - nxt_thread_mutex_lock(&mmaps->mutex); - - end_port_mmap = mmaps->elts + mmaps->size; - - for (port_mmap = mmaps->elts; - port_mmap < end_port_mmap; - port_mmap++) - { - mmap_handler = port_mmap->mmap_handler; - hdr = mmap_handler->hdr; - - if (hdr->sent_over != 0xFFFFu) { - continue; - } - - *c = 0; - - free_map = tracking ? hdr->free_tracking_map : hdr->free_map; - - while (nxt_port_mmap_get_free_chunk(free_map, c)) { - nchunks = 1; - - while (nchunks < n) { - res = nxt_port_mmap_chk_set_chunk_busy(free_map, *c + nchunks); - - if (res == 0) { - for (i = 0; i < nchunks; i++) { - nxt_port_mmap_set_chunk_free(free_map, *c + i); - } - - *c += nchunks + 1; - nchunks = 0; - break; - } - - nchunks++; - } - - if (nchunks == n) { - goto unlock_return; - } - } - - hdr->oosm = 1; - } - - /* TODO introduce port_mmap limit and release wait. */ - - *c = 0; - mmap_handler = nxt_port_new_port_mmap(task, mmaps, tracking, n); - -unlock_return: - - nxt_thread_mutex_unlock(&mmaps->mutex); - - return mmap_handler; -} - - -static nxt_port_mmap_handler_t * -nxt_port_get_port_incoming_mmap(nxt_task_t *task, nxt_pid_t spid, uint32_t id) -{ - nxt_process_t *process; - nxt_port_mmap_handler_t *mmap_handler; - - process = nxt_runtime_process_find(task->thread->runtime, spid); - if (nxt_slow_path(process == NULL)) { - return NULL; - } - - nxt_thread_mutex_lock(&process->incoming.mutex); - - if (nxt_fast_path(process->incoming.size > id)) { - mmap_handler = process->incoming.elts[id].mmap_handler; - - } else { - mmap_handler = NULL; - - nxt_debug(task, "invalid incoming mmap id %uD for pid %PI", id, spid); - } - - nxt_thread_mutex_unlock(&process->incoming.mutex); - - return mmap_handler; -} - - -nxt_buf_t * -nxt_port_mmap_get_buf(nxt_task_t *task, nxt_port_mmaps_t *mmaps, size_t size) -{ - nxt_mp_t *mp; - nxt_buf_t *b; - nxt_int_t nchunks; - nxt_chunk_id_t c; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - nxt_debug(task, "request %z bytes shm buffer", size); - - nchunks = (size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE; - - if (nxt_slow_path(nchunks > PORT_MMAP_CHUNK_COUNT)) { - nxt_alert(task, "requested buffer (%z) too big", size); - - return NULL; - } - - b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 0); - if (nxt_slow_path(b == NULL)) { - return NULL; - } - - b->completion_handler = nxt_port_mmap_buf_completion; - nxt_buf_set_port_mmap(b); - - mmap_handler = nxt_port_mmap_get(task, mmaps, &c, nchunks, 0); - if (nxt_slow_path(mmap_handler == NULL)) { - mp = task->thread->engine->mem_pool; - nxt_mp_free(mp, b); - nxt_mp_release(mp); - return NULL; - } - - b->parent = mmap_handler; - - nxt_port_mmap_handler_use(mmap_handler, 1); - - hdr = mmap_handler->hdr; - - b->mem.start = nxt_port_mmap_chunk_start(hdr, c); - b->mem.pos = b->mem.start; - b->mem.free = b->mem.start; - b->mem.end = b->mem.start + nchunks * PORT_MMAP_CHUNK_SIZE; - - nxt_debug(task, "outgoing mmap buf allocation: %p [%p,%uz] %PI->%PI,%d,%d", - b, b->mem.start, b->mem.end - b->mem.start, - hdr->src_pid, hdr->dst_pid, hdr->id, c); - - return b; -} - - -nxt_int_t -nxt_port_mmap_increase_buf(nxt_task_t *task, nxt_buf_t *b, size_t size, - size_t min_size) -{ - size_t nchunks, free_size; - nxt_chunk_id_t c, start; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - nxt_debug(task, "request increase %z bytes shm buffer", size); - - if (nxt_slow_path(nxt_buf_is_port_mmap(b) == 0)) { - nxt_log(task, NXT_LOG_WARN, - "failed to increase, not a mmap buffer"); - return NXT_ERROR; - } - - free_size = nxt_buf_mem_free_size(&b->mem); - - if (nxt_slow_path(size <= free_size)) { - return NXT_OK; - } - - mmap_handler = b->parent; - hdr = mmap_handler->hdr; - - start = nxt_port_mmap_chunk_id(hdr, b->mem.end); - - size -= free_size; - - nchunks = (size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE; - - c = start; - - /* Try to acquire as much chunks as required. */ - while (nchunks > 0) { - - if (nxt_port_mmap_chk_set_chunk_busy(hdr->free_map, c) == 0) { - break; - } - - c++; - nchunks--; - } - - if (nchunks != 0 - && min_size > free_size + PORT_MMAP_CHUNK_SIZE * (c - start)) - { - c--; - while (c >= start) { - nxt_port_mmap_set_chunk_free(hdr->free_map, c); - c--; - } - - nxt_debug(task, "failed to increase, %uz chunks busy", nchunks); - - return NXT_ERROR; - - } else { - b->mem.end += PORT_MMAP_CHUNK_SIZE * (c - start); - - return NXT_OK; - } -} - - -static nxt_buf_t * -nxt_port_mmap_get_incoming_buf(nxt_task_t *task, nxt_port_t *port, - nxt_pid_t spid, nxt_port_mmap_msg_t *mmap_msg) -{ - size_t nchunks; - nxt_buf_t *b; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - mmap_handler = nxt_port_get_port_incoming_mmap(task, spid, - mmap_msg->mmap_id); - if (nxt_slow_path(mmap_handler == NULL)) { - return NULL; - } - - b = nxt_buf_mem_ts_alloc(task, port->mem_pool, 0); - if (nxt_slow_path(b == NULL)) { - return NULL; - } - - b->completion_handler = nxt_port_mmap_buf_completion; - - nxt_buf_set_port_mmap(b); - - nchunks = mmap_msg->size / PORT_MMAP_CHUNK_SIZE; - if ((mmap_msg->size % PORT_MMAP_CHUNK_SIZE) != 0) { - nchunks++; - } - - hdr = mmap_handler->hdr; - - b->mem.start = nxt_port_mmap_chunk_start(hdr, mmap_msg->chunk_id); - b->mem.pos = b->mem.start; - b->mem.free = b->mem.start + mmap_msg->size; - b->mem.end = b->mem.start + nchunks * PORT_MMAP_CHUNK_SIZE; - - b->parent = mmap_handler; - nxt_port_mmap_handler_use(mmap_handler, 1); - - nxt_debug(task, "incoming mmap buf allocation: %p [%p,%uz] %PI->%PI,%d,%d", - b, b->mem.start, b->mem.end - b->mem.start, - hdr->src_pid, hdr->dst_pid, hdr->id, mmap_msg->chunk_id); - - return b; -} - - -void -nxt_port_mmap_write(nxt_task_t *task, nxt_port_t *port, - nxt_port_send_msg_t *msg, nxt_sendbuf_coalesce_t *sb, void *mmsg_buf) -{ - size_t bsize; - nxt_buf_t *bmem; - nxt_uint_t i; - nxt_port_mmap_msg_t *mmap_msg; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - nxt_debug(task, "prepare %z bytes message for transfer to process %PI " - "via shared memory", sb->size, port->pid); - - bsize = sb->niov * sizeof(nxt_port_mmap_msg_t); - mmap_msg = mmsg_buf; - - bmem = msg->buf; - - for (i = 0; i < sb->niov; i++, mmap_msg++) { - - /* Lookup buffer which starts current iov_base. */ - while (bmem && sb->iobuf[i].iov_base != bmem->mem.pos) { - bmem = bmem->next; - } - - if (nxt_slow_path(bmem == NULL)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "failed to find buf for iobuf[%d]", i); - return; - /* TODO clear b and exit */ - } - - mmap_handler = bmem->parent; - hdr = mmap_handler->hdr; - - mmap_msg->mmap_id = hdr->id; - mmap_msg->chunk_id = nxt_port_mmap_chunk_id(hdr, bmem->mem.pos); - mmap_msg->size = sb->iobuf[i].iov_len; - - nxt_debug(task, "mmap_msg={%D, %D, %D} to %PI", - mmap_msg->mmap_id, mmap_msg->chunk_id, mmap_msg->size, - port->pid); - } - - sb->iobuf[0].iov_base = mmsg_buf; - sb->iobuf[0].iov_len = bsize; - sb->niov = 1; - sb->size = bsize; - - msg->port_msg.mmap = 1; -} - - -void -nxt_port_mmap_read(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_buf_t *b, **pb; - nxt_port_mmap_msg_t *end, *mmap_msg; - - pb = &msg->buf; - msg->size = 0; - - for (b = msg->buf; b != NULL; b = b->next) { - - mmap_msg = (nxt_port_mmap_msg_t *) b->mem.pos; - end = (nxt_port_mmap_msg_t *) b->mem.free; - - while (mmap_msg < end) { - nxt_debug(task, "mmap_msg={%D, %D, %D} from %PI", - mmap_msg->mmap_id, mmap_msg->chunk_id, mmap_msg->size, - msg->port_msg.pid); - - *pb = nxt_port_mmap_get_incoming_buf(task, msg->port, - msg->port_msg.pid, mmap_msg); - if (nxt_slow_path(*pb == NULL)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "failed to get mmap buffer"); - - break; - } - - msg->size += mmap_msg->size; - pb = &(*pb)->next; - mmap_msg++; - - /* Mark original buf as complete. */ - b->mem.pos += sizeof(nxt_port_mmap_msg_t); - } - } -} - - -nxt_port_method_t -nxt_port_mmap_get_method(nxt_task_t *task, nxt_port_t *port, nxt_buf_t *b) -{ - nxt_port_method_t m; - - m = NXT_PORT_METHOD_ANY; - - for (/* void */; b != NULL; b = b->next) { - if (nxt_buf_used_size(b) == 0) { - /* empty buffers does not affect method */ - continue; - } - - if (nxt_buf_is_port_mmap(b)) { - if (m == NXT_PORT_METHOD_PLAIN) { - nxt_log_error(NXT_LOG_ERR, task->log, - "mixing plain and mmap buffers, " - "using plain mode"); - - break; - } - - if (m == NXT_PORT_METHOD_ANY) { - nxt_debug(task, "using mmap mode"); - - m = NXT_PORT_METHOD_MMAP; - } - } else { - if (m == NXT_PORT_METHOD_MMAP) { - nxt_log_error(NXT_LOG_ERR, task->log, - "mixing mmap and plain buffers, " - "switching to plain mode"); - - m = NXT_PORT_METHOD_PLAIN; - - break; - } - - if (m == NXT_PORT_METHOD_ANY) { - nxt_debug(task, "using plain mode"); - - m = NXT_PORT_METHOD_PLAIN; - } - } - } - - return m; -} - - -void -nxt_process_broadcast_shm_ack(nxt_task_t *task, nxt_process_t *process) -{ - nxt_port_t *port; - - if (nxt_slow_path(process == NULL || nxt_queue_is_empty(&process->ports))) - { - return; - } - - port = nxt_process_port_first(process); - - if (port->type == NXT_PROCESS_APP) { - nxt_port_post(task, port, nxt_port_broadcast_shm_ack, process); - } -} - - -static void -nxt_port_broadcast_shm_ack(nxt_task_t *task, nxt_port_t *port, void *data) -{ - nxt_process_t *process; - - process = data; - - nxt_queue_each(port, &process->ports, nxt_port_t, link) { - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_SHM_ACK, - -1, 0, 0, NULL); - } nxt_queue_loop; -} diff --git a/src/nxt_port_memory.h b/src/nxt_port_memory.h deleted file mode 100644 index f1e70964..00000000 --- a/src/nxt_port_memory.h +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PORT_MEMORY_H_INCLUDED_ -#define _NXT_PORT_MEMORY_H_INCLUDED_ - - -#define PORT_MMAP_MIN_SIZE (3 * sizeof(uint32_t)) - -typedef struct nxt_port_mmap_header_s nxt_port_mmap_header_t; -typedef struct nxt_port_mmap_handler_s nxt_port_mmap_handler_t; - -void nxt_port_mmaps_destroy(nxt_port_mmaps_t *port_mmaps, nxt_bool_t free_elts); - -/* - * Allocates nxt_but_t structure from task's thread engine mem_pool, assigns - * this buf 'mem' pointers to first available shared mem bucket(s). 'size' - * used as a hint to acquire several successive buckets if possible. - */ -nxt_buf_t * -nxt_port_mmap_get_buf(nxt_task_t *task, nxt_port_mmaps_t *mmaps, size_t size); - -nxt_int_t nxt_port_mmap_increase_buf(nxt_task_t *task, nxt_buf_t *b, - size_t size, size_t min_size); - -nxt_port_mmap_handler_t * -nxt_port_incoming_port_mmap(nxt_task_t *task, nxt_process_t *process, - nxt_fd_t fd); - -void -nxt_port_mmap_write(nxt_task_t *task, nxt_port_t *port, - nxt_port_send_msg_t *msg, nxt_sendbuf_coalesce_t *sb, void *mmsg_buf); - -void -nxt_port_mmap_read(nxt_task_t *task, nxt_port_recv_msg_t *msg); - -enum nxt_port_method_e { - NXT_PORT_METHOD_ANY = 0, - NXT_PORT_METHOD_PLAIN, - NXT_PORT_METHOD_MMAP -}; - -typedef enum nxt_port_method_e nxt_port_method_t; - -nxt_port_method_t -nxt_port_mmap_get_method(nxt_task_t *task, nxt_port_t *port, nxt_buf_t *b); - -nxt_int_t nxt_shm_open(nxt_task_t *task, size_t size); - -void nxt_process_broadcast_shm_ack(nxt_task_t *task, nxt_process_t *process); - -#endif /* _NXT_PORT_MEMORY_H_INCLUDED_ */ diff --git a/src/nxt_port_memory_int.h b/src/nxt_port_memory_int.h deleted file mode 100644 index 21a05b10..00000000 --- a/src/nxt_port_memory_int.h +++ /dev/null @@ -1,196 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PORT_MEMORY_INT_H_INCLUDED_ -#define _NXT_PORT_MEMORY_INT_H_INCLUDED_ - - -#include -#include - - -#ifdef NXT_MMAP_TINY_CHUNK - -#define PORT_MMAP_CHUNK_SIZE 16 -#define PORT_MMAP_HEADER_SIZE 1024 -#define PORT_MMAP_DATA_SIZE 1024 - -#else - -#define PORT_MMAP_CHUNK_SIZE (1024 * 16) -#define PORT_MMAP_HEADER_SIZE (1024 * 4) -#define PORT_MMAP_DATA_SIZE (1024 * 1024 * 10) - -#endif - - -#define PORT_MMAP_SIZE (PORT_MMAP_HEADER_SIZE + PORT_MMAP_DATA_SIZE) -#define PORT_MMAP_CHUNK_COUNT (PORT_MMAP_DATA_SIZE / PORT_MMAP_CHUNK_SIZE) - - -typedef uint32_t nxt_chunk_id_t; - -typedef nxt_atomic_uint_t nxt_free_map_t; - -#define FREE_BITS (sizeof(nxt_free_map_t) * 8) - -#define FREE_IDX(nchunk) ((nchunk) / FREE_BITS) - -#define FREE_MASK(nchunk) \ - ( 1ULL << ( (nchunk) % FREE_BITS ) ) - -#define MAX_FREE_IDX FREE_IDX(PORT_MMAP_CHUNK_COUNT) - - -/* Mapped at the start of shared memory segment. */ -struct nxt_port_mmap_header_s { - uint32_t id; - nxt_pid_t src_pid; /* For sanity check. */ - nxt_pid_t dst_pid; /* For sanity check. */ - nxt_port_id_t sent_over; - nxt_atomic_t oosm; - nxt_free_map_t free_map[MAX_FREE_IDX]; - nxt_free_map_t free_map_padding; - nxt_free_map_t free_tracking_map[MAX_FREE_IDX]; - nxt_free_map_t free_tracking_map_padding; - nxt_atomic_t tracking[PORT_MMAP_CHUNK_COUNT]; -}; - - -struct nxt_port_mmap_handler_s { - nxt_port_mmap_header_t *hdr; - nxt_atomic_t use_count; - nxt_fd_t fd; -}; - -/* - * Element of nxt_process_t.incoming/outgoing, shared memory segment - * descriptor. - */ -struct nxt_port_mmap_s { - nxt_port_mmap_handler_t *mmap_handler; -}; - -typedef struct nxt_port_mmap_msg_s nxt_port_mmap_msg_t; - -/* Passed as a second iov chunk when 'mmap' bit in nxt_port_msg_t is 1. */ -struct nxt_port_mmap_msg_s { - uint32_t mmap_id; /* Mmap index in nxt_process_t.outgoing. */ - nxt_chunk_id_t chunk_id; /* Mmap chunk index. */ - uint32_t size; /* Payload data size. */ -}; - - -nxt_inline nxt_bool_t -nxt_port_mmap_get_free_chunk(nxt_free_map_t *m, nxt_chunk_id_t *c); - -#define nxt_port_mmap_get_chunk_busy(m, c) \ - ((m[FREE_IDX(c)] & FREE_MASK(c)) == 0) - -nxt_inline void -nxt_port_mmap_set_chunk_busy(nxt_free_map_t *m, nxt_chunk_id_t c); - -nxt_inline nxt_bool_t -nxt_port_mmap_chk_set_chunk_busy(nxt_free_map_t *m, nxt_chunk_id_t c); - -nxt_inline void -nxt_port_mmap_set_chunk_free(nxt_free_map_t *m, nxt_chunk_id_t c); - -nxt_inline nxt_chunk_id_t -nxt_port_mmap_chunk_id(nxt_port_mmap_header_t *hdr, const u_char *p) -{ - u_char *mm_start; - - mm_start = (u_char *) hdr; - - return ((p - mm_start) - PORT_MMAP_HEADER_SIZE) / PORT_MMAP_CHUNK_SIZE; -} - - -nxt_inline u_char * -nxt_port_mmap_chunk_start(nxt_port_mmap_header_t *hdr, nxt_chunk_id_t c) -{ - u_char *mm_start; - - mm_start = (u_char *) hdr; - - return mm_start + PORT_MMAP_HEADER_SIZE + c * PORT_MMAP_CHUNK_SIZE; -} - - -nxt_inline nxt_bool_t -nxt_port_mmap_get_free_chunk(nxt_free_map_t *m, nxt_chunk_id_t *c) -{ - const nxt_free_map_t default_mask = (nxt_free_map_t) -1; - - int ffs; - size_t i, start; - nxt_chunk_id_t chunk; - nxt_free_map_t bits, mask; - - start = FREE_IDX(*c); - mask = default_mask << ((*c) % FREE_BITS); - - for (i = start; i < MAX_FREE_IDX; i++) { - bits = m[i] & mask; - mask = default_mask; - - if (bits == 0) { - continue; - } - - ffs = __builtin_ffsll(bits); - if (ffs != 0) { - chunk = i * FREE_BITS + ffs - 1; - - if (nxt_port_mmap_chk_set_chunk_busy(m, chunk)) { - *c = chunk; - return 1; - } - } - } - - return 0; -} - - -nxt_inline void -nxt_port_mmap_set_chunk_busy(nxt_free_map_t *m, nxt_chunk_id_t c) -{ - nxt_atomic_and_fetch(m + FREE_IDX(c), ~FREE_MASK(c)); -} - - -nxt_inline nxt_bool_t -nxt_port_mmap_chk_set_chunk_busy(nxt_free_map_t *m, nxt_chunk_id_t c) -{ - nxt_free_map_t *f; - nxt_free_map_t free_val, busy_val; - - f = m + FREE_IDX(c); - - while ( (*f & FREE_MASK(c)) != 0 ) { - - free_val = *f | FREE_MASK(c); - busy_val = free_val & ~FREE_MASK(c); - - if (nxt_atomic_cmp_set(f, free_val, busy_val) != 0) { - return 1; - } - } - - return 0; -} - - -nxt_inline void -nxt_port_mmap_set_chunk_free(nxt_free_map_t *m, nxt_chunk_id_t c) -{ - nxt_atomic_or_fetch(m + FREE_IDX(c), FREE_MASK(c)); -} - - -#endif /* _NXT_PORT_MEMORY_INT_H_INCLUDED_ */ diff --git a/src/nxt_port_queue.h b/src/nxt_port_queue.h deleted file mode 100644 index d2b2326b..00000000 --- a/src/nxt_port_queue.h +++ /dev/null @@ -1,102 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PORT_QUEUE_H_INCLUDED_ -#define _NXT_PORT_QUEUE_H_INCLUDED_ - - -#include - - -/* Using Numeric Naive Circular Queue as a backend. */ - -#define NXT_PORT_QUEUE_SIZE NXT_NNCQ_SIZE -#define NXT_PORT_QUEUE_MSG_SIZE 31 - - -typedef struct { - uint8_t size; - uint8_t data[NXT_PORT_QUEUE_MSG_SIZE]; -} nxt_port_queue_item_t; - - -typedef struct { - nxt_nncq_atomic_t nitems; - nxt_nncq_t free_items; - nxt_nncq_t queue; - nxt_port_queue_item_t items[NXT_PORT_QUEUE_SIZE]; -} nxt_port_queue_t; - - -nxt_inline void -nxt_port_queue_init(nxt_port_queue_t volatile *q) -{ - nxt_nncq_atomic_t i; - - nxt_nncq_init(&q->free_items); - nxt_nncq_init(&q->queue); - - for (i = 0; i < NXT_PORT_QUEUE_SIZE; i++) { - nxt_nncq_enqueue(&q->free_items, i); - } - - q->nitems = 0; -} - - -nxt_inline nxt_int_t -nxt_port_queue_send(nxt_port_queue_t volatile *q, const void *p, uint8_t size, - int *notify) -{ - nxt_nncq_atomic_t i; - nxt_port_queue_item_t *qi; - - i = nxt_nncq_dequeue(&q->free_items); - if (i == nxt_nncq_empty(&q->free_items)) { - *notify = 0; - return NXT_AGAIN; - } - - qi = (nxt_port_queue_item_t *) &q->items[i]; - - qi->size = size; - nxt_memcpy(qi->data, p, size); - - nxt_nncq_enqueue(&q->queue, i); - - i = nxt_atomic_fetch_add(&q->nitems, 1); - - *notify = (i == 0); - - return NXT_OK; -} - - -nxt_inline ssize_t -nxt_port_queue_recv(nxt_port_queue_t volatile *q, void *p) -{ - ssize_t res; - nxt_nncq_atomic_t i; - nxt_port_queue_item_t *qi; - - i = nxt_nncq_dequeue(&q->queue); - if (i == nxt_nncq_empty(&q->queue)) { - return -1; - } - - qi = (nxt_port_queue_item_t *) &q->items[i]; - - res = qi->size; - nxt_memcpy(p, qi->data, qi->size); - - nxt_nncq_enqueue(&q->free_items, i); - - nxt_atomic_fetch_add(&q->nitems, -1); - - return res; -} - - -#endif /* _NXT_PORT_QUEUE_H_INCLUDED_ */ diff --git a/src/nxt_port_rpc.c b/src/nxt_port_rpc.c deleted file mode 100644 index 28590933..00000000 --- a/src/nxt_port_rpc.c +++ /dev/null @@ -1,521 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -static volatile uint32_t *nxt_stream_ident; - -typedef struct nxt_port_rpc_reg_s nxt_port_rpc_reg_t; - -struct nxt_port_rpc_reg_s { - uint32_t stream; - - nxt_pid_t peer; - nxt_queue_link_t link; - nxt_bool_t link_first; - - nxt_port_rpc_handler_t ready_handler; - nxt_port_rpc_handler_t error_handler; - void *data; -}; - - -static void -nxt_port_rpc_remove_from_peers(nxt_task_t *task, nxt_port_t *port, - nxt_port_rpc_reg_t *reg); - - -nxt_int_t -nxt_port_rpc_init(void) -{ - void *p; - - if (nxt_stream_ident != NULL) { - return NXT_OK; - } - - p = nxt_mem_mmap(NULL, sizeof(*nxt_stream_ident), PROT_READ | PROT_WRITE, - MAP_ANON | MAP_SHARED, -1, 0); - - if (nxt_slow_path(p == MAP_FAILED)) { - return NXT_ERROR; - } - - nxt_stream_ident = p; - *nxt_stream_ident = 1; - - return NXT_OK; -} - - -static nxt_int_t -nxt_rpc_reg_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - return NXT_OK; -} - - -static const nxt_lvlhsh_proto_t lvlhsh_rpc_reg_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_rpc_reg_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -nxt_inline void -nxt_port_rpc_lhq_stream(nxt_lvlhsh_query_t *lhq, uint32_t *stream) -{ - lhq->key_hash = nxt_murmur_hash2(stream, sizeof(*stream)); - lhq->key.length = sizeof(*stream); - lhq->key.start = (u_char *) stream; - lhq->proto = &lvlhsh_rpc_reg_proto; -} - - -nxt_inline void -nxt_port_rpc_lhq_peer(nxt_lvlhsh_query_t *lhq, nxt_pid_t *peer) -{ - lhq->key_hash = nxt_murmur_hash2(peer, sizeof(*peer)); - lhq->key.length = sizeof(*peer); - lhq->key.start = (u_char *) peer; - lhq->proto = &lvlhsh_rpc_reg_proto; -} - - -uint32_t -nxt_port_rpc_register_handler(nxt_task_t *task, nxt_port_t *port, - nxt_port_rpc_handler_t ready_handler, nxt_port_rpc_handler_t error_handler, - nxt_pid_t peer, void *data) -{ - void *ex; - nxt_port_rpc_reg_t *reg; - - ex = nxt_port_rpc_register_handler_ex(task, port, ready_handler, - error_handler, 0); - - if (ex == NULL) { - return 0; - } - - if (peer != -1) { - nxt_port_rpc_ex_set_peer(task, port, ex, peer); - } - - reg = nxt_pointer_to(ex, -sizeof(nxt_port_rpc_reg_t)); - - nxt_assert(reg->data == ex); - - reg->data = data; - - return reg->stream; -} - - -void * -nxt_port_rpc_register_handler_ex(nxt_task_t *task, nxt_port_t *port, - nxt_port_rpc_handler_t ready_handler, nxt_port_rpc_handler_t error_handler, - size_t ex_size) -{ - uint32_t stream; - nxt_port_rpc_reg_t *reg; - nxt_lvlhsh_query_t lhq; - - nxt_assert(port->pair[0] != -1); - - stream = nxt_atomic_fetch_add(nxt_stream_ident, 1); - - reg = nxt_mp_zalloc(port->mem_pool, sizeof(nxt_port_rpc_reg_t) + ex_size); - - if (nxt_slow_path(reg == NULL)) { - nxt_debug(task, "rpc: stream #%uD failed to allocate reg", stream); - - return NULL; - } - - reg->stream = stream; - reg->peer = -1; - reg->ready_handler = ready_handler; - reg->error_handler = error_handler; - reg->data = reg + 1; - - nxt_port_rpc_lhq_stream(&lhq, &stream); - lhq.replace = 0; - lhq.value = reg; - lhq.pool = port->mem_pool; - - switch (nxt_lvlhsh_insert(&port->rpc_streams, &lhq)) { - - case NXT_OK: - break; - - default: - nxt_log_error(NXT_LOG_ERR, task->log, "rpc: stream #%uD failed to add " - "reg ", stream); - - nxt_mp_free(port->mem_pool, reg); - - return NULL; - } - - nxt_debug(task, "rpc: stream #%uD registered", stream); - - nxt_port_inc_use(port); - - return reg->data; -} - - -uint32_t -nxt_port_rpc_ex_stream(void *ex) -{ - nxt_port_rpc_reg_t *reg; - - reg = nxt_pointer_to(ex, -sizeof(nxt_port_rpc_reg_t)); - - nxt_assert(reg->data == ex); - - return reg->stream; -} - - -void -nxt_port_rpc_ex_set_peer(nxt_task_t *task, nxt_port_t *port, - void *ex, nxt_pid_t peer) -{ - nxt_int_t ret; - nxt_queue_link_t *peer_link; - nxt_port_rpc_reg_t *reg; - nxt_lvlhsh_query_t lhq; - - reg = nxt_pointer_to(ex, -sizeof(nxt_port_rpc_reg_t)); - - nxt_assert(reg->data == ex); - - if (nxt_slow_path(peer == reg->peer)) { - return; - } - - if (reg->peer != -1) { - nxt_port_rpc_remove_from_peers(task, port, reg); - - reg->peer = -1; - } - - if (peer == -1) { - return; - } - - reg->peer = peer; - - nxt_port_rpc_lhq_peer(&lhq, &peer); - lhq.replace = 0; - lhq.value = ®->link; - lhq.pool = port->mem_pool; - - ret = nxt_lvlhsh_insert(&port->rpc_peers, &lhq); - - switch (ret) { - - case NXT_OK: - reg->link_first = 1; - nxt_queue_self(®->link); - - nxt_debug(task, "rpc: stream #%uD assigned uniq pid %PI (%p)", - reg->stream, reg->peer, reg->link.next); - break; - - case NXT_DECLINED: - reg->link_first = 0; - peer_link = lhq.value; - nxt_queue_insert_after(peer_link, ®->link); - - nxt_debug(task, "rpc: stream #%uD assigned duplicate pid %PI (%p)", - reg->stream, reg->peer, reg->link.next); - break; - - default: - nxt_log_error(NXT_LOG_ERR, task->log, "rpc: failed to add " - "peer for stream #%uD (%d)", reg->stream, ret); - - reg->peer = -1; - break; - } - -} - - -static void -nxt_port_rpc_remove_from_peers(nxt_task_t *task, nxt_port_t *port, - nxt_port_rpc_reg_t *reg) -{ - uint32_t stream; - nxt_int_t ret; - nxt_lvlhsh_query_t lhq; - nxt_port_rpc_reg_t *r; - - stream = reg->stream; - - if (reg->link_first != 0) { - nxt_port_rpc_lhq_peer(&lhq, ®->peer); - lhq.pool = port->mem_pool; - - if (reg->link.next == ®->link) { - nxt_assert(reg->link.prev == ®->link); - - nxt_debug(task, "rpc: stream #%uD remove first and last pid %PI " - "registration (%p)", stream, reg->peer, reg->link.next); - - ret = nxt_lvlhsh_delete(&port->rpc_peers, &lhq); - - } else { - nxt_debug(task, "rpc: stream #%uD remove first pid %PI " - "registration (%p)", stream, reg->peer, reg->link.next); - - lhq.replace = 1; - lhq.value = reg->link.next; - - r = nxt_queue_link_data(reg->link.next, nxt_port_rpc_reg_t, link); - r->link_first = 1; - - nxt_queue_remove(®->link); - - ret = nxt_lvlhsh_insert(&port->rpc_peers, &lhq); - } - - } else { - nxt_debug(task, "rpc: stream #%uD remove pid %PI " - "registration (%p)", stream, reg->peer, reg->link.next); - - nxt_queue_remove(®->link); - ret = NXT_OK; - } - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, "rpc: stream #%uD failed" - " to delete peer %PI (%d)", stream, reg->peer, ret); - } -} - - -void -nxt_port_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - uint8_t last; - uint32_t stream; - nxt_int_t ret; - nxt_port_t *port; - nxt_port_rpc_reg_t *reg; - nxt_lvlhsh_query_t lhq; - nxt_port_msg_type_t type; - - stream = msg->port_msg.stream; - port = msg->port; - last = msg->port_msg.last; - type = msg->port_msg.type; - - nxt_port_rpc_lhq_stream(&lhq, &stream); - lhq.pool = port->mem_pool; - - if (last != 0) { - ret = nxt_lvlhsh_delete(&port->rpc_streams, &lhq); - - } else { - ret = nxt_lvlhsh_find(&port->rpc_streams, &lhq); - } - - if (ret != NXT_OK) { - nxt_debug(task, "rpc: stream #%uD no handler found", stream); - - return; - } - - nxt_debug(task, "rpc: stream #%uD %shandler, type %d", stream, - (last ? "last " : ""), type); - - reg = lhq.value; - - if (type == _NXT_PORT_MSG_RPC_ERROR) { - reg->error_handler(task, msg, reg->data); - - } else { - reg->ready_handler(task, msg, reg->data); - } - - if (last == 0) { - return; - } - - if (reg->peer != -1) { - nxt_port_rpc_remove_from_peers(task, port, reg); - } - - nxt_debug(task, "rpc: stream #%uD free registration", stream); - - nxt_mp_free(port->mem_pool, reg); - - nxt_port_use(task, port, -1); -} - - -void -nxt_port_rpc_remove_peer(nxt_task_t *task, nxt_port_t *port, nxt_pid_t peer) -{ - uint8_t last; - uint32_t stream; - nxt_int_t ret; - nxt_buf_t buf; - nxt_queue_link_t *peer_link, *next_link; - nxt_port_rpc_reg_t *reg; - nxt_lvlhsh_query_t lhq; - nxt_port_recv_msg_t msg; - - nxt_port_rpc_lhq_peer(&lhq, &peer); - lhq.pool = port->mem_pool; - - ret = nxt_lvlhsh_delete(&port->rpc_peers, &lhq); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_debug(task, "rpc: no reg found for peer %PI", peer); - - return; - } - - nxt_memzero(&msg, sizeof(msg)); - nxt_memzero(&buf, sizeof(buf)); - - msg.fd[0] = -1; - msg.fd[1] = -1; - msg.buf = &buf; - msg.port = port; - msg.u.removed_pid = peer; - msg.port_msg.pid = nxt_pid; - msg.port_msg.type = _NXT_PORT_MSG_REMOVE_PID; - - peer_link = lhq.value; - last = 0; - - while (last == 0) { - - reg = nxt_queue_link_data(peer_link, nxt_port_rpc_reg_t, link); - - nxt_assert(reg->peer == peer); - - stream = reg->stream; - - nxt_debug(task, "rpc: stream #%uD trigger error", stream); - - msg.port_msg.stream = stream; - msg.port_msg.last = 1; - - if (peer_link == peer_link->next) { - nxt_assert(peer_link->prev == peer_link); - - last = 1; - - } else { - nxt_assert(peer_link->next->prev == peer_link); - nxt_assert(peer_link->prev->next == peer_link); - - next_link = peer_link->next; - nxt_queue_remove(peer_link); - - peer_link = next_link; - } - - reg->peer = -1; - - reg->error_handler(task, &msg, reg->data); - - /* Reset 'last' flag to preserve rpc handler. */ - if (msg.port_msg.last == 0) { - continue; - } - - nxt_port_rpc_lhq_stream(&lhq, &stream); - lhq.pool = port->mem_pool; - - ret = nxt_lvlhsh_delete(&port->rpc_streams, &lhq); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "rpc: stream #%uD failed to delete handler", stream); - - return; - } - - nxt_mp_free(port->mem_pool, reg); - - nxt_port_use(task, port, -1); - } -} - - -void -nxt_port_rpc_cancel(nxt_task_t *task, nxt_port_t *port, uint32_t stream) -{ - nxt_int_t ret; - nxt_port_rpc_reg_t *reg; - nxt_lvlhsh_query_t lhq; - - nxt_port_rpc_lhq_stream(&lhq, &stream); - lhq.pool = port->mem_pool; - - ret = nxt_lvlhsh_delete(&port->rpc_streams, &lhq); - - if (ret != NXT_OK) { - nxt_debug(task, "rpc: stream #%uD no handler found", stream); - - return; - } - - reg = lhq.value; - - if (reg->peer != -1) { - nxt_port_rpc_remove_from_peers(task, port, reg); - } - - nxt_debug(task, "rpc: stream #%uD cancel registration", stream); - - nxt_mp_free(port->mem_pool, reg); - - nxt_port_use(task, port, -1); -} - -static nxt_buf_t nxt_port_close_dummy_buf; - -void -nxt_port_rpc_close(nxt_task_t *task, nxt_port_t *port) -{ - nxt_port_rpc_reg_t *reg; - nxt_port_recv_msg_t msg; - - for ( ;; ) { - reg = nxt_lvlhsh_peek(&port->rpc_streams, &lvlhsh_rpc_reg_proto); - if (reg == NULL) { - return; - } - - msg.fd[0] = -1; - msg.fd[1] = -1; - msg.buf = &nxt_port_close_dummy_buf; - msg.port = port; - msg.port_msg.stream = reg->stream; - msg.port_msg.pid = nxt_pid; - msg.port_msg.type = _NXT_PORT_MSG_RPC_ERROR; - msg.port_msg.last = 1; - msg.port_msg.mmap = 0; - msg.port_msg.nf = 0; - msg.port_msg.mf = 0; - msg.size = 0; - msg.cancelled = 0; - msg.u.data = NULL; - - nxt_port_rpc_handler(task, &msg); - } -} diff --git a/src/nxt_port_rpc.h b/src/nxt_port_rpc.h deleted file mode 100644 index c07683fb..00000000 --- a/src/nxt_port_rpc.h +++ /dev/null @@ -1,35 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PORT_RPC_H_INCLUDED_ -#define _NXT_PORT_RPC_H_INCLUDED_ - - -typedef void (*nxt_port_rpc_handler_t)(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); - -nxt_int_t nxt_port_rpc_init(void); - -uint32_t nxt_port_rpc_register_handler(nxt_task_t *task, nxt_port_t *port, - nxt_port_rpc_handler_t ready_handler, nxt_port_rpc_handler_t error_handler, - nxt_pid_t peer, void *data); -void *nxt_port_rpc_register_handler_ex(nxt_task_t *task, nxt_port_t *port, - nxt_port_rpc_handler_t ready_handler, nxt_port_rpc_handler_t error_handler, - size_t ex_size); - -uint32_t nxt_port_rpc_ex_stream(void *ex); -void nxt_port_rpc_ex_set_peer(nxt_task_t *task, nxt_port_t *port, - void *ex, nxt_pid_t peer); - -void nxt_port_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -void nxt_port_rpc_remove_peer(nxt_task_t *task, nxt_port_t *port, - nxt_pid_t peer); -void nxt_port_rpc_cancel(nxt_task_t *task, nxt_port_t *port, uint32_t stream); -void nxt_port_rpc_close(nxt_task_t *task, nxt_port_t *port); - - -#endif /* _NXT_PORT_RPC_H_INCLUDED_ */ - diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c deleted file mode 100644 index 5752d5ab..00000000 --- a/src/nxt_port_socket.c +++ /dev/null @@ -1,1386 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include - - -#define NXT_PORT_MAX_ENQUEUE_BUF_SIZE \ - (int) (NXT_PORT_QUEUE_MSG_SIZE - sizeof(nxt_port_msg_t)) - - -static nxt_bool_t nxt_port_can_enqueue_buf(nxt_buf_t *b); -static uint8_t nxt_port_enqueue_buf(nxt_task_t *task, nxt_port_msg_t *pm, - void *qbuf, nxt_buf_t *b); -static nxt_int_t nxt_port_msg_chk_insert(nxt_task_t *task, nxt_port_t *port, - nxt_port_send_msg_t *msg); -static nxt_port_send_msg_t *nxt_port_msg_alloc(const nxt_port_send_msg_t *m); -static void nxt_port_write_handler(nxt_task_t *task, void *obj, void *data); -static nxt_port_send_msg_t *nxt_port_msg_first(nxt_port_t *port); -nxt_inline void nxt_port_msg_close_fd(nxt_port_send_msg_t *msg); -nxt_inline void nxt_port_close_fds(nxt_fd_t *fd); -static nxt_buf_t *nxt_port_buf_completion(nxt_task_t *task, - nxt_work_queue_t *wq, nxt_buf_t *b, size_t sent, nxt_bool_t mmap_mode); -static nxt_port_send_msg_t *nxt_port_msg_insert_tail(nxt_port_t *port, - nxt_port_send_msg_t *msg); -static void nxt_port_read_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_port_queue_read_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_port_read_msg_process(nxt_task_t *task, nxt_port_t *port, - nxt_port_recv_msg_t *msg); -static nxt_buf_t *nxt_port_buf_alloc(nxt_port_t *port); -static void nxt_port_buf_free(nxt_port_t *port, nxt_buf_t *b); -static void nxt_port_error_handler(nxt_task_t *task, void *obj, void *data); - - -nxt_int_t -nxt_port_socket_init(nxt_task_t *task, nxt_port_t *port, size_t max_size) -{ - nxt_int_t sndbuf, rcvbuf, size; - nxt_socket_t snd, rcv; - - port->socket.task = task; - - port->pair[0] = -1; - port->pair[1] = -1; - - if (nxt_slow_path(nxt_socketpair_create(task, port->pair) != NXT_OK)) { - goto socketpair_fail; - } - - snd = port->pair[1]; - - sndbuf = nxt_socket_getsockopt(task, snd, SOL_SOCKET, SO_SNDBUF); - if (nxt_slow_path(sndbuf < 0)) { - goto getsockopt_fail; - } - - rcv = port->pair[0]; - - rcvbuf = nxt_socket_getsockopt(task, rcv, SOL_SOCKET, SO_RCVBUF); - if (nxt_slow_path(rcvbuf < 0)) { - goto getsockopt_fail; - } - - if (max_size == 0) { - max_size = 16 * 1024; - } - - if ((size_t) sndbuf < max_size) { - /* - * On Unix domain sockets - * Linux uses 224K on both send and receive directions; - * FreeBSD, MacOSX, NetBSD, and OpenBSD use 2K buffer size - * on send direction and 4K buffer size on receive direction; - * Solaris uses 16K on send direction and 5K on receive direction. - */ - (void) nxt_socket_setsockopt(task, snd, SOL_SOCKET, SO_SNDBUF, - max_size); - - sndbuf = nxt_socket_getsockopt(task, snd, SOL_SOCKET, SO_SNDBUF); - if (nxt_slow_path(sndbuf < 0)) { - goto getsockopt_fail; - } - - size = sndbuf * 4; - - if (rcvbuf < size) { - (void) nxt_socket_setsockopt(task, rcv, SOL_SOCKET, SO_RCVBUF, - size); - - rcvbuf = nxt_socket_getsockopt(task, rcv, SOL_SOCKET, SO_RCVBUF); - if (nxt_slow_path(rcvbuf < 0)) { - goto getsockopt_fail; - } - } - } - - port->max_size = nxt_min(max_size, (size_t) sndbuf); - port->max_share = (64 * 1024); - - return NXT_OK; - -getsockopt_fail: - - nxt_socket_close(task, port->pair[0]); - nxt_socket_close(task, port->pair[1]); - -socketpair_fail: - - return NXT_ERROR; -} - - -void -nxt_port_destroy(nxt_port_t *port) -{ - nxt_socket_close(port->socket.task, port->socket.fd); - nxt_mp_destroy(port->mem_pool); -} - - -void -nxt_port_write_enable(nxt_task_t *task, nxt_port_t *port) -{ - port->socket.fd = port->pair[1]; - port->socket.log = &nxt_main_log; - port->socket.write_ready = 1; - - port->engine = task->thread->engine; - - port->socket.write_work_queue = &port->engine->fast_work_queue; - port->socket.write_handler = nxt_port_write_handler; - port->socket.error_handler = nxt_port_error_handler; -} - - -void -nxt_port_write_close(nxt_port_t *port) -{ - nxt_socket_close(port->socket.task, port->pair[1]); - port->pair[1] = -1; -} - - -static void -nxt_port_release_send_msg(nxt_port_send_msg_t *msg) -{ - if (msg->allocated) { - nxt_free(msg); - } -} - - -nxt_int_t -nxt_port_socket_write2(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type, - nxt_fd_t fd, nxt_fd_t fd2, uint32_t stream, nxt_port_id_t reply_port, - nxt_buf_t *b) -{ - int notify; - uint8_t qmsg_size; - nxt_int_t res; - nxt_port_send_msg_t msg; - struct { - nxt_port_msg_t pm; - uint8_t buf[NXT_PORT_MAX_ENQUEUE_BUF_SIZE]; - } qmsg; - - msg.link.next = NULL; - msg.link.prev = NULL; - - msg.buf = b; - msg.share = 0; - msg.fd[0] = fd; - msg.fd[1] = fd2; - msg.close_fd = (type & NXT_PORT_MSG_CLOSE_FD) != 0; - msg.allocated = 0; - - msg.port_msg.stream = stream; - msg.port_msg.pid = nxt_pid; - msg.port_msg.reply_port = reply_port; - msg.port_msg.type = type & NXT_PORT_MSG_MASK; - msg.port_msg.last = (type & NXT_PORT_MSG_LAST) != 0; - msg.port_msg.mmap = 0; - msg.port_msg.nf = 0; - msg.port_msg.mf = 0; - - if (port->queue != NULL && type != _NXT_PORT_MSG_READ_QUEUE) { - - if (fd == -1 && nxt_port_can_enqueue_buf(b)) { - qmsg.pm = msg.port_msg; - - qmsg_size = sizeof(qmsg.pm); - - if (b != NULL) { - qmsg_size += nxt_port_enqueue_buf(task, &qmsg.pm, qmsg.buf, b); - } - - res = nxt_port_queue_send(port->queue, &qmsg, qmsg_size, ¬ify); - - nxt_debug(task, "port{%d,%d} %d: enqueue %d notify %d, %d", - (int) port->pid, (int) port->id, port->socket.fd, - (int) qmsg_size, notify, res); - - if (b != NULL && nxt_fast_path(res == NXT_OK)) { - if (qmsg.pm.mmap) { - b->is_port_mmap_sent = 1; - } - - b->mem.pos = b->mem.free; - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - b->completion_handler, task, b, b->parent); - } - - if (notify == 0) { - return res; - } - - msg.port_msg.type = _NXT_PORT_MSG_READ_QUEUE; - msg.buf = NULL; - - } else { - qmsg.buf[0] = _NXT_PORT_MSG_READ_SOCKET; - - res = nxt_port_queue_send(port->queue, qmsg.buf, 1, ¬ify); - - nxt_debug(task, "port{%d,%d} %d: enqueue 1 notify %d, %d", - (int) port->pid, (int) port->id, port->socket.fd, - notify, res); - - if (nxt_slow_path(res == NXT_AGAIN)) { - return NXT_AGAIN; - } - } - } - - res = nxt_port_msg_chk_insert(task, port, &msg); - if (nxt_fast_path(res == NXT_DECLINED)) { - nxt_port_write_handler(task, &port->socket, &msg); - res = NXT_OK; - } - - return res; -} - - -static nxt_bool_t -nxt_port_can_enqueue_buf(nxt_buf_t *b) -{ - if (b == NULL) { - return 1; - } - - if (b->next != NULL) { - return 0; - } - - return (nxt_buf_mem_used_size(&b->mem) <= NXT_PORT_MAX_ENQUEUE_BUF_SIZE - || nxt_buf_is_port_mmap(b)); -} - - -static uint8_t -nxt_port_enqueue_buf(nxt_task_t *task, nxt_port_msg_t *pm, void *qbuf, - nxt_buf_t *b) -{ - ssize_t size; - nxt_port_mmap_msg_t *mm; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - size = nxt_buf_mem_used_size(&b->mem); - - if (size <= NXT_PORT_MAX_ENQUEUE_BUF_SIZE) { - nxt_memcpy(qbuf, b->mem.pos, size); - - return size; - } - - mmap_handler = b->parent; - hdr = mmap_handler->hdr; - mm = qbuf; - - mm->mmap_id = hdr->id; - mm->chunk_id = nxt_port_mmap_chunk_id(hdr, b->mem.pos); - mm->size = nxt_buf_mem_used_size(&b->mem); - - pm->mmap = 1; - - nxt_debug(task, "mmap_msg={%D, %D, %D}", mm->mmap_id, mm->chunk_id, - mm->size); - - return sizeof(nxt_port_mmap_msg_t); -} - - -static nxt_int_t -nxt_port_msg_chk_insert(nxt_task_t *task, nxt_port_t *port, - nxt_port_send_msg_t *msg) -{ - nxt_int_t res; - - nxt_thread_mutex_lock(&port->write_mutex); - - if (nxt_fast_path(port->socket.write_ready - && nxt_queue_is_empty(&port->messages))) - { - res = NXT_DECLINED; - - } else { - msg = nxt_port_msg_alloc(msg); - - if (nxt_fast_path(msg != NULL)) { - nxt_queue_insert_tail(&port->messages, &msg->link); - nxt_port_use(task, port, 1); - res = NXT_OK; - - } else { - res = NXT_ERROR; - } - } - - nxt_thread_mutex_unlock(&port->write_mutex); - - return res; -} - - -static nxt_port_send_msg_t * -nxt_port_msg_alloc(const nxt_port_send_msg_t *m) -{ - nxt_port_send_msg_t *msg; - - msg = nxt_malloc(sizeof(nxt_port_send_msg_t)); - if (nxt_slow_path(msg == NULL)) { - return NULL; - } - - *msg = *m; - - msg->allocated = 1; - - return msg; -} - - -static void -nxt_port_fd_block_write(nxt_task_t *task, nxt_port_t *port, void *data) -{ - nxt_fd_event_block_write(task->thread->engine, &port->socket); -} - - -static void -nxt_port_fd_enable_write(nxt_task_t *task, nxt_port_t *port, void *data) -{ - nxt_fd_event_enable_write(task->thread->engine, &port->socket); -} - - -static void -nxt_port_write_handler(nxt_task_t *task, void *obj, void *data) -{ - int use_delta; - size_t plain_size; - ssize_t n; - uint32_t mmsg_buf[3 * NXT_IOBUF_MAX * 10]; - nxt_bool_t block_write, enable_write; - nxt_port_t *port; - struct iovec iov[NXT_IOBUF_MAX * 10]; - nxt_work_queue_t *wq; - nxt_port_method_t m; - nxt_port_send_msg_t *msg; - nxt_sendbuf_coalesce_t sb; - - port = nxt_container_of(obj, nxt_port_t, socket); - - block_write = 0; - enable_write = 0; - use_delta = 0; - - wq = &task->thread->engine->fast_work_queue; - - do { - if (data) { - msg = data; - - } else { - msg = nxt_port_msg_first(port); - - if (msg == NULL) { - block_write = 1; - goto cleanup; - } - } - -next_fragment: - - iov[0].iov_base = &msg->port_msg; - iov[0].iov_len = sizeof(nxt_port_msg_t); - - sb.buf = msg->buf; - sb.iobuf = &iov[1]; - sb.nmax = NXT_IOBUF_MAX - 1; - sb.sync = 0; - sb.last = 0; - sb.size = 0; - sb.limit = port->max_size; - - sb.limit_reached = 0; - sb.nmax_reached = 0; - - m = nxt_port_mmap_get_method(task, port, msg->buf); - - if (m == NXT_PORT_METHOD_MMAP) { - sb.limit = (1ULL << 31) - 1; - sb.nmax = nxt_min(NXT_IOBUF_MAX * 10 - 1, - port->max_size / PORT_MMAP_MIN_SIZE); - } - - sb.limit -= iov[0].iov_len; - - nxt_sendbuf_mem_coalesce(task, &sb); - - plain_size = sb.size; - - /* - * Send through mmap enabled only when payload - * is bigger than PORT_MMAP_MIN_SIZE. - */ - if (m == NXT_PORT_METHOD_MMAP && plain_size > PORT_MMAP_MIN_SIZE) { - nxt_port_mmap_write(task, port, msg, &sb, mmsg_buf); - - } else { - m = NXT_PORT_METHOD_PLAIN; - } - - msg->port_msg.last |= sb.last; - msg->port_msg.mf = sb.limit_reached || sb.nmax_reached; - - n = nxt_socketpair_send(&port->socket, msg->fd, iov, sb.niov + 1); - - if (n > 0) { - if (nxt_slow_path((size_t) n != sb.size + iov[0].iov_len)) { - nxt_alert(task, "port %d: short write: %z instead of %uz", - port->socket.fd, n, sb.size + iov[0].iov_len); - goto fail; - } - - nxt_port_msg_close_fd(msg); - - msg->buf = nxt_port_buf_completion(task, wq, msg->buf, plain_size, - m == NXT_PORT_METHOD_MMAP); - - if (msg->buf != NULL) { - nxt_debug(task, "port %d: frag stream #%uD", port->socket.fd, - msg->port_msg.stream); - - /* - * A file descriptor is sent only - * in the first message of a stream. - */ - msg->fd[0] = -1; - msg->fd[1] = -1; - msg->share += n; - msg->port_msg.nf = 1; - - if (msg->share >= port->max_share) { - msg->share = 0; - - if (msg->link.next != NULL) { - nxt_thread_mutex_lock(&port->write_mutex); - - nxt_queue_remove(&msg->link); - nxt_queue_insert_tail(&port->messages, &msg->link); - - nxt_thread_mutex_unlock(&port->write_mutex); - - } else { - msg = nxt_port_msg_insert_tail(port, msg); - if (nxt_slow_path(msg == NULL)) { - goto fail; - } - - use_delta++; - } - - } else { - goto next_fragment; - } - - } else { - if (msg->link.next != NULL) { - nxt_thread_mutex_lock(&port->write_mutex); - - nxt_queue_remove(&msg->link); - msg->link.next = NULL; - - nxt_thread_mutex_unlock(&port->write_mutex); - - use_delta--; - } - - nxt_port_release_send_msg(msg); - } - - if (data != NULL) { - goto cleanup; - } - - } else { - if (nxt_slow_path(n == NXT_ERROR)) { - if (msg->link.next == NULL) { - nxt_port_msg_close_fd(msg); - - nxt_port_release_send_msg(msg); - } - - goto fail; - } - - if (msg->link.next == NULL) { - msg = nxt_port_msg_insert_tail(port, msg); - if (nxt_slow_path(msg == NULL)) { - goto fail; - } - - use_delta++; - } - } - - } while (port->socket.write_ready); - - if (nxt_fd_event_is_disabled(port->socket.write)) { - enable_write = 1; - } - - goto cleanup; - -fail: - - use_delta++; - - nxt_work_queue_add(wq, nxt_port_error_handler, task, &port->socket, - &port->socket); - -cleanup: - - if (block_write && nxt_fd_event_is_active(port->socket.write)) { - nxt_port_post(task, port, nxt_port_fd_block_write, NULL); - } - - if (enable_write) { - nxt_port_post(task, port, nxt_port_fd_enable_write, NULL); - } - - if (use_delta != 0) { - nxt_port_use(task, port, use_delta); - } -} - - -static nxt_port_send_msg_t * -nxt_port_msg_first(nxt_port_t *port) -{ - nxt_queue_link_t *lnk; - nxt_port_send_msg_t *msg; - - nxt_thread_mutex_lock(&port->write_mutex); - - lnk = nxt_queue_first(&port->messages); - - if (lnk == nxt_queue_tail(&port->messages)) { - msg = NULL; - - } else { - msg = nxt_queue_link_data(lnk, nxt_port_send_msg_t, link); - } - - nxt_thread_mutex_unlock(&port->write_mutex); - - return msg; -} - - -nxt_inline void -nxt_port_msg_close_fd(nxt_port_send_msg_t *msg) -{ - if (!msg->close_fd) { - return; - } - - nxt_port_close_fds(msg->fd); -} - - -nxt_inline void -nxt_port_close_fds(nxt_fd_t *fd) -{ - if (fd[0] != -1) { - nxt_fd_close(fd[0]); - fd[0] = -1; - } - - if (fd[1] != -1) { - nxt_fd_close(fd[1]); - fd[1] = -1; - } -} - - -static nxt_buf_t * -nxt_port_buf_completion(nxt_task_t *task, nxt_work_queue_t *wq, nxt_buf_t *b, - size_t sent, nxt_bool_t mmap_mode) -{ - size_t size; - nxt_buf_t *next; - - while (b != NULL) { - - nxt_prefetch(b->next); - - if (!nxt_buf_is_sync(b)) { - - size = nxt_buf_used_size(b); - - if (size != 0) { - - if (sent == 0) { - break; - } - - if (nxt_buf_is_port_mmap(b) && mmap_mode) { - /* - * buffer has been sent to other side which is now - * responsible for shared memory bucket release - */ - b->is_port_mmap_sent = 1; - } - - if (sent < size) { - - if (nxt_buf_is_mem(b)) { - b->mem.pos += sent; - } - - if (nxt_buf_is_file(b)) { - b->file_pos += sent; - } - - break; - } - - /* b->mem.free is NULL in file-only buffer. */ - b->mem.pos = b->mem.free; - - if (nxt_buf_is_file(b)) { - b->file_pos = b->file_end; - } - - sent -= size; - } - } - - nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent); - - next = b->next; - b->next = NULL; - b = next; - } - - return b; -} - - -static nxt_port_send_msg_t * -nxt_port_msg_insert_tail(nxt_port_t *port, nxt_port_send_msg_t *msg) -{ - if (msg->allocated == 0) { - msg = nxt_port_msg_alloc(msg); - - if (nxt_slow_path(msg == NULL)) { - return NULL; - } - } - - nxt_thread_mutex_lock(&port->write_mutex); - - nxt_queue_insert_tail(&port->messages, &msg->link); - - nxt_thread_mutex_unlock(&port->write_mutex); - - return msg; -} - - -void -nxt_port_read_enable(nxt_task_t *task, nxt_port_t *port) -{ - port->socket.fd = port->pair[0]; - port->socket.log = &nxt_main_log; - - port->engine = task->thread->engine; - - port->socket.read_work_queue = &port->engine->fast_work_queue; - port->socket.read_handler = port->queue != NULL - ? nxt_port_queue_read_handler - : nxt_port_read_handler; - port->socket.error_handler = nxt_port_error_handler; - - nxt_fd_event_enable_read(port->engine, &port->socket); -} - - -void -nxt_port_read_close(nxt_port_t *port) -{ - port->socket.read_ready = 0; - port->socket.read = NXT_EVENT_INACTIVE; - nxt_socket_close(port->socket.task, port->pair[0]); - port->pair[0] = -1; -} - - -static void -nxt_port_read_handler(nxt_task_t *task, void *obj, void *data) -{ - ssize_t n; - nxt_buf_t *b; - nxt_int_t ret; - nxt_port_t *port; - nxt_recv_oob_t oob; - nxt_port_recv_msg_t msg; - struct iovec iov[2]; - - port = msg.port = nxt_container_of(obj, nxt_port_t, socket); - - nxt_assert(port->engine == task->thread->engine); - - for ( ;; ) { - b = nxt_port_buf_alloc(port); - - if (nxt_slow_path(b == NULL)) { - /* TODO: disable event for some time */ - } - - iov[0].iov_base = &msg.port_msg; - iov[0].iov_len = sizeof(nxt_port_msg_t); - - iov[1].iov_base = b->mem.pos; - iov[1].iov_len = port->max_size; - - n = nxt_socketpair_recv(&port->socket, iov, 2, &oob); - - if (n > 0) { - msg.fd[0] = -1; - msg.fd[1] = -1; - - ret = nxt_socket_msg_oob_get(&oob, msg.fd, - nxt_recv_msg_cmsg_pid_ref(&msg)); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "failed to get oob data from %d", - port->socket.fd); - - nxt_port_close_fds(msg.fd); - - goto fail; - } - - msg.buf = b; - msg.size = n; - - nxt_port_read_msg_process(task, port, &msg); - - /* - * To disable instant completion or buffer re-usage, - * handler should reset 'msg.buf'. - */ - if (msg.buf == b) { - nxt_port_buf_free(port, b); - } - - if (port->socket.read_ready) { - continue; - } - - return; - } - - if (n == NXT_AGAIN) { - nxt_port_buf_free(port, b); - - nxt_fd_event_enable_read(task->thread->engine, &port->socket); - return; - } - -fail: - /* n == 0 || error */ - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - nxt_port_error_handler, task, &port->socket, NULL); - return; - } -} - - -static void -nxt_port_queue_read_handler(nxt_task_t *task, void *obj, void *data) -{ - ssize_t n; - nxt_buf_t *b; - nxt_int_t ret; - nxt_port_t *port; - struct iovec iov[2]; - nxt_recv_oob_t oob; - nxt_port_queue_t *queue; - nxt_port_recv_msg_t msg, *smsg; - uint8_t qmsg[NXT_PORT_QUEUE_MSG_SIZE]; - - port = nxt_container_of(obj, nxt_port_t, socket); - msg.port = port; - - nxt_assert(port->engine == task->thread->engine); - - queue = port->queue; - nxt_atomic_fetch_add(&queue->nitems, 1); - - for ( ;; ) { - - if (port->from_socket == 0) { - n = nxt_port_queue_recv(queue, qmsg); - - if (n < 0 && !port->socket.read_ready) { - nxt_atomic_fetch_add(&queue->nitems, -1); - - n = nxt_port_queue_recv(queue, qmsg); - if (n < 0) { - return; - } - - nxt_atomic_fetch_add(&queue->nitems, 1); - } - - if (n == 1 && qmsg[0] == _NXT_PORT_MSG_READ_SOCKET) { - port->from_socket++; - - nxt_debug(task, "port{%d,%d} %d: dequeue 1 read_socket %d", - (int) port->pid, (int) port->id, port->socket.fd, - port->from_socket); - - continue; - } - - nxt_debug(task, "port{%d,%d} %d: dequeue %d", - (int) port->pid, (int) port->id, port->socket.fd, - (int) n); - - } else { - if ((smsg = port->socket_msg) != NULL && smsg->size != 0) { - msg.port_msg = smsg->port_msg; - b = smsg->buf; - n = smsg->size; - msg.fd[0] = smsg->fd[0]; - msg.fd[1] = smsg->fd[1]; - - smsg->size = 0; - - port->from_socket--; - - nxt_debug(task, "port{%d,%d} %d: use suspended message %d", - (int) port->pid, (int) port->id, port->socket.fd, - (int) n); - - goto process; - } - - n = -1; - } - - if (n < 0 && !port->socket.read_ready) { - nxt_atomic_fetch_add(&queue->nitems, -1); - return; - } - - b = nxt_port_buf_alloc(port); - - if (nxt_slow_path(b == NULL)) { - /* TODO: disable event for some time */ - } - - if (n >= (ssize_t) sizeof(nxt_port_msg_t)) { - nxt_memcpy(&msg.port_msg, qmsg, sizeof(nxt_port_msg_t)); - - if (n > (ssize_t) sizeof(nxt_port_msg_t)) { - nxt_memcpy(b->mem.pos, qmsg + sizeof(nxt_port_msg_t), - n - sizeof(nxt_port_msg_t)); - } - - } else { - iov[0].iov_base = &msg.port_msg; - iov[0].iov_len = sizeof(nxt_port_msg_t); - - iov[1].iov_base = b->mem.pos; - iov[1].iov_len = port->max_size; - - n = nxt_socketpair_recv(&port->socket, iov, 2, &oob); - - if (n > 0) { - msg.fd[0] = -1; - msg.fd[1] = -1; - - ret = nxt_socket_msg_oob_get(&oob, msg.fd, - nxt_recv_msg_cmsg_pid_ref(&msg)); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "failed to get oob data from %d", - port->socket.fd); - - nxt_port_close_fds(msg.fd); - - return; - } - } - - if (n == (ssize_t) sizeof(nxt_port_msg_t) - && msg.port_msg.type == _NXT_PORT_MSG_READ_QUEUE) - { - nxt_port_buf_free(port, b); - - nxt_debug(task, "port{%d,%d} %d: recv %d read_queue", - (int) port->pid, (int) port->id, port->socket.fd, - (int) n); - - continue; - } - - nxt_debug(task, "port{%d,%d} %d: recvmsg %d", - (int) port->pid, (int) port->id, port->socket.fd, - (int) n); - - if (n > 0) { - if (port->from_socket == 0) { - nxt_debug(task, "port{%d,%d} %d: suspend message %d", - (int) port->pid, (int) port->id, port->socket.fd, - (int) n); - - smsg = port->socket_msg; - - if (nxt_slow_path(smsg == NULL)) { - smsg = nxt_mp_alloc(port->mem_pool, - sizeof(nxt_port_recv_msg_t)); - - if (nxt_slow_path(smsg == NULL)) { - nxt_alert(task, "port{%d,%d} %d: suspend message " - "failed", - (int) port->pid, (int) port->id, - port->socket.fd); - - return; - } - - port->socket_msg = smsg; - - } else { - if (nxt_slow_path(smsg->size != 0)) { - nxt_alert(task, "port{%d,%d} %d: too many suspend " - "messages", - (int) port->pid, (int) port->id, - port->socket.fd); - - return; - } - } - - smsg->port_msg = msg.port_msg; - smsg->buf = b; - smsg->size = n; - smsg->fd[0] = msg.fd[0]; - smsg->fd[1] = msg.fd[1]; - - continue; - } - - port->from_socket--; - } - } - - process: - - if (n > 0) { - msg.buf = b; - msg.size = n; - - nxt_port_read_msg_process(task, port, &msg); - - /* - * To disable instant completion or buffer re-usage, - * handler should reset 'msg.buf'. - */ - if (msg.buf == b) { - nxt_port_buf_free(port, b); - } - - continue; - } - - if (n == NXT_AGAIN) { - nxt_port_buf_free(port, b); - - nxt_fd_event_enable_read(task->thread->engine, &port->socket); - - continue; - } - - /* n == 0 || n == NXT_ERROR */ - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - nxt_port_error_handler, task, &port->socket, NULL); - return; - } -} - - -typedef struct { - uint32_t stream; - uint32_t pid; -} nxt_port_frag_key_t; - - -static nxt_int_t -nxt_port_lvlhsh_frag_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_port_recv_msg_t *fmsg; - nxt_port_frag_key_t *frag_key; - - fmsg = data; - frag_key = (nxt_port_frag_key_t *) lhq->key.start; - - if (lhq->key.length == sizeof(nxt_port_frag_key_t) - && frag_key->stream == fmsg->port_msg.stream - && frag_key->pid == (uint32_t) fmsg->port_msg.pid) - { - return NXT_OK; - } - - return NXT_DECLINED; -} - - -static void * -nxt_port_lvlhsh_frag_alloc(void *ctx, size_t size) -{ - return nxt_mp_align(ctx, size, size); -} - - -static void -nxt_port_lvlhsh_frag_free(void *ctx, void *p) -{ - nxt_mp_free(ctx, p); -} - - -static const nxt_lvlhsh_proto_t lvlhsh_frag_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_port_lvlhsh_frag_test, - nxt_port_lvlhsh_frag_alloc, - nxt_port_lvlhsh_frag_free, -}; - - -static nxt_port_recv_msg_t * -nxt_port_frag_start(nxt_task_t *task, nxt_port_t *port, - nxt_port_recv_msg_t *msg) -{ - nxt_int_t res; - nxt_lvlhsh_query_t lhq; - nxt_port_recv_msg_t *fmsg; - nxt_port_frag_key_t frag_key; - - nxt_debug(task, "start frag stream #%uD", msg->port_msg.stream); - - fmsg = nxt_mp_alloc(port->mem_pool, sizeof(nxt_port_recv_msg_t)); - - if (nxt_slow_path(fmsg == NULL)) { - return NULL; - } - - *fmsg = *msg; - - frag_key.stream = fmsg->port_msg.stream; - frag_key.pid = fmsg->port_msg.pid; - - lhq.key_hash = nxt_murmur_hash2(&frag_key, sizeof(nxt_port_frag_key_t)); - lhq.key.length = sizeof(nxt_port_frag_key_t); - lhq.key.start = (u_char *) &frag_key; - lhq.proto = &lvlhsh_frag_proto; - lhq.replace = 0; - lhq.value = fmsg; - lhq.pool = port->mem_pool; - - res = nxt_lvlhsh_insert(&port->frags, &lhq); - - switch (res) { - - case NXT_OK: - return fmsg; - - case NXT_DECLINED: - nxt_log(task, NXT_LOG_WARN, "duplicate frag stream #%uD", - fmsg->port_msg.stream); - nxt_mp_free(port->mem_pool, fmsg); - - return NULL; - - default: - nxt_log(task, NXT_LOG_WARN, "failed to add frag stream #%uD", - fmsg->port_msg.stream); - - nxt_mp_free(port->mem_pool, fmsg); - - return NULL; - - } -} - - -static nxt_port_recv_msg_t * -nxt_port_frag_find(nxt_task_t *task, nxt_port_t *port, nxt_port_recv_msg_t *msg) -{ - nxt_int_t res; - nxt_bool_t last; - nxt_lvlhsh_query_t lhq; - nxt_port_frag_key_t frag_key; - - last = msg->port_msg.mf == 0; - - nxt_debug(task, "%s frag stream #%uD", last ? "last" : "next", - msg->port_msg.stream); - - frag_key.stream = msg->port_msg.stream; - frag_key.pid = msg->port_msg.pid; - - lhq.key_hash = nxt_murmur_hash2(&frag_key, sizeof(nxt_port_frag_key_t)); - lhq.key.length = sizeof(nxt_port_frag_key_t); - lhq.key.start = (u_char *) &frag_key; - lhq.proto = &lvlhsh_frag_proto; - lhq.pool = port->mem_pool; - - res = last != 0 ? nxt_lvlhsh_delete(&port->frags, &lhq) : - nxt_lvlhsh_find(&port->frags, &lhq); - - switch (res) { - - case NXT_OK: - return lhq.value; - - default: - nxt_log(task, NXT_LOG_INFO, "frag stream #%uD not found", - frag_key.stream); - - return NULL; - } -} - - -static void -nxt_port_read_msg_process(nxt_task_t *task, nxt_port_t *port, - nxt_port_recv_msg_t *msg) -{ - nxt_buf_t *b, *orig_b, *next; - nxt_port_recv_msg_t *fmsg; - - if (nxt_slow_path(msg->size < sizeof(nxt_port_msg_t))) { - nxt_alert(task, "port %d: too small message:%uz", - port->socket.fd, msg->size); - - nxt_port_close_fds(msg->fd); - - return; - } - - /* adjust size to actual buffer used size */ - msg->size -= sizeof(nxt_port_msg_t); - - b = orig_b = msg->buf; - b->mem.free += msg->size; - - msg->cancelled = 0; - - if (nxt_slow_path(msg->port_msg.nf != 0)) { - - fmsg = nxt_port_frag_find(task, port, msg); - - if (nxt_slow_path(fmsg == NULL)) { - goto fmsg_failed; - } - - if (nxt_fast_path(fmsg->cancelled == 0)) { - - if (msg->port_msg.mmap) { - nxt_port_mmap_read(task, msg); - } - - nxt_buf_chain_add(&fmsg->buf, msg->buf); - - fmsg->size += msg->size; - msg->buf = NULL; - b = NULL; - - if (nxt_fast_path(msg->port_msg.mf == 0)) { - - b = fmsg->buf; - - port->handler(task, fmsg); - - msg->buf = fmsg->buf; - msg->fd[0] = fmsg->fd[0]; - msg->fd[1] = fmsg->fd[1]; - - /* - * To disable instant completion or buffer re-usage, - * handler should reset 'msg.buf'. - */ - if (!msg->port_msg.mmap && msg->buf == b) { - nxt_port_buf_free(port, b); - } - } - } - - if (nxt_fast_path(msg->port_msg.mf == 0)) { - nxt_mp_free(port->mem_pool, fmsg); - } - } else { - if (nxt_slow_path(msg->port_msg.mf != 0)) { - - if (msg->port_msg.mmap && msg->cancelled == 0) { - nxt_port_mmap_read(task, msg); - b = msg->buf; - } - - fmsg = nxt_port_frag_start(task, port, msg); - - if (nxt_slow_path(fmsg == NULL)) { - goto fmsg_failed; - } - - fmsg->port_msg.nf = 0; - fmsg->port_msg.mf = 0; - - if (nxt_fast_path(msg->cancelled == 0)) { - msg->buf = NULL; - msg->fd[0] = -1; - msg->fd[1] = -1; - b = NULL; - - } else { - nxt_port_close_fds(msg->fd); - } - } else { - if (nxt_fast_path(msg->cancelled == 0)) { - - if (msg->port_msg.mmap) { - nxt_port_mmap_read(task, msg); - b = msg->buf; - } - - port->handler(task, msg); - } - } - } - -fmsg_failed: - - if (msg->port_msg.mmap && orig_b != b) { - - /* - * To disable instant buffer completion, - * handler should reset 'msg->buf'. - */ - if (msg->buf == b) { - /* complete mmap buffers */ - while (b != NULL) { - nxt_debug(task, "complete buffer %p", b); - - nxt_work_queue_add(port->socket.read_work_queue, - b->completion_handler, task, b, b->parent); - - next = b->next; - b->next = NULL; - b = next; - } - } - - /* restore original buf */ - msg->buf = orig_b; - } -} - - -static nxt_buf_t * -nxt_port_buf_alloc(nxt_port_t *port) -{ - nxt_buf_t *b; - - if (port->free_bufs != NULL) { - b = port->free_bufs; - port->free_bufs = b->next; - - b->mem.pos = b->mem.start; - b->mem.free = b->mem.start; - b->next = NULL; - } else { - b = nxt_buf_mem_alloc(port->mem_pool, port->max_size, 0); - if (nxt_slow_path(b == NULL)) { - return NULL; - } - } - - return b; -} - - -static void -nxt_port_buf_free(nxt_port_t *port, nxt_buf_t *b) -{ - nxt_buf_chain_add(&b, port->free_bufs); - port->free_bufs = b; -} - - -static void -nxt_port_error_handler(nxt_task_t *task, void *obj, void *data) -{ - int use_delta; - nxt_buf_t *b, *next; - nxt_port_t *port; - nxt_work_queue_t *wq; - nxt_port_send_msg_t *msg; - - nxt_debug(task, "port error handler %p", obj); - /* TODO */ - - port = nxt_container_of(obj, nxt_port_t, socket); - - use_delta = 0; - - if (obj == data) { - use_delta--; - } - - wq = &task->thread->engine->fast_work_queue; - - nxt_thread_mutex_lock(&port->write_mutex); - - nxt_queue_each(msg, &port->messages, nxt_port_send_msg_t, link) { - - nxt_port_msg_close_fd(msg); - - for (b = msg->buf; b != NULL; b = next) { - next = b->next; - b->next = NULL; - - if (nxt_buf_is_sync(b)) { - continue; - } - - nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent); - } - - nxt_queue_remove(&msg->link); - use_delta--; - - nxt_port_release_send_msg(msg); - - } nxt_queue_loop; - - nxt_thread_mutex_unlock(&port->write_mutex); - - if (use_delta != 0) { - nxt_port_use(task, port, use_delta); - } -} diff --git a/src/nxt_process.c b/src/nxt_process.c deleted file mode 100644 index ce2de774..00000000 --- a/src/nxt_process.c +++ /dev/null @@ -1,1280 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include - -#if (NXT_HAVE_LINUX_NS) -#include -#endif - -#include - -#if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) -#include -#endif - - -#if (NXT_HAVE_LINUX_NS) && (NXT_HAVE_CLONE_NEWPID) -#define nxt_is_pid_isolated(process) \ - nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID) -#else -#define nxt_is_pid_isolated(process) \ - (0) -#endif - - -#if (NXT_HAVE_LINUX_NS) -static nxt_int_t nxt_process_pipe_timer(nxt_fd_t fd, short event); -static nxt_int_t nxt_process_check_pid_status(const nxt_fd_t *gc_pipe); -static nxt_pid_t nxt_process_recv_pid(const nxt_fd_t *pid_pipe, - const nxt_fd_t *gc_pipe); -static void nxt_process_send_pid(const nxt_fd_t *pid_pipe, nxt_pid_t pid); -static nxt_int_t nxt_process_unshare(nxt_task_t *task, nxt_process_t *process, - nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe, nxt_bool_t use_pidns); -static nxt_int_t nxt_process_init_pidns(nxt_task_t *task, - const nxt_process_t *process, nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe, - nxt_bool_t *use_pidns); -#endif - -static nxt_pid_t nxt_process_create(nxt_task_t *task, nxt_process_t *process); -static nxt_int_t nxt_process_do_start(nxt_task_t *task, nxt_process_t *process); -static nxt_int_t nxt_process_whoami(nxt_task_t *task, nxt_process_t *process); -static nxt_int_t nxt_process_setup(nxt_task_t *task, nxt_process_t *process); -static nxt_int_t nxt_process_child_fixup(nxt_task_t *task, - nxt_process_t *process); -static void nxt_process_whoami_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data); -static void nxt_process_whoami_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data); -static nxt_int_t nxt_process_send_created(nxt_task_t *task, - nxt_process_t *process); -static nxt_int_t nxt_process_send_ready(nxt_task_t *task, - nxt_process_t *process); -static void nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data); -static void nxt_process_created_error(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); - - -/* A cached process pid. */ -nxt_pid_t nxt_pid; - -/* An original parent process pid. */ -nxt_pid_t nxt_ppid; - -/* A cached process effective uid */ -nxt_uid_t nxt_euid; - -/* A cached process effective gid */ -nxt_gid_t nxt_egid; - -uint8_t nxt_proc_keep_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { - { 1, 1, 1, 1, 1, 1 }, - { 1, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 1, 0, 0 }, - { 1, 0, 1, 1, 1, 1 }, - { 1, 0, 0, 1, 0, 0 }, - { 1, 0, 0, 1, 0, 0 }, -}; - -uint8_t nxt_proc_send_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { - { 1, 1, 1, 1, 1, 1 }, - { 1, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 1, 0, 0 }, - { 1, 0, 1, 1, 1, 1 }, - { 1, 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0, 0 }, -}; - -uint8_t nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 0, 0 }, - { 0, 0, 1, 0, 1, 1 }, - { 0, 0, 0, 1, 0, 0 }, - { 1, 0, 0, 1, 0, 0 }, -}; - - -static const nxt_port_handlers_t nxt_process_whoami_port_handlers = { - .quit = nxt_signal_quit_handler, - .rpc_ready = nxt_port_rpc_handler, - .rpc_error = nxt_port_rpc_handler, -}; - - -nxt_process_t * -nxt_process_new(nxt_runtime_t *rt) -{ - nxt_process_t *process; - - process = nxt_mp_zalloc(rt->mem_pool, sizeof(nxt_process_t) - + sizeof(nxt_process_init_t)); - - if (nxt_slow_path(process == NULL)) { - return NULL; - } - - nxt_queue_init(&process->ports); - - nxt_thread_mutex_create(&process->incoming.mutex); - - process->use_count = 1; - - nxt_queue_init(&process->children); - - return process; -} - - -void -nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i) -{ - process->use_count += i; - - if (process->use_count == 0) { - nxt_runtime_process_release(task->thread->runtime, process); - } -} - - -nxt_int_t -nxt_process_init_start(nxt_task_t *task, nxt_process_init_t init) -{ - nxt_int_t ret; - nxt_runtime_t *rt; - nxt_process_t *process; - nxt_process_init_t *pinit; - - rt = task->thread->runtime; - - process = nxt_process_new(rt); - if (nxt_slow_path(process == NULL)) { - return NXT_ERROR; - } - - process->parent_port = rt->port_by_type[rt->type]; - - process->name = init.name; - process->user_cred = &rt->user_cred; - - pinit = nxt_process_init(process); - *pinit = init; - - ret = nxt_process_start(task, process); - if (nxt_slow_path(ret == NXT_ERROR)) { - nxt_process_use(task, process, -1); - } - - return ret; -} - - -nxt_int_t -nxt_process_start(nxt_task_t *task, nxt_process_t *process) -{ - nxt_mp_t *tmp_mp; - nxt_int_t ret; - nxt_pid_t pid; - nxt_port_t *port; - nxt_process_init_t *init; - - init = nxt_process_init(process); - - port = nxt_port_new(task, 0, 0, init->type); - if (nxt_slow_path(port == NULL)) { - return NXT_ERROR; - } - - nxt_process_port_add(task, process, port); - - ret = nxt_port_socket_init(task, port, 0); - if (nxt_slow_path(ret != NXT_OK)) { - goto free_port; - } - - tmp_mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(tmp_mp == NULL)) { - ret = NXT_ERROR; - - goto close_port; - } - - if (init->prefork) { - ret = init->prefork(task, process, tmp_mp); - if (nxt_slow_path(ret != NXT_OK)) { - goto free_mempool; - } - } - - pid = nxt_process_create(task, process); - - switch (pid) { - - case -1: - ret = NXT_ERROR; - break; - - case 0: - /* The child process: return to the event engine work queue loop. */ - - nxt_process_use(task, process, -1); - - ret = NXT_AGAIN; - break; - - default: - /* The parent process created a new process. */ - - nxt_process_use(task, process, -1); - - nxt_port_read_close(port); - nxt_port_write_enable(task, port); - - ret = NXT_OK; - break; - } - -free_mempool: - - nxt_mp_destroy(tmp_mp); - -close_port: - - if (nxt_slow_path(ret == NXT_ERROR)) { - nxt_port_close(task, port); - } - -free_port: - - nxt_port_use(task, port, -1); - - return ret; -} - - -static nxt_int_t -nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process) -{ - nxt_process_t *p; - nxt_runtime_t *rt; - nxt_process_init_t *init; - nxt_process_type_t ptype; - - init = nxt_process_init(process); - - nxt_ppid = nxt_pid; - - nxt_pid = getpid(); - - process->pid = nxt_pid; - process->isolated_pid = nxt_pid; - - /* Clean inherited cached thread tid. */ - task->thread->tid = 0; - - ptype = init->type; - - nxt_port_reset_next_id(); - - nxt_event_engine_thread_adopt(task->thread->engine); - - rt = task->thread->runtime; - - /* Remove not ready processes. */ - nxt_runtime_process_each(rt, p) { - - if (nxt_proc_keep_matrix[ptype][nxt_process_type(p)] == 0 - && p->pid != nxt_ppid) /* Always keep parent's port. */ - { - nxt_debug(task, "remove not required process %PI", p->pid); - - nxt_process_close_ports(task, p); - - continue; - } - - if (p->state != NXT_PROCESS_STATE_READY) { - nxt_debug(task, "remove not ready process %PI", p->pid); - - nxt_process_close_ports(task, p); - - continue; - } - - nxt_port_mmaps_destroy(&p->incoming, 0); - - } nxt_runtime_process_loop; - - if (init->siblings != NULL) { - nxt_queue_each(p, init->siblings, nxt_process_t, link) { - - nxt_debug(task, "remove sibling process %PI", p->pid); - - nxt_process_close_ports(task, p); - - } nxt_queue_loop; - } - - return NXT_OK; -} - - -#if (NXT_HAVE_LINUX_NS) - -static nxt_int_t -nxt_process_pipe_timer(nxt_fd_t fd, short event) -{ - int ret; - sigset_t mask; - struct pollfd pfd; - - static const struct timespec ts = { .tv_sec = 5 }; - - /* - * Temporarily block the signals we are handling, (except - * for SIGINT & SIGTERM) so that ppoll(2) doesn't get - * interrupted. After ppoll(2) returns, our old sigmask - * will be back in effect and any pending signals will be - * delivered. - * - * This is because while the kernel ppoll syscall updates - * the struct timespec with the time remaining if it got - * interrupted with EINTR, the glibc wrapper hides this - * from us so we have no way of knowing how long to retry - * the ppoll(2) for and if we just retry with the same - * timeout we could find ourselves in an infinite loop. - */ - pthread_sigmask(SIG_SETMASK, NULL, &mask); - sigdelset(&mask, SIGINT); - sigdelset(&mask, SIGTERM); - - pfd.fd = fd; - pfd.events = event; - - ret = ppoll(&pfd, 1, &ts, &mask); - if (ret <= 0 || (ret == 1 && pfd.revents & POLLERR)) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_process_check_pid_status(const nxt_fd_t *gc_pipe) -{ - int8_t status; - ssize_t ret; - - close(gc_pipe[1]); - - ret = nxt_process_pipe_timer(gc_pipe[0], POLLIN); - if (ret == NXT_OK) { - ret = read(gc_pipe[0], &status, sizeof(int8_t)); - } - - if (ret <= 0) { - status = -1; - } - - close(gc_pipe[0]); - - return status; -} - - -static nxt_pid_t -nxt_process_recv_pid(const nxt_fd_t *pid_pipe, const nxt_fd_t *gc_pipe) -{ - int8_t status; - ssize_t ret; - nxt_pid_t pid; - - close(pid_pipe[1]); - close(gc_pipe[0]); - - status = 0; - - ret = nxt_process_pipe_timer(pid_pipe[0], POLLIN); - if (ret == NXT_OK) { - ret = read(pid_pipe[0], &pid, sizeof(nxt_pid_t)); - } - - if (ret <= 0) { - status = -1; - pid = -1; - } - - write(gc_pipe[1], &status, sizeof(int8_t)); - - close(pid_pipe[0]); - close(gc_pipe[1]); - - return pid; -} - - -static void -nxt_process_send_pid(const nxt_fd_t *pid_pipe, nxt_pid_t pid) -{ - nxt_int_t ret; - - close(pid_pipe[0]); - - ret = nxt_process_pipe_timer(pid_pipe[1], POLLOUT); - if (ret == NXT_OK) { - write(pid_pipe[1], &pid, sizeof(nxt_pid_t)); - } - - close(pid_pipe[1]); -} - - -static nxt_int_t -nxt_process_unshare(nxt_task_t *task, nxt_process_t *process, - nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe, - nxt_bool_t use_pidns) -{ - int ret; - nxt_pid_t pid; - - if (process->isolation.clone.flags == 0) { - return NXT_OK; - } - - ret = unshare(process->isolation.clone.flags); - if (nxt_slow_path(ret == -1)) { - nxt_alert(task, "unshare() failed for %s %E", process->name, - nxt_errno); - - if (use_pidns) { - nxt_pipe_close(task, gc_pipe); - nxt_pipe_close(task, pid_pipe); - } - - return NXT_ERROR; - } - - if (!use_pidns) { - return NXT_OK; - } - - /* - * PID namespace requested. Employ a double fork(2) technique - * so that the prototype process will be placed into the new - * namespace and end up with PID 1 (as before with clone). - */ - pid = fork(); - if (nxt_slow_path(pid < 0)) { - nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno); - nxt_pipe_close(task, gc_pipe); - nxt_pipe_close(task, pid_pipe); - - return NXT_ERROR; - - } else if (pid > 0) { - nxt_pipe_close(task, gc_pipe); - nxt_process_send_pid(pid_pipe, pid); - - _exit(EXIT_SUCCESS); - } - - nxt_pipe_close(task, pid_pipe); - ret = nxt_process_check_pid_status(gc_pipe); - if (ret == -1) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_process_init_pidns(nxt_task_t *task, const nxt_process_t *process, - nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe, - nxt_bool_t *use_pidns) -{ - int ret; - - *use_pidns = 0; - -#if (NXT_HAVE_CLONE_NEWPID) - *use_pidns = nxt_is_pid_isolated(process); -#endif - - if (!*use_pidns) { - return NXT_OK; - } - - ret = nxt_pipe_create(task, pid_pipe, 0, 0); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NXT_ERROR; - } - - ret = nxt_pipe_create(task, gc_pipe, 0, 0); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NXT_ERROR; - } - -#if (NXT_HAVE_PR_SET_CHILD_SUBREAPER) - ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); - if (nxt_slow_path(ret == -1)) { - nxt_alert(task, "prctl(PR_SET_CHILD_SUBREAPER) failed for %s %E", - process->name, nxt_errno); - } -#endif - - return NXT_OK; -} - -#endif /* NXT_HAVE_LINUX_NS */ - - -static nxt_pid_t -nxt_process_create(nxt_task_t *task, nxt_process_t *process) -{ - nxt_int_t ret; - nxt_pid_t pid; - nxt_runtime_t *rt; - -#if (NXT_HAVE_LINUX_NS) - nxt_fd_t pid_pipe[2], gc_pipe[2]; - nxt_bool_t use_pidns; - - ret = nxt_process_init_pidns(task, process, pid_pipe, gc_pipe, &use_pidns); - if (ret == NXT_ERROR) { - return -1; - } -#endif - - pid = fork(); - if (nxt_slow_path(pid < 0)) { - nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno); - return pid; - } - - if (pid == 0) { - /* Child. */ - -#if (NXT_HAVE_LINUX_NS) - ret = nxt_process_unshare(task, process, pid_pipe, gc_pipe, use_pidns); - if (ret == NXT_ERROR) { - _exit(EXIT_FAILURE); - } -#endif - - ret = nxt_process_child_fixup(task, process); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_process_quit(task, 1); - return -1; - } - - ret = nxt_process_setup(task, process); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_process_quit(task, 1); - } - - /* - * Explicitly return 0 to notice the caller function this is the child. - * The caller must return to the event engine work queue loop. - */ - return 0; - } - - /* Parent. */ - - nxt_debug(task, "fork(%s): %PI", process->name, pid); - -#if (NXT_HAVE_LINUX_NS) - if (use_pidns) { - pid = nxt_process_recv_pid(pid_pipe, gc_pipe); - if (pid == -1) { - return pid; - } - } -#endif - - process->pid = pid; - process->isolated_pid = pid; - - rt = task->thread->runtime; - - if (rt->is_pid_isolated) { - /* - * Do not register process in runtime with isolated pid. - * Only global pid can be the key to avoid clash. - */ - nxt_assert(!nxt_queue_is_empty(&process->ports)); - - nxt_port_use(task, nxt_process_port_first(process), 1); - - } else { - nxt_runtime_process_add(task, process); - } - -#if (NXT_HAVE_CGROUP) - ret = nxt_cgroup_proc_add(task, process); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "cgroup: failed to add process %s to %s %E", - process->name, process->isolation.cgroup.path, nxt_errno); - nxt_cgroup_cleanup(task, process); - kill(pid, SIGTERM); - return -1; - } -#endif - - return pid; -} - - -static nxt_int_t -nxt_process_setup(nxt_task_t *task, nxt_process_t *process) -{ - nxt_int_t ret; - nxt_thread_t *thread; - nxt_runtime_t *rt; - nxt_process_init_t *init; - nxt_event_engine_t *engine; - const nxt_event_interface_t *interface; - - init = nxt_process_init(process); - - nxt_debug(task, "%s setup", process->name); - - nxt_process_title(task, "unit: %s", process->name); - - thread = task->thread; - rt = thread->runtime; - - if (process->parent_port == rt->port_by_type[NXT_PROCESS_PROTOTYPE]) { - nxt_app_set_logs(); - } - - nxt_random_init(&thread->random); - - rt->type = init->type; - - engine = thread->engine; - - /* Update inherited main process event engine and signals processing. */ - engine->signals->sigev = init->signals; - - interface = nxt_service_get(rt->services, "engine", rt->engine); - if (nxt_slow_path(interface == NULL)) { - return NXT_ERROR; - } - - if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) { - return NXT_ERROR; - } - - ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads, - 60000 * 1000000LL); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - nxt_port_read_close(process->parent_port); - nxt_port_write_enable(task, process->parent_port); - - /* - * If the parent process is already isolated, rt->pid_isolation is already - * set to 1 at this point. - */ - if (nxt_is_pid_isolated(process)) { - rt->is_pid_isolated = 1; - } - - if (rt->is_pid_isolated - || process->parent_port != rt->port_by_type[NXT_PROCESS_MAIN]) - { - ret = nxt_process_whoami(task, process); - - } else { - ret = nxt_process_do_start(task, process); - } - - return ret; -} - - -static nxt_int_t -nxt_process_do_start(nxt_task_t *task, nxt_process_t *process) -{ - nxt_int_t ret; - nxt_port_t *port; - nxt_process_init_t *init; - - nxt_runtime_process_add(task, process); - - init = nxt_process_init(process); - port = nxt_process_port_first(process); - - nxt_port_enable(task, port, init->port_handlers); - - ret = init->setup(task, process); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - switch (process->state) { - - case NXT_PROCESS_STATE_CREATED: - ret = nxt_process_send_created(task, process); - break; - - case NXT_PROCESS_STATE_READY: - ret = nxt_process_send_ready(task, process); - - if (nxt_slow_path(ret != NXT_OK)) { - break; - } - - ret = init->start(task, &process->data); - - nxt_port_write_close(port); - - break; - - default: - nxt_assert(0); - } - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "%s failed to start", process->name); - } - - return ret; -} - - -static nxt_int_t -nxt_process_whoami(nxt_task_t *task, nxt_process_t *process) -{ - uint32_t stream; - nxt_fd_t fd; - nxt_buf_t *buf; - nxt_int_t ret; - nxt_port_t *my_port, *main_port; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - my_port = nxt_process_port_first(process); - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - - nxt_assert(my_port != NULL && main_port != NULL); - - nxt_port_enable(task, my_port, &nxt_process_whoami_port_handlers); - - buf = nxt_buf_mem_alloc(main_port->mem_pool, sizeof(nxt_pid_t), 0); - if (nxt_slow_path(buf == NULL)) { - return NXT_ERROR; - } - - buf->mem.free = nxt_cpymem(buf->mem.free, &nxt_ppid, sizeof(nxt_pid_t)); - - stream = nxt_port_rpc_register_handler(task, my_port, - nxt_process_whoami_ok, - nxt_process_whoami_error, - main_port->pid, process); - if (nxt_slow_path(stream == 0)) { - nxt_mp_free(main_port->mem_pool, buf); - - return NXT_ERROR; - } - - fd = (process->parent_port != main_port) ? my_port->pair[1] : -1; - - ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_WHOAMI, - fd, stream, my_port->id, buf); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "%s failed to send WHOAMI message", process->name); - nxt_port_rpc_cancel(task, my_port, stream); - nxt_mp_free(main_port->mem_pool, buf); - - return NXT_ERROR; - } - - return NXT_OK; -} - - -static void -nxt_process_whoami_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) -{ - nxt_pid_t pid, isolated_pid; - nxt_buf_t *buf; - nxt_port_t *port; - nxt_process_t *process; - nxt_runtime_t *rt; - - process = data; - - buf = msg->buf; - - nxt_assert(nxt_buf_used_size(buf) == sizeof(nxt_pid_t)); - - nxt_memcpy(&pid, buf->mem.pos, sizeof(nxt_pid_t)); - - isolated_pid = nxt_pid; - - if (isolated_pid != pid) { - nxt_pid = pid; - process->pid = pid; - - nxt_process_port_each(process, port) { - port->pid = pid; - } nxt_process_port_loop; - } - - rt = task->thread->runtime; - - if (process->parent_port != rt->port_by_type[NXT_PROCESS_MAIN]) { - port = process->parent_port; - - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_PROCESS_CREATED, - -1, 0, 0, NULL); - - nxt_log(task, NXT_LOG_INFO, "%s started", process->name); - } - - if (nxt_slow_path(nxt_process_do_start(task, process) != NXT_OK)) { - nxt_process_quit(task, 1); - } -} - - -static void -nxt_process_whoami_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) -{ - nxt_alert(task, "WHOAMI error"); - - nxt_process_quit(task, 1); -} - - -static nxt_int_t -nxt_process_send_created(nxt_task_t *task, nxt_process_t *process) -{ - uint32_t stream; - nxt_int_t ret; - nxt_port_t *my_port, *main_port; - nxt_runtime_t *rt; - - nxt_assert(process->state == NXT_PROCESS_STATE_CREATED); - - rt = task->thread->runtime; - - my_port = nxt_process_port_first(process); - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - - nxt_assert(my_port != NULL && main_port != NULL); - - stream = nxt_port_rpc_register_handler(task, my_port, - nxt_process_created_ok, - nxt_process_created_error, - main_port->pid, process); - - if (nxt_slow_path(stream == 0)) { - return NXT_ERROR; - } - - ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_CREATED, - -1, stream, my_port->id, NULL); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "%s failed to send CREATED message", process->name); - nxt_port_rpc_cancel(task, my_port, stream); - return NXT_ERROR; - } - - nxt_debug(task, "%s created", process->name); - - return NXT_OK; -} - - -static void -nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) -{ - nxt_int_t ret; - nxt_process_t *process; - nxt_process_init_t *init; - - process = data; - - process->state = NXT_PROCESS_STATE_READY; - - init = nxt_process_init(process); - - ret = nxt_process_apply_creds(task, process); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - nxt_log(task, NXT_LOG_INFO, "%s started", process->name); - - ret = nxt_process_send_ready(task, process); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - ret = init->start(task, &process->data); - - if (nxt_process_type(process) != NXT_PROCESS_PROTOTYPE) { - nxt_port_write_close(nxt_process_port_first(process)); - } - - if (nxt_fast_path(ret == NXT_OK)) { - return; - } - -fail: - nxt_process_quit(task, 1); -} - - -static void -nxt_process_created_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_process_t *process; - nxt_process_init_t *init; - - process = data; - init = nxt_process_init(process); - - nxt_alert(task, "%s failed to start", init->name); - - nxt_process_quit(task, 1); -} - - -nxt_int_t -nxt_process_core_setup(nxt_task_t *task, nxt_process_t *process) -{ - nxt_int_t ret; - - ret = nxt_process_apply_creds(task, process); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - process->state = NXT_PROCESS_STATE_READY; - - return NXT_OK; -} - - -nxt_int_t -nxt_process_creds_set(nxt_task_t *task, nxt_process_t *process, nxt_str_t *user, - nxt_str_t *group) -{ - char *str; - - process->user_cred = nxt_mp_zalloc(process->mem_pool, - sizeof(nxt_credential_t)); - - if (nxt_slow_path(process->user_cred == NULL)) { - return NXT_ERROR; - } - - str = nxt_mp_zalloc(process->mem_pool, user->length + 1); - if (nxt_slow_path(str == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy(str, user->start, user->length); - str[user->length] = '\0'; - - process->user_cred->user = str; - - if (group->start != NULL) { - str = nxt_mp_zalloc(process->mem_pool, group->length + 1); - if (nxt_slow_path(str == NULL)) { - return NXT_ERROR; - } - - nxt_memcpy(str, group->start, group->length); - str[group->length] = '\0'; - - } else { - str = NULL; - } - - return nxt_credential_get(task, process->mem_pool, process->user_cred, str); -} - - -nxt_int_t -nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process) -{ - nxt_int_t ret, cap_setid; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - cap_setid = rt->capabilities.setid; - -#if (NXT_HAVE_LINUX_NS && NXT_HAVE_CLONE_NEWUSER) - if (!cap_setid - && nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) - { - cap_setid = 1; - } -#endif - - if (cap_setid) { - ret = nxt_credential_setgids(task, process->user_cred); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - ret = nxt_credential_setuid(task, process->user_cred); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - -#if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) - if (nxt_slow_path(process->isolation.new_privs == 0 - && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0)) - { - nxt_alert(task, "failed to set no_new_privs %E", nxt_errno); - return NXT_ERROR; - } -#endif - - return NXT_OK; -} - - -static nxt_int_t -nxt_process_send_ready(nxt_task_t *task, nxt_process_t *process) -{ - nxt_int_t ret; - - ret = nxt_port_socket_write(task, process->parent_port, - NXT_PORT_MSG_PROCESS_READY, - -1, process->stream, 0, NULL); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "%s failed to send READY message", process->name); - return NXT_ERROR; - } - - nxt_debug(task, "%s sent ready", process->name); - - return NXT_OK; -} - - -/* - * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve(). - * Linux glibc 2.4 posix_spawn() without file actions and spawn - * attributes uses vfork()/execve(). - * - * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve(). - * - * Solaris 10: - * In the Solaris 10 OS, posix_spawn() is currently implemented using - * private-to-libc vfork(), execve(), and exit() functions. They are - * identical to regular vfork(), execve(), and exit() in functionality, - * but they are not exported from libc and therefore don't cause the - * deadlock-in-the-dynamic-linker problem that any multithreaded code - * outside of libc that calls vfork() can cause. - * - * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented - * as syscall. - */ - -nxt_pid_t -nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp) -{ - nxt_pid_t pid; - - nxt_debug(task, "posix_spawn(\"%s\")", name); - - if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) { - nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno); - return -1; - } - - return pid; -} - - -nxt_int_t -nxt_process_daemon(nxt_task_t *task) -{ - nxt_fd_t fd; - nxt_pid_t pid; - const char *msg; - - fd = -1; - - /* - * fork() followed by a parent process's exit() detaches a child process - * from an init script or terminal shell process which has started the - * parent process and allows the child process to run in background. - */ - - pid = fork(); - - switch (pid) { - - case -1: - msg = "fork() failed %E"; - goto fail; - - case 0: - /* A child. */ - break; - - default: - /* A parent. */ - nxt_debug(task, "fork(): %PI", pid); - exit(0); - nxt_unreachable(); - } - - nxt_pid = getpid(); - - /* Clean inherited cached thread tid. */ - task->thread->tid = 0; - - nxt_debug(task, "daemon"); - - /* Detach from controlling terminal. */ - - if (setsid() == -1) { - nxt_alert(task, "setsid() failed %E", nxt_errno); - return NXT_ERROR; - } - - /* - * Set a sefe umask to give at most 755/644 permissions on - * directories/files. - */ - umask(0022); - - /* Redirect STDIN and STDOUT to the "/dev/null". */ - - fd = open("/dev/null", O_RDWR); - if (fd == -1) { - msg = "open(\"/dev/null\") failed %E"; - goto fail; - } - - if (dup2(fd, STDIN_FILENO) == -1) { - msg = "dup2(\"/dev/null\", STDIN) failed %E"; - goto fail; - } - - if (dup2(fd, STDOUT_FILENO) == -1) { - msg = "dup2(\"/dev/null\", STDOUT) failed %E"; - goto fail; - } - - if (fd > STDERR_FILENO) { - nxt_fd_close(fd); - } - - return NXT_OK; - -fail: - - nxt_alert(task, msg, nxt_errno); - - if (fd != -1) { - nxt_fd_close(fd); - } - - return NXT_ERROR; -} - - -void -nxt_nanosleep(nxt_nsec_t ns) -{ - struct timespec ts; - - ts.tv_sec = ns / 1000000000; - ts.tv_nsec = ns % 1000000000; - - (void) nanosleep(&ts, NULL); -} - - -void -nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port) -{ - nxt_assert(port->process == NULL); - - port->process = process; - nxt_queue_insert_tail(&process->ports, &port->link); - - nxt_process_use(task, process, 1); -} - - -nxt_process_type_t -nxt_process_type(nxt_process_t *process) -{ - return nxt_queue_is_empty(&process->ports) ? 0 : - (nxt_process_port_first(process))->type; -} - - -void -nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process) -{ - nxt_port_t *port; - - nxt_process_use(task, process, 1); - - nxt_process_port_each(process, port) { - - nxt_port_close(task, port); - - nxt_runtime_port_remove(task, port); - - } nxt_process_port_loop; - - nxt_process_use(task, process, -1); -} - - -void -nxt_process_quit(nxt_task_t *task, nxt_uint_t exit_status) -{ - nxt_queue_t *listen; - nxt_queue_link_t *link, *next; - nxt_listen_event_t *lev; - - nxt_debug(task, "close listen connections"); - - listen = &task->thread->engine->listen_connections; - - for (link = nxt_queue_first(listen); - link != nxt_queue_tail(listen); - link = next) - { - next = nxt_queue_next(link); - lev = nxt_queue_link_data(link, nxt_listen_event_t, link); - nxt_queue_remove(link); - - nxt_fd_event_close(task->thread->engine, &lev->socket); - } - - nxt_runtime_quit(task, exit_status); -} diff --git a/src/nxt_process.h b/src/nxt_process.h deleted file mode 100644 index 42fd1bed..00000000 --- a/src/nxt_process.h +++ /dev/null @@ -1,241 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PROCESS_H_INCLUDED_ -#define _NXT_PROCESS_H_INCLUDED_ - -#if (NXT_HAVE_LINUX_NS) -#include -#include -#endif - - -typedef pid_t nxt_pid_t; - - -typedef struct nxt_common_app_conf_s nxt_common_app_conf_t; - - -typedef struct { - nxt_runtime_t *rt; -} nxt_discovery_init_t; - - -typedef struct { - nxt_str_t conf; -#if (NXT_TLS) - nxt_array_t *certs; -#endif -#if (NXT_HAVE_NJS) - nxt_array_t *scripts; -#endif -} nxt_controller_init_t; - - -typedef union { - void *discovery; - nxt_controller_init_t controller; - void *router; - nxt_common_app_conf_t *app; -} nxt_process_data_t; - - -typedef enum { - NXT_PROCESS_STATE_CREATING = 0, - NXT_PROCESS_STATE_CREATED, - NXT_PROCESS_STATE_READY, -} nxt_process_state_t; - - -typedef struct nxt_port_mmap_s nxt_port_mmap_t; -typedef struct nxt_process_s nxt_process_t; -typedef struct nxt_cgroup_s nxt_cgroup_t; -typedef void (*nxt_isolation_cleanup_t)(nxt_task_t *task, - nxt_process_t *process); -typedef void (*nxt_cgroup_cleanup_t)(nxt_task_t *task, - const nxt_process_t *process); - - -typedef struct { - nxt_thread_mutex_t mutex; - uint32_t size; - uint32_t cap; - nxt_port_mmap_t *elts; -} nxt_port_mmaps_t; - - -typedef struct { - uint8_t language_deps; /* 1-bit */ - uint8_t tmpfs; /* 1-bit */ - uint8_t procfs; /* 1-bit */ -} nxt_process_automount_t; - - -struct nxt_cgroup_s { - char *path; -}; - - -typedef struct { - u_char *rootfs; - nxt_process_automount_t automount; - nxt_array_t *mounts; /* of nxt_mount_t */ - - nxt_isolation_cleanup_t cleanup; - - nxt_cgroup_cleanup_t cgroup_cleanup; -#if (NXT_HAVE_CGROUP) - nxt_cgroup_t cgroup; -#endif - -#if (NXT_HAVE_LINUX_NS) - nxt_clone_t clone; -#endif - -#if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) - uint8_t new_privs; /* 1 bit */ -#endif -} nxt_process_isolation_t; - - -struct nxt_process_s { - nxt_pid_t pid; - nxt_queue_t ports; /* of nxt_port_t.link */ - nxt_process_state_t state; - nxt_bool_t registered; - nxt_int_t use_count; - - nxt_port_mmaps_t incoming; - - - nxt_pid_t isolated_pid; - const char *name; - nxt_port_t *parent_port; - - uint32_t stream; - - nxt_mp_t *mem_pool; - nxt_credential_t *user_cred; - - nxt_queue_t children; /* of nxt_process_t.link */ - nxt_queue_link_t link; /* for nxt_process_t.children */ - - nxt_process_data_t data; - - nxt_process_isolation_t isolation; -}; - - -typedef nxt_int_t (*nxt_process_prefork_t)(nxt_task_t *task, - nxt_process_t *process, nxt_mp_t *mp); -typedef nxt_int_t (*nxt_process_postfork_t)(nxt_task_t *task, - nxt_process_t *process, nxt_mp_t *mp); -typedef nxt_int_t (*nxt_process_setup_t)(nxt_task_t *task, - nxt_process_t *process); -typedef nxt_int_t (*nxt_process_start_t)(nxt_task_t *task, - nxt_process_data_t *data); - - -typedef struct { - const char *name; - nxt_process_type_t type; - - nxt_process_prefork_t prefork; - - nxt_process_setup_t setup; - nxt_process_start_t start; - - uint8_t restart; /* 1-bit */ - - const nxt_port_handlers_t *port_handlers; - const nxt_sig_event_t *signals; - - nxt_queue_t *siblings; -} nxt_process_init_t; - - -extern uint8_t nxt_proc_keep_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX]; -extern uint8_t nxt_proc_send_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX]; -extern uint8_t nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX]; - -NXT_EXPORT nxt_pid_t nxt_process_execute(nxt_task_t *task, char *name, - char **argv, char **envp); -NXT_EXPORT nxt_int_t nxt_process_daemon(nxt_task_t *task); -NXT_EXPORT void nxt_nanosleep(nxt_nsec_t ns); - -NXT_EXPORT void nxt_process_arguments(nxt_task_t *task, char **orig_argv, - char ***orig_envp); - -#define nxt_process_init(process) \ - (nxt_pointer_to(process, sizeof(nxt_process_t))) - -#define nxt_process_port_remove(port) \ - nxt_queue_remove(&port->link) - -#define nxt_process_port_first(process) \ - nxt_queue_link_data(nxt_queue_first(&process->ports), nxt_port_t, link) - -NXT_EXPORT void nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, - nxt_port_t *port); - -#define nxt_process_port_each(process, port) \ - nxt_queue_each(port, &process->ports, nxt_port_t, link) - -#define nxt_process_port_loop \ - nxt_queue_loop - -nxt_process_t *nxt_process_new(nxt_runtime_t *rt); -void nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i); -nxt_int_t nxt_process_init_start(nxt_task_t *task, nxt_process_init_t init); -nxt_int_t nxt_process_start(nxt_task_t *task, nxt_process_t *process); -nxt_process_type_t nxt_process_type(nxt_process_t *process); - -void nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i); - -void nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process); - -void nxt_process_quit(nxt_task_t *task, nxt_uint_t exit_status); -void nxt_signal_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); - -nxt_int_t nxt_process_core_setup(nxt_task_t *task, nxt_process_t *process); -nxt_int_t nxt_process_creds_set(nxt_task_t *task, nxt_process_t *process, - nxt_str_t *user, nxt_str_t *group); -nxt_int_t nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process); - -#if (NXT_HAVE_SETPROCTITLE) - -#define nxt_process_title(task, fmt, ...) \ - setproctitle(fmt, __VA_ARGS__) - -#elif (NXT_LINUX || NXT_SOLARIS || NXT_MACOSX) - -#define NXT_SETPROCTITLE_ARGV 1 -NXT_EXPORT void nxt_process_title(nxt_task_t *task, const char *fmt, ...); - -#endif - - -#define nxt_sched_yield() \ - sched_yield() - -/* - * Solaris declares abort() as __NORETURN, - * raise(SIGABRT) is mostly the same. - */ - -#define nxt_abort() \ - (void) raise(SIGABRT) - - -NXT_EXPORT extern nxt_pid_t nxt_pid; -NXT_EXPORT extern nxt_pid_t nxt_ppid; -NXT_EXPORT extern nxt_uid_t nxt_euid; -NXT_EXPORT extern nxt_gid_t nxt_egid; -NXT_EXPORT extern char **nxt_process_argv; -NXT_EXPORT extern char ***nxt_process_environ; - - -#endif /* _NXT_PROCESS_H_INCLUDED_ */ diff --git a/src/nxt_process_title.c b/src/nxt_process_title.c deleted file mode 100644 index 3c20ac59..00000000 --- a/src/nxt_process_title.c +++ /dev/null @@ -1,256 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* The arguments passed to main(). */ -char **nxt_process_argv; - -/* - * MacOSX environ(7): - * - * Shared libraries and bundles don't have direct access to environ, - * which is only available to the loader ld(1) when a complete program - * is being linked. - * - * So nxt_process_environ contains an address of environ to allow - * change environ[] placement. - */ -char ***nxt_process_environ; - - -#if (NXT_SETPROCTITLE_ARGV) - -/* - * A process title on Linux, Solaris, and MacOSX can be changed by - * copying a new title to a place where the program argument argv[0] - * points originally to. However, the argv[0] may be too small to hold - * the new title. Fortunately, these OSes place the program argument - * argv[] strings and the environment environ[] strings contiguously - * and their space can be used for the long new process title. - * - * Solaris "ps" command shows the new title only if it is run in - * UCB mode: either "/usr/ucb/ps -axwww" or "/usr/bin/ps axwww". - */ - - -static u_char *nxt_process_title_start; -static u_char *nxt_process_title_end; - - -void -nxt_process_arguments(nxt_task_t *task, char **orig_argv, char ***orig_envp) -{ - u_char *p, *end, *argv_end, **argv, **env; - size_t size, argv_size, environ_size, strings_size; - nxt_uint_t i; - - nxt_process_argv = orig_argv; - nxt_process_environ = orig_envp; - - if (orig_envp == NULL) { - return; - } - - /* - * Set a conservative title space for a case if program argument - * strings and environment strings are not contiguous. - */ - argv = (u_char **) orig_argv; - nxt_process_title_start = argv[0]; - nxt_process_title_end = argv[0] + nxt_strlen(argv[0]); - - end = argv[0]; - strings_size = 0; - argv_size = sizeof(void *); - - for (i = 0; argv[i] != NULL; i++) { - argv_size += sizeof(void *); - - if (argv[i] == end) { - /* Argument strings are contiguous. */ - size = nxt_strlen(argv[i]) + 1; - strings_size += size; - end = argv[i] + size; - } - } - - argv = nxt_malloc(argv_size); - if (argv == NULL) { - return; - } - - /* - * Copy the entire original argv[] array. The elements of this array - * can point to copied strings or if original argument strings are not - * contiguous, to the original argument strings. - */ - nxt_memcpy(argv, orig_argv, argv_size); - - /* - * The argv[1] must be set to NULL on Solaris otherwise the "ps" - * command outputs strings pointed by original argv[] elements. - * The original argv[] array has always at least two elements so - * it is safe to set argv[1]. - */ - orig_argv[1] = NULL; - - nxt_process_argv = (char **) argv; - - argv_end = end; - env = (u_char **) *orig_envp; - environ_size = sizeof(void *); - - for (i = 0; env[i] != NULL; i++) { - environ_size += sizeof(void *); - - if (env[i] == end) { - /* Environment strings are contiguous. */ - size = nxt_strlen(env[i]) + 1; - strings_size += size; - end = env[i] + size; - } - } - - p = nxt_malloc(strings_size); - if (p == NULL) { - return; - } - - if (argv_end == end) { - /* - * There is no reason to modify environ if arguments - * and environment are not contiguous. - */ - nxt_debug(task, "arguments and environment are not contiguous"); - goto done; - } - - end = argv[0]; - - for (i = 0; argv[i] != NULL; i++) { - - if (argv[i] != end) { - /* Argument strings are not contiguous. */ - goto done; - } - - size = nxt_strlen(argv[i]) + 1; - nxt_memcpy(p, argv[i], size); - - end = argv[i] + size; - argv[i] = p; - p += size; - } - - env = nxt_malloc(environ_size); - if (env == NULL) { - return; - } - - /* - * Copy the entire original environ[] array. The elements of - * this array can point to copied strings or if original environ - * strings are not contiguous, to the original environ strings. - */ - nxt_memcpy(env, *orig_envp, environ_size); - - /* Set the global environ variable to the new array. */ - *orig_envp = (char **) env; - - for (i = 0; env[i] != NULL; i++) { - - if (env[i] != end) { - /* Environment strings are not contiguous. */ - goto done; - } - - size = nxt_strlen(env[i]) + 1; - nxt_memcpy(p, env[i], size); - - end = env[i] + size; - env[i] = p; - p += size; - } - -done: - - /* Preserve space for the trailing zero. */ - end--; - - nxt_process_title_end = end; -} - - -void -nxt_process_title(nxt_task_t *task, const char *fmt, ...) -{ - u_char *p, *start, *end; - va_list args; - - start = nxt_process_title_start; - - if (start == NULL) { - return; - } - - end = nxt_process_title_end; - - va_start(args, fmt); - p = nxt_vsprintf(start, end, fmt, args); - va_end(args); - -#if (NXT_SOLARIS) - /* - * Solaris "ps" command shows a new process title only if it is - * longer than original command line. A simple workaround is just - * to append the original command line in parenthesis to the title. - */ - { - size_t size; - nxt_uint_t i; - - size = 0; - - for (i = 0; nxt_process_argv[i] != NULL; i++) { - size += nxt_strlen(nxt_process_argv[i]); - } - - if (size > (size_t) (p - start)) { - - p = nxt_sprintf(p, end, " ("); - - for (i = 0; nxt_process_argv[i] != NULL; i++) { - p = nxt_sprintf(p, end, "%s ", nxt_process_argv[i]); - } - - if (*(p - 1) == ' ') { - *(p - 1) = ')'; - } - } - } -#endif - - /* - * A process title must be padded with zeros on MacOSX. Otherwise - * the "ps" command may output parts of environment strings. - */ - nxt_memset(p, '\0', end - p); - - nxt_debug(task, "setproctitle: \"%s\"", start); -} - -#else /* !(NXT_SETPROCTITLE_ARGV) */ - -void -nxt_process_arguments(nxt_task_t *task, char **orig_argv, char ***orig_envp) -{ - nxt_process_argv = orig_argv; - nxt_process_environ = orig_envp; -} - -#endif diff --git a/src/nxt_process_type.h b/src/nxt_process_type.h deleted file mode 100644 index d0093431..00000000 --- a/src/nxt_process_type.h +++ /dev/null @@ -1,23 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PROCESS_TYPE_H_INCLUDED_ -#define _NXT_PROCESS_TYPE_H_INCLUDED_ - - -typedef enum { - NXT_PROCESS_MAIN = 0, - NXT_PROCESS_DISCOVERY, - NXT_PROCESS_CONTROLLER, - NXT_PROCESS_ROUTER, - NXT_PROCESS_PROTOTYPE, - NXT_PROCESS_APP, - - NXT_PROCESS_MAX, -} nxt_process_type_t; - - -#endif /* _NXT_PROCESS_TYPE_H_INCLUDED_ */ diff --git a/src/nxt_queue.c b/src/nxt_queue.c deleted file mode 100644 index c81356db..00000000 --- a/src/nxt_queue.c +++ /dev/null @@ -1,85 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - - -#include - - -/* - * Find the middle queue element if the queue has odd number of elements, - * or the first element of the queue's second part otherwise. - */ - -nxt_queue_link_t * -nxt_queue_middle(nxt_queue_t *queue) -{ - nxt_queue_link_t *middle, *next; - - middle = nxt_queue_first(queue); - - if (middle == nxt_queue_last(queue)) { - return middle; - } - - next = middle; - - for ( ;; ) { - middle = nxt_queue_next(middle); - - next = nxt_queue_next(next); - - if (next == nxt_queue_last(queue)) { - return middle; - } - - next = nxt_queue_next(next); - - if (next == nxt_queue_last(queue)) { - return middle; - } - } -} - - -/* - * nxt_queue_sort() provides a stable sort because it uses the insertion - * sort algorithm. Its worst and average computational complexity is O^2. - */ - -void -nxt_queue_sort(nxt_queue_t *queue, - nxt_int_t (*cmp)(const void *data, const nxt_queue_link_t *, - const nxt_queue_link_t *), const void *data) -{ - nxt_queue_link_t *link, *prev, *next; - - link = nxt_queue_first(queue); - - if (link == nxt_queue_last(queue)) { - return; - } - - for (link = nxt_queue_next(link); - link != nxt_queue_tail(queue); - link = next) - { - prev = nxt_queue_prev(link); - next = nxt_queue_next(link); - - nxt_queue_remove(link); - - do { - if (cmp(data, prev, link) <= 0) { - break; - } - - prev = nxt_queue_prev(prev); - - } while (prev != nxt_queue_head(queue)); - - nxt_queue_insert_after(prev, link); - } -} diff --git a/src/nxt_queue.h b/src/nxt_queue.h deleted file mode 100644 index 6b7f5d57..00000000 --- a/src/nxt_queue.h +++ /dev/null @@ -1,219 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_QUEUE_H_INCLUDED_ -#define _NXT_QUEUE_H_INCLUDED_ - - -typedef struct nxt_queue_link_s nxt_queue_link_t; - -struct nxt_queue_link_s { - nxt_queue_link_t *prev; - nxt_queue_link_t *next; -}; - - -typedef struct { - nxt_queue_link_t head; -} nxt_queue_t; - - -#define nxt_queue_init(queue) \ - do { \ - (queue)->head.prev = &(queue)->head; \ - (queue)->head.next = &(queue)->head; \ - } while (0) - - -#define nxt_queue_sentinel(link) \ - do { \ - (link)->prev = (link); \ - (link)->next = (link); \ - } while (0) - - -/* - * Short-circuit a queue link to itself to allow once remove safely it - * using nxt_queue_remove(). - */ - -#define nxt_queue_self(link) \ - nxt_queue_sentinel(link) - - -#define nxt_queue_is_empty(queue) \ - (&(queue)->head == (queue)->head.prev) - -/* - * A loop to iterate all queue links starting from head: - * - * nxt_queue_link_t link; - * } nxt_type_t *tp; - * - * - * for (lnk = nxt_queue_first(queue); - * lnk != nxt_queue_tail(queue); - * lnk = nxt_queue_next(lnk)) - * { - * tp = nxt_queue_link_data(lnk, nxt_type_t, link); - * - * or starting from tail: - * - * for (lnk = nxt_queue_last(queue); - * lnk != nxt_queue_head(queue); - * lnk = nxt_queue_prev(lnk)) - * { - * tp = nxt_queue_link_data(lnk, nxt_type_t, link); - */ - -#define nxt_queue_first(queue) \ - (queue)->head.next - - -#define nxt_queue_last(queue) \ - (queue)->head.prev - - -#define nxt_queue_head(queue) \ - (&(queue)->head) - - -#define nxt_queue_tail(queue) \ - (&(queue)->head) - - -#define nxt_queue_next(link) \ - (link)->next - - -#define nxt_queue_prev(link) \ - (link)->prev - - -#define nxt_queue_insert_head(queue, link) \ - do { \ - (link)->next = (queue)->head.next; \ - (link)->next->prev = (link); \ - (link)->prev = &(queue)->head; \ - (queue)->head.next = (link); \ - } while (0) - - -#define nxt_queue_insert_tail(queue, link) \ - do { \ - (link)->prev = (queue)->head.prev; \ - (link)->prev->next = (link); \ - (link)->next = &(queue)->head; \ - (queue)->head.prev = (link); \ - } while (0) - - -#define nxt_queue_insert_after(target, link) \ - do { \ - (link)->next = (target)->next; \ - (link)->next->prev = (link); \ - (link)->prev = (target); \ - (target)->next = (link); \ - } while (0) - - -#define nxt_queue_insert_before(target, link) \ - do { \ - (link)->next = (target); \ - (link)->prev = (target)->prev; \ - (target)->prev = (link); \ - (link)->prev->next = (link); \ - } while (0) - - -#if (NXT_DEBUG) - -#define nxt_queue_remove(link) \ - do { \ - (link)->next->prev = (link)->prev; \ - (link)->prev->next = (link)->next; \ - (link)->prev = NULL; \ - (link)->next = NULL; \ - } while (0) - -#else - -#define nxt_queue_remove(link) \ - do { \ - (link)->next->prev = (link)->prev; \ - (link)->prev->next = (link)->next; \ - } while (0) - -#endif - - -/* - * Split the queue "queue" starting at the element "link", - * the "tail" is the new tail queue. - */ - -#define nxt_queue_split(queue, link, tail) \ - do { \ - (tail)->head.prev = (queue)->head.prev; \ - (tail)->head.prev->next = &(tail)->head; \ - (tail)->head.next = (link); \ - (queue)->head.prev = (link)->prev; \ - (queue)->head.prev->next = &(queue)->head; \ - (link)->prev = &(tail)->head; \ - } while (0) - - -/* Truncate the queue "queue" starting at element "link". */ - -#define nxt_queue_truncate(queue, link) \ - do { \ - (queue)->head.prev = (link)->prev; \ - (queue)->head.prev->next = &(queue)->head; \ - } while (0) - - -/* - * Add the queue "tail" to the queue "queue". - * If the queue "tail" is intended to be reused again, - * it must be initiated with nxt_queue_init(tail). - */ - -#define nxt_queue_add(queue, tail) \ - do { \ - (queue)->head.prev->next = (tail)->head.next; \ - (tail)->head.next->prev = (queue)->head.prev; \ - (queue)->head.prev = (tail)->head.prev; \ - (queue)->head.prev->next = &(queue)->head; \ - } while (0) - - -#define nxt_queue_link_data(lnk, type, link) \ - nxt_container_of(lnk, type, link) - - -NXT_EXPORT nxt_queue_link_t *nxt_queue_middle(nxt_queue_t *queue); -NXT_EXPORT void nxt_queue_sort(nxt_queue_t *queue, - nxt_int_t (*cmp)(const void *, const nxt_queue_link_t *, - const nxt_queue_link_t *), const void *data); - - -#define nxt_queue_each(elt, queue, type, link) \ - do { \ - nxt_queue_link_t *_lnk, *_nxt; \ - \ - for (_lnk = nxt_queue_first(queue); \ - _lnk != nxt_queue_tail(queue); \ - _lnk = _nxt) { \ - \ - _nxt = nxt_queue_next(_lnk); \ - elt = nxt_queue_link_data(_lnk, type, link); \ - -#define nxt_queue_loop \ - } \ - } while(0) - - -#endif /* _NXT_QUEUE_H_INCLUDED_ */ diff --git a/src/nxt_random.c b/src/nxt_random.c deleted file mode 100644 index 1211896c..00000000 --- a/src/nxt_random.c +++ /dev/null @@ -1,216 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - - -#include - - -/* - * The pseudorandom generator based on OpenBSD arc4random. Although it is - * usually stated that arc4random uses RC4 pseudorandom generation algorithm - * they are actually different in nxt_random_add(). - */ - - -#define NXT_RANDOM_KEY_SIZE 128 - - -nxt_inline void nxt_random_start_schedule(nxt_random_t *r); -static void nxt_random_stir(nxt_random_t *r); -static void nxt_random_add(nxt_random_t *r, const u_char *key, uint32_t len); -nxt_inline uint8_t nxt_random_byte(nxt_random_t *r); - - -void -nxt_random_init(nxt_random_t *r) -{ - nxt_random_start_schedule(r); - - nxt_random_stir(r); -} - - -nxt_inline void -nxt_random_start_schedule(nxt_random_t *r) -{ - nxt_uint_t i; - - r->i = 0; - r->j = 0; - - for (i = 0; i < 256; i++) { - r->s[i] = i; - } -} - - -static void -nxt_random_stir(nxt_random_t *r) -{ - int fd; - ssize_t n; - struct timeval tv; - union { - uint32_t value[4]; - u_char bytes[NXT_RANDOM_KEY_SIZE]; - } key; - -#if (NXT_HAVE_GETRANDOM) - - n = getrandom(&key, NXT_RANDOM_KEY_SIZE, 0); - -#elif (NXT_HAVE_LINUX_SYS_GETRANDOM) - - /* Linux 3.17 SYS_getrandom. */ - - n = syscall(SYS_getrandom, &key, NXT_RANDOM_KEY_SIZE, 0); - -#elif (NXT_HAVE_GETENTROPY || NXT_HAVE_GETENTROPY_SYS_RANDOM) - - n = 0; - - if (getentropy(&key, NXT_RANDOM_KEY_SIZE) == 0) { - n = NXT_RANDOM_KEY_SIZE; - } - -#else - - n = 0; - -#endif - - if (n != NXT_RANDOM_KEY_SIZE) { - fd = open("/dev/urandom", O_RDONLY); - - if (fd >= 0) { - n = read(fd, &key, NXT_RANDOM_KEY_SIZE); - (void) close(fd); - } - } - - if (n != NXT_RANDOM_KEY_SIZE) { - (void) gettimeofday(&tv, NULL); - - /* XOR with stack garbage. */ - - key.value[0] ^= tv.tv_usec; - key.value[1] ^= tv.tv_sec; - key.value[2] ^= nxt_pid; - key.value[3] ^= (uintptr_t) nxt_thread_tid(nxt_thread()); - } - - nxt_random_add(r, key.bytes, NXT_RANDOM_KEY_SIZE); - - /* Drop the first 3072 bytes. */ - for (n = 3072; n != 0; n--) { - (void) nxt_random_byte(r); - } - - /* Stir again after 1,600,000 bytes. */ - r->count = 400000; -} - - -static void -nxt_random_add(nxt_random_t *r, const u_char *key, uint32_t len) -{ - uint8_t val; - uint32_t n; - - for (n = 0; n < 256; n++) { - val = r->s[r->i]; - r->j += val + key[n % len]; - - r->s[r->i] = r->s[r->j]; - r->s[r->j] = val; - - r->i++; - } - - /* This index is not decremented in RC4 algorithm. */ - r->i--; - - r->j = r->i; -} - - -uint32_t -nxt_random(nxt_random_t *r) -{ - uint32_t val; - - r->count--; - - if (r->count <= 0) { - nxt_random_stir(r); - } - - val = nxt_random_byte(r) << 24; - val |= nxt_random_byte(r) << 16; - val |= nxt_random_byte(r) << 8; - val |= nxt_random_byte(r); - - return val; -} - - -nxt_inline uint8_t -nxt_random_byte(nxt_random_t *r) -{ - uint8_t si, sj; - - r->i++; - si = r->s[r->i]; - r->j += si; - - sj = r->s[r->j]; - r->s[r->i] = sj; - r->s[r->j] = si; - - si += sj; - - return r->s[si]; -} - - -#if (NXT_TESTS) - -nxt_int_t -nxt_random_test(nxt_thread_t *thr) -{ - nxt_uint_t n; - nxt_random_t r; - - nxt_random_start_schedule(&r); - - r.count = 400000; - - nxt_random_add(&r, (u_char *) "arc4random", nxt_length("arc4random")); - - /* - * Test arc4random() numbers. - * RC4 pseudorandom numbers would be 0x4642AFC3 and 0xBAF0FFF0. - */ - - if (nxt_random(&r) == 0xD6270B27) { - - for (n = 100000; n != 0; n--) { - (void) nxt_random(&r); - } - - if (nxt_random(&r) == 0x6FCAE186) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random test passed"); - - return NXT_OK; - } - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random test failed"); - - return NXT_ERROR; -} - -#endif diff --git a/src/nxt_random.h b/src/nxt_random.h deleted file mode 100644 index 962fdf8f..00000000 --- a/src/nxt_random.h +++ /dev/null @@ -1,27 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_RANDOM_H_INCLUDED_ -#define _NXT_RANDOM_H_INCLUDED_ - - -typedef struct { - uint8_t i; - uint8_t j; - uint8_t s[256]; - int32_t count; -} nxt_random_t; - - -void nxt_random_init(nxt_random_t *r); -uint32_t nxt_random(nxt_random_t *r); - -#if (NXT_TESTS) -nxt_int_t nxt_random_test(nxt_thread_t *thr); -#endif - - -#endif /* _NXT_RANDOM_H_INCLUDED_ */ diff --git a/src/nxt_rbtree.c b/src/nxt_rbtree.c deleted file mode 100644 index 4a0f9c22..00000000 --- a/src/nxt_rbtree.c +++ /dev/null @@ -1,533 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * The red-black tree code is based on the algorithm described in - * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest. - */ - - -static void nxt_rbtree_insert_fixup(nxt_rbtree_node_t *node); -static void nxt_rbtree_delete_fixup(nxt_rbtree_t *tree, - nxt_rbtree_node_t *node); -nxt_inline void nxt_rbtree_left_rotate(nxt_rbtree_node_t *node); -nxt_inline void nxt_rbtree_right_rotate(nxt_rbtree_node_t *node); -nxt_inline void nxt_rbtree_parent_relink(nxt_rbtree_node_t *subst, - nxt_rbtree_node_t *node); - - -#define NXT_RBTREE_BLACK 0 -#define NXT_RBTREE_RED 1 - - -#define nxt_rbtree_comparison_callback(tree) \ - ((nxt_rbtree_compare_t) (tree)->sentinel.right) - - -void -nxt_rbtree_init(nxt_rbtree_t *tree, nxt_rbtree_compare_t compare) -{ - /* - * The sentinel is used as a leaf node sentinel and as a tree root - * sentinel: it is a parent of a root node and the root node is - * the left child of the sentinel. Combining two sentinels in one - * entry and the fact that the sentinel's left child is a root node - * simplifies nxt_rbtree_node_successor() and eliminates explicit - * root node test before or inside nxt_rbtree_min(). - */ - - /* The root is empty. */ - tree->sentinel.left = &tree->sentinel; - - /* - * The sentinel's right child is never used so - * comparison callback can be safely stored here. - */ - tree->sentinel.right = (void *) compare; - - /* The root and leaf sentinel must be black. */ - tree->sentinel.color = NXT_RBTREE_BLACK; -} - - -void -nxt_rbtree_insert(nxt_rbtree_t *tree, nxt_rbtree_part_t *part) -{ - nxt_rbtree_node_t *node, *new_node, *sentinel, **child; - nxt_rbtree_compare_t compare; - - new_node = (nxt_rbtree_node_t *) part; - - node = nxt_rbtree_root(tree); - sentinel = nxt_rbtree_sentinel(tree); - - new_node->left = sentinel; - new_node->right = sentinel; - new_node->color = NXT_RBTREE_RED; - - compare = (nxt_rbtree_compare_t) tree->sentinel.right; - child = &nxt_rbtree_root(tree); - - while (*child != sentinel) { - node = *child; - - nxt_prefetch(node->left); - nxt_prefetch(node->right); - - child = (compare(new_node, node) < 0) ? &node->left : &node->right; - } - - *child = new_node; - new_node->parent = node; - - nxt_rbtree_insert_fixup(new_node); - - node = nxt_rbtree_root(tree); - node->color = NXT_RBTREE_BLACK; -} - - -static void -nxt_rbtree_insert_fixup(nxt_rbtree_node_t *node) -{ - nxt_rbtree_node_t *parent, *grandparent, *uncle; - - /* - * Prefetching parent nodes does not help here because they are - * already traversed during insertion. - */ - - for ( ;; ) { - parent = node->parent; - - /* - * Testing whether a node is a tree root is not required here since - * a root node's parent is the sentinel and it is always black. - */ - if (parent->color == NXT_RBTREE_BLACK) { - return; - } - - grandparent = parent->parent; - - if (parent == grandparent->left) { - uncle = grandparent->right; - - if (uncle->color == NXT_RBTREE_BLACK) { - - if (node == parent->right) { - node = parent; - nxt_rbtree_left_rotate(node); - } - - /* - * nxt_rbtree_left_rotate() swaps parent and - * child whilst keeps grandparent the same. - */ - parent = node->parent; - - parent->color = NXT_RBTREE_BLACK; - grandparent->color = NXT_RBTREE_RED; - - nxt_rbtree_right_rotate(grandparent); - /* - * nxt_rbtree_right_rotate() does not change node->parent - * color which is now black, so testing color is not required - * to return from function. - */ - return; - } - - } else { - uncle = grandparent->left; - - if (uncle->color == NXT_RBTREE_BLACK) { - - if (node == parent->left) { - node = parent; - nxt_rbtree_right_rotate(node); - } - - /* See the comment in the symmetric branch above. */ - parent = node->parent; - - parent->color = NXT_RBTREE_BLACK; - grandparent->color = NXT_RBTREE_RED; - - nxt_rbtree_left_rotate(grandparent); - - /* See the comment in the symmetric branch above. */ - return; - } - } - - uncle->color = NXT_RBTREE_BLACK; - parent->color = NXT_RBTREE_BLACK; - grandparent->color = NXT_RBTREE_RED; - - node = grandparent; - } -} - - -nxt_rbtree_node_t * -nxt_rbtree_find(nxt_rbtree_t *tree, nxt_rbtree_part_t *part) -{ - intptr_t n; - nxt_rbtree_node_t *node, *next, *sentinel; - nxt_rbtree_compare_t compare; - - node = (nxt_rbtree_node_t *) part; - - next = nxt_rbtree_root(tree); - sentinel = nxt_rbtree_sentinel(tree); - compare = nxt_rbtree_comparison_callback(tree); - - while (next != sentinel) { - nxt_prefetch(next->left); - nxt_prefetch(next->right); - - n = compare(node, next); - - if (n < 0) { - next = next->left; - - } else if (n > 0) { - next = next->right; - - } else { - return next; - } - } - - return NULL; -} - - -nxt_rbtree_node_t * -nxt_rbtree_find_less_or_equal(nxt_rbtree_t *tree, nxt_rbtree_part_t *part) -{ - intptr_t n; - nxt_rbtree_node_t *node, *retval, *next, *sentinel; - nxt_rbtree_compare_t compare; - - node = (nxt_rbtree_node_t *) part; - - retval = NULL; - next = nxt_rbtree_root(tree); - sentinel = nxt_rbtree_sentinel(tree); - compare = nxt_rbtree_comparison_callback(tree); - - while (next != sentinel) { - nxt_prefetch(next->left); - nxt_prefetch(next->right); - - n = compare(node, next); - - if (n < 0) { - next = next->left; - - } else if (n > 0) { - retval = next; - next = next->right; - - } else { - /* Exact match. */ - return next; - } - } - - return retval; -} - - -nxt_rbtree_node_t * -nxt_rbtree_find_greater_or_equal(nxt_rbtree_t *tree, nxt_rbtree_part_t *part) -{ - intptr_t n; - nxt_rbtree_node_t *node, *retval, *next, *sentinel; - nxt_rbtree_compare_t compare; - - node = (nxt_rbtree_node_t *) part; - - retval = NULL; - next = nxt_rbtree_root(tree); - sentinel = nxt_rbtree_sentinel(tree); - compare = nxt_rbtree_comparison_callback(tree); - - while (next != sentinel) { - nxt_prefetch(next->left); - nxt_prefetch(next->right); - - n = compare(node, next); - - if (n < 0) { - retval = next; - next = next->left; - - } else if (n > 0) { - next = next->right; - - } else { - /* Exact match. */ - return next; - } - } - - return retval; -} - - -void -nxt_rbtree_delete(nxt_rbtree_t *tree, nxt_rbtree_part_t *part) -{ - uint8_t color; - nxt_rbtree_node_t *node, *sentinel, *subst, *child; - - node = (nxt_rbtree_node_t *) part; - - subst = node; - sentinel = nxt_rbtree_sentinel(tree); - - if (node->left == sentinel) { - child = node->right; - - } else if (node->right == sentinel) { - child = node->left; - - } else { - subst = nxt_rbtree_branch_min(tree, node->right); - child = subst->right; - } - - nxt_rbtree_parent_relink(child, subst); - - color = subst->color; - - if (subst != node) { - /* Move the subst node to the deleted node position in the tree. */ - - subst->color = node->color; - - subst->left = node->left; - subst->left->parent = subst; - - subst->right = node->right; - subst->right->parent = subst; - - nxt_rbtree_parent_relink(subst, node); - } - -#if (NXT_DEBUG) - node->left = NULL; - node->right = NULL; - node->parent = NULL; -#endif - - if (color == NXT_RBTREE_BLACK) { - nxt_rbtree_delete_fixup(tree, child); - } -} - - -static void -nxt_rbtree_delete_fixup(nxt_rbtree_t *tree, nxt_rbtree_node_t *node) -{ - nxt_rbtree_node_t *parent, *sibling; - - while (node != nxt_rbtree_root(tree) && node->color == NXT_RBTREE_BLACK) { - /* - * Prefetching parent nodes does not help here according - * to microbenchmarks. - */ - - parent = node->parent; - - if (node == parent->left) { - sibling = parent->right; - - if (sibling->color != NXT_RBTREE_BLACK) { - - sibling->color = NXT_RBTREE_BLACK; - parent->color = NXT_RBTREE_RED; - - nxt_rbtree_left_rotate(parent); - - sibling = parent->right; - } - - if (sibling->right->color == NXT_RBTREE_BLACK) { - - sibling->color = NXT_RBTREE_RED; - - if (sibling->left->color == NXT_RBTREE_BLACK) { - node = parent; - continue; - } - - sibling->left->color = NXT_RBTREE_BLACK; - - nxt_rbtree_right_rotate(sibling); - /* - * If the node is the leaf sentinel then the right - * rotate above changes its parent so a sibling below - * becames the leaf sentinel as well and this causes - * segmentation fault. This is the reason why usual - * red-black tree implementations with a leaf sentinel - * which does not require to test leaf nodes at all - * nevertheless test the leaf sentinel in the left and - * right rotate procedures. Since according to the - * algorithm node->parent must not be changed by both - * the left and right rotates above, it can be cached - * in a local variable. This not only eliminates the - * sentinel test in nxt_rbtree_parent_relink() but also - * decreases the code size because C forces to reload - * non-restrict pointers. - */ - sibling = parent->right; - } - - sibling->color = parent->color; - parent->color = NXT_RBTREE_BLACK; - sibling->right->color = NXT_RBTREE_BLACK; - - nxt_rbtree_left_rotate(parent); - - return; - - } else { - sibling = parent->left; - - if (sibling->color != NXT_RBTREE_BLACK) { - - sibling->color = NXT_RBTREE_BLACK; - parent->color = NXT_RBTREE_RED; - - nxt_rbtree_right_rotate(parent); - - sibling = parent->left; - } - - if (sibling->left->color == NXT_RBTREE_BLACK) { - - sibling->color = NXT_RBTREE_RED; - - if (sibling->right->color == NXT_RBTREE_BLACK) { - node = parent; - continue; - } - - sibling->right->color = NXT_RBTREE_BLACK; - - nxt_rbtree_left_rotate(sibling); - - /* See the comment in the symmetric branch above. */ - sibling = parent->left; - } - - sibling->color = parent->color; - parent->color = NXT_RBTREE_BLACK; - sibling->left->color = NXT_RBTREE_BLACK; - - nxt_rbtree_right_rotate(parent); - - return; - } - } - - node->color = NXT_RBTREE_BLACK; -} - - -nxt_inline void -nxt_rbtree_left_rotate(nxt_rbtree_node_t *node) -{ - nxt_rbtree_node_t *child; - - child = node->right; - node->right = child->left; - child->left->parent = node; - child->left = node; - - nxt_rbtree_parent_relink(child, node); - - node->parent = child; -} - - -nxt_inline void -nxt_rbtree_right_rotate(nxt_rbtree_node_t *node) -{ - nxt_rbtree_node_t *child; - - child = node->left; - node->left = child->right; - child->right->parent = node; - child->right = node; - - nxt_rbtree_parent_relink(child, node); - - node->parent = child; -} - - -/* Relink a parent from the node to the subst node. */ - -nxt_inline void -nxt_rbtree_parent_relink(nxt_rbtree_node_t *subst, nxt_rbtree_node_t *node) -{ - nxt_rbtree_node_t *parent, **link; - - parent = node->parent; - /* - * The leaf sentinel's parent can be safely changed here. - * See the comment in nxt_rbtree_delete_fixup() for details. - */ - subst->parent = parent; - /* - * If the node's parent is the root sentinel it is safely changed - * because the root sentinel's left child is the tree root. - */ - link = (node == parent->left) ? &parent->left : &parent->right; - *link = subst; -} - - -nxt_rbtree_node_t * -nxt_rbtree_destroy_next(nxt_rbtree_t *tree, nxt_rbtree_node_t **next) -{ - nxt_rbtree_node_t *node, *subst, *parent, *sentinel; - - sentinel = nxt_rbtree_sentinel(tree); - - /* Find the leftmost node. */ - for (node = *next; node->left != sentinel; node = node->left); - - /* Replace the leftmost node with its right child. */ - subst = node->right; - parent = node->parent; - - parent->left = subst; - subst->parent = parent; - - /* - * The right child is used as the next start node. If the right child - * is the sentinel then parent of the leftmost node is used as the next - * start node. The parent of the root node is the sentinel so after - * the single root node will be replaced with the sentinel, the next - * start node will be equal to the sentinel and iteration will stop. - */ - if (subst == sentinel) { - subst = parent; - } - - *next = subst; - - return node; -} diff --git a/src/nxt_rbtree.h b/src/nxt_rbtree.h deleted file mode 100644 index 4bf479ea..00000000 --- a/src/nxt_rbtree.h +++ /dev/null @@ -1,131 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_RBTREE_H_INCLUDED_ -#define _NXT_RBTREE_H_INCLUDED_ - - -typedef struct nxt_rbtree_node_s nxt_rbtree_node_t; - -struct nxt_rbtree_node_s { - nxt_rbtree_node_t *left; - nxt_rbtree_node_t *right; - nxt_rbtree_node_t *parent; - - uint8_t color; -}; - - -typedef struct { - nxt_rbtree_node_t *left; - nxt_rbtree_node_t *right; - nxt_rbtree_node_t *parent; -} nxt_rbtree_part_t; - - -#define NXT_RBTREE_NODE(node) \ - nxt_rbtree_part_t node; \ - uint8_t node##_color - - -#define NXT_RBTREE_NODE_INIT { NULL, NULL, NULL }, 0 - - -typedef struct { - nxt_rbtree_node_t sentinel; -} nxt_rbtree_t; - - -/* - * A comparison function should return intptr_t result because - * this eliminates overhead required to implement correct addresses - * comparison without result truncation. - */ -typedef intptr_t (*nxt_rbtree_compare_t)(nxt_rbtree_node_t *node1, - nxt_rbtree_node_t *node2); - - -#define nxt_rbtree_root(tree) \ - ((tree)->sentinel.left) - - -#define nxt_rbtree_sentinel(tree) \ - (&(tree)->sentinel) - - -#define nxt_rbtree_is_empty(tree) \ - (nxt_rbtree_root(tree) == nxt_rbtree_sentinel(tree)) - - -#define nxt_rbtree_min(tree) \ - nxt_rbtree_branch_min(tree, &(tree)->sentinel) - - -nxt_inline nxt_rbtree_node_t * -nxt_rbtree_branch_min(nxt_rbtree_t *tree, nxt_rbtree_node_t *node) -{ - while (node->left != nxt_rbtree_sentinel(tree)) { - node = node->left; - } - - return node; -} - - -#define nxt_rbtree_is_there_successor(tree, node) \ - ((node) != nxt_rbtree_sentinel(tree)) - - -nxt_inline nxt_rbtree_node_t * -nxt_rbtree_node_successor(nxt_rbtree_t *tree, nxt_rbtree_node_t *node) -{ - nxt_rbtree_node_t *parent; - - if (node->right != nxt_rbtree_sentinel(tree)) { - return nxt_rbtree_branch_min(tree, node->right); - } - - for ( ;; ) { - parent = node->parent; - - /* - * Explicit test for a root node is not required here, because - * the root node is always the left child of the sentinel. - */ - if (node == parent->left) { - return parent; - } - - node = parent; - } -} - - -NXT_EXPORT void nxt_rbtree_init(nxt_rbtree_t *tree, - nxt_rbtree_compare_t compare); -NXT_EXPORT void nxt_rbtree_insert(nxt_rbtree_t *tree, nxt_rbtree_part_t *node); -NXT_EXPORT nxt_rbtree_node_t *nxt_rbtree_find(nxt_rbtree_t *tree, - nxt_rbtree_part_t *node); -NXT_EXPORT nxt_rbtree_node_t *nxt_rbtree_find_less_or_equal(nxt_rbtree_t *tree, - nxt_rbtree_part_t *node); -NXT_EXPORT nxt_rbtree_node_t - *nxt_rbtree_find_greater_or_equal(nxt_rbtree_t *tree, - nxt_rbtree_part_t *node); -NXT_EXPORT void nxt_rbtree_delete(nxt_rbtree_t *tree, nxt_rbtree_part_t *node); - -/* - * nxt_rbtree_destroy_next() is iterator to use only while rbtree destruction. - * It deletes a node from rbtree and returns the node. The rbtree is not - * rebalanced after deletion. At the beginning the "next" parameter should - * be equal to rbtree root. The iterator should be called in loop until - * the "next" parameter will be equal to the rbtree sentinel. No other - * operations must be performed on the rbtree while destruction. - */ -NXT_EXPORT nxt_rbtree_node_t *nxt_rbtree_destroy_next(nxt_rbtree_t *tree, - nxt_rbtree_node_t **next); - - -#endif /* _NXT_RBTREE_H_INCLUDED_ */ diff --git a/src/nxt_recvbuf.c b/src/nxt_recvbuf.c deleted file mode 100644 index 29a2b65d..00000000 --- a/src/nxt_recvbuf.c +++ /dev/null @@ -1,82 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_uint_t -nxt_recvbuf_mem_coalesce(nxt_recvbuf_coalesce_t *rb) -{ - u_char *last; - size_t size, total; - nxt_int_t n; - nxt_buf_t *b; - - total = 0; - last = NULL; - n = -1; - - for (b = rb->buf; b != NULL; b = b->next) { - - nxt_prefetch(b->next); - - size = b->mem.end - b->mem.free; - - if (b->mem.free != last) { - - if (++n >= rb->nmax) { - goto done; - } - - nxt_iobuf_set(&rb->iobuf[n], b->mem.free, size); - - } else { - nxt_iobuf_add(&rb->iobuf[n], size); - } - - nxt_thread_log_debug("recvbuf: %ui, %p, %uz", n, - nxt_iobuf_data(&rb->iobuf[n]), - nxt_iobuf_size(&rb->iobuf[n])); - - total += size; - last = b->mem.end; - } - - n++; - -done: - - rb->size = total; - - return n; -} - - -void -nxt_recvbuf_update(nxt_buf_t *b, size_t sent) -{ - size_t size; - - while (b != NULL && sent != 0) { - - nxt_prefetch(b->next); - - if (!nxt_buf_is_sync(b)) { - - size = b->mem.end - b->mem.free; - - if (sent < size) { - b->mem.free += sent; - return; - } - - b->mem.free = b->mem.end; - sent -= size; - } - - b = b->next; - } -} diff --git a/src/nxt_recvbuf.h b/src/nxt_recvbuf.h deleted file mode 100644 index 69b51498..00000000 --- a/src/nxt_recvbuf.h +++ /dev/null @@ -1,24 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_RECVBUF_H_INCLUDED_ -#define _NXT_RECVBUF_H_INCLUDED_ - - -typedef struct { - nxt_buf_t *buf; - nxt_iobuf_t *iobuf; - - int32_t nmax; - size_t size; -} nxt_recvbuf_coalesce_t; - - -nxt_uint_t nxt_recvbuf_mem_coalesce(nxt_recvbuf_coalesce_t *rb); -void nxt_recvbuf_update(nxt_buf_t *b, size_t sent); - - -#endif /* _NXT_RECVBUF_H_INCLUDED_ */ diff --git a/src/nxt_regex.h b/src/nxt_regex.h deleted file mode 100644 index a24c50f8..00000000 --- a/src/nxt_regex.h +++ /dev/null @@ -1,41 +0,0 @@ - -/* - * Copyright (C) Axel Duch - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_REGEX_H_INCLUDED_ -#define _NXT_REGEX_H_INCLUDED_ - -#if (NXT_HAVE_REGEX) - -typedef struct nxt_regex_s nxt_regex_t; - - #if (NXT_HAVE_PCRE2) -typedef void nxt_regex_match_t; -#else -typedef struct nxt_regex_match_s nxt_regex_match_t; -#endif - -typedef struct { - size_t offset; - -#if (NXT_HAVE_PCRE2) -#define ERR_BUF_SIZE 256 - u_char msg[ERR_BUF_SIZE]; -#else - const char *msg; -#endif -} nxt_regex_err_t; - - -NXT_EXPORT void nxt_regex_init(void); -NXT_EXPORT nxt_regex_t *nxt_regex_compile(nxt_mp_t *mp, nxt_str_t *source, - nxt_regex_err_t *err); -NXT_EXPORT nxt_regex_match_t *nxt_regex_match_create(nxt_mp_t *mp, size_t size); -NXT_EXPORT nxt_int_t nxt_regex_match(nxt_regex_t *re, u_char *subject, - size_t length, nxt_regex_match_t *match); - -#endif /* NXT_HAVE_REGEX */ - -#endif /* _NXT_REGEX_H_INCLUDED_ */ diff --git a/src/nxt_router.c b/src/nxt_router.c deleted file mode 100644 index 1a1aca2b..00000000 --- a/src/nxt_router.c +++ /dev/null @@ -1,5878 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#if (NXT_TLS) -#include -#endif -#if (NXT_HAVE_NJS) -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#define NXT_SHARED_PORT_ID 0xFFFFu - -typedef struct { - nxt_str_t type; - uint32_t processes; - uint32_t max_processes; - uint32_t spare_processes; - nxt_msec_t timeout; - nxt_msec_t idle_timeout; - nxt_conf_value_t *limits_value; - nxt_conf_value_t *processes_value; - nxt_conf_value_t *targets_value; -} nxt_router_app_conf_t; - - -typedef struct { - nxt_str_t pass; - nxt_str_t application; -} nxt_router_listener_conf_t; - - -#if (NXT_TLS) - -typedef struct { - nxt_str_t name; - nxt_socket_conf_t *socket_conf; - nxt_router_temp_conf_t *temp_conf; - nxt_tls_init_t *tls_init; - nxt_bool_t last; - - nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */ -} nxt_router_tlssock_t; - -#endif - - -#if (NXT_HAVE_NJS) - -typedef struct { - nxt_str_t name; - nxt_router_temp_conf_t *temp_conf; - nxt_queue_link_t link; -} nxt_router_js_module_t; - -#endif - - -typedef struct { - nxt_str_t *name; - nxt_socket_conf_t *socket_conf; - nxt_router_temp_conf_t *temp_conf; - nxt_bool_t last; -} nxt_socket_rpc_t; - - -typedef struct { - nxt_app_t *app; - nxt_router_temp_conf_t *temp_conf; - uint8_t proto; /* 1 bit */ -} nxt_app_rpc_t; - - -typedef struct { - nxt_app_joint_t *app_joint; - uint32_t generation; - uint8_t proto; /* 1 bit */ -} nxt_app_joint_rpc_t; - - -static nxt_int_t nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, - nxt_mp_t *mp); -static nxt_int_t nxt_router_start(nxt_task_t *task, nxt_process_data_t *data); -static void nxt_router_greet_controller(nxt_task_t *task, - nxt_port_t *controller_port); - -static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app); - -static void nxt_router_new_port_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_router_conf_data_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_router_app_restart_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_router_status_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_router_remove_pid_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); - -static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); -static void nxt_router_conf_ready(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf); -static void nxt_router_conf_send(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); - -static nxt_int_t nxt_router_conf_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); -static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, - nxt_router_conf_t *rtcf, nxt_conf_value_t *conf); -static nxt_http_forward_t *nxt_router_conf_forward(nxt_task_t *task, - nxt_mp_t *mp, nxt_conf_value_t *conf); -static nxt_int_t nxt_router_conf_forward_header(nxt_mp_t *mp, - nxt_conf_value_t *conf, nxt_http_forward_header_t *fh); - -static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); -static nxt_int_t nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data); -static nxt_int_t nxt_router_apps_hash_add(nxt_router_conf_t *rtcf, - nxt_app_t *app); -static nxt_app_t *nxt_router_apps_hash_get(nxt_router_conf_t *rtcf, - nxt_str_t *name); -static void nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf, - int i); - -static nxt_int_t nxt_router_app_queue_init(nxt_task_t *task, - nxt_port_t *port); -static nxt_int_t nxt_router_port_queue_init(nxt_task_t *task, - nxt_port_t *port); -static nxt_int_t nxt_router_port_queue_map(nxt_task_t *task, - nxt_port_t *port, nxt_fd_t fd); -static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); -static void nxt_router_listen_socket_ready(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_router_listen_socket_error(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -#if (NXT_TLS) -static void nxt_router_tls_rpc_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *value, nxt_socket_conf_t *skcf, nxt_tls_init_t *tls_init, - nxt_bool_t last); -#endif -#if (NXT_HAVE_NJS) -static void nxt_router_js_module_rpc_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static nxt_int_t nxt_router_js_module_insert(nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *value); -#endif -static void nxt_router_app_rpc_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_app_t *app); -static void nxt_router_app_prefork_ready(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_router_app_prefork_error(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_str_t *name); -static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, - nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa); - -static nxt_int_t nxt_router_engines_create(nxt_task_t *task, - nxt_router_t *router, nxt_router_temp_conf_t *tmcf, - const nxt_event_interface_t *interface); -static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf); -static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf); -static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf); -static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, - nxt_work_handler_t handler); -static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf); -static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); - -static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, - nxt_router_temp_conf_t *tmcf); -static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, - nxt_event_engine_t *engine); -static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, - nxt_router_temp_conf_t *tmcf); - -static void nxt_router_engines_post(nxt_router_t *router, - nxt_router_temp_conf_t *tmcf); -static void nxt_router_engine_post(nxt_event_engine_t *engine, - nxt_work_t *jobs); - -static void nxt_router_thread_start(void *data); -static void nxt_router_rt_add_port(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_req_headers_ack_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data); -static void nxt_router_listen_socket_release(nxt_task_t *task, - nxt_socket_conf_t *skcf); - -static void nxt_router_app_port_ready(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_router_app_port_error(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); - -static void nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i); -static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app); - -static void nxt_router_app_port_release(nxt_task_t *task, nxt_app_t *app, - nxt_port_t *port, nxt_apr_action_t action); -static void nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app, - nxt_request_rpc_data_t *req_rpc_data); -static void nxt_router_http_request_error(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_http_request_done(nxt_task_t *task, void *obj, - void *data); - -static void nxt_router_app_prepare_request(nxt_task_t *task, - nxt_request_rpc_data_t *req_rpc_data); -static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, - nxt_http_request_t *r, nxt_app_t *app, const nxt_str_t *prefix); - -static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); -static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data); - -static const nxt_http_request_state_t nxt_http_request_send_state; -static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); - -static void nxt_router_app_joint_use(nxt_task_t *task, - nxt_app_joint_t *app_joint, int i); - -static void nxt_router_http_request_release_post(nxt_task_t *task, - nxt_http_request_t *r); -static void nxt_router_http_request_release(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -static void nxt_router_get_port_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); -static void nxt_router_get_mmap_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); - -extern const nxt_http_request_state_t nxt_http_websocket; - -nxt_router_t *nxt_router; - -static const nxt_str_t http_prefix = nxt_string("HTTP_"); -static const nxt_str_t empty_prefix = nxt_string(""); - -static const nxt_str_t *nxt_app_msg_prefix[] = { - [NXT_APP_EXTERNAL] = &empty_prefix, - [NXT_APP_PYTHON] = &empty_prefix, - [NXT_APP_PHP] = &http_prefix, - [NXT_APP_PERL] = &http_prefix, - [NXT_APP_RUBY] = &http_prefix, - [NXT_APP_JAVA] = &empty_prefix, - [NXT_APP_WASM] = &empty_prefix, - [NXT_APP_WASM_WC] = &empty_prefix, -}; - - -static const nxt_port_handlers_t nxt_router_process_port_handlers = { - .quit = nxt_signal_quit_handler, - .new_port = nxt_router_new_port_handler, - .get_port = nxt_router_get_port_handler, - .change_file = nxt_port_change_log_file_handler, - .mmap = nxt_port_mmap_handler, - .get_mmap = nxt_router_get_mmap_handler, - .data = nxt_router_conf_data_handler, - .app_restart = nxt_router_app_restart_handler, - .status = nxt_router_status_handler, - .remove_pid = nxt_router_remove_pid_handler, - .access_log = nxt_router_access_log_reopen_handler, - .rpc_ready = nxt_port_rpc_handler, - .rpc_error = nxt_port_rpc_handler, - .oosm = nxt_router_oosm_handler, -}; - - -const nxt_process_init_t nxt_router_process = { - .name = "router", - .type = NXT_PROCESS_ROUTER, - .prefork = nxt_router_prefork, - .restart = 1, - .setup = nxt_process_core_setup, - .start = nxt_router_start, - .port_handlers = &nxt_router_process_port_handlers, - .signals = nxt_process_signals, -}; - - -/* Queues of nxt_socket_conf_t */ -nxt_queue_t creating_sockets; -nxt_queue_t pending_sockets; -nxt_queue_t updating_sockets; -nxt_queue_t keeping_sockets; -nxt_queue_t deleting_sockets; - - -static nxt_int_t -nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp) -{ - nxt_runtime_stop_app_processes(task, task->thread->runtime); - - return NXT_OK; -} - - -static nxt_int_t -nxt_router_start(nxt_task_t *task, nxt_process_data_t *data) -{ - nxt_int_t ret; - nxt_port_t *controller_port; - nxt_router_t *router; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - nxt_log(task, NXT_LOG_INFO, "router started"); - -#if (NXT_TLS) - rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); - if (nxt_slow_path(rt->tls == NULL)) { - return NXT_ERROR; - } - - ret = rt->tls->library_init(task); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } -#endif - - ret = nxt_http_init(task); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - router = nxt_zalloc(sizeof(nxt_router_t)); - if (nxt_slow_path(router == NULL)) { - return NXT_ERROR; - } - - nxt_queue_init(&router->engines); - nxt_queue_init(&router->sockets); - nxt_queue_init(&router->apps); - - nxt_router = router; - - controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; - if (controller_port != NULL) { - nxt_router_greet_controller(task, controller_port); - } - - return NXT_OK; -} - - -static void -nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port) -{ - nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY, - -1, 0, 0, NULL); -} - - -static void -nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, - void *data) -{ - size_t size; - uint32_t stream; - nxt_fd_t port_fd, queue_fd; - nxt_int_t ret; - nxt_app_t *app; - nxt_buf_t *b; - nxt_port_t *dport; - nxt_runtime_t *rt; - nxt_app_joint_rpc_t *app_joint_rpc; - - app = data; - - nxt_thread_mutex_lock(&app->mutex); - - dport = app->proto_port; - - nxt_thread_mutex_unlock(&app->mutex); - - if (dport != NULL) { - nxt_debug(task, "app '%V' %p start process", &app->name, app); - - b = NULL; - port_fd = -1; - queue_fd = -1; - - } else { - if (app->proto_port_requests > 0) { - nxt_debug(task, "app '%V' %p wait for prototype process", - &app->name, app); - - app->proto_port_requests++; - - goto skip; - } - - nxt_debug(task, "app '%V' %p start prototype process", &app->name, app); - - rt = task->thread->runtime; - dport = rt->port_by_type[NXT_PROCESS_MAIN]; - - size = app->name.length + 1 + app->conf.length; - - b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, size, 0); - if (nxt_slow_path(b == NULL)) { - goto failed; - } - - nxt_buf_cpystr(b, &app->name); - *b->mem.free++ = '\0'; - nxt_buf_cpystr(b, &app->conf); - - port_fd = app->shared_port->pair[0]; - queue_fd = app->shared_port->queue_fd; - } - - app_joint_rpc = nxt_port_rpc_register_handler_ex(task, port, - nxt_router_app_port_ready, - nxt_router_app_port_error, - sizeof(nxt_app_joint_rpc_t)); - if (nxt_slow_path(app_joint_rpc == NULL)) { - goto failed; - } - - stream = nxt_port_rpc_ex_stream(app_joint_rpc); - - ret = nxt_port_socket_write2(task, dport, NXT_PORT_MSG_START_PROCESS, - port_fd, queue_fd, stream, port->id, b); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_rpc_cancel(task, port, stream); - - goto failed; - } - - app_joint_rpc->app_joint = app->joint; - app_joint_rpc->generation = app->generation; - app_joint_rpc->proto = (b != NULL); - - if (b != NULL) { - app->proto_port_requests++; - - b = NULL; - } - - nxt_router_app_joint_use(task, app->joint, 1); - -failed: - - if (b != NULL) { - nxt_mp_free(b->data, b); - } - -skip: - - nxt_router_app_use(task, app, -1); -} - - -static void -nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i) -{ - app_joint->use_count += i; - - if (app_joint->use_count == 0) { - nxt_assert(app_joint->app == NULL); - - nxt_free(app_joint); - } -} - - -static nxt_int_t -nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) -{ - nxt_int_t res; - nxt_port_t *router_port; - nxt_runtime_t *rt; - - nxt_debug(task, "app '%V' start process", &app->name); - - rt = task->thread->runtime; - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - nxt_router_app_use(task, app, 1); - - res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, - app); - - if (res == NXT_OK) { - return res; - } - - nxt_thread_mutex_lock(&app->mutex); - - app->pending_processes--; - - nxt_thread_mutex_unlock(&app->mutex); - - nxt_router_app_use(task, app, -1); - - return NXT_ERROR; -} - - -nxt_inline nxt_bool_t -nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data) -{ - nxt_buf_t *b, *next; - nxt_bool_t cancelled; - nxt_port_t *app_port; - nxt_msg_info_t *msg_info; - - msg_info = &req_rpc_data->msg_info; - - if (msg_info->buf == NULL) { - return 0; - } - - app_port = req_rpc_data->app_port; - - if (app_port != NULL && app_port->id == NXT_SHARED_PORT_ID) { - cancelled = nxt_app_queue_cancel(app_port->queue, - msg_info->tracking_cookie, - req_rpc_data->stream); - - if (cancelled) { - nxt_debug(task, "stream #%uD: cancelled by router", - req_rpc_data->stream); - } - - } else { - cancelled = 0; - } - - for (b = msg_info->buf; b != NULL; b = next) { - next = b->next; - b->next = NULL; - - if (b->is_port_mmap_sent) { - b->is_port_mmap_sent = cancelled == 0; - } - - b->completion_handler(task, b, b->parent); - } - - msg_info->buf = NULL; - - return cancelled; -} - - -nxt_inline nxt_bool_t -nxt_queue_chk_remove(nxt_queue_link_t *lnk) -{ - if (lnk->next != NULL) { - nxt_queue_remove(lnk); - - lnk->next = NULL; - - return 1; - } - - return 0; -} - - -nxt_inline void -nxt_request_rpc_data_unlink(nxt_task_t *task, - nxt_request_rpc_data_t *req_rpc_data) -{ - nxt_app_t *app; - nxt_bool_t unlinked; - nxt_http_request_t *r; - - nxt_router_msg_cancel(task, req_rpc_data); - - app = req_rpc_data->app; - - if (req_rpc_data->app_port != NULL) { - nxt_router_app_port_release(task, app, req_rpc_data->app_port, - req_rpc_data->apr_action); - - req_rpc_data->app_port = NULL; - } - - r = req_rpc_data->request; - - if (r != NULL) { - r->timer_data = NULL; - - nxt_router_http_request_release_post(task, r); - - r->req_rpc_data = NULL; - req_rpc_data->request = NULL; - - if (app != NULL) { - unlinked = 0; - - nxt_thread_mutex_lock(&app->mutex); - - if (r->app_link.next != NULL) { - nxt_queue_remove(&r->app_link); - r->app_link.next = NULL; - - unlinked = 1; - } - - nxt_thread_mutex_unlock(&app->mutex); - - if (unlinked) { - nxt_mp_release(r->mem_pool); - } - } - } - - if (app != NULL) { - nxt_router_app_use(task, app, -1); - - req_rpc_data->app = NULL; - } - - if (req_rpc_data->msg_info.body_fd != -1) { - nxt_fd_close(req_rpc_data->msg_info.body_fd); - - req_rpc_data->msg_info.body_fd = -1; - } - - if (req_rpc_data->rpc_cancel) { - req_rpc_data->rpc_cancel = 0; - - nxt_port_rpc_cancel(task, task->thread->engine->port, - req_rpc_data->stream); - } -} - - -static void -nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_int_t res; - nxt_app_t *app; - nxt_port_t *port, *main_app_port; - nxt_runtime_t *rt; - - nxt_port_new_port_handler(task, msg); - - port = msg->u.new_port; - - if (port != NULL && port->type == NXT_PROCESS_CONTROLLER) { - nxt_router_greet_controller(task, msg->u.new_port); - } - - if (port != NULL && port->type == NXT_PROCESS_PROTOTYPE) { - nxt_port_rpc_handler(task, msg); - - return; - } - - if (port == NULL || port->type != NXT_PROCESS_APP) { - - if (msg->port_msg.stream == 0) { - return; - } - - msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; - - } else { - if (msg->fd[1] != -1) { - res = nxt_router_port_queue_map(task, port, msg->fd[1]); - if (nxt_slow_path(res != NXT_OK)) { - return; - } - - nxt_fd_close(msg->fd[1]); - msg->fd[1] = -1; - } - } - - if (msg->port_msg.stream != 0) { - nxt_port_rpc_handler(task, msg); - return; - } - - nxt_debug(task, "new port id %d (%d)", port->id, port->type); - - /* - * Port with "id == 0" is application 'main' port and it always - * should come with non-zero stream. - */ - nxt_assert(port->id != 0); - - /* Find 'main' app port and get app reference. */ - rt = task->thread->runtime; - - /* - * It is safe to access 'runtime->ports' hash because 'NEW_PORT' - * sent to main port (with id == 0) and processed in main thread. - */ - main_app_port = nxt_port_hash_find(&rt->ports, port->pid, 0); - nxt_assert(main_app_port != NULL); - - app = main_app_port->app; - - if (nxt_fast_path(app != NULL)) { - nxt_thread_mutex_lock(&app->mutex); - - /* TODO here should be find-and-add code because there can be - port waiters in port_hash */ - nxt_port_hash_add(&app->port_hash, port); - app->port_hash_count++; - - nxt_thread_mutex_unlock(&app->mutex); - - port->app = app; - } - - port->main_app_port = main_app_port; - - nxt_port_socket_write(task, port, NXT_PORT_MSG_PORT_ACK, -1, 0, 0, NULL); -} - - -static void -nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - void *p; - size_t size; - nxt_int_t ret; - nxt_port_t *port; - nxt_router_temp_conf_t *tmcf; - - port = nxt_runtime_port_find(task->thread->runtime, - msg->port_msg.pid, - msg->port_msg.reply_port); - if (nxt_slow_path(port == NULL)) { - nxt_alert(task, "conf_data_handler: reply port not found"); - return; - } - - p = MAP_FAILED; - - /* - * Ancient compilers like gcc 4.8.5 on CentOS 7 wants 'size' to be - * initialized in 'cleanup' section. - */ - size = 0; - - tmcf = nxt_router_temp_conf(task); - if (nxt_slow_path(tmcf == NULL)) { - goto fail; - } - - if (nxt_slow_path(msg->fd[0] == -1)) { - nxt_alert(task, "conf_data_handler: invalid shm fd"); - goto fail; - } - - if (nxt_buf_mem_used_size(&msg->buf->mem) != sizeof(size_t)) { - nxt_alert(task, "conf_data_handler: unexpected buffer size (%d)", - (int) nxt_buf_mem_used_size(&msg->buf->mem)); - goto fail; - } - - nxt_memcpy(&size, msg->buf->mem.pos, sizeof(size_t)); - - p = nxt_mem_mmap(NULL, size, PROT_READ, MAP_SHARED, msg->fd[0], 0); - - nxt_fd_close(msg->fd[0]); - msg->fd[0] = -1; - - if (nxt_slow_path(p == MAP_FAILED)) { - goto fail; - } - - nxt_debug(task, "conf_data_handler(%uz): %*s", size, size, p); - - tmcf->router_conf->router = nxt_router; - tmcf->stream = msg->port_msg.stream; - tmcf->port = port; - - nxt_port_use(task, tmcf->port, 1); - - ret = nxt_router_conf_create(task, tmcf, p, nxt_pointer_to(p, size)); - - if (nxt_fast_path(ret == NXT_OK)) { - nxt_router_conf_apply(task, tmcf, NULL); - - } else { - nxt_router_conf_error(task, tmcf); - } - - goto cleanup; - -fail: - - nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1, - msg->port_msg.stream, 0, NULL); - - if (tmcf != NULL) { - nxt_mp_release(tmcf->mem_pool); - } - -cleanup: - - if (p != MAP_FAILED) { - nxt_mem_munmap(p, size); - } - - if (msg->fd[0] != -1) { - nxt_fd_close(msg->fd[0]); - msg->fd[0] = -1; - } -} - - -static void -nxt_router_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_app_t *app; - nxt_int_t ret; - nxt_str_t app_name; - nxt_port_t *reply_port, *shared_port, *old_shared_port; - nxt_port_t *proto_port; - nxt_port_msg_type_t reply; - - reply_port = nxt_runtime_port_find(task->thread->runtime, - msg->port_msg.pid, - msg->port_msg.reply_port); - if (nxt_slow_path(reply_port == NULL)) { - nxt_alert(task, "app_restart_handler: reply port not found"); - return; - } - - app_name.length = nxt_buf_mem_used_size(&msg->buf->mem); - app_name.start = msg->buf->mem.pos; - - nxt_debug(task, "app_restart_handler: %V", &app_name); - - app = nxt_router_app_find(&nxt_router->apps, &app_name); - - if (nxt_fast_path(app != NULL)) { - shared_port = nxt_port_new(task, NXT_SHARED_PORT_ID, nxt_pid, - NXT_PROCESS_APP); - if (nxt_slow_path(shared_port == NULL)) { - goto fail; - } - - ret = nxt_port_socket_init(task, shared_port, 0); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_use(task, shared_port, -1); - goto fail; - } - - ret = nxt_router_app_queue_init(task, shared_port); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_write_close(shared_port); - nxt_port_read_close(shared_port); - nxt_port_use(task, shared_port, -1); - goto fail; - } - - nxt_port_write_enable(task, shared_port); - - nxt_thread_mutex_lock(&app->mutex); - - proto_port = app->proto_port; - - if (proto_port != NULL) { - nxt_debug(task, "send QUIT to prototype '%V' pid %PI", &app->name, - proto_port->pid); - - app->proto_port = NULL; - proto_port->app = NULL; - } - - app->generation++; - - shared_port->app = app; - - old_shared_port = app->shared_port; - old_shared_port->app = NULL; - - app->shared_port = shared_port; - - nxt_thread_mutex_unlock(&app->mutex); - - nxt_port_close(task, old_shared_port); - nxt_port_use(task, old_shared_port, -1); - - if (proto_port != NULL) { - (void) nxt_port_socket_write(task, proto_port, NXT_PORT_MSG_QUIT, - -1, 0, 0, NULL); - - nxt_port_close(task, proto_port); - - nxt_port_use(task, proto_port, -1); - } - - reply = NXT_PORT_MSG_RPC_READY_LAST; - - } else { - -fail: - - reply = NXT_PORT_MSG_RPC_ERROR; - } - - nxt_port_socket_write(task, reply_port, reply, -1, msg->port_msg.stream, - 0, NULL); -} - - -static void -nxt_router_status_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - u_char *p; - size_t alloc; - nxt_app_t *app; - nxt_buf_t *b; - nxt_uint_t type; - nxt_port_t *port; - nxt_status_app_t *app_stat; - nxt_event_engine_t *engine; - nxt_status_report_t *report; - - port = nxt_runtime_port_find(task->thread->runtime, - msg->port_msg.pid, - msg->port_msg.reply_port); - if (nxt_slow_path(port == NULL)) { - nxt_alert(task, "nxt_router_status_handler(): reply port not found"); - return; - } - - alloc = sizeof(nxt_status_report_t); - - nxt_queue_each(app, &nxt_router->apps, nxt_app_t, link) { - - alloc += sizeof(nxt_status_app_t) + app->name.length; - - } nxt_queue_loop; - - b = nxt_buf_mem_alloc(port->mem_pool, alloc, 0); - if (nxt_slow_path(b == NULL)) { - type = NXT_PORT_MSG_RPC_ERROR; - goto fail; - } - - report = (nxt_status_report_t *) b->mem.free; - b->mem.free = b->mem.end; - - nxt_memzero(report, sizeof(nxt_status_report_t)); - - nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) { - - report->accepted_conns += engine->accepted_conns_cnt; - report->idle_conns += engine->idle_conns_cnt; - report->closed_conns += engine->closed_conns_cnt; - report->requests += engine->requests_cnt; - - } nxt_queue_loop; - - report->apps_count = 0; - app_stat = report->apps; - p = b->mem.end; - - nxt_queue_each(app, &nxt_router->apps, nxt_app_t, link) { - p -= app->name.length; - - nxt_memcpy(p, app->name.start, app->name.length); - - app_stat->name.length = app->name.length; - app_stat->name.start = (u_char *) (p - b->mem.pos); - - app_stat->active_requests = app->active_requests; - app_stat->pending_processes = app->pending_processes; - app_stat->processes = app->processes; - app_stat->idle_processes = app->idle_processes; - - report->apps_count++; - app_stat++; - } nxt_queue_loop; - - type = NXT_PORT_MSG_RPC_READY_LAST; - -fail: - - nxt_port_socket_write(task, port, type, -1, msg->port_msg.stream, 0, b); -} - - -static void -nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, - void *data) -{ - union { - nxt_pid_t removed_pid; - void *data; - } u; - - u.data = data; - - nxt_port_rpc_remove_peer(task, port, u.removed_pid); -} - - -static void -nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_event_engine_t *engine; - - nxt_port_remove_pid_handler(task, msg); - - nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) - { - if (nxt_fast_path(engine->port != NULL)) { - nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, - msg->u.data); - } - } - nxt_queue_loop; - - if (msg->port_msg.stream == 0) { - return; - } - - msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; - - nxt_port_rpc_handler(task, msg); -} - - -static nxt_router_temp_conf_t * -nxt_router_temp_conf(nxt_task_t *task) -{ - nxt_mp_t *mp, *tmp; - nxt_router_conf_t *rtcf; - nxt_router_temp_conf_t *tmcf; - - mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { - return NULL; - } - - rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); - if (nxt_slow_path(rtcf == NULL)) { - goto fail; - } - - rtcf->mem_pool = mp; - - rtcf->tstr_state = nxt_tstr_state_new(mp, 0); - if (nxt_slow_path(rtcf->tstr_state == NULL)) { - goto fail; - } - -#if (NXT_HAVE_NJS) - nxt_http_register_js_proto(rtcf->tstr_state->jcf); -#endif - - tmp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(tmp == NULL)) { - goto fail; - } - - tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); - if (nxt_slow_path(tmcf == NULL)) { - goto temp_fail; - } - - tmcf->mem_pool = tmp; - tmcf->router_conf = rtcf; - tmcf->count = 1; - tmcf->engine = task->thread->engine; - - tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, - sizeof(nxt_router_engine_conf_t)); - if (nxt_slow_path(tmcf->engines == NULL)) { - goto temp_fail; - } - - nxt_queue_init(&creating_sockets); - nxt_queue_init(&pending_sockets); - nxt_queue_init(&updating_sockets); - nxt_queue_init(&keeping_sockets); - nxt_queue_init(&deleting_sockets); - -#if (NXT_TLS) - nxt_queue_init(&tmcf->tls); -#endif - -#if (NXT_HAVE_NJS) - nxt_queue_init(&tmcf->js_modules); -#endif - - nxt_queue_init(&tmcf->apps); - nxt_queue_init(&tmcf->previous); - - return tmcf; - -temp_fail: - - nxt_mp_destroy(tmp); - -fail: - - if (rtcf->tstr_state != NULL) { - nxt_tstr_state_release(rtcf->tstr_state); - } - - nxt_mp_destroy(mp); - - return NULL; -} - - -nxt_inline nxt_bool_t -nxt_router_app_can_start(nxt_app_t *app) -{ - return app->processes + app->pending_processes < app->max_processes - && app->pending_processes < app->max_pending_processes; -} - - -nxt_inline nxt_bool_t -nxt_router_app_need_start(nxt_app_t *app) -{ - return (app->active_requests - > app->port_hash_count + app->pending_processes) - || (app->spare_processes - > app->idle_processes + app->pending_processes); -} - - -void -nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) -{ - nxt_int_t ret; - nxt_app_t *app; - nxt_router_t *router; - nxt_runtime_t *rt; - nxt_queue_link_t *qlk; - nxt_socket_conf_t *skcf; - nxt_router_conf_t *rtcf; - nxt_router_temp_conf_t *tmcf; - const nxt_event_interface_t *interface; -#if (NXT_TLS) - nxt_router_tlssock_t *tls; -#endif -#if (NXT_HAVE_NJS) - nxt_router_js_module_t *js_module; -#endif - - tmcf = obj; - - qlk = nxt_queue_first(&pending_sockets); - - if (qlk != nxt_queue_tail(&pending_sockets)) { - nxt_queue_remove(qlk); - nxt_queue_insert_tail(&creating_sockets, qlk); - - skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); - - nxt_router_listen_socket_rpc_create(task, tmcf, skcf); - - return; - } - -#if (NXT_TLS) - qlk = nxt_queue_last(&tmcf->tls); - - if (qlk != nxt_queue_head(&tmcf->tls)) { - nxt_queue_remove(qlk); - - tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link); - - nxt_cert_store_get(task, &tls->name, tmcf->mem_pool, - nxt_router_tls_rpc_handler, tls); - return; - } -#endif - -#if (NXT_HAVE_NJS) - qlk = nxt_queue_last(&tmcf->js_modules); - - if (qlk != nxt_queue_head(&tmcf->js_modules)) { - nxt_queue_remove(qlk); - - js_module = nxt_queue_link_data(qlk, nxt_router_js_module_t, link); - - nxt_script_store_get(task, &js_module->name, tmcf->mem_pool, - nxt_router_js_module_rpc_handler, js_module); - return; - } -#endif - - rtcf = tmcf->router_conf; - - ret = nxt_tstr_state_done(rtcf->tstr_state, NULL); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { - - if (nxt_router_app_need_start(app)) { - nxt_router_app_rpc_create(task, tmcf, app); - return; - } - - } nxt_queue_loop; - - if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) { - nxt_router_access_log_open(task, tmcf); - return; - } - - rt = task->thread->runtime; - - interface = nxt_service_get(rt->services, "engine", NULL); - - router = rtcf->router; - - ret = nxt_router_engines_create(task, router, tmcf, interface); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - ret = nxt_router_threads_create(task, rt, tmcf); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - nxt_router_apps_sort(task, router, tmcf); - - nxt_router_apps_hash_use(task, rtcf, 1); - - nxt_router_engines_post(router, tmcf); - - nxt_queue_add(&router->sockets, &updating_sockets); - nxt_queue_add(&router->sockets, &creating_sockets); - - if (router->access_log != rtcf->access_log) { - nxt_router_access_log_use(&router->lock, rtcf->access_log); - - nxt_router_access_log_release(task, &router->lock, router->access_log); - - router->access_log = rtcf->access_log; - } - - nxt_router_conf_ready(task, tmcf); - - return; - -fail: - - nxt_router_conf_error(task, tmcf); - - return; -} - - -static void -nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) -{ - nxt_joint_job_t *job; - - job = obj; - - nxt_router_conf_ready(task, job->tmcf); -} - - -static void -nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) -{ - uint32_t count; - nxt_router_conf_t *rtcf; - nxt_thread_spinlock_t *lock; - - nxt_debug(task, "temp conf %p count: %D", tmcf, tmcf->count); - - if (--tmcf->count > 0) { - return; - } - - nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); - - rtcf = tmcf->router_conf; - - lock = &rtcf->router->lock; - - nxt_thread_spin_lock(lock); - - count = rtcf->count; - - nxt_thread_spin_unlock(lock); - - nxt_debug(task, "rtcf %p: %D", rtcf, count); - - if (count == 0) { - nxt_router_apps_hash_use(task, rtcf, -1); - - nxt_router_access_log_release(task, lock, rtcf->access_log); - - nxt_mp_destroy(rtcf->mem_pool); - } - - nxt_mp_release(tmcf->mem_pool); -} - - -void -nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) -{ - nxt_app_t *app; - nxt_socket_t s; - nxt_router_t *router; - nxt_queue_link_t *qlk; - nxt_socket_conf_t *skcf; - nxt_router_conf_t *rtcf; - - nxt_alert(task, "failed to apply new conf"); - - for (qlk = nxt_queue_first(&creating_sockets); - qlk != nxt_queue_tail(&creating_sockets); - qlk = nxt_queue_next(qlk)) - { - skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); - s = skcf->listen->socket; - - if (s != -1) { - nxt_socket_close(task, s); - } - - nxt_free(skcf->listen); - } - - rtcf = tmcf->router_conf; - - nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { - - nxt_router_app_unlink(task, app); - - } nxt_queue_loop; - - router = rtcf->router; - - nxt_queue_add(&router->sockets, &keeping_sockets); - nxt_queue_add(&router->sockets, &deleting_sockets); - - nxt_queue_add(&router->apps, &tmcf->previous); - - // TODO: new engines and threads - - nxt_router_access_log_release(task, &router->lock, rtcf->access_log); - - nxt_mp_destroy(rtcf->mem_pool); - - nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); - - nxt_mp_release(tmcf->mem_pool); -} - - -static void -nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_port_msg_type_t type) -{ - nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); - - nxt_port_use(task, tmcf->port, -1); - - tmcf->port = NULL; -} - - -static nxt_conf_map_t nxt_router_conf[] = { - { - nxt_string("listeners_threads"), - NXT_CONF_MAP_INT32, - offsetof(nxt_router_conf_t, threads), - }, -}; - - -static nxt_conf_map_t nxt_router_app_conf[] = { - { - nxt_string("type"), - NXT_CONF_MAP_STR, - offsetof(nxt_router_app_conf_t, type), - }, - - { - nxt_string("limits"), - NXT_CONF_MAP_PTR, - offsetof(nxt_router_app_conf_t, limits_value), - }, - - { - nxt_string("processes"), - NXT_CONF_MAP_INT32, - offsetof(nxt_router_app_conf_t, processes), - }, - - { - nxt_string("processes"), - NXT_CONF_MAP_PTR, - offsetof(nxt_router_app_conf_t, processes_value), - }, - - { - nxt_string("targets"), - NXT_CONF_MAP_PTR, - offsetof(nxt_router_app_conf_t, targets_value), - }, -}; - - -static nxt_conf_map_t nxt_router_app_limits_conf[] = { - { - nxt_string("timeout"), - NXT_CONF_MAP_MSEC, - offsetof(nxt_router_app_conf_t, timeout), - }, -}; - - -static nxt_conf_map_t nxt_router_app_processes_conf[] = { - { - nxt_string("spare"), - NXT_CONF_MAP_INT32, - offsetof(nxt_router_app_conf_t, spare_processes), - }, - - { - nxt_string("max"), - NXT_CONF_MAP_INT32, - offsetof(nxt_router_app_conf_t, max_processes), - }, - - { - nxt_string("idle_timeout"), - NXT_CONF_MAP_MSEC, - offsetof(nxt_router_app_conf_t, idle_timeout), - }, -}; - - -static nxt_conf_map_t nxt_router_listener_conf[] = { - { - nxt_string("pass"), - NXT_CONF_MAP_STR_COPY, - offsetof(nxt_router_listener_conf_t, pass), - }, - - { - nxt_string("application"), - NXT_CONF_MAP_STR_COPY, - offsetof(nxt_router_listener_conf_t, application), - }, -}; - - -static nxt_conf_map_t nxt_router_http_conf[] = { - { - nxt_string("header_buffer_size"), - NXT_CONF_MAP_SIZE, - offsetof(nxt_socket_conf_t, header_buffer_size), - }, - - { - nxt_string("large_header_buffer_size"), - NXT_CONF_MAP_SIZE, - offsetof(nxt_socket_conf_t, large_header_buffer_size), - }, - - { - nxt_string("large_header_buffers"), - NXT_CONF_MAP_SIZE, - offsetof(nxt_socket_conf_t, large_header_buffers), - }, - - { - nxt_string("body_buffer_size"), - NXT_CONF_MAP_SIZE, - offsetof(nxt_socket_conf_t, body_buffer_size), - }, - - { - nxt_string("max_body_size"), - NXT_CONF_MAP_SIZE, - offsetof(nxt_socket_conf_t, max_body_size), - }, - - { - nxt_string("idle_timeout"), - NXT_CONF_MAP_MSEC, - offsetof(nxt_socket_conf_t, idle_timeout), - }, - - { - nxt_string("header_read_timeout"), - NXT_CONF_MAP_MSEC, - offsetof(nxt_socket_conf_t, header_read_timeout), - }, - - { - nxt_string("body_read_timeout"), - NXT_CONF_MAP_MSEC, - offsetof(nxt_socket_conf_t, body_read_timeout), - }, - - { - nxt_string("send_timeout"), - NXT_CONF_MAP_MSEC, - offsetof(nxt_socket_conf_t, send_timeout), - }, - - { - nxt_string("body_temp_path"), - NXT_CONF_MAP_STR, - offsetof(nxt_socket_conf_t, body_temp_path), - }, - - { - nxt_string("discard_unsafe_fields"), - NXT_CONF_MAP_INT8, - offsetof(nxt_socket_conf_t, discard_unsafe_fields), - }, - - { - nxt_string("log_route"), - NXT_CONF_MAP_INT8, - offsetof(nxt_socket_conf_t, log_route), - }, - - { - nxt_string("server_version"), - NXT_CONF_MAP_INT8, - offsetof(nxt_socket_conf_t, server_version), - }, -}; - - -static nxt_conf_map_t nxt_router_websocket_conf[] = { - { - nxt_string("max_frame_size"), - NXT_CONF_MAP_SIZE, - offsetof(nxt_websocket_conf_t, max_frame_size), - }, - - { - nxt_string("read_timeout"), - NXT_CONF_MAP_MSEC, - offsetof(nxt_websocket_conf_t, read_timeout), - }, - - { - nxt_string("keepalive_interval"), - NXT_CONF_MAP_MSEC, - offsetof(nxt_websocket_conf_t, keepalive_interval), - }, - -}; - - -static nxt_int_t -nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - u_char *start, u_char *end) -{ - u_char *p; - size_t size; - nxt_mp_t *mp, *app_mp; - uint32_t next, next_target; - nxt_int_t ret; - nxt_str_t name, target; - nxt_app_t *app, *prev; - nxt_str_t *t, *s, *targets; - nxt_uint_t n, i; - nxt_port_t *port; - nxt_router_t *router; - nxt_app_joint_t *app_joint; -#if (NXT_TLS) - nxt_tls_init_t *tls_init; - nxt_conf_value_t *certificate; -#endif -#if (NXT_HAVE_NJS) - nxt_conf_value_t *js_module; -#endif - nxt_conf_value_t *root, *conf, *http, *value, *websocket; - nxt_conf_value_t *applications, *application; - nxt_conf_value_t *listeners, *listener; - nxt_socket_conf_t *skcf; - nxt_router_conf_t *rtcf; - nxt_http_routes_t *routes; - nxt_event_engine_t *engine; - nxt_app_lang_module_t *lang; - nxt_router_app_conf_t apcf; - nxt_router_listener_conf_t lscf; - - static nxt_str_t http_path = nxt_string("/settings/http"); - static nxt_str_t applications_path = nxt_string("/applications"); - static nxt_str_t listeners_path = nxt_string("/listeners"); - static nxt_str_t routes_path = nxt_string("/routes"); - static nxt_str_t access_log_path = nxt_string("/access_log"); -#if (NXT_TLS) - static nxt_str_t certificate_path = nxt_string("/tls/certificate"); - static nxt_str_t conf_commands_path = nxt_string("/tls/conf_commands"); - static nxt_str_t conf_cache_path = nxt_string("/tls/session/cache_size"); - static nxt_str_t conf_timeout_path = nxt_string("/tls/session/timeout"); - static nxt_str_t conf_tickets = nxt_string("/tls/session/tickets"); -#endif -#if (NXT_HAVE_NJS) - static nxt_str_t js_module_path = nxt_string("/settings/js_module"); -#endif - static nxt_str_t static_path = nxt_string("/settings/http/static"); - static nxt_str_t websocket_path = nxt_string("/settings/http/websocket"); - static nxt_str_t forwarded_path = nxt_string("/forwarded"); - static nxt_str_t client_ip_path = nxt_string("/client_ip"); - - root = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); - if (root == NULL) { - nxt_alert(task, "configuration parsing error"); - return NXT_ERROR; - } - - rtcf = tmcf->router_conf; - mp = rtcf->mem_pool; - - ret = nxt_conf_map_object(mp, root, nxt_router_conf, - nxt_nitems(nxt_router_conf), rtcf); - if (ret != NXT_OK) { - nxt_alert(task, "root map error"); - return NXT_ERROR; - } - - if (rtcf->threads == 0) { - rtcf->threads = nxt_ncpu; - } - - conf = nxt_conf_get_path(root, &static_path); - - ret = nxt_router_conf_process_static(task, rtcf, conf); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - router = rtcf->router; - - applications = nxt_conf_get_path(root, &applications_path); - - if (applications != NULL) { - next = 0; - - for ( ;; ) { - application = nxt_conf_next_object_member(applications, - &name, &next); - if (application == NULL) { - break; - } - - nxt_debug(task, "application \"%V\"", &name); - - size = nxt_conf_json_length(application, NULL); - - app_mp = nxt_mp_create(4096, 128, 1024, 64); - if (nxt_slow_path(app_mp == NULL)) { - goto fail; - } - - app = nxt_mp_get(app_mp, sizeof(nxt_app_t) + name.length + size); - if (app == NULL) { - goto app_fail; - } - - nxt_memzero(app, sizeof(nxt_app_t)); - - app->mem_pool = app_mp; - - app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); - app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) - + name.length); - - p = nxt_conf_json_print(app->conf.start, application, NULL); - app->conf.length = p - app->conf.start; - - nxt_assert(app->conf.length <= size); - - nxt_debug(task, "application conf \"%V\"", &app->conf); - - prev = nxt_router_app_find(&router->apps, &name); - - if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { - nxt_mp_destroy(app_mp); - - nxt_queue_remove(&prev->link); - nxt_queue_insert_tail(&tmcf->previous, &prev->link); - - ret = nxt_router_apps_hash_add(rtcf, prev); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - continue; - } - - apcf.processes = 1; - apcf.max_processes = 1; - apcf.spare_processes = 0; - apcf.timeout = 0; - apcf.idle_timeout = 15000; - apcf.limits_value = NULL; - apcf.processes_value = NULL; - apcf.targets_value = NULL; - - app_joint = nxt_malloc(sizeof(nxt_app_joint_t)); - if (nxt_slow_path(app_joint == NULL)) { - goto app_fail; - } - - nxt_memzero(app_joint, sizeof(nxt_app_joint_t)); - - ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, - nxt_nitems(nxt_router_app_conf), &apcf); - if (ret != NXT_OK) { - nxt_alert(task, "application map error"); - goto app_fail; - } - - if (apcf.limits_value != NULL) { - - if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { - nxt_alert(task, "application limits is not object"); - goto app_fail; - } - - ret = nxt_conf_map_object(mp, apcf.limits_value, - nxt_router_app_limits_conf, - nxt_nitems(nxt_router_app_limits_conf), - &apcf); - if (ret != NXT_OK) { - nxt_alert(task, "application limits map error"); - goto app_fail; - } - } - - if (apcf.processes_value != NULL - && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) - { - ret = nxt_conf_map_object(mp, apcf.processes_value, - nxt_router_app_processes_conf, - nxt_nitems(nxt_router_app_processes_conf), - &apcf); - if (ret != NXT_OK) { - nxt_alert(task, "application processes map error"); - goto app_fail; - } - - } else { - apcf.max_processes = apcf.processes; - apcf.spare_processes = apcf.processes; - } - - if (apcf.targets_value != NULL) { - n = nxt_conf_object_members_count(apcf.targets_value); - - targets = nxt_mp_get(app_mp, sizeof(nxt_str_t) * n); - if (nxt_slow_path(targets == NULL)) { - goto app_fail; - } - - next_target = 0; - - for (i = 0; i < n; i++) { - (void) nxt_conf_next_object_member(apcf.targets_value, - &target, &next_target); - - s = nxt_str_dup(app_mp, &targets[i], &target); - if (nxt_slow_path(s == NULL)) { - goto app_fail; - } - } - - } else { - targets = NULL; - } - - nxt_debug(task, "application type: %V", &apcf.type); - nxt_debug(task, "application processes: %D", apcf.processes); - nxt_debug(task, "application request timeout: %M", apcf.timeout); - - lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); - - if (lang == NULL) { - nxt_alert(task, "unknown application type: \"%V\"", &apcf.type); - goto app_fail; - } - - nxt_debug(task, "application language module: \"%s\"", lang->file); - - ret = nxt_thread_mutex_create(&app->mutex); - if (ret != NXT_OK) { - goto app_fail; - } - - nxt_queue_init(&app->ports); - nxt_queue_init(&app->spare_ports); - nxt_queue_init(&app->idle_ports); - nxt_queue_init(&app->ack_waiting_req); - - app->name.length = name.length; - nxt_memcpy(app->name.start, name.start, name.length); - - app->type = lang->type; - app->max_processes = apcf.max_processes; - app->spare_processes = apcf.spare_processes; - app->max_pending_processes = apcf.spare_processes - ? apcf.spare_processes : 1; - app->timeout = apcf.timeout; - app->idle_timeout = apcf.idle_timeout; - - app->targets = targets; - - engine = task->thread->engine; - - app->engine = engine; - - app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; - app->adjust_idle_work.task = &engine->task; - app->adjust_idle_work.obj = app; - - nxt_queue_insert_tail(&tmcf->apps, &app->link); - - ret = nxt_router_apps_hash_add(rtcf, app); - if (nxt_slow_path(ret != NXT_OK)) { - goto app_fail; - } - - nxt_router_app_use(task, app, 1); - - app->joint = app_joint; - - app_joint->use_count = 1; - app_joint->app = app; - - app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS; - app_joint->idle_timer.work_queue = &engine->fast_work_queue; - app_joint->idle_timer.handler = nxt_router_app_idle_timeout; - app_joint->idle_timer.task = &engine->task; - app_joint->idle_timer.log = app_joint->idle_timer.task->log; - - app_joint->free_app_work.handler = nxt_router_free_app; - app_joint->free_app_work.task = &engine->task; - app_joint->free_app_work.obj = app_joint; - - port = nxt_port_new(task, NXT_SHARED_PORT_ID, nxt_pid, - NXT_PROCESS_APP); - if (nxt_slow_path(port == NULL)) { - return NXT_ERROR; - } - - ret = nxt_port_socket_init(task, port, 0); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_use(task, port, -1); - return NXT_ERROR; - } - - ret = nxt_router_app_queue_init(task, port); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_write_close(port); - nxt_port_read_close(port); - nxt_port_use(task, port, -1); - return NXT_ERROR; - } - - nxt_port_write_enable(task, port); - port->app = app; - - app->shared_port = port; - - nxt_thread_mutex_create(&app->outgoing.mutex); - } - } - - conf = nxt_conf_get_path(root, &routes_path); - if (nxt_fast_path(conf != NULL)) { - routes = nxt_http_routes_create(task, tmcf, conf); - if (nxt_slow_path(routes == NULL)) { - return NXT_ERROR; - } - - rtcf->routes = routes; - } - - ret = nxt_upstreams_create(task, tmcf, root); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - http = nxt_conf_get_path(root, &http_path); -#if 0 - if (http == NULL) { - nxt_alert(task, "no \"http\" block"); - return NXT_ERROR; - } -#endif - - websocket = nxt_conf_get_path(root, &websocket_path); - - listeners = nxt_conf_get_path(root, &listeners_path); - - if (listeners != NULL) { - next = 0; - - for ( ;; ) { - listener = nxt_conf_next_object_member(listeners, &name, &next); - if (listener == NULL) { - break; - } - - skcf = nxt_router_socket_conf(task, tmcf, &name); - if (skcf == NULL) { - goto fail; - } - - nxt_memzero(&lscf, sizeof(lscf)); - - ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, - nxt_nitems(nxt_router_listener_conf), - &lscf); - if (ret != NXT_OK) { - nxt_alert(task, "listener map error"); - goto fail; - } - - nxt_debug(task, "application: %V", &lscf.application); - - // STUB, default values if http block is not defined. - skcf->header_buffer_size = 2048; - skcf->large_header_buffer_size = 8192; - skcf->large_header_buffers = 4; - skcf->discard_unsafe_fields = 1; - skcf->body_buffer_size = 16 * 1024; - skcf->max_body_size = 8 * 1024 * 1024; - skcf->proxy_header_buffer_size = 64 * 1024; - skcf->proxy_buffer_size = 4096; - skcf->proxy_buffers = 256; - skcf->idle_timeout = 180 * 1000; - skcf->header_read_timeout = 30 * 1000; - skcf->body_read_timeout = 30 * 1000; - skcf->send_timeout = 30 * 1000; - skcf->proxy_timeout = 60 * 1000; - skcf->proxy_send_timeout = 30 * 1000; - skcf->proxy_read_timeout = 30 * 1000; - - skcf->server_version = 1; - - skcf->websocket_conf.max_frame_size = 1024 * 1024; - skcf->websocket_conf.read_timeout = 60 * 1000; - skcf->websocket_conf.keepalive_interval = 30 * 1000; - - nxt_str_null(&skcf->body_temp_path); - - if (http != NULL) { - ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, - nxt_nitems(nxt_router_http_conf), - skcf); - if (ret != NXT_OK) { - nxt_alert(task, "http map error"); - goto fail; - } - } - - if (websocket != NULL) { - ret = nxt_conf_map_object(mp, websocket, - nxt_router_websocket_conf, - nxt_nitems(nxt_router_websocket_conf), - &skcf->websocket_conf); - if (ret != NXT_OK) { - nxt_alert(task, "websocket map error"); - goto fail; - } - } - - t = &skcf->body_temp_path; - - if (t->length == 0) { - t->start = (u_char *) task->thread->runtime->tmp; - t->length = nxt_strlen(t->start); - } - - conf = nxt_conf_get_path(listener, &forwarded_path); - - if (conf != NULL) { - skcf->forwarded = nxt_router_conf_forward(task, mp, conf); - if (nxt_slow_path(skcf->forwarded == NULL)) { - return NXT_ERROR; - } - } - - conf = nxt_conf_get_path(listener, &client_ip_path); - - if (conf != NULL) { - skcf->client_ip = nxt_router_conf_forward(task, mp, conf); - if (nxt_slow_path(skcf->client_ip == NULL)) { - return NXT_ERROR; - } - } - -#if (NXT_TLS) - certificate = nxt_conf_get_path(listener, &certificate_path); - - if (certificate != NULL) { - tls_init = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_tls_init_t)); - if (nxt_slow_path(tls_init == NULL)) { - return NXT_ERROR; - } - - tls_init->cache_size = 0; - tls_init->timeout = 300; - - value = nxt_conf_get_path(listener, &conf_cache_path); - if (value != NULL) { - tls_init->cache_size = nxt_conf_get_number(value); - } - - value = nxt_conf_get_path(listener, &conf_timeout_path); - if (value != NULL) { - tls_init->timeout = nxt_conf_get_number(value); - } - - tls_init->conf_cmds = nxt_conf_get_path(listener, - &conf_commands_path); - - tls_init->tickets_conf = nxt_conf_get_path(listener, - &conf_tickets); - - n = nxt_conf_array_elements_count_or_1(certificate); - - for (i = 0; i < n; i++) { - value = nxt_conf_get_array_element_or_itself(certificate, - i); - nxt_assert(value != NULL); - - ret = nxt_router_conf_tls_insert(tmcf, value, skcf, - tls_init, i == 0); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - } - } -#endif - - skcf->listen->handler = nxt_http_conn_init; - skcf->router_conf = rtcf; - skcf->router_conf->count++; - - if (lscf.pass.length != 0) { - skcf->action = nxt_http_action_create(task, tmcf, &lscf.pass); - - /* COMPATIBILITY: listener application. */ - } else if (lscf.application.length > 0) { - skcf->action = nxt_http_pass_application(task, rtcf, - &lscf.application); - } - - if (nxt_slow_path(skcf->action == NULL)) { - goto fail; - } - } - } - - ret = nxt_http_routes_resolve(task, tmcf); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - value = nxt_conf_get_path(root, &access_log_path); - - if (value != NULL) { - ret = nxt_router_access_log_create(task, rtcf, value); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - } - -#if (NXT_HAVE_NJS) - js_module = nxt_conf_get_path(root, &js_module_path); - - if (js_module != NULL) { - if (nxt_conf_type(js_module) == NXT_CONF_ARRAY) { - n = nxt_conf_array_elements_count(js_module); - - for (i = 0; i < n; i++) { - value = nxt_conf_get_array_element(js_module, i); - - ret = nxt_router_js_module_insert(tmcf, value); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - } - - } else { - /* NXT_CONF_STRING */ - - ret = nxt_router_js_module_insert(tmcf, js_module); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - } - } - -#endif - - nxt_queue_add(&deleting_sockets, &router->sockets); - nxt_queue_init(&router->sockets); - - return NXT_OK; - -app_fail: - - nxt_mp_destroy(app_mp); - -fail: - - nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { - - nxt_queue_remove(&app->link); - nxt_thread_mutex_destroy(&app->mutex); - nxt_mp_destroy(app->mem_pool); - - } nxt_queue_loop; - - return NXT_ERROR; -} - - -#if (NXT_TLS) - -static nxt_int_t -nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *value, nxt_socket_conf_t *skcf, - nxt_tls_init_t *tls_init, nxt_bool_t last) -{ - nxt_router_tlssock_t *tls; - - tls = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_router_tlssock_t)); - if (nxt_slow_path(tls == NULL)) { - return NXT_ERROR; - } - - tls->tls_init = tls_init; - tls->socket_conf = skcf; - tls->temp_conf = tmcf; - tls->last = last; - nxt_conf_get_string(value, &tls->name); - - nxt_queue_insert_tail(&tmcf->tls, &tls->link); - - return NXT_OK; -} - -#endif - - -#if (NXT_HAVE_NJS) - -static void -nxt_router_js_module_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_int_t ret; - nxt_str_t text; - nxt_router_conf_t *rtcf; - nxt_router_temp_conf_t *tmcf; - nxt_router_js_module_t *js_module; - - nxt_debug(task, "auto module rpc handler"); - - js_module = data; - tmcf = js_module->temp_conf; - - if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { - goto fail; - } - - rtcf = tmcf->router_conf; - - ret = nxt_script_file_read(msg->fd[0], &text); - - nxt_fd_close(msg->fd[0]); - - if (nxt_slow_path(ret == NXT_ERROR)) { - goto fail; - } - - if (text.length > 0) { - ret = nxt_js_add_module(rtcf->tstr_state->jcf, &js_module->name, &text); - - nxt_free(text.start); - - if (nxt_slow_path(ret == NXT_ERROR)) { - goto fail; - } - } - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - nxt_router_conf_apply, task, tmcf, NULL); - return; - -fail: - - nxt_router_conf_error(task, tmcf); -} - - -static nxt_int_t -nxt_router_js_module_insert(nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *value) -{ - nxt_router_js_module_t *js_module; - - js_module = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_router_js_module_t)); - if (nxt_slow_path(js_module == NULL)) { - return NXT_ERROR; - } - - js_module->temp_conf = tmcf; - nxt_conf_get_string(value, &js_module->name); - - nxt_queue_insert_tail(&tmcf->js_modules, &js_module->link); - - return NXT_OK; -} - -#endif - - -static nxt_int_t -nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, - nxt_conf_value_t *conf) -{ - uint32_t next, i; - nxt_mp_t *mp; - nxt_str_t *type, exten, str, *s; - nxt_int_t ret; - nxt_uint_t exts; - nxt_conf_value_t *mtypes_conf, *ext_conf, *value; - - static nxt_str_t mtypes_path = nxt_string("/mime_types"); - - mp = rtcf->mem_pool; - - ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - if (conf == NULL) { - return NXT_OK; - } - - mtypes_conf = nxt_conf_get_path(conf, &mtypes_path); - - if (mtypes_conf != NULL) { - next = 0; - - for ( ;; ) { - ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next); - - if (ext_conf == NULL) { - break; - } - - type = nxt_str_dup(mp, NULL, &str); - if (nxt_slow_path(type == NULL)) { - return NXT_ERROR; - } - - if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) { - s = nxt_conf_get_string_dup(ext_conf, mp, &exten); - if (nxt_slow_path(s == NULL)) { - return NXT_ERROR; - } - - ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash, - &exten, type); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - continue; - } - - exts = nxt_conf_array_elements_count(ext_conf); - - for (i = 0; i < exts; i++) { - value = nxt_conf_get_array_element(ext_conf, i); - - s = nxt_conf_get_string_dup(value, mp, &exten); - if (nxt_slow_path(s == NULL)) { - return NXT_ERROR; - } - - ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash, - &exten, type); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - } - } - - return NXT_OK; -} - - -static nxt_http_forward_t * -nxt_router_conf_forward(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *conf) -{ - nxt_int_t ret; - nxt_conf_value_t *header_conf, *client_ip_conf, *protocol_conf; - nxt_conf_value_t *source_conf, *recursive_conf; - nxt_http_forward_t *forward; - nxt_http_route_addr_rule_t *source; - - static nxt_str_t header_path = nxt_string("/header"); - static nxt_str_t client_ip_path = nxt_string("/client_ip"); - static nxt_str_t protocol_path = nxt_string("/protocol"); - static nxt_str_t source_path = nxt_string("/source"); - static nxt_str_t recursive_path = nxt_string("/recursive"); - - header_conf = nxt_conf_get_path(conf, &header_path); - - if (header_conf != NULL) { - client_ip_conf = nxt_conf_get_path(conf, &header_path); - protocol_conf = NULL; - - } else { - client_ip_conf = nxt_conf_get_path(conf, &client_ip_path); - protocol_conf = nxt_conf_get_path(conf, &protocol_path); - } - - source_conf = nxt_conf_get_path(conf, &source_path); - recursive_conf = nxt_conf_get_path(conf, &recursive_path); - - if (source_conf == NULL - || (protocol_conf == NULL && client_ip_conf == NULL)) - { - return NULL; - } - - forward = nxt_mp_zget(mp, sizeof(nxt_http_forward_t)); - if (nxt_slow_path(forward == NULL)) { - return NULL; - } - - source = nxt_http_route_addr_rule_create(task, mp, source_conf); - if (nxt_slow_path(source == NULL)) { - return NULL; - } - - forward->source = source; - - if (recursive_conf != NULL) { - forward->recursive = nxt_conf_get_boolean(recursive_conf); - } - - if (client_ip_conf != NULL) { - ret = nxt_router_conf_forward_header(mp, client_ip_conf, - &forward->client_ip); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - } - - if (protocol_conf != NULL) { - ret = nxt_router_conf_forward_header(mp, protocol_conf, - &forward->protocol); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - } - - return forward; -} - - -static nxt_int_t -nxt_router_conf_forward_header(nxt_mp_t *mp, nxt_conf_value_t *conf, - nxt_http_forward_header_t *fh) -{ - char c; - size_t i; - uint32_t hash; - - fh->header = nxt_conf_get_string_dup(conf, mp, NULL); - if (nxt_slow_path(fh->header == NULL)) { - return NXT_ERROR; - } - - hash = NXT_HTTP_FIELD_HASH_INIT; - - for (i = 0; i < fh->header->length; i++) { - c = fh->header->start[i]; - hash = nxt_http_field_hash_char(hash, nxt_lowcase(c)); - } - - hash = nxt_http_field_hash_end(hash) & 0xFFFF; - - fh->header_hash = hash; - - return NXT_OK; -} - - -static nxt_app_t * -nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) -{ - nxt_app_t *app; - - nxt_queue_each(app, queue, nxt_app_t, link) { - - if (nxt_strstr_eq(name, &app->name)) { - return app; - } - - } nxt_queue_loop; - - return NULL; -} - - -static nxt_int_t -nxt_router_app_queue_init(nxt_task_t *task, nxt_port_t *port) -{ - void *mem; - nxt_int_t fd; - - fd = nxt_shm_open(task, sizeof(nxt_app_queue_t)); - if (nxt_slow_path(fd == -1)) { - return NXT_ERROR; - } - - mem = nxt_mem_mmap(NULL, sizeof(nxt_app_queue_t), - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (nxt_slow_path(mem == MAP_FAILED)) { - nxt_fd_close(fd); - - return NXT_ERROR; - } - - nxt_app_queue_init(mem); - - port->queue_fd = fd; - port->queue = mem; - - return NXT_OK; -} - - -static nxt_int_t -nxt_router_port_queue_init(nxt_task_t *task, nxt_port_t *port) -{ - void *mem; - nxt_int_t fd; - - fd = nxt_shm_open(task, sizeof(nxt_port_queue_t)); - if (nxt_slow_path(fd == -1)) { - return NXT_ERROR; - } - - mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t), - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (nxt_slow_path(mem == MAP_FAILED)) { - nxt_fd_close(fd); - - return NXT_ERROR; - } - - nxt_port_queue_init(mem); - - port->queue_fd = fd; - port->queue = mem; - - return NXT_OK; -} - - -static nxt_int_t -nxt_router_port_queue_map(nxt_task_t *task, nxt_port_t *port, nxt_fd_t fd) -{ - void *mem; - - nxt_assert(fd != -1); - - mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t), - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (nxt_slow_path(mem == MAP_FAILED)) { - - return NXT_ERROR; - } - - port->queue = mem; - - return NXT_OK; -} - - -static const nxt_lvlhsh_proto_t nxt_router_apps_hash_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_router_apps_hash_test, - nxt_mp_lvlhsh_alloc, - nxt_mp_lvlhsh_free, -}; - - -static nxt_int_t -nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_app_t *app; - - app = data; - - return nxt_strstr_eq(&lhq->key, &app->name) ? NXT_OK : NXT_DECLINED; -} - - -static nxt_int_t -nxt_router_apps_hash_add(nxt_router_conf_t *rtcf, nxt_app_t *app) -{ - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_djb_hash(app->name.start, app->name.length); - lhq.replace = 0; - lhq.key = app->name; - lhq.value = app; - lhq.proto = &nxt_router_apps_hash_proto; - lhq.pool = rtcf->mem_pool; - - switch (nxt_lvlhsh_insert(&rtcf->apps_hash, &lhq)) { - - case NXT_OK: - return NXT_OK; - - case NXT_DECLINED: - nxt_thread_log_alert("router app hash adding failed: " - "\"%V\" is already in hash", &lhq.key); - /* Fall through. */ - default: - return NXT_ERROR; - } -} - - -static nxt_app_t * -nxt_router_apps_hash_get(nxt_router_conf_t *rtcf, nxt_str_t *name) -{ - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_djb_hash(name->start, name->length); - lhq.key = *name; - lhq.proto = &nxt_router_apps_hash_proto; - - if (nxt_lvlhsh_find(&rtcf->apps_hash, &lhq) != NXT_OK) { - return NULL; - } - - return lhq.value; -} - - -static void -nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf, int i) -{ - nxt_app_t *app; - nxt_lvlhsh_each_t lhe; - - nxt_lvlhsh_each_init(&lhe, &nxt_router_apps_hash_proto); - - for ( ;; ) { - app = nxt_lvlhsh_each(&rtcf->apps_hash, &lhe); - - if (app == NULL) { - break; - } - - nxt_router_app_use(task, app, i); - } -} - - -typedef struct { - nxt_app_t *app; - nxt_int_t target; -} nxt_http_app_conf_t; - - -nxt_int_t -nxt_router_application_init(nxt_router_conf_t *rtcf, nxt_str_t *name, - nxt_str_t *target, nxt_http_action_t *action) -{ - nxt_app_t *app; - nxt_str_t *targets; - nxt_uint_t i; - nxt_http_app_conf_t *conf; - - app = nxt_router_apps_hash_get(rtcf, name); - if (app == NULL) { - return NXT_DECLINED; - } - - conf = nxt_mp_get(rtcf->mem_pool, sizeof(nxt_http_app_conf_t)); - if (nxt_slow_path(conf == NULL)) { - return NXT_ERROR; - } - - action->handler = nxt_http_application_handler; - action->u.conf = conf; - - conf->app = app; - - if (target != NULL && target->length != 0) { - targets = app->targets; - - for (i = 0; !nxt_strstr_eq(target, &targets[i]); i++); - - conf->target = i; - - } else { - conf->target = 0; - } - - return NXT_OK; -} - - -static nxt_socket_conf_t * -nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_str_t *name) -{ - size_t size; - nxt_int_t ret; - nxt_bool_t wildcard; - nxt_sockaddr_t *sa; - nxt_socket_conf_t *skcf; - nxt_listen_socket_t *ls; - - sa = nxt_sockaddr_parse(tmcf->mem_pool, name); - if (nxt_slow_path(sa == NULL)) { - nxt_alert(task, "invalid listener \"%V\"", name); - return NULL; - } - - sa->type = SOCK_STREAM; - - nxt_debug(task, "router listener: \"%*s\"", - (size_t) sa->length, nxt_sockaddr_start(sa)); - - skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t)); - if (nxt_slow_path(skcf == NULL)) { - return NULL; - } - - size = nxt_sockaddr_size(sa); - - ret = nxt_router_listen_socket_find(tmcf, skcf, sa); - - if (ret != NXT_OK) { - - ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); - if (nxt_slow_path(ls == NULL)) { - return NULL; - } - - skcf->listen = ls; - - ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); - nxt_memcpy(ls->sockaddr, sa, size); - - nxt_listen_socket_remote_size(ls); - - ls->socket = -1; - ls->backlog = NXT_LISTEN_BACKLOG; - ls->flags = NXT_NONBLOCK; - ls->read_after_accept = 1; - } - - switch (sa->u.sockaddr.sa_family) { -#if (NXT_HAVE_UNIX_DOMAIN) - case AF_UNIX: - wildcard = 0; - break; -#endif -#if (NXT_INET6) - case AF_INET6: - wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); - break; -#endif - case AF_INET: - default: - wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); - break; - } - - if (!wildcard) { - skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size); - if (nxt_slow_path(skcf->sockaddr == NULL)) { - return NULL; - } - - nxt_memcpy(skcf->sockaddr, sa, size); - } - - return skcf; -} - - -static nxt_int_t -nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, - nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) -{ - nxt_router_t *router; - nxt_queue_link_t *qlk; - nxt_socket_conf_t *skcf; - - router = tmcf->router_conf->router; - - for (qlk = nxt_queue_first(&router->sockets); - qlk != nxt_queue_tail(&router->sockets); - qlk = nxt_queue_next(qlk)) - { - skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); - - if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { - nskcf->listen = skcf->listen; - - nxt_queue_remove(qlk); - nxt_queue_insert_tail(&keeping_sockets, qlk); - - nxt_queue_insert_tail(&updating_sockets, &nskcf->link); - - return NXT_OK; - } - } - - nxt_queue_insert_tail(&pending_sockets, &nskcf->link); - - return NXT_DECLINED; -} - - -static void -nxt_router_listen_socket_rpc_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) -{ - size_t size; - uint32_t stream; - nxt_int_t ret; - nxt_buf_t *b; - nxt_port_t *main_port, *router_port; - nxt_runtime_t *rt; - nxt_socket_rpc_t *rpc; - - rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); - if (rpc == NULL) { - goto fail; - } - - rpc->socket_conf = skcf; - rpc->temp_conf = tmcf; - - size = nxt_sockaddr_size(skcf->listen->sockaddr); - - b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); - if (b == NULL) { - goto fail; - } - - b->completion_handler = nxt_buf_dummy_completion; - - b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); - - rt = task->thread->runtime; - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - stream = nxt_port_rpc_register_handler(task, router_port, - nxt_router_listen_socket_ready, - nxt_router_listen_socket_error, - main_port->pid, rpc); - if (nxt_slow_path(stream == 0)) { - goto fail; - } - - ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, - stream, router_port->id, b); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_rpc_cancel(task, router_port, stream); - goto fail; - } - - return; - -fail: - - nxt_router_conf_error(task, tmcf); -} - - -static void -nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_int_t ret; - nxt_socket_t s; - nxt_socket_rpc_t *rpc; - - rpc = data; - - s = msg->fd[0]; - - ret = nxt_socket_nonblocking(task, s); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); - - ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - rpc->socket_conf->listen->socket = s; - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - nxt_router_conf_apply, task, rpc->temp_conf, NULL); - - return; - -fail: - - nxt_socket_close(task, s); - - nxt_router_conf_error(task, rpc->temp_conf); -} - - -static void -nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_socket_rpc_t *rpc; - nxt_router_temp_conf_t *tmcf; - - rpc = data; - tmcf = rpc->temp_conf; - -#if 0 - u_char *p; - size_t size; - uint8_t error; - nxt_buf_t *in, *out; - nxt_sockaddr_t *sa; - - static nxt_str_t socket_errors[] = { - nxt_string("ListenerSystem"), - nxt_string("ListenerNoIPv6"), - nxt_string("ListenerPort"), - nxt_string("ListenerInUse"), - nxt_string("ListenerNoAddress"), - nxt_string("ListenerNoAccess"), - nxt_string("ListenerPath"), - }; - - sa = rpc->socket_conf->listen->sockaddr; - - in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); - - if (nxt_slow_path(in == NULL)) { - return; - } - - p = in->mem.pos; - - error = *p++; - - size = nxt_length("listen socket error: ") - + nxt_length("{listener: \"\", code:\"\", message: \"\"}") - + sa->length + socket_errors[error].length + (in->mem.free - p); - - out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); - if (nxt_slow_path(out == NULL)) { - return; - } - - out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, - "listen socket error: " - "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", - (size_t) sa->length, nxt_sockaddr_start(sa), - &socket_errors[error], in->mem.free - p, p); - - nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); -#endif - - nxt_router_conf_error(task, tmcf); -} - - -#if (NXT_TLS) - -static void -nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_mp_t *mp; - nxt_int_t ret; - nxt_tls_conf_t *tlscf; - nxt_router_tlssock_t *tls; - nxt_tls_bundle_conf_t *bundle; - nxt_router_temp_conf_t *tmcf; - - nxt_debug(task, "tls rpc handler"); - - tls = data; - tmcf = tls->temp_conf; - - if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { - goto fail; - } - - mp = tmcf->router_conf->mem_pool; - - if (tls->socket_conf->tls == NULL) { - tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); - if (nxt_slow_path(tlscf == NULL)) { - goto fail; - } - - tlscf->no_wait_shutdown = 1; - tls->socket_conf->tls = tlscf; - - } else { - tlscf = tls->socket_conf->tls; - } - - tls->tls_init->conf = tlscf; - - bundle = nxt_mp_get(mp, sizeof(nxt_tls_bundle_conf_t)); - if (nxt_slow_path(bundle == NULL)) { - goto fail; - } - - if (nxt_slow_path(nxt_str_dup(mp, &bundle->name, &tls->name) == NULL)) { - goto fail; - } - - bundle->chain_file = msg->fd[0]; - bundle->next = tlscf->bundle; - tlscf->bundle = bundle; - - ret = task->thread->runtime->tls->server_init(task, mp, tls->tls_init, - tls->last); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - nxt_router_conf_apply, task, tmcf, NULL); - return; - -fail: - - nxt_router_conf_error(task, tmcf); -} - -#endif - - -static void -nxt_router_app_rpc_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_app_t *app) -{ - size_t size; - uint32_t stream; - nxt_fd_t port_fd, queue_fd; - nxt_int_t ret; - nxt_buf_t *b; - nxt_port_t *router_port, *dport; - nxt_runtime_t *rt; - nxt_app_rpc_t *rpc; - - rt = task->thread->runtime; - - dport = app->proto_port; - - if (dport == NULL) { - nxt_debug(task, "app '%V' prototype prefork", &app->name); - - size = app->name.length + 1 + app->conf.length; - - b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); - if (nxt_slow_path(b == NULL)) { - goto fail; - } - - b->completion_handler = nxt_buf_dummy_completion; - - nxt_buf_cpystr(b, &app->name); - *b->mem.free++ = '\0'; - nxt_buf_cpystr(b, &app->conf); - - dport = rt->port_by_type[NXT_PROCESS_MAIN]; - - port_fd = app->shared_port->pair[0]; - queue_fd = app->shared_port->queue_fd; - - } else { - nxt_debug(task, "app '%V' prefork", &app->name); - - b = NULL; - port_fd = -1; - queue_fd = -1; - } - - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - rpc = nxt_port_rpc_register_handler_ex(task, router_port, - nxt_router_app_prefork_ready, - nxt_router_app_prefork_error, - sizeof(nxt_app_rpc_t)); - if (nxt_slow_path(rpc == NULL)) { - goto fail; - } - - rpc->app = app; - rpc->temp_conf = tmcf; - rpc->proto = (b != NULL); - - stream = nxt_port_rpc_ex_stream(rpc); - - ret = nxt_port_socket_write2(task, dport, NXT_PORT_MSG_START_PROCESS, - port_fd, queue_fd, stream, router_port->id, b); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_rpc_cancel(task, router_port, stream); - goto fail; - } - - if (b == NULL) { - nxt_port_rpc_ex_set_peer(task, router_port, rpc, dport->pid); - - app->pending_processes++; - } - - return; - -fail: - - nxt_router_conf_error(task, tmcf); -} - - -static void -nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_app_t *app; - nxt_port_t *port; - nxt_app_rpc_t *rpc; - nxt_event_engine_t *engine; - - rpc = data; - app = rpc->app; - - port = msg->u.new_port; - - nxt_assert(port != NULL); - nxt_assert(port->id == 0); - - if (rpc->proto) { - nxt_assert(app->proto_port == NULL); - nxt_assert(port->type == NXT_PROCESS_PROTOTYPE); - - nxt_port_inc_use(port); - - app->proto_port = port; - port->app = app; - - nxt_router_app_rpc_create(task, rpc->temp_conf, app); - - return; - } - - nxt_assert(port->type == NXT_PROCESS_APP); - - port->app = app; - port->main_app_port = port; - - app->pending_processes--; - app->processes++; - app->idle_processes++; - - engine = task->thread->engine; - - nxt_queue_insert_tail(&app->ports, &port->app_link); - nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); - - nxt_debug(task, "app '%V' move new port %PI:%d to spare_ports", - &app->name, port->pid, port->id); - - nxt_port_hash_add(&app->port_hash, port); - app->port_hash_count++; - - port->idle_start = 0; - - nxt_port_inc_use(port); - - nxt_port_socket_write(task, port, NXT_PORT_MSG_PORT_ACK, -1, 0, 0, NULL); - - nxt_work_queue_add(&engine->fast_work_queue, - nxt_router_conf_apply, task, rpc->temp_conf, NULL); -} - - -static void -nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_app_t *app; - nxt_app_rpc_t *rpc; - nxt_router_temp_conf_t *tmcf; - - rpc = data; - app = rpc->app; - tmcf = rpc->temp_conf; - - if (rpc->proto) { - nxt_log(task, NXT_LOG_WARN, "failed to start prototype \"%V\"", - &app->name); - - } else { - nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", - &app->name); - - app->pending_processes--; - } - - nxt_router_conf_error(task, tmcf); -} - - -static nxt_int_t -nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, - nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) -{ - nxt_int_t ret; - nxt_uint_t n, threads; - nxt_queue_link_t *qlk; - nxt_router_engine_conf_t *recf; - - threads = tmcf->router_conf->threads; - - tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, - sizeof(nxt_router_engine_conf_t)); - if (nxt_slow_path(tmcf->engines == NULL)) { - return NXT_ERROR; - } - - n = 0; - - for (qlk = nxt_queue_first(&router->engines); - qlk != nxt_queue_tail(&router->engines); - qlk = nxt_queue_next(qlk)) - { - recf = nxt_array_zero_add(tmcf->engines); - if (nxt_slow_path(recf == NULL)) { - return NXT_ERROR; - } - - recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); - - if (n < threads) { - recf->action = NXT_ROUTER_ENGINE_KEEP; - ret = nxt_router_engine_conf_update(tmcf, recf); - - } else { - recf->action = NXT_ROUTER_ENGINE_DELETE; - ret = nxt_router_engine_conf_delete(tmcf, recf); - } - - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - n++; - } - - tmcf->new_threads = n; - - while (n < threads) { - recf = nxt_array_zero_add(tmcf->engines); - if (nxt_slow_path(recf == NULL)) { - return NXT_ERROR; - } - - recf->action = NXT_ROUTER_ENGINE_ADD; - - recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); - if (nxt_slow_path(recf->engine == NULL)) { - return NXT_ERROR; - } - - ret = nxt_router_engine_conf_create(tmcf, recf); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - n++; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf) -{ - nxt_int_t ret; - - ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets, - nxt_router_listen_socket_create); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets, - nxt_router_listen_socket_create); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - return ret; -} - - -static nxt_int_t -nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf) -{ - nxt_int_t ret; - - ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets, - nxt_router_listen_socket_create); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets, - nxt_router_listen_socket_update); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - ret = nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - return ret; -} - - -static nxt_int_t -nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf) -{ - nxt_int_t ret; - - ret = nxt_router_engine_quit(tmcf, recf); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - ret = nxt_router_engine_joints_delete(tmcf, recf, &updating_sockets); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - return nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets); -} - - -static nxt_int_t -nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, - nxt_work_handler_t handler) -{ - nxt_int_t ret; - nxt_joint_job_t *job; - nxt_queue_link_t *qlk; - nxt_socket_conf_t *skcf; - nxt_socket_conf_joint_t *joint; - - for (qlk = nxt_queue_first(sockets); - qlk != nxt_queue_tail(sockets); - qlk = nxt_queue_next(qlk)) - { - job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); - if (nxt_slow_path(job == NULL)) { - return NXT_ERROR; - } - - job->work.next = recf->jobs; - recf->jobs = &job->work; - - job->task = tmcf->engine->task; - job->work.handler = handler; - job->work.task = &job->task; - job->work.obj = job; - job->tmcf = tmcf; - - tmcf->count++; - - joint = nxt_mp_alloc(tmcf->router_conf->mem_pool, - sizeof(nxt_socket_conf_joint_t)); - if (nxt_slow_path(joint == NULL)) { - return NXT_ERROR; - } - - job->work.data = joint; - - ret = nxt_upstreams_joint_create(tmcf, &joint->upstreams); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - joint->count = 1; - - skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); - skcf->count++; - joint->socket_conf = skcf; - - joint->engine = recf->engine; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf) -{ - nxt_joint_job_t *job; - - job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); - if (nxt_slow_path(job == NULL)) { - return NXT_ERROR; - } - - job->work.next = recf->jobs; - recf->jobs = &job->work; - - job->task = tmcf->engine->task; - job->work.handler = nxt_router_worker_thread_quit; - job->work.task = &job->task; - job->work.obj = NULL; - job->work.data = NULL; - job->tmcf = NULL; - - return NXT_OK; -} - - -static nxt_int_t -nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, - nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) -{ - nxt_joint_job_t *job; - nxt_queue_link_t *qlk; - - for (qlk = nxt_queue_first(sockets); - qlk != nxt_queue_tail(sockets); - qlk = nxt_queue_next(qlk)) - { - job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); - if (nxt_slow_path(job == NULL)) { - return NXT_ERROR; - } - - job->work.next = recf->jobs; - recf->jobs = &job->work; - - job->task = tmcf->engine->task; - job->work.handler = nxt_router_listen_socket_delete; - job->work.task = &job->task; - job->work.obj = job; - job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); - job->tmcf = tmcf; - - tmcf->count++; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, - nxt_router_temp_conf_t *tmcf) -{ - nxt_int_t ret; - nxt_uint_t i, threads; - nxt_router_engine_conf_t *recf; - - recf = tmcf->engines->elts; - threads = tmcf->router_conf->threads; - - for (i = tmcf->new_threads; i < threads; i++) { - ret = nxt_router_thread_create(task, rt, recf[i].engine); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, - nxt_event_engine_t *engine) -{ - nxt_int_t ret; - nxt_thread_link_t *link; - nxt_thread_handle_t handle; - - link = nxt_zalloc(sizeof(nxt_thread_link_t)); - - if (nxt_slow_path(link == NULL)) { - return NXT_ERROR; - } - - link->start = nxt_router_thread_start; - link->engine = engine; - link->work.handler = nxt_router_thread_exit_handler; - link->work.task = task; - link->work.data = link; - - nxt_queue_insert_tail(&rt->engines, &engine->link); - - ret = nxt_thread_create(&handle, link); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_queue_remove(&engine->link); - } - - return ret; -} - - -static void -nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, - nxt_router_temp_conf_t *tmcf) -{ - nxt_app_t *app; - - nxt_queue_each(app, &router->apps, nxt_app_t, link) { - - nxt_router_app_unlink(task, app); - - } nxt_queue_loop; - - nxt_queue_add(&router->apps, &tmcf->previous); - nxt_queue_add(&router->apps, &tmcf->apps); -} - - -static void -nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) -{ - nxt_uint_t n; - nxt_event_engine_t *engine; - nxt_router_engine_conf_t *recf; - - recf = tmcf->engines->elts; - - for (n = tmcf->engines->nelts; n != 0; n--) { - engine = recf->engine; - - switch (recf->action) { - - case NXT_ROUTER_ENGINE_KEEP: - break; - - case NXT_ROUTER_ENGINE_ADD: - nxt_queue_insert_tail(&router->engines, &engine->link0); - break; - - case NXT_ROUTER_ENGINE_DELETE: - nxt_queue_remove(&engine->link0); - break; - } - - nxt_router_engine_post(engine, recf->jobs); - - recf++; - } -} - - -static void -nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) -{ - nxt_work_t *work, *next; - - for (work = jobs; work != NULL; work = next) { - next = work->next; - work->next = NULL; - - nxt_event_engine_post(engine, work); - } -} - - -static nxt_port_handlers_t nxt_router_app_port_handlers = { - .rpc_error = nxt_port_rpc_handler, - .mmap = nxt_port_mmap_handler, - .data = nxt_port_rpc_handler, - .oosm = nxt_router_oosm_handler, - .req_headers_ack = nxt_port_rpc_handler, -}; - - -static void -nxt_router_thread_start(void *data) -{ - nxt_int_t ret; - nxt_port_t *port; - nxt_task_t *task; - nxt_work_t *work; - nxt_thread_t *thread; - nxt_thread_link_t *link; - nxt_event_engine_t *engine; - - link = data; - engine = link->engine; - task = &engine->task; - - thread = nxt_thread(); - - nxt_event_engine_thread_adopt(engine); - - /* STUB */ - thread->runtime = engine->task.thread->runtime; - - engine->task.thread = thread; - engine->task.log = thread->log; - thread->engine = engine; - thread->task = &engine->task; -#if 0 - thread->fiber = &engine->fibers->fiber; -#endif - - engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); - if (nxt_slow_path(engine->mem_pool == NULL)) { - return; - } - - port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, - NXT_PROCESS_ROUTER); - if (nxt_slow_path(port == NULL)) { - return; - } - - ret = nxt_port_socket_init(task, port, 0); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_use(task, port, -1); - return; - } - - ret = nxt_router_port_queue_init(task, port); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_use(task, port, -1); - return; - } - - engine->port = port; - - nxt_port_enable(task, port, &nxt_router_app_port_handlers); - - work = nxt_zalloc(sizeof(nxt_work_t)); - if (nxt_slow_path(work == NULL)) { - return; - } - - work->handler = nxt_router_rt_add_port; - work->task = link->work.task; - work->obj = work; - work->data = port; - - nxt_event_engine_post(link->work.task->thread->engine, work); - - nxt_event_engine_start(engine); -} - - -static void -nxt_router_rt_add_port(nxt_task_t *task, void *obj, void *data) -{ - nxt_int_t res; - nxt_port_t *port; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - port = data; - - nxt_free(obj); - - res = nxt_port_hash_add(&rt->ports, port); - - if (nxt_fast_path(res == NXT_OK)) { - nxt_port_use(task, port, 1); - } -} - - -static void -nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) -{ - nxt_joint_job_t *job; - nxt_socket_conf_t *skcf; - nxt_listen_event_t *lev; - nxt_listen_socket_t *ls; - nxt_thread_spinlock_t *lock; - nxt_socket_conf_joint_t *joint; - - job = obj; - joint = data; - - nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); - - skcf = joint->socket_conf; - ls = skcf->listen; - - lev = nxt_listen_event(task, ls); - if (nxt_slow_path(lev == NULL)) { - nxt_router_listen_socket_release(task, skcf); - return; - } - - lev->socket.data = joint; - - lock = &skcf->router_conf->router->lock; - - nxt_thread_spin_lock(lock); - ls->count++; - nxt_thread_spin_unlock(lock); - - job->work.next = NULL; - job->work.handler = nxt_router_conf_wait; - - nxt_event_engine_post(job->tmcf->engine, &job->work); -} - - -nxt_inline nxt_listen_event_t * -nxt_router_listen_event(nxt_queue_t *listen_connections, - nxt_socket_conf_t *skcf) -{ - nxt_socket_t fd; - nxt_queue_link_t *qlk; - nxt_listen_event_t *lev; - - fd = skcf->listen->socket; - - for (qlk = nxt_queue_first(listen_connections); - qlk != nxt_queue_tail(listen_connections); - qlk = nxt_queue_next(qlk)) - { - lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); - - if (fd == lev->socket.fd) { - return lev; - } - } - - return NULL; -} - - -static void -nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) -{ - nxt_joint_job_t *job; - nxt_event_engine_t *engine; - nxt_listen_event_t *lev; - nxt_socket_conf_joint_t *joint, *old; - - job = obj; - joint = data; - - engine = task->thread->engine; - - nxt_queue_insert_tail(&engine->joints, &joint->link); - - lev = nxt_router_listen_event(&engine->listen_connections, - joint->socket_conf); - - old = lev->socket.data; - lev->socket.data = joint; - lev->listen = joint->socket_conf->listen; - - job->work.next = NULL; - job->work.handler = nxt_router_conf_wait; - - nxt_event_engine_post(job->tmcf->engine, &job->work); - - /* - * The task is allocated from configuration temporary - * memory pool so it can be freed after engine post operation. - */ - - nxt_router_conf_release(&engine->task, old); -} - - -static void -nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) -{ - nxt_socket_conf_t *skcf; - nxt_listen_event_t *lev; - nxt_event_engine_t *engine; - nxt_socket_conf_joint_t *joint; - - skcf = data; - - engine = task->thread->engine; - - lev = nxt_router_listen_event(&engine->listen_connections, skcf); - - nxt_fd_event_delete(engine, &lev->socket); - - nxt_debug(task, "engine %p: listen socket delete: %d", engine, - lev->socket.fd); - - joint = lev->socket.data; - joint->close_job = obj; - - lev->timer.handler = nxt_router_listen_socket_close; - lev->timer.work_queue = &engine->fast_work_queue; - - nxt_timer_add(engine, &lev->timer, 0); -} - - -static void -nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) -{ - nxt_event_engine_t *engine; - - nxt_debug(task, "router worker thread quit"); - - engine = task->thread->engine; - - engine->shutdown = 1; - - if (nxt_queue_is_empty(&engine->joints)) { - nxt_thread_exit(task->thread); - } -} - - -static void -nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) -{ - nxt_timer_t *timer; - nxt_joint_job_t *job; - nxt_listen_event_t *lev; - nxt_socket_conf_joint_t *joint; - - timer = obj; - lev = nxt_timer_data(timer, nxt_listen_event_t, timer); - - nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, - lev->socket.fd); - - nxt_queue_remove(&lev->link); - - joint = lev->socket.data; - lev->socket.data = NULL; - - /* 'task' refers to lev->task and we cannot use after nxt_free() */ - task = &task->thread->engine->task; - - nxt_router_listen_socket_release(task, joint->socket_conf); - - job = joint->close_job; - job->work.next = NULL; - job->work.handler = nxt_router_conf_wait; - - nxt_event_engine_post(job->tmcf->engine, &job->work); - - nxt_router_listen_event_release(task, lev, joint); -} - - -static void -nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) -{ -#if (NXT_HAVE_UNIX_DOMAIN) - size_t size; - nxt_buf_t *b; - nxt_port_t *main_port; - nxt_runtime_t *rt; - nxt_sockaddr_t *sa; -#endif - nxt_listen_socket_t *ls; - nxt_thread_spinlock_t *lock; - - ls = skcf->listen; - lock = &skcf->router_conf->router->lock; - - nxt_thread_spin_lock(lock); - - nxt_debug(task, "engine %p: listen socket release: ls->count %D", - task->thread->engine, ls->count); - - if (--ls->count != 0) { - ls = NULL; - } - - nxt_thread_spin_unlock(lock); - - if (ls == NULL) { - return; - } - - nxt_socket_close(task, ls->socket); - -#if (NXT_HAVE_UNIX_DOMAIN) - sa = ls->sockaddr; - if (sa->u.sockaddr.sa_family != AF_UNIX - || sa->u.sockaddr_un.sun_path[0] == '\0') - { - goto out_free_ls; - } - - size = nxt_sockaddr_size(ls->sockaddr); - - b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, size, 0); - if (b == NULL) { - goto out_free_ls; - } - - b->mem.free = nxt_cpymem(b->mem.free, ls->sockaddr, size); - - rt = task->thread->runtime; - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - - (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET_UNLINK, - -1, 0, 0, b); - -out_free_ls: -#endif - nxt_free(ls); -} - - -void -nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev, - nxt_socket_conf_joint_t *joint) -{ - nxt_event_engine_t *engine; - - nxt_debug(task, "listen event count: %D", lev->count); - - engine = task->thread->engine; - - if (--lev->count == 0) { - if (lev->next != NULL) { - nxt_sockaddr_cache_free(engine, lev->next); - - nxt_conn_free(task, lev->next); - } - - nxt_free(lev); - } - - if (joint != NULL) { - nxt_router_conf_release(task, joint); - } - - if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) { - nxt_thread_exit(task->thread); - } -} - - -void -nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) -{ - nxt_socket_conf_t *skcf; - nxt_router_conf_t *rtcf; - nxt_thread_spinlock_t *lock; - - nxt_debug(task, "conf joint %p count: %D", joint, joint->count); - - if (--joint->count != 0) { - return; - } - - nxt_queue_remove(&joint->link); - - /* - * The joint content can not be safely used after the critical - * section protected by the spinlock because its memory pool may - * be already destroyed by another thread. - */ - skcf = joint->socket_conf; - rtcf = skcf->router_conf; - lock = &rtcf->router->lock; - - nxt_thread_spin_lock(lock); - - nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, - rtcf, rtcf->count); - - if (--skcf->count != 0) { - skcf = NULL; - rtcf = NULL; - - } else { - nxt_queue_remove(&skcf->link); - - if (--rtcf->count != 0) { - rtcf = NULL; - } - } - - nxt_thread_spin_unlock(lock); - -#if (NXT_TLS) - if (skcf != NULL && skcf->tls != NULL) { - task->thread->runtime->tls->server_free(task, skcf->tls); - } -#endif - - /* TODO remove engine->port */ - - if (rtcf != NULL) { - nxt_debug(task, "old router conf is destroyed"); - - nxt_router_apps_hash_use(task, rtcf, -1); - - nxt_router_access_log_release(task, lock, rtcf->access_log); - - nxt_tstr_state_release(rtcf->tstr_state); - - nxt_mp_thread_adopt(rtcf->mem_pool); - - nxt_mp_destroy(rtcf->mem_pool); - } -} - - -static void -nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_port_t *port; - nxt_thread_link_t *link; - nxt_event_engine_t *engine; - nxt_thread_handle_t handle; - - handle = (nxt_thread_handle_t) (uintptr_t) obj; - link = data; - - nxt_thread_wait(handle); - - engine = link->engine; - - nxt_queue_remove(&engine->link); - - port = engine->port; - - // TODO notify all apps - - port->engine = task->thread->engine; - nxt_mp_thread_adopt(port->mem_pool); - nxt_port_use(task, port, -1); - - nxt_mp_thread_adopt(engine->mem_pool); - nxt_mp_destroy(engine->mem_pool); - - nxt_event_engine_free(engine); - - nxt_free(link); -} - - -static void -nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - size_t b_size, count; - nxt_int_t ret; - nxt_app_t *app; - nxt_buf_t *b, *next; - nxt_port_t *app_port; - nxt_unit_field_t *f; - nxt_http_field_t *field; - nxt_http_request_t *r; - nxt_unit_response_t *resp; - nxt_request_rpc_data_t *req_rpc_data; - - req_rpc_data = data; - - r = req_rpc_data->request; - if (nxt_slow_path(r == NULL)) { - return; - } - - if (r->error) { - nxt_request_rpc_data_unlink(task, req_rpc_data); - return; - } - - app = req_rpc_data->app; - nxt_assert(app != NULL); - - if (msg->port_msg.type == _NXT_PORT_MSG_REQ_HEADERS_ACK) { - nxt_router_req_headers_ack_handler(task, msg, req_rpc_data); - - return; - } - - b = (msg->size == 0) ? NULL : msg->buf; - - if (msg->port_msg.last != 0) { - nxt_debug(task, "router data create last buf"); - - nxt_buf_chain_add(&b, nxt_http_buf_last(r)); - - req_rpc_data->rpc_cancel = 0; - - if (req_rpc_data->apr_action == NXT_APR_REQUEST_FAILED) { - req_rpc_data->apr_action = NXT_APR_GOT_RESPONSE; - } - - nxt_request_rpc_data_unlink(task, req_rpc_data); - - } else { - if (app->timeout != 0) { - r->timer.handler = nxt_router_app_timeout; - r->timer_data = req_rpc_data; - nxt_timer_add(task->thread->engine, &r->timer, app->timeout); - } - } - - if (b == NULL) { - return; - } - - if (msg->buf == b) { - /* Disable instant buffer completion/re-using by port. */ - msg->buf = NULL; - } - - if (r->header_sent) { - nxt_buf_chain_add(&r->out, b); - nxt_http_request_send_body(task, r, NULL); - - } else { - b_size = nxt_buf_is_mem(b) ? nxt_buf_mem_used_size(&b->mem) : 0; - - if (nxt_slow_path(b_size < sizeof(nxt_unit_response_t))) { - nxt_alert(task, "response buffer too small: %z", b_size); - goto fail; - } - - resp = (void *) b->mem.pos; - count = (b_size - sizeof(nxt_unit_response_t)) - / sizeof(nxt_unit_field_t); - - if (nxt_slow_path(count < resp->fields_count)) { - nxt_alert(task, "response buffer too small for fields count: %D", - resp->fields_count); - goto fail; - } - - field = NULL; - - for (f = resp->fields; f < resp->fields + resp->fields_count; f++) { - if (f->skip) { - continue; - } - - field = nxt_list_add(r->resp.fields); - - if (nxt_slow_path(field == NULL)) { - goto fail; - } - - field->hash = f->hash; - field->skip = 0; - field->hopbyhop = 0; - - field->name_length = f->name_length; - field->value_length = f->value_length; - field->name = nxt_unit_sptr_get(&f->name); - field->value = nxt_unit_sptr_get(&f->value); - - ret = nxt_http_field_process(field, &nxt_response_fields_hash, r); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - nxt_debug(task, "header%s: %*s: %*s", - (field->skip ? " skipped" : ""), - (size_t) field->name_length, field->name, - (size_t) field->value_length, field->value); - - if (field->skip) { - r->resp.fields->last->nelts--; - } - } - - r->status = resp->status; - - if (resp->piggyback_content_length != 0) { - b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content); - b->mem.free = b->mem.pos + resp->piggyback_content_length; - - } else { - b->mem.pos = b->mem.free; - } - - if (nxt_buf_mem_used_size(&b->mem) == 0) { - next = b->next; - b->next = NULL; - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - b->completion_handler, task, b, b->parent); - - b = next; - } - - if (b != NULL) { - nxt_buf_chain_add(&r->out, b); - } - - nxt_http_request_header_send(task, r, nxt_http_request_send_body, NULL); - - if (r->websocket_handshake - && r->status == NXT_HTTP_SWITCHING_PROTOCOLS) - { - app_port = req_rpc_data->app_port; - if (nxt_slow_path(app_port == NULL)) { - goto fail; - } - - nxt_thread_mutex_lock(&app->mutex); - - app_port->main_app_port->active_websockets++; - - nxt_thread_mutex_unlock(&app->mutex); - - nxt_router_app_port_release(task, app, app_port, NXT_APR_UPGRADE); - req_rpc_data->apr_action = NXT_APR_CLOSE; - - nxt_debug(task, "stream #%uD upgrade", req_rpc_data->stream); - - r->state = &nxt_http_websocket; - - } else { - r->state = &nxt_http_request_send_state; - } - } - - return; - -fail: - - nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); - - nxt_request_rpc_data_unlink(task, req_rpc_data); -} - - -static void -nxt_router_req_headers_ack_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data) -{ - int res; - nxt_app_t *app; - nxt_buf_t *b; - nxt_bool_t start_process, unlinked; - nxt_port_t *app_port, *main_app_port, *idle_port; - nxt_queue_link_t *idle_lnk; - nxt_http_request_t *r; - - nxt_debug(task, "stream #%uD: got ack from %PI:%d", - req_rpc_data->stream, - msg->port_msg.pid, msg->port_msg.reply_port); - - nxt_port_rpc_ex_set_peer(task, msg->port, req_rpc_data, - msg->port_msg.pid); - - app = req_rpc_data->app; - r = req_rpc_data->request; - - start_process = 0; - unlinked = 0; - - nxt_thread_mutex_lock(&app->mutex); - - if (r->app_link.next != NULL) { - nxt_queue_remove(&r->app_link); - r->app_link.next = NULL; - - unlinked = 1; - } - - app_port = nxt_port_hash_find(&app->port_hash, msg->port_msg.pid, - msg->port_msg.reply_port); - if (nxt_slow_path(app_port == NULL)) { - nxt_thread_mutex_unlock(&app->mutex); - - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - - if (unlinked) { - nxt_mp_release(r->mem_pool); - } - - return; - } - - main_app_port = app_port->main_app_port; - - if (nxt_queue_chk_remove(&main_app_port->idle_link)) { - app->idle_processes--; - - nxt_debug(task, "app '%V' move port %PI:%d out of %s (ack)", - &app->name, main_app_port->pid, main_app_port->id, - (main_app_port->idle_start ? "idle_ports" : "spare_ports")); - - /* Check port was in 'spare_ports' using idle_start field. */ - if (main_app_port->idle_start == 0 - && app->idle_processes >= app->spare_processes) - { - /* - * If there is a vacant space in spare ports, - * move the last idle to spare_ports. - */ - nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); - - idle_lnk = nxt_queue_last(&app->idle_ports); - idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); - nxt_queue_remove(idle_lnk); - - nxt_queue_insert_tail(&app->spare_ports, idle_lnk); - - idle_port->idle_start = 0; - - nxt_debug(task, "app '%V' move port %PI:%d from idle_ports " - "to spare_ports", - &app->name, idle_port->pid, idle_port->id); - } - - if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) { - app->pending_processes++; - start_process = 1; - } - } - - main_app_port->active_requests++; - - nxt_port_inc_use(app_port); - - nxt_thread_mutex_unlock(&app->mutex); - - if (unlinked) { - nxt_mp_release(r->mem_pool); - } - - if (start_process) { - nxt_router_start_app_process(task, app); - } - - nxt_port_use(task, req_rpc_data->app_port, -1); - - req_rpc_data->app_port = app_port; - - b = req_rpc_data->msg_info.buf; - - if (b != NULL) { - /* First buffer is already sent. Start from second. */ - b = b->next; - - req_rpc_data->msg_info.buf->next = NULL; - } - - if (req_rpc_data->msg_info.body_fd != -1 || b != NULL) { - nxt_debug(task, "stream #%uD: send body fd %d", req_rpc_data->stream, - req_rpc_data->msg_info.body_fd); - - if (req_rpc_data->msg_info.body_fd != -1) { - lseek(req_rpc_data->msg_info.body_fd, 0, SEEK_SET); - } - - res = nxt_port_socket_write(task, app_port, NXT_PORT_MSG_REQ_BODY, - req_rpc_data->msg_info.body_fd, - req_rpc_data->stream, - task->thread->engine->port->id, b); - - if (nxt_slow_path(res != NXT_OK)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - } - } - - if (app->timeout != 0) { - r->timer.handler = nxt_router_app_timeout; - r->timer_data = req_rpc_data; - nxt_timer_add(task->thread->engine, &r->timer, app->timeout); - } -} - - -static const nxt_http_request_state_t nxt_http_request_send_state - nxt_aligned(64) = -{ - .error_handler = nxt_http_request_error_handler, -}; - - -static void -nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) -{ - nxt_buf_t *out; - nxt_http_request_t *r; - - r = obj; - - out = r->out; - - if (out != NULL) { - r->out = NULL; - nxt_http_request_send(task, r, out); - } -} - - -static void -nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_request_rpc_data_t *req_rpc_data; - - req_rpc_data = data; - - req_rpc_data->rpc_cancel = 0; - - /* TODO cancel message and return if cancelled. */ - // nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream); - - if (req_rpc_data->request != NULL) { - nxt_http_request_error(task, req_rpc_data->request, - NXT_HTTP_SERVICE_UNAVAILABLE); - } - - nxt_request_rpc_data_unlink(task, req_rpc_data); -} - - -static void -nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - uint32_t n; - nxt_app_t *app; - nxt_bool_t start_process, restarted; - nxt_port_t *port; - nxt_app_joint_t *app_joint; - nxt_app_joint_rpc_t *app_joint_rpc; - - nxt_assert(data != NULL); - - app_joint_rpc = data; - app_joint = app_joint_rpc->app_joint; - port = msg->u.new_port; - - nxt_assert(app_joint != NULL); - nxt_assert(port != NULL); - nxt_assert(port->id == 0); - - app = app_joint->app; - - nxt_router_app_joint_use(task, app_joint, -1); - - if (nxt_slow_path(app == NULL)) { - nxt_debug(task, "new port ready for released app, send QUIT"); - - nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); - - return; - } - - nxt_thread_mutex_lock(&app->mutex); - - restarted = (app->generation != app_joint_rpc->generation); - - if (app_joint_rpc->proto) { - nxt_assert(app->proto_port == NULL); - nxt_assert(port->type == NXT_PROCESS_PROTOTYPE); - - n = app->proto_port_requests; - app->proto_port_requests = 0; - - if (nxt_slow_path(restarted)) { - nxt_thread_mutex_unlock(&app->mutex); - - nxt_debug(task, "proto port ready for restarted app, send QUIT"); - - nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, - NULL); - - } else { - port->app = app; - app->proto_port = port; - - nxt_thread_mutex_unlock(&app->mutex); - - nxt_port_use(task, port, 1); - } - - port = task->thread->runtime->port_by_type[NXT_PROCESS_ROUTER]; - - while (n > 0) { - nxt_router_app_use(task, app, 1); - - nxt_router_start_app_process_handler(task, port, app); - - n--; - } - - return; - } - - nxt_assert(port->type == NXT_PROCESS_APP); - nxt_assert(app->pending_processes != 0); - - app->pending_processes--; - - if (nxt_slow_path(restarted)) { - nxt_debug(task, "new port ready for restarted app, send QUIT"); - - start_process = !task->thread->engine->shutdown - && nxt_router_app_can_start(app) - && nxt_router_app_need_start(app); - - if (start_process) { - app->pending_processes++; - } - - nxt_thread_mutex_unlock(&app->mutex); - - nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); - - if (start_process) { - nxt_router_start_app_process(task, app); - } - - return; - } - - port->app = app; - port->main_app_port = port; - - app->processes++; - nxt_port_hash_add(&app->port_hash, port); - app->port_hash_count++; - - nxt_thread_mutex_unlock(&app->mutex); - - nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", - &app->name, port->pid, app->processes, app->pending_processes); - - nxt_port_socket_write(task, port, NXT_PORT_MSG_PORT_ACK, -1, 0, 0, NULL); - - nxt_router_app_port_release(task, app, port, NXT_APR_NEW_PORT); -} - - -static void -nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_app_t *app; - nxt_app_joint_t *app_joint; - nxt_queue_link_t *link; - nxt_http_request_t *r; - nxt_app_joint_rpc_t *app_joint_rpc; - - nxt_assert(data != NULL); - - app_joint_rpc = data; - app_joint = app_joint_rpc->app_joint; - - nxt_assert(app_joint != NULL); - - app = app_joint->app; - - nxt_router_app_joint_use(task, app_joint, -1); - - if (nxt_slow_path(app == NULL)) { - nxt_debug(task, "start error for released app"); - - return; - } - - nxt_debug(task, "app '%V' %p start error", &app->name, app); - - link = NULL; - - nxt_thread_mutex_lock(&app->mutex); - - nxt_assert(app->pending_processes != 0); - - app->pending_processes--; - - if (app->processes == 0 && !nxt_queue_is_empty(&app->ack_waiting_req)) { - link = nxt_queue_first(&app->ack_waiting_req); - - nxt_queue_remove(link); - link->next = NULL; - } - - nxt_thread_mutex_unlock(&app->mutex); - - while (link != NULL) { - r = nxt_container_of(link, nxt_http_request_t, app_link); - - nxt_event_engine_post(r->engine, &r->err_work); - - link = NULL; - - nxt_thread_mutex_lock(&app->mutex); - - if (app->processes == 0 && app->pending_processes == 0 - && !nxt_queue_is_empty(&app->ack_waiting_req)) - { - link = nxt_queue_first(&app->ack_waiting_req); - - nxt_queue_remove(link); - link->next = NULL; - } - - nxt_thread_mutex_unlock(&app->mutex); - } -} - - -nxt_inline nxt_port_t * -nxt_router_app_get_port_for_quit(nxt_task_t *task, nxt_app_t *app) -{ - nxt_port_t *port; - - port = NULL; - - nxt_thread_mutex_lock(&app->mutex); - - nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { - - /* Caller is responsible to decrease port use count. */ - nxt_queue_chk_remove(&port->app_link); - - if (nxt_queue_chk_remove(&port->idle_link)) { - app->idle_processes--; - - nxt_debug(task, "app '%V' move port %PI:%d out of %s for quit", - &app->name, port->pid, port->id, - (port->idle_start ? "idle_ports" : "spare_ports")); - } - - nxt_port_hash_remove(&app->port_hash, port); - app->port_hash_count--; - - port->app = NULL; - app->processes--; - - break; - - } nxt_queue_loop; - - nxt_thread_mutex_unlock(&app->mutex); - - return port; -} - - -static void -nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) -{ - int c; - - c = nxt_atomic_fetch_add(&app->use_count, i); - - if (i < 0 && c == -i) { - - if (task->thread->engine != app->engine) { - nxt_event_engine_post(app->engine, &app->joint->free_app_work); - - } else { - nxt_router_free_app(task, app->joint, NULL); - } - } -} - - -static void -nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app) -{ - nxt_debug(task, "app '%V' %p unlink", &app->name, app); - - nxt_queue_remove(&app->link); - - nxt_router_app_use(task, app, -1); -} - - -static void -nxt_router_app_port_release(nxt_task_t *task, nxt_app_t *app, nxt_port_t *port, - nxt_apr_action_t action) -{ - int inc_use; - uint32_t got_response, dec_requests; - nxt_bool_t adjust_idle_timer; - nxt_port_t *main_app_port; - - nxt_assert(port != NULL); - - inc_use = 0; - got_response = 0; - dec_requests = 0; - - switch (action) { - case NXT_APR_NEW_PORT: - break; - case NXT_APR_REQUEST_FAILED: - dec_requests = 1; - inc_use = -1; - break; - case NXT_APR_GOT_RESPONSE: - got_response = 1; - inc_use = -1; - break; - case NXT_APR_UPGRADE: - got_response = 1; - break; - case NXT_APR_CLOSE: - inc_use = -1; - break; - } - - nxt_debug(task, "app '%V' release port %PI:%d: %d %d", &app->name, - port->pid, port->id, - (int) inc_use, (int) got_response); - - if (port->id == NXT_SHARED_PORT_ID) { - nxt_thread_mutex_lock(&app->mutex); - - app->active_requests -= got_response + dec_requests; - - nxt_thread_mutex_unlock(&app->mutex); - - goto adjust_use; - } - - main_app_port = port->main_app_port; - - nxt_thread_mutex_lock(&app->mutex); - - main_app_port->active_requests -= got_response + dec_requests; - app->active_requests -= got_response + dec_requests; - - if (main_app_port->pair[1] != -1 && main_app_port->app_link.next == NULL) { - nxt_queue_insert_tail(&app->ports, &main_app_port->app_link); - - nxt_port_inc_use(main_app_port); - } - - adjust_idle_timer = 0; - - if (main_app_port->pair[1] != -1 - && main_app_port->active_requests == 0 - && main_app_port->active_websockets == 0 - && main_app_port->idle_link.next == NULL) - { - if (app->idle_processes == app->spare_processes - && app->adjust_idle_work.data == NULL) - { - adjust_idle_timer = 1; - app->adjust_idle_work.data = app; - app->adjust_idle_work.next = NULL; - } - - if (app->idle_processes < app->spare_processes) { - nxt_queue_insert_tail(&app->spare_ports, &main_app_port->idle_link); - - nxt_debug(task, "app '%V' move port %PI:%d to spare_ports", - &app->name, main_app_port->pid, main_app_port->id); - } else { - nxt_queue_insert_tail(&app->idle_ports, &main_app_port->idle_link); - - main_app_port->idle_start = task->thread->engine->timers.now; - - nxt_debug(task, "app '%V' move port %PI:%d to idle_ports", - &app->name, main_app_port->pid, main_app_port->id); - } - - app->idle_processes++; - } - - nxt_thread_mutex_unlock(&app->mutex); - - if (adjust_idle_timer) { - nxt_router_app_use(task, app, 1); - nxt_event_engine_post(app->engine, &app->adjust_idle_work); - } - - /* ? */ - if (main_app_port->pair[1] == -1) { - nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", - &app->name, app, main_app_port, main_app_port->pid); - - goto adjust_use; - } - - nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", - &app->name, app); - -adjust_use: - - nxt_port_use(task, port, inc_use); -} - - -void -nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) -{ - nxt_app_t *app; - nxt_bool_t unchain, start_process; - nxt_port_t *idle_port; - nxt_queue_link_t *idle_lnk; - - app = port->app; - - nxt_assert(app != NULL); - - nxt_thread_mutex_lock(&app->mutex); - - if (port == app->proto_port) { - app->proto_port = NULL; - port->app = NULL; - - nxt_thread_mutex_unlock(&app->mutex); - - nxt_debug(task, "app '%V' prototype pid %PI closed", &app->name, - port->pid); - - nxt_port_use(task, port, -1); - - return; - } - - nxt_port_hash_remove(&app->port_hash, port); - app->port_hash_count--; - - if (port->id != 0) { - nxt_thread_mutex_unlock(&app->mutex); - - nxt_debug(task, "app '%V' port (%PI, %d) closed", &app->name, - port->pid, port->id); - - return; - } - - unchain = nxt_queue_chk_remove(&port->app_link); - - if (nxt_queue_chk_remove(&port->idle_link)) { - app->idle_processes--; - - nxt_debug(task, "app '%V' move port %PI:%d out of %s before close", - &app->name, port->pid, port->id, - (port->idle_start ? "idle_ports" : "spare_ports")); - - if (port->idle_start == 0 - && app->idle_processes >= app->spare_processes) - { - nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); - - idle_lnk = nxt_queue_last(&app->idle_ports); - idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); - nxt_queue_remove(idle_lnk); - - nxt_queue_insert_tail(&app->spare_ports, idle_lnk); - - idle_port->idle_start = 0; - - nxt_debug(task, "app '%V' move port %PI:%d from idle_ports " - "to spare_ports", - &app->name, idle_port->pid, idle_port->id); - } - } - - app->processes--; - - start_process = !task->thread->engine->shutdown - && nxt_router_app_can_start(app) - && nxt_router_app_need_start(app); - - if (start_process) { - app->pending_processes++; - } - - nxt_thread_mutex_unlock(&app->mutex); - - nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); - - if (unchain) { - nxt_port_use(task, port, -1); - } - - if (start_process) { - nxt_router_start_app_process(task, app); - } -} - - -static void -nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) -{ - nxt_app_t *app; - nxt_bool_t queued; - nxt_port_t *port; - nxt_msec_t timeout, threshold; - nxt_queue_link_t *lnk; - nxt_event_engine_t *engine; - - app = obj; - queued = (data == app); - - nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", - &app->name, queued); - - engine = task->thread->engine; - - nxt_assert(app->engine == engine); - - threshold = engine->timers.now + app->joint->idle_timer.bias; - timeout = 0; - - nxt_thread_mutex_lock(&app->mutex); - - if (queued) { - app->adjust_idle_work.data = NULL; - } - - nxt_debug(task, "app '%V' idle_processes %d, spare_processes %d", - &app->name, - (int) app->idle_processes, (int) app->spare_processes); - - while (app->idle_processes > app->spare_processes) { - - nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); - - lnk = nxt_queue_first(&app->idle_ports); - port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); - - timeout = port->idle_start + app->idle_timeout; - - nxt_debug(task, "app '%V' pid %PI, start %M, timeout %M, threshold %M", - &app->name, port->pid, - port->idle_start, timeout, threshold); - - if (timeout > threshold) { - break; - } - - nxt_queue_remove(lnk); - lnk->next = NULL; - - nxt_debug(task, "app '%V' move port %PI:%d out of idle_ports (timeout)", - &app->name, port->pid, port->id); - - nxt_queue_chk_remove(&port->app_link); - - nxt_port_hash_remove(&app->port_hash, port); - app->port_hash_count--; - - app->idle_processes--; - app->processes--; - port->app = NULL; - - nxt_thread_mutex_unlock(&app->mutex); - - nxt_debug(task, "app '%V' send QUIT to idle port %PI", - &app->name, port->pid); - - nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); - - nxt_port_use(task, port, -1); - - nxt_thread_mutex_lock(&app->mutex); - } - - nxt_thread_mutex_unlock(&app->mutex); - - if (timeout > threshold) { - nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold); - - } else { - nxt_timer_disable(engine, &app->joint->idle_timer); - } - - if (queued) { - nxt_router_app_use(task, app, -1); - } -} - - -static void -nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_timer_t *timer; - nxt_app_joint_t *app_joint; - - timer = obj; - app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); - - if (nxt_fast_path(app_joint->app != NULL)) { - nxt_router_adjust_idle_timer(task, app_joint->app, NULL); - } -} - - -static void -nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_timer_t *timer; - nxt_app_joint_t *app_joint; - - timer = obj; - app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); - - nxt_router_app_joint_use(task, app_joint, -1); -} - - -static void -nxt_router_free_app(nxt_task_t *task, void *obj, void *data) -{ - nxt_app_t *app; - nxt_port_t *port, *proto_port; - nxt_app_joint_t *app_joint; - - app_joint = obj; - app = app_joint->app; - - for ( ;; ) { - port = nxt_router_app_get_port_for_quit(task, app); - if (port == NULL) { - break; - } - - nxt_port_use(task, port, -1); - } - - nxt_thread_mutex_lock(&app->mutex); - - for ( ;; ) { - port = nxt_port_hash_retrieve(&app->port_hash); - if (port == NULL) { - break; - } - - app->port_hash_count--; - - port->app = NULL; - - nxt_port_close(task, port); - - nxt_port_use(task, port, -1); - } - - proto_port = app->proto_port; - - if (proto_port != NULL) { - nxt_debug(task, "send QUIT to prototype '%V' pid %PI", &app->name, - proto_port->pid); - - app->proto_port = NULL; - proto_port->app = NULL; - } - - nxt_thread_mutex_unlock(&app->mutex); - - if (proto_port != NULL) { - nxt_port_socket_write(task, proto_port, NXT_PORT_MSG_QUIT, - -1, 0, 0, NULL); - - nxt_port_close(task, proto_port); - - nxt_port_use(task, proto_port, -1); - } - - nxt_assert(app->proto_port == NULL); - nxt_assert(app->processes == 0); - nxt_assert(app->active_requests == 0); - nxt_assert(app->port_hash_count == 0); - nxt_assert(app->idle_processes == 0); - nxt_assert(nxt_queue_is_empty(&app->ports)); - nxt_assert(nxt_queue_is_empty(&app->spare_ports)); - nxt_assert(nxt_queue_is_empty(&app->idle_ports)); - - nxt_port_mmaps_destroy(&app->outgoing, 1); - - nxt_thread_mutex_destroy(&app->outgoing.mutex); - - if (app->shared_port != NULL) { - app->shared_port->app = NULL; - nxt_port_close(task, app->shared_port); - nxt_port_use(task, app->shared_port, -1); - - app->shared_port = NULL; - } - - nxt_thread_mutex_destroy(&app->mutex); - nxt_mp_destroy(app->mem_pool); - - app_joint->app = NULL; - - if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) { - app_joint->idle_timer.handler = nxt_router_app_joint_release_handler; - nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0); - - } else { - nxt_router_app_joint_use(task, app_joint, -1); - } -} - - -static void -nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app, - nxt_request_rpc_data_t *req_rpc_data) -{ - nxt_bool_t start_process; - nxt_port_t *port; - nxt_http_request_t *r; - - start_process = 0; - - nxt_thread_mutex_lock(&app->mutex); - - port = app->shared_port; - nxt_port_inc_use(port); - - app->active_requests++; - - if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) { - app->pending_processes++; - start_process = 1; - } - - r = req_rpc_data->request; - - /* - * Put request into application-wide list to be able to cancel request - * if something goes wrong with application processes. - */ - nxt_queue_insert_tail(&app->ack_waiting_req, &r->app_link); - - nxt_thread_mutex_unlock(&app->mutex); - - /* - * Retain request memory pool while request is linked in ack_waiting_req - * to guarantee request structure memory is accessble. - */ - nxt_mp_retain(r->mem_pool); - - req_rpc_data->app_port = port; - req_rpc_data->apr_action = NXT_APR_REQUEST_FAILED; - - if (start_process) { - nxt_router_start_app_process(task, app); - } -} - - -void -nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *action) -{ - nxt_event_engine_t *engine; - nxt_http_app_conf_t *conf; - nxt_request_rpc_data_t *req_rpc_data; - - conf = action->u.conf; - engine = task->thread->engine; - - r->app_target = conf->target; - - req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port, - nxt_router_response_ready_handler, - nxt_router_response_error_handler, - sizeof(nxt_request_rpc_data_t)); - if (nxt_slow_path(req_rpc_data == NULL)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - /* - * At this point we have request req_rpc_data allocated and registered - * in port handlers. Need to fixup request memory pool. Counterpart - * release will be called via following call chain: - * nxt_request_rpc_data_unlink() -> - * nxt_router_http_request_release_post() -> - * nxt_router_http_request_release() - */ - nxt_mp_retain(r->mem_pool); - - r->timer.task = &engine->task; - r->timer.work_queue = &engine->fast_work_queue; - r->timer.log = engine->task.log; - r->timer.bias = NXT_TIMER_DEFAULT_BIAS; - - r->engine = engine; - r->err_work.handler = nxt_router_http_request_error; - r->err_work.task = task; - r->err_work.obj = r; - - req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data); - req_rpc_data->app = conf->app; - req_rpc_data->msg_info.body_fd = -1; - req_rpc_data->rpc_cancel = 1; - - nxt_router_app_use(task, conf->app, 1); - - req_rpc_data->request = r; - r->req_rpc_data = req_rpc_data; - - if (r->last != NULL) { - r->last->completion_handler = nxt_router_http_request_done; - } - - nxt_router_app_port_get(task, conf->app, req_rpc_data); - nxt_router_app_prepare_request(task, req_rpc_data); -} - - -static void -nxt_router_http_request_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_request_t *r; - - r = obj; - - nxt_debug(task, "router http request error (rpc_data %p)", r->req_rpc_data); - - nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); - - if (r->req_rpc_data != NULL) { - nxt_request_rpc_data_unlink(task, r->req_rpc_data); - } - - nxt_mp_release(r->mem_pool); -} - - -static void -nxt_router_http_request_done(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_request_t *r; - - r = data; - - nxt_debug(task, "router http request done (rpc_data %p)", r->req_rpc_data); - - if (r->req_rpc_data != NULL) { - nxt_request_rpc_data_unlink(task, r->req_rpc_data); - } - - nxt_http_request_close_handler(task, r, r->proto.any); -} - - -static void -nxt_router_app_prepare_request(nxt_task_t *task, - nxt_request_rpc_data_t *req_rpc_data) -{ - nxt_app_t *app; - nxt_buf_t *buf, *body; - nxt_int_t res; - nxt_port_t *port, *reply_port; - - int notify; - struct { - nxt_port_msg_t pm; - nxt_port_mmap_msg_t mm; - } msg; - - - app = req_rpc_data->app; - - nxt_assert(app != NULL); - - port = req_rpc_data->app_port; - - nxt_assert(port != NULL); - nxt_assert(port->queue != NULL); - - reply_port = task->thread->engine->port; - - buf = nxt_router_prepare_msg(task, req_rpc_data->request, app, - nxt_app_msg_prefix[app->type]); - if (nxt_slow_path(buf == NULL)) { - nxt_alert(task, "stream #%uD, app '%V': failed to prepare app message", - req_rpc_data->stream, &app->name); - - nxt_http_request_error(task, req_rpc_data->request, - NXT_HTTP_INTERNAL_SERVER_ERROR); - - return; - } - - nxt_debug(task, "about to send %O bytes buffer to app process port %d", - nxt_buf_used_size(buf), - port->socket.fd); - - req_rpc_data->msg_info.buf = buf; - - body = req_rpc_data->request->body; - - if (body != NULL && nxt_buf_is_file(body)) { - req_rpc_data->msg_info.body_fd = body->file->fd; - - body->file->fd = -1; - - } else { - req_rpc_data->msg_info.body_fd = -1; - } - - msg.pm.stream = req_rpc_data->stream; - msg.pm.pid = reply_port->pid; - msg.pm.reply_port = reply_port->id; - msg.pm.type = NXT_PORT_MSG_REQ_HEADERS; - msg.pm.last = 0; - msg.pm.mmap = 1; - msg.pm.nf = 0; - msg.pm.mf = 0; - - nxt_port_mmap_handler_t *mmap_handler = buf->parent; - nxt_port_mmap_header_t *hdr = mmap_handler->hdr; - - msg.mm.mmap_id = hdr->id; - msg.mm.chunk_id = nxt_port_mmap_chunk_id(hdr, buf->mem.pos); - msg.mm.size = nxt_buf_used_size(buf); - - res = nxt_app_queue_send(port->queue, &msg, sizeof(msg), - req_rpc_data->stream, ¬ify, - &req_rpc_data->msg_info.tracking_cookie); - if (nxt_fast_path(res == NXT_OK)) { - if (notify != 0) { - (void) nxt_port_socket_write(task, port, - NXT_PORT_MSG_READ_QUEUE, - -1, req_rpc_data->stream, - reply_port->id, NULL); - - } else { - nxt_debug(task, "queue is not empty"); - } - - buf->is_port_mmap_sent = 1; - buf->mem.pos = buf->mem.free; - - } else { - nxt_alert(task, "stream #%uD, app '%V': failed to send app message", - req_rpc_data->stream, &app->name); - - nxt_http_request_error(task, req_rpc_data->request, - NXT_HTTP_INTERNAL_SERVER_ERROR); - } -} - - -struct nxt_fields_iter_s { - nxt_list_part_t *part; - nxt_http_field_t *field; -}; - -typedef struct nxt_fields_iter_s nxt_fields_iter_t; - - -static nxt_http_field_t * -nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i) -{ - if (part == NULL) { - return NULL; - } - - while (part->nelts == 0) { - part = part->next; - if (part == NULL) { - return NULL; - } - } - - i->part = part; - i->field = nxt_list_data(i->part); - - return i->field; -} - - -static nxt_http_field_t * -nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i) -{ - return nxt_fields_part_first(nxt_list_part(fields), i); -} - - -static nxt_http_field_t * -nxt_fields_next(nxt_fields_iter_t *i) -{ - nxt_http_field_t *end = nxt_list_data(i->part); - - end += i->part->nelts; - i->field++; - - if (i->field < end) { - return i->field; - } - - return nxt_fields_part_first(i->part->next, i); -} - - -static nxt_buf_t * -nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r, - nxt_app_t *app, const nxt_str_t *prefix) -{ - void *target_pos, *query_pos; - u_char *pos, *end, *p, c; - size_t fields_count, req_size, size, free_size; - size_t copy_size; - nxt_off_t content_length; - nxt_buf_t *b, *buf, *out, **tail; - nxt_http_field_t *field, *dup; - nxt_unit_field_t *dst_field; - nxt_fields_iter_t iter, dup_iter; - nxt_unit_request_t *req; - - req_size = sizeof(nxt_unit_request_t) - + r->method->length + 1 - + r->version.length + 1 - + r->remote->address_length + 1 - + r->local->address_length + 1 - + nxt_sockaddr_port_length(r->local) + 1 - + r->server_name.length + 1 - + r->target.length + 1 - + (r->path->start != r->target.start ? r->path->length + 1 : 0); - - content_length = r->content_length_n < 0 ? 0 : r->content_length_n; - fields_count = 0; - - nxt_list_each(field, r->fields) { - fields_count++; - - req_size += field->name_length + prefix->length + 1 - + field->value_length + 1; - } nxt_list_loop; - - req_size += fields_count * sizeof(nxt_unit_field_t); - - if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) { - nxt_alert(task, "headers to big to fit in shared memory (%d)", - (int) req_size); - - return NULL; - } - - out = nxt_port_mmap_get_buf(task, &app->outgoing, - nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE)); - if (nxt_slow_path(out == NULL)) { - return NULL; - } - - req = (nxt_unit_request_t *) out->mem.free; - out->mem.free += req_size; - - req->app_target = r->app_target; - - req->content_length = content_length; - - p = (u_char *) (req->fields + fields_count); - - nxt_debug(task, "fields_count=%d", (int) fields_count); - - req->method_length = r->method->length; - nxt_unit_sptr_set(&req->method, p); - p = nxt_cpymem(p, r->method->start, r->method->length); - *p++ = '\0'; - - req->version_length = r->version.length; - nxt_unit_sptr_set(&req->version, p); - p = nxt_cpymem(p, r->version.start, r->version.length); - *p++ = '\0'; - - req->remote_length = r->remote->address_length; - nxt_unit_sptr_set(&req->remote, p); - p = nxt_cpymem(p, nxt_sockaddr_address(r->remote), - r->remote->address_length); - *p++ = '\0'; - - req->local_addr_length = r->local->address_length; - nxt_unit_sptr_set(&req->local_addr, p); - p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length); - *p++ = '\0'; - - req->local_port_length = nxt_sockaddr_port_length(r->local); - nxt_unit_sptr_set(&req->local_port, p); - p = nxt_cpymem(p, nxt_sockaddr_port(r->local), - nxt_sockaddr_port_length(r->local)); - *p++ = '\0'; - - req->tls = r->tls; - req->websocket_handshake = r->websocket_handshake; - - req->server_name_length = r->server_name.length; - nxt_unit_sptr_set(&req->server_name, p); - p = nxt_cpymem(p, r->server_name.start, r->server_name.length); - *p++ = '\0'; - - target_pos = p; - req->target_length = (uint32_t) r->target.length; - nxt_unit_sptr_set(&req->target, p); - p = nxt_cpymem(p, r->target.start, r->target.length); - *p++ = '\0'; - - req->path_length = (uint32_t) r->path->length; - if (r->path->start == r->target.start) { - nxt_unit_sptr_set(&req->path, target_pos); - - } else { - nxt_unit_sptr_set(&req->path, p); - p = nxt_cpymem(p, r->path->start, r->path->length); - *p++ = '\0'; - } - - req->query_length = (uint32_t) r->args->length; - if (r->args->start != NULL) { - query_pos = nxt_pointer_to(target_pos, - r->args->start - r->target.start); - - nxt_unit_sptr_set(&req->query, query_pos); - - } else { - req->query.offset = 0; - } - - req->content_length_field = NXT_UNIT_NONE_FIELD; - req->content_type_field = NXT_UNIT_NONE_FIELD; - req->cookie_field = NXT_UNIT_NONE_FIELD; - req->authorization_field = NXT_UNIT_NONE_FIELD; - - dst_field = req->fields; - - for (field = nxt_fields_first(r->fields, &iter); - field != NULL; - field = nxt_fields_next(&iter)) - { - if (field->skip) { - continue; - } - - dst_field->hash = field->hash; - dst_field->skip = 0; - dst_field->name_length = field->name_length + prefix->length; - dst_field->value_length = field->value_length; - - if (field == r->content_length) { - req->content_length_field = dst_field - req->fields; - - } else if (field == r->content_type) { - req->content_type_field = dst_field - req->fields; - - } else if (field == r->cookie) { - req->cookie_field = dst_field - req->fields; - - } else if (field == r->authorization) { - req->authorization_field = dst_field - req->fields; - } - - nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p", - (int) field->hash, (int) field->skip, - (int) field->name_length, field->name, - (int) field->value_length, field->value); - - if (prefix->length != 0) { - nxt_unit_sptr_set(&dst_field->name, p); - p = nxt_cpymem(p, prefix->start, prefix->length); - - end = field->name + field->name_length; - for (pos = field->name; pos < end; pos++) { - c = *pos; - - if (c >= 'a' && c <= 'z') { - *p++ = (c & ~0x20); - continue; - } - - if (c == '-') { - *p++ = '_'; - continue; - } - - *p++ = c; - } - - } else { - nxt_unit_sptr_set(&dst_field->name, p); - p = nxt_cpymem(p, field->name, field->name_length); - } - - *p++ = '\0'; - - nxt_unit_sptr_set(&dst_field->value, p); - p = nxt_cpymem(p, field->value, field->value_length); - - if (prefix->length != 0) { - dup_iter = iter; - - for (dup = nxt_fields_next(&dup_iter); - dup != NULL; - dup = nxt_fields_next(&dup_iter)) - { - if (dup->name_length != field->name_length - || dup->skip - || dup->hash != field->hash - || nxt_memcasecmp(dup->name, field->name, dup->name_length)) - { - continue; - } - - p = nxt_cpymem(p, ", ", 2); - p = nxt_cpymem(p, dup->value, dup->value_length); - - dst_field->value_length += 2 + dup->value_length; - - dup->skip = 1; - } - } - - *p++ = '\0'; - - dst_field++; - } - - req->fields_count = (uint32_t) (dst_field - req->fields); - - nxt_unit_sptr_set(&req->preread_content, out->mem.free); - - buf = out; - tail = &buf->next; - - for (b = r->body; b != NULL; b = b->next) { - size = nxt_buf_mem_used_size(&b->mem); - pos = b->mem.pos; - - while (size > 0) { - if (buf == NULL) { - free_size = nxt_min(size, PORT_MMAP_DATA_SIZE); - - buf = nxt_port_mmap_get_buf(task, &app->outgoing, free_size); - if (nxt_slow_path(buf == NULL)) { - while (out != NULL) { - buf = out->next; - out->next = NULL; - out->completion_handler(task, out, out->parent); - out = buf; - } - return NULL; - } - - *tail = buf; - tail = &buf->next; - - } else { - free_size = nxt_buf_mem_free_size(&buf->mem); - if (free_size < size - && nxt_port_mmap_increase_buf(task, buf, size, 1) - == NXT_OK) - { - free_size = nxt_buf_mem_free_size(&buf->mem); - } - } - - if (free_size > 0) { - copy_size = nxt_min(free_size, size); - - buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size); - - size -= copy_size; - pos += copy_size; - - if (size == 0) { - break; - } - } - - buf = NULL; - } - } - - return out; -} - - -static void -nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_timer_t *timer; - nxt_http_request_t *r; - nxt_request_rpc_data_t *req_rpc_data; - - timer = obj; - - nxt_debug(task, "router app timeout"); - - r = nxt_timer_data(timer, nxt_http_request_t, timer); - req_rpc_data = r->timer_data; - - nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); - - nxt_request_rpc_data_unlink(task, req_rpc_data); -} - - -static void -nxt_router_http_request_release_post(nxt_task_t *task, nxt_http_request_t *r) -{ - r->timer.handler = nxt_router_http_request_release; - nxt_timer_add(task->thread->engine, &r->timer, 0); -} - - -static void -nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_request_t *r; - - nxt_debug(task, "http request pool release"); - - r = nxt_timer_data(obj, nxt_http_request_t, timer); - - nxt_mp_release(r->mem_pool); -} - - -static void -nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - size_t mi; - uint32_t i; - nxt_bool_t ack; - nxt_process_t *process; - nxt_free_map_t *m; - nxt_port_mmap_handler_t *mmap_handler; - - nxt_debug(task, "oosm in %PI", msg->port_msg.pid); - - process = nxt_runtime_process_find(task->thread->runtime, - msg->port_msg.pid); - if (nxt_slow_path(process == NULL)) { - return; - } - - ack = 0; - - /* - * To mitigate possible racing condition (when OOSM message received - * after some of the memory was already freed), need to try to find - * first free segment in shared memory and send ACK if found. - */ - - nxt_thread_mutex_lock(&process->incoming.mutex); - - for (i = 0; i < process->incoming.size; i++) { - mmap_handler = process->incoming.elts[i].mmap_handler; - - if (nxt_slow_path(mmap_handler == NULL)) { - continue; - } - - m = mmap_handler->hdr->free_map; - - for (mi = 0; mi < MAX_FREE_IDX; mi++) { - if (m[mi] != 0) { - ack = 1; - - nxt_debug(task, "oosm: already free #%uD %uz = 0x%08xA", - i, mi, m[mi]); - - break; - } - } - } - - nxt_thread_mutex_unlock(&process->incoming.mutex); - - if (ack) { - nxt_process_broadcast_shm_ack(task, process); - } -} - - -static void -nxt_router_get_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_fd_t fd; - nxt_port_t *port; - nxt_runtime_t *rt; - nxt_port_mmaps_t *mmaps; - nxt_port_msg_get_mmap_t *get_mmap_msg; - nxt_port_mmap_handler_t *mmap_handler; - - rt = task->thread->runtime; - - port = nxt_runtime_port_find(rt, msg->port_msg.pid, - msg->port_msg.reply_port); - if (nxt_slow_path(port == NULL)) { - nxt_alert(task, "get_mmap_handler: reply_port %PI:%d not found", - msg->port_msg.pid, msg->port_msg.reply_port); - - return; - } - - if (nxt_slow_path(nxt_buf_used_size(msg->buf) - < (int) sizeof(nxt_port_msg_get_mmap_t))) - { - nxt_alert(task, "get_mmap_handler: message buffer too small (%d)", - (int) nxt_buf_used_size(msg->buf)); - - return; - } - - get_mmap_msg = (nxt_port_msg_get_mmap_t *) msg->buf->mem.pos; - - nxt_assert(port->type == NXT_PROCESS_APP); - - if (nxt_slow_path(port->app == NULL)) { - nxt_alert(task, "get_mmap_handler: app == NULL for reply port %PI:%d", - port->pid, port->id); - - // FIXME - nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, - -1, msg->port_msg.stream, 0, NULL); - - return; - } - - mmaps = &port->app->outgoing; - nxt_thread_mutex_lock(&mmaps->mutex); - - if (nxt_slow_path(get_mmap_msg->id >= mmaps->size)) { - nxt_thread_mutex_unlock(&mmaps->mutex); - - nxt_alert(task, "get_mmap_handler: mmap id is too big (%d)", - (int) get_mmap_msg->id); - - // FIXME - nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, - -1, msg->port_msg.stream, 0, NULL); - return; - } - - mmap_handler = mmaps->elts[get_mmap_msg->id].mmap_handler; - - fd = mmap_handler->fd; - - nxt_thread_mutex_unlock(&mmaps->mutex); - - nxt_debug(task, "get mmap %PI:%d found", - msg->port_msg.pid, (int) get_mmap_msg->id); - - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_MMAP, fd, 0, 0, NULL); -} - - -static void -nxt_router_get_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_port_t *port, *reply_port; - nxt_runtime_t *rt; - nxt_port_msg_get_port_t *get_port_msg; - - rt = task->thread->runtime; - - reply_port = nxt_runtime_port_find(rt, msg->port_msg.pid, - msg->port_msg.reply_port); - if (nxt_slow_path(reply_port == NULL)) { - nxt_alert(task, "get_port_handler: reply_port %PI:%d not found", - msg->port_msg.pid, msg->port_msg.reply_port); - - return; - } - - if (nxt_slow_path(nxt_buf_used_size(msg->buf) - < (int) sizeof(nxt_port_msg_get_port_t))) - { - nxt_alert(task, "get_port_handler: message buffer too small (%d)", - (int) nxt_buf_used_size(msg->buf)); - - return; - } - - get_port_msg = (nxt_port_msg_get_port_t *) msg->buf->mem.pos; - - port = nxt_runtime_port_find(rt, get_port_msg->pid, get_port_msg->id); - if (nxt_slow_path(port == NULL)) { - nxt_alert(task, "get_port_handler: port %PI:%d not found", - get_port_msg->pid, get_port_msg->id); - - return; - } - - nxt_debug(task, "get port %PI:%d found", get_port_msg->pid, - get_port_msg->id); - - (void) nxt_port_send_port(task, reply_port, port, msg->port_msg.stream); -} diff --git a/src/nxt_router.h b/src/nxt_router.h deleted file mode 100644 index 3e523001..00000000 --- a/src/nxt_router.h +++ /dev/null @@ -1,271 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_ROUTER_H_INCLUDED_ -#define _NXT_ROUTER_H_INCLUDED_ - - -#include -#include -#include - -typedef struct nxt_http_request_s nxt_http_request_t; -#include - - -typedef struct nxt_http_action_s nxt_http_action_t; -typedef struct nxt_http_routes_s nxt_http_routes_t; -typedef struct nxt_http_forward_s nxt_http_forward_t; -typedef struct nxt_upstream_s nxt_upstream_t; -typedef struct nxt_upstreams_s nxt_upstreams_t; -typedef struct nxt_router_access_log_s nxt_router_access_log_t; - - -#define NXT_HTTP_ACTION_ERROR ((nxt_http_action_t *) -1) - - -typedef struct { - nxt_thread_spinlock_t lock; - nxt_queue_t engines; - - nxt_queue_t sockets; /* of nxt_socket_conf_t */ - nxt_queue_t apps; /* of nxt_app_t */ - - nxt_router_access_log_t *access_log; -} nxt_router_t; - - -typedef struct { - uint32_t count; - uint32_t threads; - - nxt_mp_t *mem_pool; - nxt_tstr_state_t *tstr_state; - - nxt_router_t *router; - nxt_http_routes_t *routes; - nxt_upstreams_t *upstreams; - - nxt_lvlhsh_t mtypes_hash; - nxt_lvlhsh_t apps_hash; - - nxt_router_access_log_t *access_log; - nxt_tstr_t *log_format; - nxt_tstr_t *log_expr; - uint8_t log_negate; /* 1 bit */ -} nxt_router_conf_t; - - -typedef struct { - nxt_event_engine_t *engine; - nxt_work_t *jobs; - - enum { - NXT_ROUTER_ENGINE_KEEP = 0, - NXT_ROUTER_ENGINE_ADD, - NXT_ROUTER_ENGINE_DELETE, - } action; -} nxt_router_engine_conf_t; - - -typedef struct { -#if (NXT_TLS) - nxt_queue_t tls; /* of nxt_router_tlssock_t */ -#endif - -#if (NXT_HAVE_NJS) - nxt_queue_t js_modules; -#endif - - nxt_queue_t apps; /* of nxt_app_t */ - nxt_queue_t previous; /* of nxt_app_t */ - - uint32_t new_threads; - uint32_t stream; - uint32_t count; - - nxt_event_engine_t *engine; - nxt_port_t *port; - nxt_array_t *engines; - nxt_router_conf_t *router_conf; - nxt_mp_t *mem_pool; -} nxt_router_temp_conf_t; - - -typedef struct { - nxt_task_t task; - nxt_work_t work; - nxt_router_temp_conf_t *tmcf; -} nxt_joint_job_t; - - -typedef struct { - uint32_t use_count; - nxt_app_t *app; - nxt_timer_t idle_timer; - nxt_work_t free_app_work; -} nxt_app_joint_t; - - -struct nxt_app_s { - nxt_thread_mutex_t mutex; /* Protects ports queue. */ - nxt_queue_t ports; /* of nxt_port_t.app_link */ - nxt_lvlhsh_t port_hash; /* of nxt_port_t */ - - nxt_queue_t spare_ports; /* of nxt_port_t.idle_link */ - nxt_queue_t idle_ports; /* of nxt_port_t.idle_link */ - nxt_work_t adjust_idle_work; - nxt_event_engine_t *engine; - - nxt_str_t name; - - uint32_t port_hash_count; - - uint32_t active_requests; - uint32_t pending_processes; - uint32_t processes; - uint32_t idle_processes; - - uint32_t max_processes; - uint32_t spare_processes; - uint32_t max_pending_processes; - - uint32_t generation; - uint32_t proto_port_requests; - - nxt_msec_t timeout; - nxt_msec_t idle_timeout; - - nxt_str_t *targets; - - nxt_app_type_t type:8; - - nxt_mp_t *mem_pool; - nxt_queue_link_t link; - - nxt_str_t conf; - - nxt_atomic_t use_count; - nxt_queue_t ack_waiting_req; /* of nxt_http_request_t.app_link */ - - nxt_app_joint_t *joint; - nxt_port_t *shared_port; - nxt_port_t *proto_port; - - nxt_port_mmaps_t outgoing; -}; - - -typedef struct { - size_t max_frame_size; - nxt_msec_t read_timeout; - nxt_msec_t keepalive_interval; -} nxt_websocket_conf_t; - - -typedef struct { - uint32_t count; - nxt_queue_link_t link; - nxt_router_conf_t *router_conf; - - nxt_http_action_t *action; - - /* - * A listen socket time can be shorter than socket configuration life - * time, so a copy of the non-wildcard socket sockaddr is stored here - * to be used as a local sockaddr in connections. - */ - nxt_sockaddr_t *sockaddr; - - nxt_listen_socket_t *listen; - - size_t header_buffer_size; - size_t large_header_buffer_size; - size_t large_header_buffers; - size_t body_buffer_size; - size_t max_body_size; - size_t proxy_header_buffer_size; - size_t proxy_buffer_size; - size_t proxy_buffers; - - nxt_msec_t idle_timeout; - nxt_msec_t header_read_timeout; - nxt_msec_t body_read_timeout; - nxt_msec_t send_timeout; - nxt_msec_t proxy_timeout; - nxt_msec_t proxy_send_timeout; - nxt_msec_t proxy_read_timeout; - - nxt_websocket_conf_t websocket_conf; - - nxt_str_t body_temp_path; - - uint8_t log_route; /* 1 bit */ - - uint8_t discard_unsafe_fields; /* 1 bit */ - - uint8_t server_version; /* 1 bit */ - - nxt_http_forward_t *forwarded; - nxt_http_forward_t *client_ip; - -#if (NXT_TLS) - nxt_tls_conf_t *tls; -#endif -} nxt_socket_conf_t; - - -typedef struct { - uint32_t count; - nxt_queue_link_t link; - nxt_event_engine_t *engine; - nxt_socket_conf_t *socket_conf; - - nxt_joint_job_t *close_job; - - nxt_upstream_t **upstreams; - - /* Modules configuraitons. */ -} nxt_socket_conf_joint_t; - - -struct nxt_router_access_log_s { - void (*handler)(nxt_task_t *task, nxt_http_request_t *r, - nxt_router_access_log_t *access_log, - nxt_tstr_t *format); - nxt_fd_t fd; - nxt_str_t path; - uint32_t count; -}; - - -void nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *action); -void nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port); -nxt_int_t nxt_router_application_init(nxt_router_conf_t *rtcf, nxt_str_t *name, - nxt_str_t *target, nxt_http_action_t *action); -void nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev, - nxt_socket_conf_joint_t *joint); - -void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); -void nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf); -void nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint); - -nxt_int_t nxt_router_access_log_create(nxt_task_t *task, - nxt_router_conf_t *rtcf, nxt_conf_value_t *value); -void nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf); -void nxt_router_access_log_use(nxt_thread_spinlock_t *lock, - nxt_router_access_log_t *access_log); -void nxt_router_access_log_release(nxt_task_t *task, - nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log); -void nxt_router_access_log_reopen_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); - - -extern nxt_router_t *nxt_router; - - -#endif /* _NXT_ROUTER_H_INCLUDED_ */ diff --git a/src/nxt_router_access_log.c b/src/nxt_router_access_log.c deleted file mode 100644 index 7fc59972..00000000 --- a/src/nxt_router_access_log.c +++ /dev/null @@ -1,470 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -typedef struct { - nxt_str_t path; - nxt_str_t format; - nxt_conf_value_t *expr; -} nxt_router_access_log_conf_t; - - -typedef struct { - nxt_str_t text; - nxt_router_access_log_t *access_log; -} nxt_router_access_log_ctx_t; - - -static void nxt_router_access_log_writer(nxt_task_t *task, - nxt_http_request_t *r, nxt_router_access_log_t *access_log, - nxt_tstr_t *format); -static void nxt_router_access_log_write_ready(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_access_log_write_error(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_access_log_ready(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_router_access_log_error(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_access_log_reopen_ready(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_router_access_log_reopen_error(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); - - -static nxt_conf_map_t nxt_router_access_log_conf[] = { - { - nxt_string("path"), - NXT_CONF_MAP_STR, - offsetof(nxt_router_access_log_conf_t, path), - }, - - { - nxt_string("format"), - NXT_CONF_MAP_STR, - offsetof(nxt_router_access_log_conf_t, format), - }, - - { - nxt_string("if"), - NXT_CONF_MAP_PTR, - offsetof(nxt_router_access_log_conf_t, expr), - }, -}; - - -nxt_int_t -nxt_router_access_log_create(nxt_task_t *task, nxt_router_conf_t *rtcf, - nxt_conf_value_t *value) -{ - u_char *p; - nxt_int_t ret; - nxt_str_t str; - nxt_tstr_t *format; - nxt_router_t *router; - nxt_router_access_log_t *access_log; - nxt_router_access_log_conf_t alcf; - - static nxt_str_t log_format_str = nxt_string("$remote_addr - - " - "[$time_local] \"$request_line\" $status $body_bytes_sent " - "\"$header_referer\" \"$header_user_agent\""); - - nxt_memzero(&alcf, sizeof(nxt_router_access_log_conf_t)); - - alcf.format = log_format_str; - - if (nxt_conf_type(value) == NXT_CONF_STRING) { - nxt_conf_get_string(value, &alcf.path); - - } else { - ret = nxt_conf_map_object(rtcf->mem_pool, value, - nxt_router_access_log_conf, - nxt_nitems(nxt_router_access_log_conf), - &alcf); - if (ret != NXT_OK) { - nxt_alert(task, "access log map error"); - return NXT_ERROR; - } - } - - router = nxt_router; - - access_log = router->access_log; - - if (access_log != NULL && nxt_strstr_eq(&alcf.path, &access_log->path)) { - nxt_router_access_log_use(&router->lock, access_log); - - } else { - access_log = nxt_malloc(sizeof(nxt_router_access_log_t) - + alcf.path.length); - if (access_log == NULL) { - nxt_alert(task, "failed to allocate access log structure"); - return NXT_ERROR; - } - - access_log->fd = -1; - access_log->handler = &nxt_router_access_log_writer; - access_log->count = 1; - - access_log->path.length = alcf.path.length; - access_log->path.start = (u_char *) access_log - + sizeof(nxt_router_access_log_t); - - nxt_memcpy(access_log->path.start, alcf.path.start, alcf.path.length); - } - - str.length = alcf.format.length + 1; - - str.start = nxt_malloc(str.length); - if (str.start == NULL) { - nxt_alert(task, "failed to allocate log format structure"); - return NXT_ERROR; - } - - p = nxt_cpymem(str.start, alcf.format.start, alcf.format.length); - *p = '\n'; - - format = nxt_tstr_compile(rtcf->tstr_state, &str, NXT_TSTR_LOGGING); - if (nxt_slow_path(format == NULL)) { - return NXT_ERROR; - } - - rtcf->access_log = access_log; - rtcf->log_format = format; - - if (alcf.expr != NULL) { - nxt_conf_get_string(alcf.expr, &str); - - if (str.length > 0 && str.start[0] == '!') { - rtcf->log_negate = 1; - - str.start++; - str.length--; - } - - rtcf->log_expr = nxt_tstr_compile(rtcf->tstr_state, &str, 0); - if (nxt_slow_path(rtcf->log_expr == NULL)) { - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -static void -nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, - nxt_router_access_log_t *access_log, nxt_tstr_t *format) -{ - nxt_int_t ret; - nxt_router_conf_t *rtcf; - nxt_router_access_log_ctx_t *ctx; - - ctx = nxt_mp_get(r->mem_pool, sizeof(nxt_router_access_log_ctx_t)); - if (nxt_slow_path(ctx == NULL)) { - return; - } - - ctx->access_log = access_log; - - if (nxt_tstr_is_const(format)) { - nxt_tstr_str(format, &ctx->text); - - nxt_router_access_log_write_ready(task, r, ctx); - - } else { - rtcf = r->conf->socket_conf->router_conf; - - ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, - &r->tstr_cache, r, r->mem_pool); - if (nxt_slow_path(ret != NXT_OK)) { - return; - } - - nxt_tstr_query(task, r->tstr_query, format, &ctx->text); - nxt_tstr_query_resolve(task, r->tstr_query, ctx, - nxt_router_access_log_write_ready, - nxt_router_access_log_write_error); - } -} - - -static void -nxt_router_access_log_write_ready(nxt_task_t *task, void *obj, void *data) -{ - nxt_http_request_t *r; - nxt_router_access_log_ctx_t *ctx; - - r = obj; - ctx = data; - - nxt_fd_write(ctx->access_log->fd, ctx->text.start, ctx->text.length); - - nxt_http_request_close_handler(task, r, r->proto.any); -} - - -static void -nxt_router_access_log_write_error(nxt_task_t *task, void *obj, void *data) -{ - -} - - -void -nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) -{ - uint32_t stream; - nxt_int_t ret; - nxt_buf_t *b; - nxt_port_t *main_port, *router_port; - nxt_runtime_t *rt; - nxt_router_access_log_t *access_log; - - access_log = tmcf->router_conf->access_log; - - b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0); - if (nxt_slow_path(b == NULL)) { - goto fail; - } - - b->completion_handler = nxt_buf_dummy_completion; - - nxt_buf_cpystr(b, &access_log->path); - *b->mem.free++ = '\0'; - - rt = task->thread->runtime; - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - stream = nxt_port_rpc_register_handler(task, router_port, - nxt_router_access_log_ready, - nxt_router_access_log_error, - -1, tmcf); - if (nxt_slow_path(stream == 0)) { - goto fail; - } - - ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, - stream, router_port->id, b); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_rpc_cancel(task, router_port, stream); - goto fail; - } - - return; - -fail: - - nxt_router_conf_error(task, tmcf); -} - - -static void -nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_router_temp_conf_t *tmcf; - nxt_router_access_log_t *access_log; - - tmcf = data; - - access_log = tmcf->router_conf->access_log; - - access_log->fd = msg->fd[0]; - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - nxt_router_conf_apply, task, tmcf, NULL); -} - - -static void -nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_router_temp_conf_t *tmcf; - - tmcf = data; - - nxt_router_conf_error(task, tmcf); -} - - -void -nxt_router_access_log_use(nxt_thread_spinlock_t *lock, - nxt_router_access_log_t *access_log) -{ - if (access_log == NULL) { - return; - } - - nxt_thread_spin_lock(lock); - - access_log->count++; - - nxt_thread_spin_unlock(lock); -} - - -void -nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock, - nxt_router_access_log_t *access_log) -{ - if (access_log == NULL) { - return; - } - - nxt_thread_spin_lock(lock); - - if (--access_log->count != 0) { - access_log = NULL; - } - - nxt_thread_spin_unlock(lock); - - if (access_log != NULL) { - - if (access_log->fd != -1) { - nxt_fd_close(access_log->fd); - } - - nxt_free(access_log); - } -} - - -typedef struct { - nxt_mp_t *mem_pool; - nxt_router_access_log_t *access_log; -} nxt_router_access_log_reopen_t; - - -void -nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_mp_t *mp; - uint32_t stream; - nxt_int_t ret; - nxt_buf_t *b; - nxt_port_t *main_port, *router_port; - nxt_runtime_t *rt; - nxt_router_access_log_t *access_log; - nxt_router_access_log_reopen_t *reopen; - - access_log = nxt_router->access_log; - - if (access_log == NULL) { - return; - } - - mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { - return; - } - - reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t)); - if (nxt_slow_path(reopen == NULL)) { - goto fail; - } - - reopen->mem_pool = mp; - reopen->access_log = access_log; - - b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0); - if (nxt_slow_path(b == NULL)) { - goto fail; - } - - b->completion_handler = nxt_router_access_log_reopen_completion; - - nxt_buf_cpystr(b, &access_log->path); - *b->mem.free++ = '\0'; - - rt = task->thread->runtime; - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - stream = nxt_port_rpc_register_handler(task, router_port, - nxt_router_access_log_reopen_ready, - nxt_router_access_log_reopen_error, - -1, reopen); - if (nxt_slow_path(stream == 0)) { - goto fail; - } - - ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, - stream, router_port->id, b); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_rpc_cancel(task, router_port, stream); - goto fail; - } - - nxt_mp_retain(mp); - - return; - -fail: - - nxt_mp_destroy(mp); -} - - -static void -nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_mp_t *mp; - nxt_buf_t *b; - - b = obj; - mp = b->data; - - nxt_mp_release(mp); -} - - -static void -nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_router_access_log_t *access_log; - nxt_router_access_log_reopen_t *reopen; - - reopen = data; - - access_log = reopen->access_log; - - if (access_log == nxt_router->access_log) { - - if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) { - nxt_alert(task, "dup2(%FD, %FD) failed %E", - msg->fd[0], access_log->fd, nxt_errno); - } - } - - nxt_fd_close(msg->fd[0]); - nxt_mp_release(reopen->mem_pool); -} - - -static void -nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_router_access_log_reopen_t *reopen; - - reopen = data; - - nxt_mp_release(reopen->mem_pool); -} diff --git a/src/nxt_router_request.h b/src/nxt_router_request.h deleted file mode 100644 index 6e226bae..00000000 --- a/src/nxt_router_request.h +++ /dev/null @@ -1,40 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_ROUTER_REQUEST_H_INCLUDED_ -#define _NXT_ROUTER_REQUEST_H_INCLUDED_ - - -typedef struct { - nxt_buf_t *buf; - nxt_fd_t body_fd; - uint32_t tracking_cookie; -} nxt_msg_info_t; - - -typedef enum { - NXT_APR_NEW_PORT, - NXT_APR_REQUEST_FAILED, - NXT_APR_GOT_RESPONSE, - NXT_APR_UPGRADE, - NXT_APR_CLOSE, -} nxt_apr_action_t; - - -typedef struct { - uint32_t stream; - nxt_app_t *app; - - nxt_port_t *app_port; - nxt_apr_action_t apr_action; - - nxt_http_request_t *request; - nxt_msg_info_t msg_info; - - nxt_bool_t rpc_cancel; -} nxt_request_rpc_data_t; - - -#endif /* _NXT_ROUTER_REQUEST_H_INCLUDED_ */ diff --git a/src/nxt_runtime.c b/src/nxt_runtime.c deleted file mode 100644 index 0e7f879e..00000000 --- a/src/nxt_runtime.c +++ /dev/null @@ -1,1841 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include -#include - - -static nxt_int_t nxt_runtime_inherited_listen_sockets(nxt_task_t *task, - nxt_runtime_t *rt); -static nxt_int_t nxt_runtime_systemd_listen_sockets(nxt_task_t *task, - nxt_runtime_t *rt); -static nxt_int_t nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt); -static nxt_int_t nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt); -static void nxt_runtime_start(nxt_task_t *task, void *obj, void *data); -static void nxt_runtime_initial_start(nxt_task_t *task, nxt_uint_t status); -static void nxt_runtime_close_idle_connections(nxt_event_engine_t *engine); -static void nxt_runtime_stop_all_processes(nxt_task_t *task, nxt_runtime_t *rt); -static void nxt_runtime_exit(nxt_task_t *task, void *obj, void *data); -static nxt_int_t nxt_runtime_event_engine_change(nxt_task_t *task, - nxt_runtime_t *rt); -static nxt_int_t nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt); -static nxt_int_t nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt); -static nxt_int_t nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt); -static nxt_int_t nxt_runtime_log_files_init(nxt_runtime_t *rt); -static nxt_int_t nxt_runtime_log_files_create(nxt_task_t *task, - nxt_runtime_t *rt); -static nxt_int_t nxt_runtime_pid_file_create(nxt_task_t *task, - nxt_file_name_t *pid_file); -static void nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt, - nxt_runtime_cont_t cont); -static void nxt_runtime_thread_pool_init(void); -static void nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj, - void *data); -static nxt_process_t *nxt_runtime_process_get(nxt_runtime_t *rt, nxt_pid_t pid); -static void nxt_runtime_port_add(nxt_task_t *task, nxt_port_t *port); - - -nxt_int_t -nxt_runtime_create(nxt_task_t *task) -{ - nxt_mp_t *mp; - nxt_int_t ret; - nxt_array_t *listen_sockets; - nxt_runtime_t *rt; - nxt_app_lang_module_t *lang; - - mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { - return NXT_ERROR; - } - - rt = nxt_mp_zget(mp, sizeof(nxt_runtime_t)); - if (nxt_slow_path(rt == NULL)) { - goto fail; - } - - task->thread->runtime = rt; - rt->mem_pool = mp; - - nxt_thread_mutex_create(&rt->processes_mutex); - - rt->services = nxt_services_init(mp); - if (nxt_slow_path(rt->services == NULL)) { - goto fail; - } - - rt->languages = nxt_array_create(mp, 1, sizeof(nxt_app_lang_module_t)); - if (nxt_slow_path(rt->languages == NULL)) { - goto fail; - } - - /* Should not fail. */ - lang = nxt_array_add(rt->languages); - lang->type = NXT_APP_EXTERNAL; - lang->version = (u_char *) ""; - lang->file = NULL; - lang->module = &nxt_external_module; - - lang->mounts = nxt_array_create(mp, 1, sizeof(nxt_fs_mount_t)); - if (nxt_slow_path(lang->mounts == NULL)) { - goto fail; - } - - listen_sockets = nxt_array_create(mp, 1, sizeof(nxt_listen_socket_t)); - if (nxt_slow_path(listen_sockets == NULL)) { - goto fail; - } - - rt->listen_sockets = listen_sockets; - - ret = nxt_runtime_inherited_listen_sockets(task, rt); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - if (nxt_runtime_hostname(task, rt) != NXT_OK) { - goto fail; - } - - if (nxt_slow_path(nxt_runtime_log_files_init(rt) != NXT_OK)) { - goto fail; - } - - if (nxt_runtime_event_engines(task, rt) != NXT_OK) { - goto fail; - } - - if (nxt_slow_path(nxt_runtime_thread_pools(task->thread, rt) != NXT_OK)) { - goto fail; - } - - rt->start = nxt_runtime_initial_start; - - if (nxt_runtime_conf_init(task, rt) != NXT_OK) { - goto fail; - } - - if (nxt_port_rpc_init() != NXT_OK) { - goto fail; - } - - if (nxt_slow_path(nxt_http_register_variables() != NXT_OK)) { - goto fail; - } - - if (nxt_slow_path(nxt_var_index_init() != NXT_OK)) { - goto fail; - } - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - nxt_runtime_start, task, rt, NULL); - - return NXT_OK; - -fail: - - nxt_mp_destroy(mp); - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_runtime_inherited_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt) -{ - u_char *v, *p; - nxt_int_t type; - nxt_array_t *inherited_sockets; - nxt_socket_t s; - nxt_listen_socket_t *ls; - - v = (u_char *) getenv("NGINX"); - - if (v == NULL) { - return nxt_runtime_systemd_listen_sockets(task, rt); - } - - nxt_alert(task, "using inherited listen sockets: %s", v); - - inherited_sockets = nxt_array_create(rt->mem_pool, - 1, sizeof(nxt_listen_socket_t)); - if (inherited_sockets == NULL) { - return NXT_ERROR; - } - - rt->inherited_sockets = inherited_sockets; - - for (p = v; *p != '\0'; p++) { - - if (*p == ';') { - s = nxt_int_parse(v, p - v); - - if (nxt_slow_path(s < 0)) { - nxt_alert(task, "invalid socket number \"%s\" " - "in NGINX environment variable, " - "ignoring the rest of the variable", v); - return NXT_ERROR; - } - - v = p + 1; - - ls = nxt_array_zero_add(inherited_sockets); - if (nxt_slow_path(ls == NULL)) { - return NXT_ERROR; - } - - ls->socket = s; - - ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s); - if (nxt_slow_path(ls->sockaddr == NULL)) { - return NXT_ERROR; - } - - type = nxt_socket_getsockopt(task, s, SOL_SOCKET, SO_TYPE); - if (nxt_slow_path(type == -1)) { - return NXT_ERROR; - } - - ls->sockaddr->type = (uint16_t) type; - } - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_runtime_systemd_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt) -{ - u_char *nfd, *pid; - nxt_int_t n; - nxt_array_t *inherited_sockets; - nxt_socket_t s; - nxt_listen_socket_t *ls; - - /* - * Number of listening sockets passed. The socket - * descriptors start from number 3 and are sequential. - */ - nfd = (u_char *) getenv("LISTEN_FDS"); - if (nfd == NULL) { - return NXT_OK; - } - - /* The pid of the service process. */ - pid = (u_char *) getenv("LISTEN_PID"); - if (pid == NULL) { - return NXT_OK; - } - - n = nxt_int_parse(nfd, nxt_strlen(nfd)); - if (n < 0) { - return NXT_OK; - } - - if (nxt_pid != nxt_int_parse(pid, nxt_strlen(pid))) { - return NXT_OK; - } - - nxt_log(task, NXT_LOG_INFO, "using %i systemd listen sockets", n); - - inherited_sockets = nxt_array_create(rt->mem_pool, - n, sizeof(nxt_listen_socket_t)); - if (inherited_sockets == NULL) { - return NXT_ERROR; - } - - rt->inherited_sockets = inherited_sockets; - - for (s = 3; s < n; s++) { - ls = nxt_array_zero_add(inherited_sockets); - if (nxt_slow_path(ls == NULL)) { - return NXT_ERROR; - } - - ls->socket = s; - - ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s); - if (nxt_slow_path(ls->sockaddr == NULL)) { - return NXT_ERROR; - } - - ls->sockaddr->type = SOCK_STREAM; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt) -{ - nxt_thread_t *thread; - nxt_event_engine_t *engine; - const nxt_event_interface_t *interface; - - interface = nxt_service_get(rt->services, "engine", NULL); - - if (nxt_slow_path(interface == NULL)) { - /* TODO: log */ - return NXT_ERROR; - } - - engine = nxt_event_engine_create(task, interface, - nxt_main_process_signals, 0, 0); - - if (nxt_slow_path(engine == NULL)) { - return NXT_ERROR; - } - - thread = task->thread; - thread->engine = engine; -#if 0 - thread->fiber = &engine->fibers->fiber; -#endif - - engine->id = rt->last_engine_id++; - engine->mem_pool = nxt_mp_create(1024, 128, 256, 32); - - nxt_queue_init(&rt->engines); - nxt_queue_insert_tail(&rt->engines, &engine->link); - - return NXT_OK; -} - - -static nxt_int_t -nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt) -{ - nxt_int_t ret; - nxt_array_t *thread_pools; - - thread_pools = nxt_array_create(rt->mem_pool, 1, - sizeof(nxt_thread_pool_t *)); - - if (nxt_slow_path(thread_pools == NULL)) { - return NXT_ERROR; - } - - rt->thread_pools = thread_pools; - ret = nxt_runtime_thread_pool_create(thr, rt, 2, 60000 * 1000000LL); - - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -static void -nxt_runtime_start(nxt_task_t *task, void *obj, void *data) -{ - nxt_runtime_t *rt; - - rt = obj; - - nxt_debug(task, "rt conf done"); - - task->thread->log->ctx_handler = NULL; - task->thread->log->ctx = NULL; - - if (nxt_runtime_log_files_create(task, rt) != NXT_OK) { - goto fail; - } - - if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) { - goto fail; - } - - /* - * Thread pools should be destroyed before starting worker - * processes, because thread pool semaphores will stick in - * locked state in new processes after fork(). - */ - nxt_runtime_thread_pool_destroy(task, rt, rt->start); - - return; - -fail: - - nxt_runtime_quit(task, 1); -} - - -static void -nxt_runtime_initial_start(nxt_task_t *task, nxt_uint_t status) -{ - nxt_int_t ret; - nxt_thread_t *thr; - nxt_runtime_t *rt; - const nxt_event_interface_t *interface; - - thr = task->thread; - rt = thr->runtime; - - if (rt->inherited_sockets == NULL && rt->daemon) { - - if (nxt_process_daemon(task) != NXT_OK) { - goto fail; - } - - /* - * An event engine should be updated after fork() - * even if an event facility was not changed because: - * 1) inherited kqueue descriptor is invalid, - * 2) the signal thread is not inherited. - */ - interface = nxt_service_get(rt->services, "engine", rt->engine); - if (interface == NULL) { - goto fail; - } - - ret = nxt_event_engine_change(task->thread->engine, interface, - rt->batch); - if (ret != NXT_OK) { - goto fail; - } - } - - ret = nxt_runtime_pid_file_create(task, rt->pid_file); - if (ret != NXT_OK) { - goto fail; - } - - if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) { - goto fail; - } - - thr->engine->max_connections = rt->engine_connections; - - if (nxt_main_process_start(thr, task, rt) != NXT_ERROR) { - return; - } - -fail: - - nxt_runtime_quit(task, 1); -} - - -void -nxt_runtime_quit(nxt_task_t *task, nxt_uint_t status) -{ - nxt_bool_t done; - nxt_runtime_t *rt; - nxt_event_engine_t *engine; - - rt = task->thread->runtime; - rt->status |= status; - engine = task->thread->engine; - - nxt_debug(task, "exiting"); - - done = 1; - - if (!engine->shutdown) { - engine->shutdown = 1; - - if (!nxt_array_is_empty(rt->thread_pools)) { - nxt_runtime_thread_pool_destroy(task, rt, nxt_runtime_quit); - done = 0; - } - - if (rt->type == NXT_PROCESS_MAIN) { - nxt_runtime_stop_all_processes(task, rt); - done = 0; - } - } - - nxt_runtime_close_idle_connections(engine); - - if (done) { - nxt_work_queue_add(&engine->fast_work_queue, nxt_runtime_exit, - task, rt, engine); - } -} - - -static void -nxt_runtime_close_idle_connections(nxt_event_engine_t *engine) -{ - nxt_conn_t *c; - nxt_queue_t *idle; - nxt_queue_link_t *link, *next; - - nxt_debug(&engine->task, "close idle connections"); - - idle = &engine->idle_connections; - - for (link = nxt_queue_first(idle); - link != nxt_queue_tail(idle); - link = next) - { - next = nxt_queue_next(link); - c = nxt_queue_link_data(link, nxt_conn_t, link); - - if (!c->socket.read_ready) { - nxt_queue_remove(link); - nxt_conn_close(engine, c); - } - } -} - - -void -nxt_runtime_stop_app_processes(nxt_task_t *task, nxt_runtime_t *rt) -{ - nxt_port_t *port; - nxt_process_t *process; - nxt_process_init_t *init; - - nxt_runtime_process_each(rt, process) { - - init = nxt_process_init(process); - - if (init->type == NXT_PROCESS_APP - || init->type == NXT_PROCESS_PROTOTYPE) - { - - nxt_process_port_each(process, port) { - - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, - 0, 0, NULL); - - } nxt_process_port_loop; - } - - } nxt_runtime_process_loop; -} - - -static void -nxt_runtime_stop_all_processes(nxt_task_t *task, nxt_runtime_t *rt) -{ - nxt_port_t *port; - nxt_process_t *process; - - nxt_runtime_process_each(rt, process) { - - nxt_process_port_each(process, port) { - - nxt_debug(task, "%d sending quit to %PI", rt->type, port->pid); - - (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, - 0, NULL); - - } nxt_process_port_loop; - - } nxt_runtime_process_loop; -} - - -static void -nxt_runtime_exit(nxt_task_t *task, void *obj, void *data) -{ - int status, engine_count; - nxt_runtime_t *rt; - nxt_process_t *process; - nxt_event_engine_t *engine; - - rt = obj; - engine = data; - - nxt_debug(task, "thread pools: %d", rt->thread_pools->nelts); - - if (!nxt_array_is_empty(rt->thread_pools)) { - return; - } - - if (rt->type == NXT_PROCESS_MAIN) { - if (rt->pid_file != NULL) { - nxt_file_delete(rt->pid_file); - } - -#if (NXT_HAVE_UNIX_DOMAIN) - { - size_t i; - nxt_sockaddr_t *sa; - nxt_file_name_t *name; - - sa = rt->controller_listen; - - if (sa->u.sockaddr.sa_family == AF_UNIX) { - name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; - (void) nxt_file_delete(name); - } - - for (i = 0; i < rt->listen_sockets->nelts; i++) { - nxt_listen_socket_t *ls; - - ls = (nxt_listen_socket_t *) rt->listen_sockets->elts + i; - sa = ls->sockaddr; - - if (sa->u.sockaddr.sa_family != AF_UNIX - || sa->u.sockaddr_un.sun_path[0] == '\0') - { - continue; - } - - name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; - (void) nxt_file_delete(name); - } - } -#endif - } - - if (!engine->event.signal_support) { - nxt_event_engine_signals_stop(engine); - } - - nxt_runtime_process_each(rt, process) { - - nxt_runtime_process_remove(rt, process); - nxt_process_close_ports(task, process); - - } nxt_runtime_process_loop; - - status = rt->status; - - engine_count = 0; - - nxt_queue_each(engine, &rt->engines, nxt_event_engine_t, link) { - - engine_count++; - - } nxt_queue_loop; - - if (engine_count <= 1) { - if (rt->port_by_type[rt->type] != NULL) { - nxt_port_use(task, rt->port_by_type[rt->type], -1); - } - - nxt_thread_mutex_destroy(&rt->processes_mutex); - - nxt_mp_destroy(rt->mem_pool); - } - - nxt_debug(task, "exit: %d", status); - - exit(status); - nxt_unreachable(); -} - - -static nxt_int_t -nxt_runtime_event_engine_change(nxt_task_t *task, nxt_runtime_t *rt) -{ - nxt_event_engine_t *engine; - const nxt_event_interface_t *interface; - - engine = task->thread->engine; - - if (engine->batch == rt->batch - && nxt_strcmp(engine->event.name, rt->engine) == 0) - { - return NXT_OK; - } - - interface = nxt_service_get(rt->services, "engine", rt->engine); - - if (interface != NULL) { - return nxt_event_engine_change(engine, interface, rt->batch); - } - - return NXT_ERROR; -} - - -void -nxt_runtime_event_engine_free(nxt_runtime_t *rt) -{ - nxt_queue_link_t *link; - nxt_event_engine_t *engine; - - link = nxt_queue_first(&rt->engines); - nxt_queue_remove(link); - - engine = nxt_queue_link_data(link, nxt_event_engine_t, link); - nxt_event_engine_free(engine); -} - - -nxt_int_t -nxt_runtime_thread_pool_create(nxt_thread_t *thr, nxt_runtime_t *rt, - nxt_uint_t max_threads, nxt_nsec_t timeout) -{ - nxt_thread_pool_t *thread_pool, **tp; - - tp = nxt_array_add(rt->thread_pools); - if (tp == NULL) { - return NXT_ERROR; - } - - thread_pool = nxt_thread_pool_create(max_threads, timeout, - nxt_runtime_thread_pool_init, - thr->engine, - nxt_runtime_thread_pool_exit); - - if (nxt_fast_path(thread_pool != NULL)) { - *tp = thread_pool; - } - - return NXT_OK; -} - - -static void -nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt, - nxt_runtime_cont_t cont) -{ - nxt_uint_t n; - nxt_thread_pool_t **tp; - - rt->continuation = cont; - - n = rt->thread_pools->nelts; - - if (n == 0) { - cont(task, 0); - return; - } - - tp = rt->thread_pools->elts; - - do { - nxt_thread_pool_destroy(*tp); - - tp++; - n--; - } while (n != 0); -} - - -static void -nxt_runtime_thread_pool_init(void) -{ -} - - -static void -nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj, void *data) -{ - nxt_uint_t i, n; - nxt_runtime_t *rt; - nxt_thread_pool_t *tp, **thread_pools; - nxt_thread_handle_t handle; - - tp = obj; - - if (data != NULL) { - handle = (nxt_thread_handle_t) (uintptr_t) data; - nxt_thread_wait(handle); - } - - rt = task->thread->runtime; - - thread_pools = rt->thread_pools->elts; - n = rt->thread_pools->nelts; - - nxt_debug(task, "thread pools: %ui", n); - - for (i = 0; i < n; i++) { - - if (tp == thread_pools[i]) { - nxt_array_remove(rt->thread_pools, &thread_pools[i]); - - nxt_free(tp); - - if (n == 1) { - /* The last thread pool. */ - rt->continuation(task, 0); - } - - return; - } - } -} - - -static nxt_int_t -nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt) -{ - nxt_int_t ret; - nxt_str_t control; - nxt_uint_t n; - nxt_file_t *file; - const char *slash; - nxt_sockaddr_t *sa; - nxt_file_name_str_t file_name; - const nxt_event_interface_t *interface; - - rt->daemon = 1; - rt->engine_connections = 256; - rt->auxiliary_threads = 2; - rt->user_cred.user = NXT_USER; - rt->group = NXT_GROUP; - rt->pid = NXT_PID; - rt->log = NXT_LOG; - rt->modules = NXT_MODULESDIR; - rt->state = NXT_STATEDIR; - rt->control = NXT_CONTROL_SOCK; - rt->tmp = NXT_TMPDIR; - - nxt_memzero(&rt->capabilities, sizeof(nxt_capabilities_t)); - - if (nxt_runtime_conf_read_cmd(task, rt) != NXT_OK) { - return NXT_ERROR; - } - - if (nxt_capability_set(task, &rt->capabilities) != NXT_OK) { - return NXT_ERROR; - } - - if (rt->capabilities.setid) { - ret = nxt_credential_get(task, rt->mem_pool, &rt->user_cred, - rt->group); - - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - } else { - nxt_log(task, NXT_LOG_WARN, "Unit is running unprivileged, then it " - "cannot use arbitrary user and group."); - } - - /* An engine's parameters. */ - - interface = nxt_service_get(rt->services, "engine", rt->engine); - if (interface == NULL) { - return NXT_ERROR; - } - - rt->engine = interface->name; - - ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%Z", rt->pid); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - rt->pid_file = file_name.start; - - ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%Z", rt->log); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - file = nxt_list_first(rt->log_files); - file->name = file_name.start; - - slash = ""; - n = nxt_strlen(rt->modules); - - if (n > 1 && rt->modules[n - 1] != '/') { - slash = "/"; - } - - ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%s*.unit.so%Z", - rt->modules, slash); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - rt->modules = (char *) file_name.start; - - slash = ""; - n = nxt_strlen(rt->state); - - if (n > 1 && rt->state[n - 1] != '/') { - slash = "/"; - } - - ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%sversion%Z", - rt->state, slash); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - rt->ver = (char *) file_name.start; - - ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s.tmp%Z", rt->ver); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - rt->ver_tmp = (char *) file_name.start; - - ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%sconf.json%Z", - rt->state, slash); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - rt->conf = (char *) file_name.start; - - ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s.tmp%Z", rt->conf); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - rt->conf_tmp = (char *) file_name.start; - - ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%scerts/%Z", - rt->state, slash); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - ret = mkdir((char *) file_name.start, S_IRWXU); - - if (nxt_fast_path(ret == 0 || nxt_errno == EEXIST)) { - rt->certs.length = file_name.len; - rt->certs.start = file_name.start; - - } else { - nxt_alert(task, "Unable to create certificates storage directory: " - "mkdir(%s) failed %E", file_name.start, nxt_errno); - } - - ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%sscripts/%Z", - rt->state, slash); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - ret = mkdir((char *) file_name.start, S_IRWXU); - - if (nxt_fast_path(ret == 0 || nxt_errno == EEXIST)) { - rt->scripts.length = file_name.len; - rt->scripts.start = file_name.start; - - } else { - nxt_alert(task, "Unable to create scripts storage directory: " - "mkdir(%s) failed %E", file_name.start, nxt_errno); - } - - control.length = nxt_strlen(rt->control); - control.start = (u_char *) rt->control; - - sa = nxt_sockaddr_parse(rt->mem_pool, &control); - if (nxt_slow_path(sa == NULL)) { - return NXT_ERROR; - } - - sa->type = SOCK_STREAM; - - rt->controller_listen = sa; - - if (nxt_runtime_controller_socket(task, rt) != NXT_OK) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt) -{ - char *p, **argv; - u_char *end; - u_char buf[1024]; - - static const char version[] = - "unit version: " NXT_VERSION "\n" - "configured as ./configure" NXT_CONFIGURE_OPTIONS "\n"; - - static const char no_control[] = - "option \"--control\" requires socket address\n"; - static const char no_control_mode[] = - "option \"--control-mode\" requires a mode\n"; - static const char no_control_user[] = - "option \"--control-user\" requires a username\n"; - static const char no_control_group[] = - "option \"--control-group\" requires a group name\n"; - static const char no_user[] = "option \"--user\" requires username\n"; - static const char no_group[] = "option \"--group\" requires group name\n"; - static const char no_pid[] = "option \"--pid\" requires filename\n"; - static const char no_log[] = "option \"--log\" requires filename\n"; - static const char no_modules[] = - "option \"--modulesdir\" requires directory\n"; - static const char no_state[] = - "option \"--statedir\" requires directory\n"; - static const char no_tmp[] = "option \"--tmpdir\" requires directory\n"; - - static const char modules_deprecated[] = - "option \"--modules\" is deprecated; use \"--modulesdir\" instead\n"; - static const char state_deprecated[] = - "option \"--state\" is deprecated; use \"--statedir\" instead\n"; - static const char tmp_deprecated[] = - "option \"--tmp\" is deprecated; use \"--tmpdir\" instead\n"; - - static const char help[] = - "\n" - "unit options:\n" - "\n" - " --version print unit version and configure options\n" - "\n" - " --no-daemon run unit in non-daemon mode\n" - "\n" - " --control ADDRESS set address of control API socket\n" - " default: \"" NXT_CONTROL_SOCK "\"\n" - "\n" - " --control-mode MODE set mode of the control API socket\n" - " default: 0600\n" - "\n" - " --control-user USER set the owner of the control API socket\n" - "\n" - " --control-group GROUP set the group of the control API socket\n" - "\n" - " --pid FILE set pid filename\n" - " default: \"" NXT_PID "\"\n" - "\n" - " --log FILE set log filename\n" - " default: \"" NXT_LOG "\"\n" - "\n" - " --modulesdir DIR set modules directory name\n" - " default: \"" NXT_MODULESDIR "\"\n" - "\n" - " --statedir DIR set state directory name\n" - " default: \"" NXT_STATEDIR "\"\n" - "\n" - " --tmpdir DIR set tmp directory name\n" - " default: \"" NXT_TMPDIR "\"\n" - "\n" - " --modules DIR [deprecated] synonym for --modulesdir\n" - " --state DIR [deprecated] synonym for --statedir\n" - " --tmp DIR [deprecated] synonym for --tmpdir\n" - "\n" - " --user USER set non-privileged processes to run" - " as specified user\n" - " default: \"" NXT_USER "\"\n" - "\n" - " --group GROUP set non-privileged processes to run" - " as specified group\n" - " default: "; - - static const char group[] = "\"" NXT_GROUP "\"\n\n"; - static const char primary[] = "user's primary group\n\n"; - - argv = &nxt_process_argv[1]; - - while (*argv != NULL) { - p = *argv++; - - if (nxt_strcmp(p, "--control") == 0) { - if (*argv == NULL) { - write(STDERR_FILENO, no_control, nxt_length(no_control)); - return NXT_ERROR; - } - - p = *argv++; - - rt->control = p; - - continue; - } - - if (nxt_strcmp(p, "--control-mode") == 0) { - if (*argv == NULL) { - write(STDERR_FILENO, no_control_mode, - nxt_length(no_control_mode)); - return NXT_ERROR; - } - - p = *argv++; - - rt->control_mode = strtoul(p, NULL, 8); - - continue; - } - - if (nxt_strcmp(p, "--control-user") == 0) { - if (*argv == NULL) { - write(STDERR_FILENO, no_control_user, - nxt_length(no_control_user)); - return NXT_ERROR; - } - - p = *argv++; - - rt->control_user = p; - - continue; - } - - if (nxt_strcmp(p, "--control-group") == 0) { - if (*argv == NULL) { - write(STDERR_FILENO, no_control_group, - nxt_length(no_control_group)); - return NXT_ERROR; - } - - p = *argv++; - - rt->control_group = p; - - continue; - } - - if (nxt_strcmp(p, "--user") == 0) { - if (*argv == NULL) { - write(STDERR_FILENO, no_user, nxt_length(no_user)); - return NXT_ERROR; - } - - p = *argv++; - - rt->user_cred.user = p; - - continue; - } - - if (nxt_strcmp(p, "--group") == 0) { - if (*argv == NULL) { - write(STDERR_FILENO, no_group, nxt_length(no_group)); - return NXT_ERROR; - } - - p = *argv++; - - rt->group = p; - - continue; - } - - if (nxt_strcmp(p, "--pid") == 0) { - if (*argv == NULL) { - write(STDERR_FILENO, no_pid, nxt_length(no_pid)); - return NXT_ERROR; - } - - p = *argv++; - - rt->pid = p; - - continue; - } - - if (nxt_strcmp(p, "--log") == 0) { - if (*argv == NULL) { - write(STDERR_FILENO, no_log, nxt_length(no_log)); - return NXT_ERROR; - } - - p = *argv++; - - rt->log = p; - - continue; - } - - if (nxt_strcmp(p, "--modules") == 0) { - write(STDERR_FILENO, modules_deprecated, - nxt_length(modules_deprecated)); - goto modulesdir; - } - - if (nxt_strcmp(p, "--modulesdir") == 0) { -modulesdir: - if (*argv == NULL) { - write(STDERR_FILENO, no_modules, nxt_length(no_modules)); - return NXT_ERROR; - } - - p = *argv++; - - rt->modules = p; - - continue; - } - - if (nxt_strcmp(p, "--state") == 0) { - write(STDERR_FILENO, state_deprecated, - nxt_length(state_deprecated)); - goto statedir; - } - - if (nxt_strcmp(p, "--statedir") == 0) { -statedir: - if (*argv == NULL) { - write(STDERR_FILENO, no_state, nxt_length(no_state)); - return NXT_ERROR; - } - - p = *argv++; - - rt->state = p; - - continue; - } - - if (nxt_strcmp(p, "--tmp") == 0) { - write(STDERR_FILENO, tmp_deprecated, nxt_length(tmp_deprecated)); - goto tmpdir; - } - - if (nxt_strcmp(p, "--tmpdir") == 0) { -tmpdir: - if (*argv == NULL) { - write(STDERR_FILENO, no_tmp, nxt_length(no_tmp)); - return NXT_ERROR; - } - - p = *argv++; - - rt->tmp = p; - - continue; - } - - if (nxt_strcmp(p, "--no-daemon") == 0) { - rt->daemon = 0; - continue; - } - - if (nxt_strcmp(p, "--version") == 0) { - write(STDERR_FILENO, version, nxt_length(version)); - exit(0); - } - - if (nxt_strcmp(p, "--help") == 0 || nxt_strcmp(p, "-h") == 0) { - write(STDOUT_FILENO, help, nxt_length(help)); - - if (sizeof(NXT_GROUP) == 1) { - write(STDOUT_FILENO, primary, nxt_length(primary)); - - } else { - write(STDOUT_FILENO, group, nxt_length(group)); - } - - exit(0); - } - - end = nxt_sprintf(buf, buf + sizeof(buf), "unknown option \"%s\", " - "try \"%s -h\" for available options\n", - p, nxt_process_argv[0]); - - write(STDERR_FILENO, buf, end - buf); - - return NXT_ERROR; - } - - return NXT_OK; -} - - -nxt_listen_socket_t * -nxt_runtime_listen_socket_add(nxt_runtime_t *rt, nxt_sockaddr_t *sa) -{ - nxt_mp_t *mp; - nxt_listen_socket_t *ls; - - ls = nxt_array_zero_add(rt->listen_sockets); - if (ls == NULL) { - return NULL; - } - - mp = rt->mem_pool; - - ls->sockaddr = nxt_sockaddr_create(mp, &sa->u.sockaddr, sa->socklen, - sa->length); - if (ls->sockaddr == NULL) { - return NULL; - } - - ls->sockaddr->type = sa->type; - - nxt_sockaddr_text(ls->sockaddr); - - ls->socket = -1; - ls->backlog = NXT_LISTEN_BACKLOG; - - return ls; -} - - -static nxt_int_t -nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt) -{ - size_t length; - char hostname[NXT_MAXHOSTNAMELEN + 1]; - - if (gethostname(hostname, NXT_MAXHOSTNAMELEN) != 0) { - nxt_alert(task, "gethostname() failed %E", nxt_errno); - return NXT_ERROR; - } - - /* - * Linux gethostname(2): - * - * If the null-terminated hostname is too large to fit, - * then the name is truncated, and no error is returned. - * - * For this reason an additional byte is reserved in the buffer. - */ - hostname[NXT_MAXHOSTNAMELEN] = '\0'; - - length = nxt_strlen(hostname); - rt->hostname.length = length; - - rt->hostname.start = nxt_mp_nget(rt->mem_pool, length); - - if (rt->hostname.start != NULL) { - nxt_memcpy_lowcase(rt->hostname.start, (u_char *) hostname, length); - return NXT_OK; - } - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_runtime_log_files_init(nxt_runtime_t *rt) -{ - nxt_file_t *file; - nxt_list_t *log_files; - - log_files = nxt_list_create(rt->mem_pool, 1, sizeof(nxt_file_t)); - - if (nxt_fast_path(log_files != NULL)) { - rt->log_files = log_files; - - /* Preallocate the main log. This allocation cannot fail. */ - file = nxt_list_zero_add(log_files); - - file->fd = NXT_FILE_INVALID; - file->log_level = NXT_LOG_ALERT; - - return NXT_OK; - } - - return NXT_ERROR; -} - - -nxt_file_t * -nxt_runtime_log_file_add(nxt_runtime_t *rt, nxt_str_t *name) -{ - nxt_int_t ret; - nxt_file_t *file; - nxt_file_name_str_t file_name; - - ret = nxt_file_name_create(rt->mem_pool, &file_name, "V%Z", name); - - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - nxt_list_each(file, rt->log_files) { - - /* STUB: hardecoded case sensitive/insensitive. */ - - if (file->name != NULL - && nxt_file_name_eq(file->name, file_name.start)) - { - return file; - } - - } nxt_list_loop; - - file = nxt_list_zero_add(rt->log_files); - - if (nxt_slow_path(file == NULL)) { - return NULL; - } - - file->fd = NXT_FILE_INVALID; - file->log_level = NXT_LOG_ALERT; - file->name = file_name.start; - - return file; -} - - -static nxt_int_t -nxt_runtime_log_files_create(nxt_task_t *task, nxt_runtime_t *rt) -{ - nxt_int_t ret; - nxt_file_t *file; - - nxt_list_each(file, rt->log_files) { - - ret = nxt_file_open(task, file, O_WRONLY | O_APPEND, O_CREAT, - NXT_FILE_OWNER_ACCESS); - - if (ret != NXT_OK) { - return NXT_ERROR; - } - - } nxt_list_loop; - - file = nxt_list_first(rt->log_files); - - return nxt_file_stderr(file); -} - - -nxt_int_t -nxt_runtime_listen_sockets_create(nxt_task_t *task, nxt_runtime_t *rt) -{ - nxt_int_t ret; - nxt_uint_t c, p, ncurr, nprev; - nxt_listen_socket_t *curr, *prev; - - curr = rt->listen_sockets->elts; - ncurr = rt->listen_sockets->nelts; - - if (rt->inherited_sockets != NULL) { - prev = rt->inherited_sockets->elts; - nprev = rt->inherited_sockets->nelts; - - } else { - prev = NULL; - nprev = 0; - } - - for (c = 0; c < ncurr; c++) { - - for (p = 0; p < nprev; p++) { - - if (nxt_sockaddr_cmp(curr[c].sockaddr, prev[p].sockaddr)) { - - ret = nxt_listen_socket_update(task, &curr[c], &prev[p]); - if (ret != NXT_OK) { - return NXT_ERROR; - } - - goto next; - } - } - - if (nxt_listen_socket_create(task, rt->mem_pool, &curr[c]) != NXT_OK) { - return NXT_ERROR; - } - - next: - - continue; - } - - return NXT_OK; -} - - -nxt_int_t -nxt_runtime_listen_sockets_enable(nxt_task_t *task, nxt_runtime_t *rt) -{ - nxt_uint_t i, n; - nxt_listen_socket_t *ls; - - ls = rt->listen_sockets->elts; - n = rt->listen_sockets->nelts; - - for (i = 0; i < n; i++) { - if (ls[i].flags == NXT_NONBLOCK) { - if (nxt_listen_event(task, &ls[i]) == NULL) { - return NXT_ERROR; - } - } - } - - return NXT_OK; -} - - -nxt_str_t * -nxt_current_directory(nxt_mp_t *mp) -{ - size_t length; - u_char *p; - nxt_str_t *name; - char buf[NXT_MAX_PATH_LEN]; - - length = nxt_dir_current(buf, NXT_MAX_PATH_LEN); - - if (nxt_fast_path(length != 0)) { - name = nxt_str_alloc(mp, length + 1); - - if (nxt_fast_path(name != NULL)) { - p = nxt_cpymem(name->start, buf, length); - *p = '/'; - - return name; - } - } - - return NULL; -} - - -static nxt_int_t -nxt_runtime_pid_file_create(nxt_task_t *task, nxt_file_name_t *pid_file) -{ - ssize_t length; - nxt_int_t n; - nxt_file_t file; - u_char pid[NXT_INT64_T_LEN + nxt_length("\n")]; - - nxt_memzero(&file, sizeof(nxt_file_t)); - - file.name = pid_file; - - nxt_fs_mkdir_parent(pid_file, 0755); - - n = nxt_file_open(task, &file, O_WRONLY, O_CREAT | O_TRUNC, - NXT_FILE_DEFAULT_ACCESS); - - if (n != NXT_OK) { - return NXT_ERROR; - } - - length = nxt_sprintf(pid, pid + sizeof(pid), "%PI%n", nxt_pid) - pid; - - if (nxt_file_write(&file, pid, length, 0) != length) { - return NXT_ERROR; - } - - nxt_file_close(task, &file); - - return NXT_OK; -} - - -void -nxt_runtime_process_release(nxt_runtime_t *rt, nxt_process_t *process) -{ - nxt_process_t *child; - - if (process->registered == 1) { - nxt_runtime_process_remove(rt, process); - } - - if (process->link.next != NULL) { - nxt_queue_remove(&process->link); - } - - nxt_queue_each(child, &process->children, nxt_process_t, link) { - nxt_queue_remove(&child->link); - child->link.next = NULL; - } nxt_queue_loop; - - nxt_assert(process->use_count == 0); - nxt_assert(process->registered == 0); - nxt_assert(nxt_queue_is_empty(&process->ports)); - - nxt_port_mmaps_destroy(&process->incoming, 1); - - nxt_thread_mutex_destroy(&process->incoming.mutex); - - /* processes from nxt_runtime_process_get() have no memory pool */ - if (process->mem_pool != NULL) { - nxt_mp_destroy(process->mem_pool); - } - - nxt_mp_free(rt->mem_pool, process); -} - - -static nxt_int_t -nxt_runtime_lvlhsh_pid_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_process_t *process; - - process = data; - - if (lhq->key.length == sizeof(nxt_pid_t) - && *(nxt_pid_t *) lhq->key.start == process->pid) - { - return NXT_OK; - } - - return NXT_DECLINED; -} - -static const nxt_lvlhsh_proto_t lvlhsh_processes_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_runtime_lvlhsh_pid_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -nxt_inline void -nxt_runtime_process_lhq_pid(nxt_lvlhsh_query_t *lhq, nxt_pid_t *pid) -{ - lhq->key_hash = nxt_murmur_hash2(pid, sizeof(*pid)); - lhq->key.length = sizeof(*pid); - lhq->key.start = (u_char *) pid; - lhq->proto = &lvlhsh_processes_proto; -} - - -nxt_process_t * -nxt_runtime_process_find(nxt_runtime_t *rt, nxt_pid_t pid) -{ - nxt_process_t *process; - nxt_lvlhsh_query_t lhq; - - process = NULL; - - nxt_runtime_process_lhq_pid(&lhq, &pid); - - nxt_thread_mutex_lock(&rt->processes_mutex); - - if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) { - process = lhq.value; - - } else { - nxt_thread_log_debug("process %PI not found", pid); - } - - nxt_thread_mutex_unlock(&rt->processes_mutex); - - return process; -} - - -static nxt_process_t * -nxt_runtime_process_get(nxt_runtime_t *rt, nxt_pid_t pid) -{ - nxt_process_t *process; - nxt_lvlhsh_query_t lhq; - - nxt_runtime_process_lhq_pid(&lhq, &pid); - - nxt_thread_mutex_lock(&rt->processes_mutex); - - if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) { - nxt_thread_log_debug("process %PI found", pid); - - nxt_thread_mutex_unlock(&rt->processes_mutex); - - process = lhq.value; - process->use_count++; - - return process; - } - - process = nxt_process_new(rt); - if (nxt_slow_path(process == NULL)) { - - nxt_thread_mutex_unlock(&rt->processes_mutex); - - return NULL; - } - - process->pid = pid; - - lhq.replace = 0; - lhq.value = process; - lhq.pool = rt->mem_pool; - - switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) { - - case NXT_OK: - if (rt->nprocesses == 0) { - rt->mprocess = process; - } - - rt->nprocesses++; - - process->registered = 1; - - nxt_thread_log_debug("process %PI insert", pid); - break; - - default: - nxt_thread_log_debug("process %PI insert failed", pid); - break; - } - - nxt_thread_mutex_unlock(&rt->processes_mutex); - - return process; -} - - -void -nxt_runtime_process_add(nxt_task_t *task, nxt_process_t *process) -{ - nxt_port_t *port; - nxt_runtime_t *rt; - nxt_lvlhsh_query_t lhq; - - nxt_assert(process->registered == 0); - - rt = task->thread->runtime; - - nxt_runtime_process_lhq_pid(&lhq, &process->pid); - - lhq.replace = 0; - lhq.value = process; - lhq.pool = rt->mem_pool; - - nxt_thread_mutex_lock(&rt->processes_mutex); - - switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) { - - case NXT_OK: - if (rt->nprocesses == 0) { - rt->mprocess = process; - } - - rt->nprocesses++; - - nxt_process_port_each(process, port) { - - port->pid = process->pid; - - nxt_runtime_port_add(task, port); - - } nxt_process_port_loop; - - process->registered = 1; - - nxt_debug(task, "process %PI added", process->pid); - break; - - default: - nxt_alert(task, "process %PI failed to add", process->pid); - break; - } - - nxt_thread_mutex_unlock(&rt->processes_mutex); -} - - -void -nxt_runtime_process_remove(nxt_runtime_t *rt, nxt_process_t *process) -{ - nxt_pid_t pid; - nxt_lvlhsh_query_t lhq; - - nxt_assert(process->registered != 0); - - pid = process->pid; - - nxt_runtime_process_lhq_pid(&lhq, &pid); - - lhq.pool = rt->mem_pool; - - nxt_thread_mutex_lock(&rt->processes_mutex); - - switch (nxt_lvlhsh_delete(&rt->processes, &lhq)) { - - case NXT_OK: - nxt_assert(lhq.value == process); - - rt->nprocesses--; - - process->registered = 0; - - nxt_thread_log_debug("process %PI removed", pid); - break; - - default: - nxt_thread_log_alert("process %PI remove failed", pid); - break; - } - - nxt_thread_mutex_unlock(&rt->processes_mutex); -} - - -nxt_process_t * -nxt_runtime_process_first(nxt_runtime_t *rt, nxt_lvlhsh_each_t *lhe) -{ - nxt_lvlhsh_each_init(lhe, &lvlhsh_processes_proto); - - return nxt_runtime_process_next(rt, lhe); -} - - -nxt_port_t * -nxt_runtime_process_port_create(nxt_task_t *task, nxt_runtime_t *rt, - nxt_pid_t pid, nxt_port_id_t id, nxt_process_type_t type) -{ - nxt_port_t *port; - nxt_process_t *process; - - process = nxt_runtime_process_get(rt, pid); - if (nxt_slow_path(process == NULL)) { - return NULL; - } - - port = nxt_port_new(task, id, pid, type); - if (nxt_slow_path(port == NULL)) { - nxt_process_use(task, process, -1); - return NULL; - } - - nxt_process_port_add(task, process, port); - - nxt_process_use(task, process, -1); - - nxt_runtime_port_add(task, port); - - nxt_port_use(task, port, -1); - - return port; -} - - -static void -nxt_runtime_port_add(nxt_task_t *task, nxt_port_t *port) -{ - nxt_int_t res; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - res = nxt_port_hash_add(&rt->ports, port); - - if (res != NXT_OK) { - return; - } - - rt->port_by_type[port->type] = port; - - nxt_port_use(task, port, 1); -} - - -void -nxt_runtime_port_remove(nxt_task_t *task, nxt_port_t *port) -{ - nxt_int_t res; - nxt_runtime_t *rt; - - rt = task->thread->runtime; - - res = nxt_port_hash_remove(&rt->ports, port); - - if (res != NXT_OK) { - return; - } - - if (rt->port_by_type[port->type] == port) { - rt->port_by_type[port->type] = NULL; - } - - nxt_port_use(task, port, -1); -} - - -nxt_port_t * -nxt_runtime_port_find(nxt_runtime_t *rt, nxt_pid_t pid, - nxt_port_id_t port_id) -{ - return nxt_port_hash_find(&rt->ports, pid, port_id); -} diff --git a/src/nxt_runtime.h b/src/nxt_runtime.h deleted file mode 100644 index 7bd490d7..00000000 --- a/src/nxt_runtime.h +++ /dev/null @@ -1,171 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_RUNTIME_H_INCLUDED_ -#define _NXT_RUNTIME_H_INCLUDED_ - - -typedef void (*nxt_runtime_cont_t)(nxt_task_t *task, nxt_uint_t status); - - -struct nxt_runtime_s { - nxt_mp_t *mem_pool; - - nxt_array_t *inherited_sockets; /* of nxt_listen_socket_t */ - nxt_array_t *listen_sockets; /* of nxt_listen_socket_t */ - - nxt_array_t *services; /* of nxt_service_t */ - nxt_array_t *languages; /* of nxt_app_lang_module_t */ - void *data; - - nxt_runtime_cont_t start; - - nxt_str_t hostname; - - nxt_file_name_t *pid_file; - -#if (NXT_TLS) - const nxt_tls_lib_t *tls; -#endif - - nxt_array_t *thread_pools; /* of nxt_thread_pool_t */ - nxt_runtime_cont_t continuation; - - nxt_process_t *mprocess; - size_t nprocesses; - nxt_thread_mutex_t processes_mutex; - nxt_lvlhsh_t processes; /* of nxt_process_t */ - - nxt_port_t *port_by_type[NXT_PROCESS_MAX]; - nxt_lvlhsh_t ports; /* of nxt_port_t */ - - nxt_list_t *log_files; /* of nxt_file_t */ - - uint32_t last_engine_id; - - nxt_process_type_t type; - - nxt_timer_t timer; - - uint8_t daemon; - uint8_t batch; - uint8_t status; - uint8_t is_pid_isolated; - - const char *engine; - uint32_t engine_connections; - uint32_t auxiliary_threads; - nxt_credential_t user_cred; - nxt_capabilities_t capabilities; - const char *group; - const char *pid; - const char *log; - const char *modules; - const char *state; - const char *ver; - const char *ver_tmp; - const char *conf; - const char *conf_tmp; - const char *tmp; - const char *control; - - mode_t control_mode; - const char *control_user; - const char *control_group; - - nxt_str_t certs; - nxt_str_t scripts; - - nxt_queue_t engines; /* of nxt_event_engine_t */ - - nxt_sockaddr_t *controller_listen; - nxt_listen_socket_t *controller_socket; -}; - - - -typedef nxt_int_t (*nxt_module_init_t)(nxt_thread_t *thr, nxt_runtime_t *rt); - - -nxt_int_t nxt_runtime_create(nxt_task_t *task); -void nxt_runtime_quit(nxt_task_t *task, nxt_uint_t status); - -void nxt_runtime_event_engine_free(nxt_runtime_t *rt); - -nxt_int_t nxt_runtime_thread_pool_create(nxt_thread_t *thr, nxt_runtime_t *rt, - nxt_uint_t max_threads, nxt_nsec_t timeout); - - -void nxt_runtime_process_add(nxt_task_t *task, nxt_process_t *process); -void nxt_runtime_process_remove(nxt_runtime_t *rt, nxt_process_t *process); - -nxt_process_t *nxt_runtime_process_find(nxt_runtime_t *rt, nxt_pid_t pid); - -nxt_process_t *nxt_runtime_process_first(nxt_runtime_t *rt, - nxt_lvlhsh_each_t *lhe); - -void nxt_runtime_process_release(nxt_runtime_t *rt, nxt_process_t *process); - -#define nxt_runtime_process_next(rt, lhe) \ - nxt_lvlhsh_each(&rt->processes, lhe) - -nxt_port_t *nxt_runtime_process_port_create(nxt_task_t *task, nxt_runtime_t *rt, - nxt_pid_t pid, nxt_port_id_t id, nxt_process_type_t type); - -void nxt_runtime_port_remove(nxt_task_t *task, nxt_port_t *port); -void nxt_runtime_stop_app_processes(nxt_task_t *task, nxt_runtime_t *rt); - -NXT_EXPORT nxt_port_t *nxt_runtime_port_find(nxt_runtime_t *rt, nxt_pid_t pid, - nxt_port_id_t port_id); - - -/* STUB */ -nxt_int_t nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt); - -nxt_str_t *nxt_current_directory(nxt_mp_t *mp); - -nxt_listen_socket_t *nxt_runtime_listen_socket_add(nxt_runtime_t *rt, - nxt_sockaddr_t *sa); -nxt_int_t nxt_runtime_listen_sockets_create(nxt_task_t *task, - nxt_runtime_t *rt); -nxt_int_t nxt_runtime_listen_sockets_enable(nxt_task_t *task, - nxt_runtime_t *rt); -nxt_file_t *nxt_runtime_log_file_add(nxt_runtime_t *rt, nxt_str_t *name); - -/* STUB */ -void nxt_cdecl nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, - const char *fmt, ...); - -void nxt_stream_connection_init(nxt_task_t *task, void *obj, void *data); - -nxt_int_t nxt_http_register_variables(void); -#if (NXT_HAVE_NJS) -void nxt_http_register_js_proto(nxt_js_conf_t *jcf); -#endif - - -#define nxt_runtime_process_each(rt, process) \ - do { \ - nxt_lvlhsh_each_t _lhe; \ - nxt_process_t *_nxt; \ - \ - for (process = nxt_runtime_process_first(rt, &_lhe); \ - process != NULL; \ - process = _nxt) { \ - \ - _nxt = nxt_runtime_process_next(rt, &_lhe); \ - -#define nxt_runtime_process_loop \ - } \ - } while(0) - - -extern nxt_module_init_t nxt_init_modules[]; -extern nxt_uint_t nxt_init_modules_n; - - -#endif /* _NXT_RUNTIME_H_INCLIDED_ */ diff --git a/src/nxt_script.c b/src/nxt_script.c deleted file mode 100644 index 70045a22..00000000 --- a/src/nxt_script.c +++ /dev/null @@ -1,709 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - * Copyright (C) Zhidao HONG - */ - -#include -#include -#include -#include - - -struct nxt_script_s { - nxt_str_t text; -}; - - -typedef struct { - nxt_str_t name; - nxt_conf_value_t *value; - nxt_mp_t *mp; -} nxt_script_info_t; - - -typedef struct { - nxt_str_t name; - nxt_fd_t fd; -} nxt_script_item_t; - - -static nxt_script_t *nxt_script_get(nxt_task_t *task, nxt_str_t *name, - nxt_fd_t fd); -static nxt_conf_value_t *nxt_script_details(nxt_mp_t *mp, nxt_script_t *cert); -static void nxt_script_buf_completion(nxt_task_t *task, void *obj, void *data); - - -static nxt_lvlhsh_t nxt_script_info; - - -static njs_vm_ops_t nxt_js_ops = { - NULL, - NULL, - nxt_js_module_loader, - NULL, -}; - - -nxt_script_t * -nxt_script_new(nxt_task_t *task, nxt_str_t *name, u_char *data, size_t size, - u_char *error) -{ - u_char *start; - njs_vm_t *vm; - njs_str_t mod_name; - njs_mod_t *mod; - njs_vm_opt_t opts; - nxt_script_t *script; - - njs_vm_opt_init(&opts); - - opts.backtrace = 1; - - opts.file.start = (u_char *) "default"; - opts.file.length = 7; - - opts.ops = &nxt_js_ops; - - vm = njs_vm_create(&opts); - if (nxt_slow_path(vm == NULL)) { - return NULL; - } - - mod_name.length = name->length; - mod_name.start = name->start; - - start = data; - - mod = njs_vm_compile_module(vm, &mod_name, &start, start + size); - - if (nxt_slow_path(mod == NULL)) { - (void) nxt_js_error(vm, error); - nxt_alert(task, "JS compile module(%V) failed: %s", name, error); - - goto fail; - } - - script = nxt_zalloc(sizeof(nxt_script_t) + size); - if (nxt_slow_path(script == NULL)) { - goto fail; - } - - script->text.length = size; - script->text.start = (u_char *) script + sizeof(nxt_script_t); - - nxt_memcpy(script->text.start, data, size); - - njs_vm_destroy(vm); - - return script; - -fail: - - njs_vm_destroy(vm); - - return NULL; -} - - -static nxt_script_t * -nxt_script_get(nxt_task_t *task, nxt_str_t *name, nxt_fd_t fd) -{ - nxt_int_t ret; - nxt_str_t text; - nxt_script_t *script; - u_char error[NXT_MAX_ERROR_STR]; - - ret = nxt_script_file_read(fd, &text); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - script = nxt_script_new(task, name, text.start, text.length, error); - - nxt_free(text.start); - - return script; -} - - -void -nxt_script_destroy(nxt_script_t *script) -{ - nxt_free(script); -} - - -static nxt_int_t -nxt_script_info_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_script_info_t *info; - - info = data; - - if (nxt_strcasestr_eq(&lhq->key, &info->name)) { - return NXT_OK; - } - - return NXT_DECLINED; -} - - -static const nxt_lvlhsh_proto_t nxt_script_info_hash_proto - nxt_aligned(64) = -{ - NXT_LVLHSH_DEFAULT, - nxt_script_info_hash_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -void -nxt_script_info_init(nxt_task_t *task, nxt_array_t *scripts) -{ - uint32_t i; - nxt_script_t *script; - nxt_script_item_t *item; - - item = scripts->elts; - - for (i = 0; i < scripts->nelts; i++) { - script = nxt_script_get(task, &item->name, item->fd); - - if (nxt_slow_path(script == NULL)) { - continue; - } - - (void) nxt_script_info_save(&item->name, script); - - nxt_script_destroy(script); - - item++; - } -} - - -nxt_int_t -nxt_script_info_save(nxt_str_t *name, nxt_script_t *script) -{ - nxt_mp_t *mp; - nxt_int_t ret; - nxt_conf_value_t *value; - nxt_script_info_t *info; - nxt_lvlhsh_query_t lhq; - - mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { - return NXT_ERROR; - } - - info = nxt_mp_get(mp, sizeof(nxt_script_info_t)); - if (nxt_slow_path(info == NULL)) { - goto fail; - } - - name = nxt_str_dup(mp, &info->name, name); - if (nxt_slow_path(name == NULL)) { - goto fail; - } - - value = nxt_script_details(mp, script); - if (nxt_slow_path(value == NULL)) { - goto fail; - } - - info->mp = mp; - info->value = value; - - lhq.key_hash = nxt_djb_hash(name->start, name->length); - lhq.replace = 1; - lhq.key = *name; - lhq.value = info; - lhq.proto = &nxt_script_info_hash_proto; - - ret = nxt_lvlhsh_insert(&nxt_script_info, &lhq); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - if (lhq.value != info) { - info = lhq.value; - nxt_mp_destroy(info->mp); - } - - return NXT_OK; - -fail: - - nxt_mp_destroy(mp); - return NXT_ERROR; -} - - -nxt_conf_value_t * -nxt_script_info_get(nxt_str_t *name) -{ - nxt_int_t ret; - nxt_script_info_t *info; - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_djb_hash(name->start, name->length); - lhq.key = *name; - lhq.proto = &nxt_script_info_hash_proto; - - ret = nxt_lvlhsh_find(&nxt_script_info, &lhq); - if (ret != NXT_OK) { - return NULL; - } - - info = lhq.value; - - return info->value; -} - - -nxt_conf_value_t * -nxt_script_info_get_all(nxt_mp_t *mp) -{ - uint32_t i; - nxt_conf_value_t *all; - nxt_script_info_t *info; - nxt_lvlhsh_each_t lhe; - - nxt_lvlhsh_each_init(&lhe, &nxt_script_info_hash_proto); - - for (i = 0; /* void */; i++) { - info = nxt_lvlhsh_each(&nxt_script_info, &lhe); - - if (info == NULL) { - break; - } - } - - all = nxt_conf_create_object(mp, i); - if (nxt_slow_path(all == NULL)) { - return NULL; - } - - nxt_lvlhsh_each_init(&lhe, &nxt_script_info_hash_proto); - - for (i = 0; /* void */; i++) { - info = nxt_lvlhsh_each(&nxt_script_info, &lhe); - - if (info == NULL) { - break; - } - - nxt_conf_set_member(all, &info->name, info->value, i); - } - - return all; -} - - -static nxt_conf_value_t * -nxt_script_details(nxt_mp_t *mp, nxt_script_t *script) -{ - nxt_conf_value_t *value; - - value = nxt_conf_create_object(mp, 0); - if (nxt_slow_path(value == NULL)) { - return NULL; - } - - nxt_conf_set_string_dup(value, mp, &script->text); - - return value; -} - - -nxt_int_t -nxt_script_info_delete(nxt_str_t *name) -{ - nxt_int_t ret; - nxt_script_info_t *info; - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_djb_hash(name->start, name->length); - lhq.key = *name; - lhq.proto = &nxt_script_info_hash_proto; - - ret = nxt_lvlhsh_delete(&nxt_script_info, &lhq); - - if (ret == NXT_OK) { - info = lhq.value; - nxt_mp_destroy(info->mp); - } - - return ret; -} - - -nxt_array_t * -nxt_script_store_load(nxt_task_t *task, nxt_mp_t *mp) -{ - DIR *dir; - size_t size, alloc; - u_char *buf, *p; - nxt_str_t name; - nxt_int_t ret; - nxt_file_t file; - nxt_array_t *scripts; - nxt_runtime_t *rt; - struct dirent *de; - nxt_script_item_t *item; - - rt = task->thread->runtime; - - if (nxt_slow_path(rt->scripts.start == NULL)) { - nxt_alert(task, "no scripts storage directory"); - return NULL; - } - - scripts = nxt_array_create(mp, 16, sizeof(nxt_script_item_t)); - if (nxt_slow_path(scripts == NULL)) { - return NULL; - } - - buf = NULL; - alloc = 0; - - dir = opendir((char *) rt->scripts.start); - if (nxt_slow_path(dir == NULL)) { - nxt_alert(task, "opendir(\"%s\") failed %E", - rt->scripts.start, nxt_errno); - goto fail; - } - - for ( ;; ) { - de = readdir(dir); - if (de == NULL) { - break; - } - - nxt_debug(task, "readdir(\"%s\"): \"%s\"", - rt->scripts.start, de->d_name); - - name.length = nxt_strlen(de->d_name); - name.start = (u_char *) de->d_name; - - if (nxt_str_eq(&name, ".", 1) || nxt_str_eq(&name, "..", 2)) { - continue; - } - - item = nxt_array_add(scripts); - if (nxt_slow_path(item == NULL)) { - goto fail; - } - - item->fd = -1; - - size = rt->scripts.length + name.length + 1; - - if (size > alloc) { - size += 32; - - p = nxt_realloc(buf, size); - if (p == NULL) { - goto fail; - } - - alloc = size; - buf = p; - } - - p = nxt_cpymem(buf, rt->scripts.start, rt->scripts.length); - p = nxt_cpymem(p, name.start, name.length + 1); - - nxt_memzero(&file, sizeof(nxt_file_t)); - - file.name = buf; - - ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, - NXT_FILE_OWNER_ACCESS); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_array_remove_last(scripts); - continue; - } - - item->fd = file.fd; - - if (nxt_slow_path(nxt_str_dup(mp, &item->name, &name) == NULL)) { - goto fail; - } - } - - if (buf != NULL) { - nxt_free(buf); - } - - (void) closedir(dir); - - return scripts; - -fail: - - if (buf != NULL) { - nxt_free(buf); - } - - if (dir != NULL) { - (void) closedir(dir); - } - - nxt_script_store_release(scripts); - - return NULL; -} - - -void -nxt_script_store_release(nxt_array_t *scripts) -{ - uint32_t i; - nxt_script_item_t *item; - - item = scripts->elts; - - for (i = 0; i < scripts->nelts; i++) { - nxt_fd_close(item[i].fd); - } - - nxt_array_destroy(scripts); -} - - -void -nxt_script_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp, - nxt_port_rpc_handler_t handler, void *ctx) -{ - uint32_t stream; - nxt_int_t ret; - nxt_buf_t *b; - nxt_port_t *main_port, *recv_port; - nxt_runtime_t *rt; - - b = nxt_buf_mem_alloc(mp, name->length + 1, 0); - if (nxt_slow_path(b == NULL)) { - goto fail; - } - - nxt_mp_retain(mp); - b->completion_handler = nxt_script_buf_completion; - - nxt_buf_cpystr(b, name); - *b->mem.free++ = '\0'; - - rt = task->thread->runtime; - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - recv_port = rt->port_by_type[rt->type]; - - stream = nxt_port_rpc_register_handler(task, recv_port, handler, handler, - -1, ctx); - if (nxt_slow_path(stream == 0)) { - goto fail; - } - - ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SCRIPT_GET, -1, - stream, recv_port->id, b); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_rpc_cancel(task, recv_port, stream); - goto fail; - } - - return; - -fail: - - handler(task, NULL, ctx); -} - - -static void -nxt_script_buf_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_mp_t *mp; - nxt_buf_t *b; - - b = obj; - mp = b->data; - nxt_assert(b->next == NULL); - - nxt_mp_free(mp, b); - nxt_mp_release(mp); -} - - -void -nxt_script_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - u_char *p; - nxt_int_t ret; - nxt_str_t name; - nxt_file_t file; - nxt_port_t *port; - nxt_runtime_t *rt; - nxt_port_msg_type_t type; - - port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, - msg->port_msg.reply_port); - - if (nxt_slow_path(port == NULL)) { - nxt_alert(task, "process port not found (pid %PI, reply_port %d)", - msg->port_msg.pid, msg->port_msg.reply_port); - return; - } - - if (nxt_slow_path(port->type != NXT_PROCESS_CONTROLLER - && port->type != NXT_PROCESS_ROUTER)) - { - nxt_alert(task, "process %PI cannot store scripts", - msg->port_msg.pid); - return; - } - - nxt_memzero(&file, sizeof(nxt_file_t)); - - file.fd = -1; - type = NXT_PORT_MSG_RPC_ERROR; - - rt = task->thread->runtime; - - if (nxt_slow_path(rt->certs.start == NULL)) { - nxt_alert(task, "no scripts storage directory"); - goto error; - } - - name.start = msg->buf->mem.pos; - name.length = nxt_strlen(name.start); - - file.name = nxt_malloc(rt->scripts.length + name.length + 1); - if (nxt_slow_path(file.name == NULL)) { - goto error; - } - - p = nxt_cpymem(file.name, rt->scripts.start, rt->scripts.length); - p = nxt_cpymem(p, name.start, name.length + 1); - - ret = nxt_file_open(task, &file, NXT_FILE_RDWR, NXT_FILE_CREATE_OR_OPEN, - NXT_FILE_OWNER_ACCESS); - - nxt_free(file.name); - - if (nxt_fast_path(ret == NXT_OK)) { - type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD; - } - -error: - - (void) nxt_port_socket_write(task, port, type, file.fd, - msg->port_msg.stream, 0, NULL); -} - - -void -nxt_script_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp) -{ - nxt_buf_t *b; - nxt_port_t *main_port; - nxt_runtime_t *rt; - - b = nxt_buf_mem_alloc(mp, name->length + 1, 0); - - if (nxt_fast_path(b != NULL)) { - nxt_buf_cpystr(b, name); - *b->mem.free++ = '\0'; - - rt = task->thread->runtime; - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - - (void) nxt_port_socket_write(task, main_port, - NXT_PORT_MSG_SCRIPT_DELETE, -1, 0, 0, b); - } -} - - -void -nxt_script_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - u_char *p; - nxt_str_t name; - nxt_port_t *ctl_port; - nxt_runtime_t *rt; - nxt_file_name_t *path; - - rt = task->thread->runtime; - ctl_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; - - if (nxt_slow_path(ctl_port == NULL)) { - nxt_alert(task, "controller port not found"); - return; - } - - if (nxt_slow_path(nxt_recv_msg_cmsg_pid(msg) != ctl_port->pid)) { - nxt_alert(task, "process %PI cannot delete scripts", - nxt_recv_msg_cmsg_pid(msg)); - return; - } - - if (nxt_slow_path(rt->scripts.start == NULL)) { - nxt_alert(task, "no scripts storage directory"); - return; - } - - name.start = msg->buf->mem.pos; - name.length = nxt_strlen(name.start); - - path = nxt_malloc(rt->scripts.length + name.length + 1); - - if (nxt_fast_path(path != NULL)) { - p = nxt_cpymem(path, rt->scripts.start, rt->scripts.length); - p = nxt_cpymem(p, name.start, name.length + 1); - - (void) nxt_file_delete(path); - - nxt_free(path); - } -} - - -nxt_int_t -nxt_script_file_read(nxt_fd_t fd, nxt_str_t *str) -{ - ssize_t n; - nxt_int_t ret; - nxt_file_t file; - nxt_file_info_t fi; - - nxt_memzero(&file, sizeof(nxt_file_t)); - - file.fd = fd; - - ret = nxt_file_info(&file, &fi); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - if (nxt_slow_path(!nxt_is_file(&fi))) { - nxt_str_null(str); - return NXT_DECLINED; - } - - str->length = nxt_file_size(&fi); - str->start = nxt_malloc(str->length); - if (nxt_slow_path(str->start == NULL)) { - return NXT_ERROR; - } - - n = nxt_file_read(&file, str->start, str->length, 0); - - if (nxt_slow_path(n != (ssize_t) str->length)) { - nxt_free(str->start); - return NXT_ERROR; - } - - return NXT_OK; -} diff --git a/src/nxt_script.h b/src/nxt_script.h deleted file mode 100644 index ffefc108..00000000 --- a/src/nxt_script.h +++ /dev/null @@ -1,37 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - * Copyright (C) Zhidao HONG - */ - -#ifndef _NXT_SCRIPT_INCLUDED_ -#define _NXT_SCRIPT_INCLUDED_ - - -typedef struct nxt_script_s nxt_script_t; - -nxt_script_t *nxt_script_new(nxt_task_t *task, nxt_str_t *name, u_char *data, - size_t size, u_char *error); -void nxt_script_destroy(nxt_script_t *script); - -void nxt_script_info_init(nxt_task_t *task, nxt_array_t *scripts); -nxt_int_t nxt_script_info_save(nxt_str_t *name, nxt_script_t *script); -nxt_conf_value_t *nxt_script_info_get(nxt_str_t *name); -nxt_conf_value_t *nxt_script_info_get_all(nxt_mp_t *mp); -nxt_int_t nxt_script_info_delete(nxt_str_t *name); - -nxt_array_t *nxt_script_store_load(nxt_task_t *task, nxt_mp_t *mem_pool); -void nxt_script_store_release(nxt_array_t *scripts); - -void nxt_script_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp, - nxt_port_rpc_handler_t handler, void *ctx); -void nxt_script_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp); - -void nxt_script_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -void nxt_script_store_delete_handler(nxt_task_t *task, - nxt_port_recv_msg_t *msg); - -nxt_int_t nxt_script_file_read(nxt_fd_t fd, nxt_str_t *str); - - -#endif /* _NXT_SCRIPT_INCLUDED_ */ diff --git a/src/nxt_select_engine.c b/src/nxt_select_engine.c deleted file mode 100644 index 6f760012..00000000 --- a/src/nxt_select_engine.c +++ /dev/null @@ -1,370 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static nxt_int_t nxt_select_create(nxt_event_engine_t *engine, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_select_free(nxt_event_engine_t *engine); -static void nxt_select_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static void nxt_select_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); -static nxt_bool_t nxt_select_close(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_select_enable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_select_enable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_select_error_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_select_disable_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_select_disable_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_select_block_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_select_block_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_select_oneshot_read(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_select_oneshot_write(nxt_event_engine_t *engine, - nxt_fd_event_t *ev); -static void nxt_select_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); - - -const nxt_event_interface_t nxt_select_engine = { - "select", - nxt_select_create, - nxt_select_free, - nxt_select_enable, - nxt_select_disable, - nxt_select_disable, - nxt_select_close, - nxt_select_enable_read, - nxt_select_enable_write, - nxt_select_disable_read, - nxt_select_disable_write, - nxt_select_block_read, - nxt_select_block_write, - nxt_select_oneshot_read, - nxt_select_oneshot_write, - nxt_select_enable_read, - NULL, - NULL, - NULL, - NULL, - nxt_select_poll, - - &nxt_unix_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static nxt_int_t -nxt_select_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - engine->u.select.nfds = -1; - engine->u.select.update_nfds = 0; - - engine->u.select.events = nxt_zalloc(FD_SETSIZE * sizeof(nxt_fd_event_t *)); - - if (engine->u.select.events != NULL) { - return NXT_OK; - } - - nxt_select_free(engine); - - return NXT_ERROR; -} - - -static void -nxt_select_free(nxt_event_engine_t *engine) -{ - nxt_debug(&engine->task, "select free"); - - nxt_free(engine->u.select.events); - - nxt_memzero(&engine->u.select, sizeof(nxt_select_engine_t)); -} - - -static void -nxt_select_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_select_enable_read(engine, ev); - nxt_select_enable_write(engine, ev); -} - - -static void -nxt_select_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - nxt_select_disable_read(engine, ev); - } - - if (ev->write != NXT_EVENT_INACTIVE) { - nxt_select_disable_write(engine, ev); - } -} - - -static nxt_bool_t -nxt_select_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_select_disable(engine, ev); - - return 0; -} - - -static void -nxt_select_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_fd_t fd; - - fd = ev->fd; - - nxt_debug(ev->task, "select enable read: fd:%d", fd); - - if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { - nxt_work_queue_add(&engine->fast_work_queue, nxt_select_error_handler, - ev->task, ev, ev->data); - return; - } - - ev->read = NXT_EVENT_ACTIVE; - - FD_SET(fd, &engine->u.select.main_read_fd_set); - engine->u.select.events[fd] = ev; - - if (engine->u.select.nfds < fd) { - engine->u.select.nfds = fd; - engine->u.select.update_nfds = 0; - } -} - - -static void -nxt_select_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_fd_t fd; - - fd = ev->fd; - - nxt_debug(ev->task, "select enable write: fd:%d", fd); - - if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { - nxt_work_queue_add(&engine->fast_work_queue, nxt_select_error_handler, - ev->task, ev, ev->data); - return; - } - - ev->write = NXT_EVENT_ACTIVE; - - FD_SET(fd, &engine->u.select.main_write_fd_set); - engine->u.select.events[fd] = ev; - - if (engine->u.select.nfds < fd) { - engine->u.select.nfds = fd; - engine->u.select.update_nfds = 0; - } -} - - -static void -nxt_select_error_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_fd_event_t *ev; - - ev = obj; - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - ev->error_handler(task, ev, data); -} - - -static void -nxt_select_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_fd_t fd; - - fd = ev->fd; - - nxt_debug(ev->task, "select disable read: fd:%d", fd); - - if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { - return; - } - - FD_CLR(fd, &engine->u.select.main_read_fd_set); - - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write == NXT_EVENT_INACTIVE) { - engine->u.select.events[fd] = NULL; - engine->u.select.update_nfds = 1; - } -} - - -static void -nxt_select_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_fd_t fd; - - fd = ev->fd; - - nxt_debug(ev->task, "select disable write: fd:%d", fd); - - if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { - return; - } - - FD_CLR(fd, &engine->u.select.main_write_fd_set); - - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read == NXT_EVENT_INACTIVE) { - engine->u.select.events[fd] = NULL; - engine->u.select.update_nfds = 1; - } -} - - -static void -nxt_select_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - nxt_select_disable_read(engine, ev); - } -} - - -static void -nxt_select_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - nxt_select_disable_write(engine, ev); - } -} - - -static void -nxt_select_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_select_enable_read(engine, ev); - - ev->read = NXT_EVENT_ONESHOT; -} - - -static void -nxt_select_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) -{ - nxt_select_enable_write(engine, ev); - - ev->write = NXT_EVENT_ONESHOT; -} - - -static void -nxt_select_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) -{ - int nevents, nfds, found; - nxt_err_t err; - nxt_int_t i; - nxt_uint_t fd, level; - nxt_fd_event_t *ev; - struct timeval tv, *tp; - - if (timeout == NXT_INFINITE_MSEC) { - tp = NULL; - - } else { - tv.tv_sec = (long) (timeout / 1000); - tv.tv_usec = (long) ((timeout % 1000) * 1000); - tp = &tv; - } - - if (engine->u.select.update_nfds) { - for (i = engine->u.select.nfds; i >= 0; i--) { - if (engine->u.select.events[i] != NULL) { - engine->u.select.nfds = i; - engine->u.select.update_nfds = 0; - break; - } - } - } - - engine->u.select.work_read_fd_set = engine->u.select.main_read_fd_set; - engine->u.select.work_write_fd_set = engine->u.select.main_write_fd_set; - - nfds = engine->u.select.nfds + 1; - - nxt_debug(&engine->task, "select() nfds:%d timeout:%M", nfds, timeout); - - nevents = select(nfds, &engine->u.select.work_read_fd_set, - &engine->u.select.work_write_fd_set, NULL, tp); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(engine->task.thread); - - nxt_debug(&engine->task, "select(): %d", nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - nxt_log(&engine->task, level, "select() failed %E", err); - return; - } - - for (fd = 0; fd < (nxt_uint_t) nfds && nevents != 0; fd++) { - - found = 0; - - if (FD_ISSET(fd, &engine->u.select.work_read_fd_set)) { - ev = engine->u.select.events[fd]; - - nxt_debug(ev->task, "select() fd:%ui read rd:%d wr:%d", - fd, ev->read, ev->write); - - ev->read_ready = 1; - - if (ev->read == NXT_EVENT_ONESHOT) { - nxt_select_disable_read(engine, ev); - } - - nxt_work_queue_add(ev->read_work_queue, ev->read_handler, - ev->task, ev, ev->data); - found = 1; - } - - if (FD_ISSET(fd, &engine->u.select.work_write_fd_set)) { - ev = engine->u.select.events[fd]; - - nxt_debug(ev->task, "select() fd:%ui write rd:%d wr:%d", - fd, ev->read, ev->write); - - ev->write_ready = 1; - - if (ev->write == NXT_EVENT_ONESHOT) { - nxt_select_disable_write(engine, ev); - } - - nxt_work_queue_add(ev->write_work_queue, ev->write_handler, - ev->task, ev, ev->data); - found = 1; - } - - nevents -= found; - } -} diff --git a/src/nxt_semaphore.c b/src/nxt_semaphore.c deleted file mode 100644 index ad05d8b9..00000000 --- a/src/nxt_semaphore.c +++ /dev/null @@ -1,244 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -#if (NXT_HAVE_SEM_TIMEDWAIT) - -/* - * Linux POSIX semaphores use atomic/futex operations in since glibc 2.3. - * - * FreeBSD has two POSIX semaphore implementations. The first implementation - * has been introduced in FreeBSD 5.0 but it has some drawbacks: - * 1) it had a bug (http://bugs.freebsd.org/127545) fixed in FreeBSD 7.2; - * 2) it does not use atomic operations and always calls ksem syscalls; - * 3) a number of semaphores is just 30 by default and until FreeBSD 8.1 - * the number cannot be changed after boot time. - * - * The second implementation has been introduced in FreeBSD 6.1 in libthr - * and uses atomic operations and umtx syscall. However, until FreeBSD 9.0 - * a choice of implementation depended on linking order of libthr and libc. - * In FreeBSD 9.0 the umtx implementation has been moved to libc. - * - * Solaris have POSIX semaphores. - * - * MacOSX has limited POSIX semaphore implementation: - * 1) sem_init() exists but returns ENOSYS; - * 2) no sem_timedwait(). - */ - -nxt_int_t -nxt_sem_init(nxt_sem_t *sem, nxt_uint_t count) -{ - if (sem_init(sem, 0, count) == 0) { - nxt_thread_log_debug("sem_init(%p)", sem); - return NXT_OK; - } - - nxt_thread_log_alert("sem_init(%p) failed %E", sem, nxt_errno); - return NXT_ERROR; -} - - -void -nxt_sem_destroy(nxt_sem_t *sem) -{ - if (sem_destroy(sem) == 0) { - nxt_thread_log_debug("sem_destroy(%p)", sem); - return; - } - - nxt_thread_log_alert("sem_destroy(%p) failed %E", sem, nxt_errno); -} - - -nxt_int_t -nxt_sem_post(nxt_sem_t *sem) -{ - nxt_thread_log_debug("sem_post(%p)", sem); - - if (nxt_fast_path(sem_post(sem) == 0)) { - return NXT_OK; - } - - nxt_thread_log_alert("sem_post(%p) failed %E", sem, nxt_errno); - - return NXT_ERROR; -} - - -nxt_err_t -nxt_sem_wait(nxt_sem_t *sem, nxt_nsec_t timeout) -{ - int n; - nxt_err_t err; - nxt_nsec_t ns; - nxt_thread_t *thr; - nxt_realtime_t *now; - struct timespec ts; - - thr = nxt_thread(); - - if (timeout == NXT_INFINITE_NSEC) { - nxt_log_debug(thr->log, "sem_wait(%p) enter", sem); - - for ( ;; ) { - n = sem_wait(sem); - - err = nxt_errno; - - nxt_thread_time_update(thr); - - if (nxt_fast_path(n == 0)) { - nxt_thread_log_debug("sem_wait(%p) exit", sem); - return 0; - } - - switch (err) { - - case NXT_EINTR: - nxt_log_error(NXT_LOG_INFO, thr->log, "sem_wait(%p) failed %E", - sem, err); - continue; - - default: - nxt_log_alert(thr->log, "sem_wait(%p) failed %E", sem, err); - return err; - } - } - } - -#if (NXT_HAVE_SEM_TRYWAIT_FAST) - - nxt_log_debug(thr->log, "sem_trywait(%p) enter", sem); - - /* - * Fast sem_trywait() using atomic operations may eliminate - * timeout processing. - */ - - if (nxt_fast_path(sem_trywait(sem) == 0)) { - return 0; - } - -#endif - - nxt_log_debug(thr->log, "sem_timedwait(%p, %N) enter", sem, timeout); - - now = nxt_thread_realtime(thr); - ns = now->nsec + timeout; - ts.tv_sec = now->sec + ns / 1000000000; - ts.tv_nsec = ns % 1000000000; - - for ( ;; ) { - n = sem_timedwait(sem, &ts); - - err = nxt_errno; - - nxt_thread_time_update(thr); - - if (nxt_fast_path(n == 0)) { - nxt_thread_log_debug("sem_timedwait(%p) exit", sem); - return 0; - } - - switch (err) { - - case NXT_ETIMEDOUT: - nxt_log_debug(thr->log, "sem_timedwait(%p) exit: %d", sem, err); - return err; - - case NXT_EINTR: - nxt_log_error(NXT_LOG_INFO, thr->log, "sem_timedwait(%p) failed %E", - sem, err); - continue; - - default: - nxt_log_alert(thr->log, "sem_timedwait(%p) failed %E", sem, err); - return err; - } - } -} - -#else - -/* Semaphore implementation using pthread conditional variable. */ - -nxt_int_t -nxt_sem_init(nxt_sem_t *sem, nxt_uint_t count) -{ - if (nxt_thread_mutex_create(&sem->mutex) == NXT_OK) { - - if (nxt_thread_cond_create(&sem->cond) == NXT_OK) { - sem->count = count; - return NXT_OK; - } - - nxt_thread_mutex_destroy(&sem->mutex); - } - - return NXT_ERROR; -} - - -void -nxt_sem_destroy(nxt_sem_t *sem) -{ - nxt_thread_cond_destroy(&sem->cond); - nxt_thread_mutex_destroy(&sem->mutex); -} - - -nxt_int_t -nxt_sem_post(nxt_sem_t *sem) -{ - nxt_int_t ret; - - if (nxt_slow_path(nxt_thread_mutex_lock(&sem->mutex) != NXT_OK)) { - return NXT_ERROR; - } - - ret = nxt_thread_cond_signal(&sem->cond); - - sem->count++; - - /* NXT_ERROR overrides NXT_OK. */ - - return (nxt_thread_mutex_unlock(&sem->mutex) | ret); -} - - -nxt_err_t -nxt_sem_wait(nxt_sem_t *sem, nxt_nsec_t timeout) -{ - nxt_err_t err; - - err = 0; - - if (nxt_slow_path(nxt_thread_mutex_lock(&sem->mutex) != NXT_OK)) { - return NXT_ERROR; - } - - while (sem->count == 0) { - - err = nxt_thread_cond_wait(&sem->cond, &sem->mutex, timeout); - - if (err != 0) { - goto error; - } - } - - sem->count--; - -error: - - /* NXT_ERROR overrides NXT_OK and NXT_ETIMEDOUT. */ - - return (nxt_thread_mutex_unlock(&sem->mutex) | err); -} - -#endif diff --git a/src/nxt_semaphore.h b/src/nxt_semaphore.h deleted file mode 100644 index d1985342..00000000 --- a/src/nxt_semaphore.h +++ /dev/null @@ -1,32 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_SEMAPHORE_H_INCLUDED_ -#define _NXT_UNIX_SEMAPHORE_H_INCLUDED_ - - -#if (NXT_HAVE_SEM_TIMEDWAIT) - -typedef sem_t nxt_sem_t; - -#else - -typedef struct { - nxt_atomic_t count; - nxt_thread_mutex_t mutex; - nxt_thread_cond_t cond; -} nxt_sem_t; - -#endif - - -NXT_EXPORT nxt_int_t nxt_sem_init(nxt_sem_t *sem, nxt_uint_t count); -NXT_EXPORT void nxt_sem_destroy(nxt_sem_t *sem); -NXT_EXPORT nxt_int_t nxt_sem_post(nxt_sem_t *sem); -NXT_EXPORT nxt_err_t nxt_sem_wait(nxt_sem_t *sem, nxt_nsec_t timeout); - - -#endif /* _NXT_UNIX_SEMAPHORE_H_INCLUDED_ */ diff --git a/src/nxt_sendbuf.c b/src/nxt_sendbuf.c deleted file mode 100644 index 94f8e9eb..00000000 --- a/src/nxt_sendbuf.c +++ /dev/null @@ -1,445 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static nxt_bool_t nxt_sendbuf_copy(nxt_buf_mem_t *bm, nxt_buf_t *b, - size_t *copied); -static nxt_buf_t *nxt_sendbuf_coalesce_completion(nxt_task_t *task, - nxt_work_queue_t *wq, nxt_buf_t *start); - - -nxt_uint_t -nxt_sendbuf_mem_coalesce0(nxt_task_t *task, nxt_sendbuf_t *sb, - struct iovec *iov, nxt_uint_t niov_max) -{ - u_char *last; - size_t size, total; - nxt_buf_t *b; - nxt_uint_t n; - - total = sb->size; - last = NULL; - n = (nxt_uint_t) -1; - - for (b = sb->buf; b != NULL && total < sb->limit; b = b->next) { - - nxt_prefetch(b->next); - - if (nxt_buf_is_file(b)) { - break; - } - - if (nxt_buf_is_mem(b)) { - - size = b->mem.free - b->mem.pos; - - if (size != 0) { - - if (total + size > sb->limit) { - size = sb->limit - total; - - if (size == 0) { - break; - } - } - - if (b->mem.pos != last) { - - if (++n >= niov_max) { - goto done; - } - - iov[n].iov_base = b->mem.pos; - iov[n].iov_len = size; - - } else { - iov[n].iov_len += size; - } - - nxt_debug(task, "sendbuf: %ui, %p, %uz", - n, iov[n].iov_base, iov[n].iov_len); - - total += size; - last = b->mem.pos + size; - } - - } else { - sb->sync = 1; - sb->last |= nxt_buf_is_last(b); - } - } - - n++; - -done: - - sb->buf = b; - - return n; -} - - -nxt_uint_t -nxt_sendbuf_mem_coalesce(nxt_task_t *task, nxt_sendbuf_coalesce_t *sb) -{ - u_char *last; - size_t size, total; - nxt_buf_t *b; - nxt_uint_t n; - - total = sb->size; - last = NULL; - n = (nxt_uint_t) -1; - - for (b = sb->buf; b != NULL && total < sb->limit; b = b->next) { - - nxt_prefetch(b->next); - - if (nxt_buf_is_file(b)) { - break; - } - - if (nxt_buf_is_mem(b)) { - - size = b->mem.free - b->mem.pos; - - if (size != 0) { - - if (total + size > sb->limit) { - size = sb->limit - total; - - sb->limit_reached = 1; - - if (nxt_slow_path(size == 0)) { - break; - } - } - - if (b->mem.pos != last) { - - if (++n >= sb->nmax) { - sb->nmax_reached = 1; - - goto done; - } - - sb->iobuf[n].iov_base = b->mem.pos; - sb->iobuf[n].iov_len = size; - - } else { - sb->iobuf[n].iov_len += size; - } - - nxt_debug(task, "sendbuf: %ui, %p, %uz", - n, sb->iobuf[n].iov_base, sb->iobuf[n].iov_len); - - total += size; - last = b->mem.pos + size; - } - - } else { - sb->sync = 1; - sb->last |= nxt_buf_is_last(b); - } - } - - n++; - -done: - - sb->buf = b; - sb->size = total; - sb->niov = n; - - return n; -} - - -size_t -nxt_sendbuf_file_coalesce(nxt_sendbuf_coalesce_t *sb) -{ - size_t file_start, total; - nxt_fd_t fd; - nxt_off_t size, last; - nxt_buf_t *b; - - b = sb->buf; - fd = b->file->fd; - - total = sb->size; - - for ( ;; ) { - - nxt_prefetch(b->next); - - size = b->file_end - b->file_pos; - - if (total + size >= sb->limit) { - total = sb->limit; - break; - } - - total += size; - last = b->file_pos + size; - - b = b->next; - - if (b == NULL || !nxt_buf_is_file(b)) { - break; - } - - if (b->file_pos != last || b->file->fd != fd) { - break; - } - } - - sb->buf = b; - - file_start = sb->size; - sb->size = total; - - return total - file_start; -} - - -ssize_t -nxt_sendbuf_copy_coalesce(nxt_conn_t *c, nxt_buf_mem_t *bm, nxt_buf_t *b, - size_t limit) -{ - size_t size, bsize, copied; - ssize_t n; - nxt_bool_t flush; - - size = nxt_buf_mem_used_size(&b->mem); - bsize = nxt_buf_mem_size(bm); - - if (bsize != 0) { - - if (size > bsize && bm->pos == bm->free) { - /* - * A data buffer size is larger than the internal - * buffer size and the internal buffer is empty. - */ - goto no_buffer; - } - - if (bm->pos == NULL) { - bm->pos = nxt_malloc(bsize); - if (nxt_slow_path(bm->pos == NULL)) { - return NXT_ERROR; - } - - bm->start = bm->pos; - bm->free = bm->pos; - bm->end += (uintptr_t) bm->pos; - } - - copied = 0; - - flush = nxt_sendbuf_copy(bm, b, &copied); - - nxt_log_debug(c->socket.log, "sendbuf copy:%uz fl:%b", copied, flush); - - if (flush == 0) { - return copied; - } - - size = nxt_buf_mem_used_size(bm); - - if (size == 0 && nxt_buf_is_sync(b)) { - goto done; - } - - n = c->io->send(c, bm->pos, nxt_min(size, limit)); - - nxt_log_debug(c->socket.log, "sendbuf sent:%z", n); - - if (n > 0) { - bm->pos += n; - - if (bm->pos == bm->free) { - bm->pos = bm->start; - bm->free = bm->start; - } - - n = 0; - } - - return (copied != 0) ? (ssize_t) copied : n; - } - - /* No internal buffering. */ - - if (size == 0 && nxt_buf_is_sync(b)) { - goto done; - } - -no_buffer: - - return c->io->send(c, b->mem.pos, nxt_min(size, limit)); - -done: - - nxt_log_debug(c->socket.log, "sendbuf done"); - - return 0; -} - - -static nxt_bool_t -nxt_sendbuf_copy(nxt_buf_mem_t *bm, nxt_buf_t *b, size_t *copied) -{ - size_t size, bsize; - nxt_bool_t flush; - - flush = 0; - - do { - nxt_prefetch(b->next); - - if (nxt_buf_is_mem(b)) { - bsize = bm->end - bm->free; - size = b->mem.free - b->mem.pos; - size = nxt_min(size, bsize); - - nxt_memcpy(bm->free, b->mem.pos, size); - - *copied += size; - bm->free += size; - - if (bm->free == bm->end) { - return 1; - } - } - - flush |= nxt_buf_is_flush(b) || nxt_buf_is_last(b); - - b = b->next; - - } while (b != NULL); - - return flush; -} - - -nxt_buf_t * -nxt_sendbuf_update(nxt_buf_t *b, size_t sent) -{ - size_t size; - - while (b != NULL) { - - nxt_prefetch(b->next); - - if (!nxt_buf_is_sync(b)) { - - size = nxt_buf_used_size(b); - - if (size != 0) { - - if (sent == 0) { - break; - } - - if (sent < size) { - - if (nxt_buf_is_mem(b)) { - b->mem.pos += sent; - } - - if (nxt_buf_is_file(b)) { - b->file_pos += sent; - } - - break; - } - - /* b->mem.free is NULL in file-only buffer. */ - b->mem.pos = b->mem.free; - - if (nxt_buf_is_file(b)) { - b->file_pos = b->file_end; - } - - sent -= size; - } - } - - b = b->next; - } - - return b; -} - - -nxt_buf_t * -nxt_sendbuf_completion(nxt_task_t *task, nxt_work_queue_t *wq, nxt_buf_t *b) -{ - while (b != NULL) { - - if (!nxt_buf_is_sync(b) && nxt_buf_used_size(b) != 0) { - break; - } - - b = nxt_sendbuf_coalesce_completion(task, wq, b); - } - - return b; -} - - -void -nxt_sendbuf_drain(nxt_task_t *task, nxt_work_queue_t *wq, nxt_buf_t *b) -{ - while (b != NULL) { - b = nxt_sendbuf_coalesce_completion(task, wq, b); - } -} - - -static nxt_buf_t * -nxt_sendbuf_coalesce_completion(nxt_task_t *task, nxt_work_queue_t *wq, - nxt_buf_t *start) -{ - nxt_buf_t *b, *next, **last, *rest, **last_rest; - nxt_work_handler_t handler; - - rest = NULL; - last_rest = &rest; - last = &start->next; - b = start; - handler = b->completion_handler; - - for ( ;; ) { - next = b->next; - if (next == NULL) { - break; - } - - b->next = NULL; - b = next; - - if (!nxt_buf_is_sync(b) && nxt_buf_used_size(b) != 0) { - *last_rest = b; - break; - } - - if (handler == b->completion_handler) { - *last = b; - last = &b->next; - - } else { - *last_rest = b; - last_rest = &b->next; - } - } - - nxt_work_queue_add(wq, handler, task, start, start->parent); - - return rest; -} diff --git a/src/nxt_sendbuf.h b/src/nxt_sendbuf.h deleted file mode 100644 index fcbe1a25..00000000 --- a/src/nxt_sendbuf.h +++ /dev/null @@ -1,131 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_SENDBUF_H_INCLUDED_ -#define _NXT_SENDBUF_H_INCLUDED_ - - -/* - * The sendbuf interface is intended to send a buffer chain to a connection. - * It uses sendfile interface if available. Otherwise it can send only - * memory buffers, so file buffers must be read in memory in advance. - * - * The sendbuf interface sets c->socket.write_ready to appropriate state - * and returns: - * - * N > 0 if sendbuf sent N bytes. - * - * 0 if sendbuf was interrupted (EINTR and so on), - * or sendbuf sent previously buffered data, - * or single sync buffer has been encountered. - * In all these cases sendbuf is ready to continue - * operation, unless c->socket.write_ready is cleared. - * - * NXT_AGAIN if sendbuf did not send any bytes. - * - * NXT_ERROR if there was erorr. - * - * The sendbuf limit is size_t type since size_t is large enough and many - * sendfile implementations do not support anyway sending more than size_t - * at once. The limit support is located at the sendbuf level otherwise - * an additional limited chain must be created on each sendbuf call. - */ - - -typedef struct { - nxt_buf_t *buf; - void *tls; - nxt_socket_t socket; - nxt_err_t error; - nxt_off_t sent; - size_t size; - size_t limit; - - uint8_t ready; /* 1 bit */ - uint8_t once; /* 1 bit */ - uint8_t sync; /* 1 bit */ - uint8_t last; /* 1 bit */ -} nxt_sendbuf_t; - - -typedef struct { - nxt_buf_t *buf; - nxt_iobuf_t *iobuf; - nxt_uint_t niov; - - uint32_t nmax; - uint8_t sync; /* 1 bit */ - uint8_t last; /* 1 bit */ - uint8_t limit_reached; - uint8_t nmax_reached; - - size_t size; - size_t limit; -} nxt_sendbuf_coalesce_t; - - -#if (NXT_HAVE_LINUX_SENDFILE) -#define NXT_HAVE_SENDFILE 1 -ssize_t nxt_linux_event_conn_io_sendfile(nxt_conn_t *c, nxt_buf_t *b, - size_t limit); -#endif - -#if (NXT_HAVE_FREEBSD_SENDFILE) -#define NXT_HAVE_SENDFILE 1 -ssize_t nxt_freebsd_event_conn_io_sendfile(nxt_conn_t *c, nxt_buf_t *b, - size_t limit); -#endif - -#if (NXT_HAVE_SOLARIS_SENDFILEV) -#define NXT_HAVE_SENDFILE 1 -ssize_t nxt_solaris_event_conn_io_sendfilev(nxt_conn_t *c, nxt_buf_t *b, - size_t limit); -#endif - -#if (NXT_HAVE_MACOSX_SENDFILE) -#define NXT_HAVE_SENDFILE 1 -ssize_t nxt_macosx_event_conn_io_sendfile(nxt_conn_t *c, nxt_buf_t *b, - size_t limit); -#endif - -#if (NXT_HAVE_AIX_SEND_FILE) -#define NXT_HAVE_SENDFILE 1 -ssize_t nxt_aix_event_conn_io_send_file(nxt_conn_t *c, nxt_buf_t *b, - size_t limit); -#endif - -#if (NXT_HAVE_HPUX_SENDFILE) -#define NXT_HAVE_SENDFILE 1 -ssize_t nxt_hpux_event_conn_io_sendfile(nxt_conn_t *c, nxt_buf_t *b, - size_t limit); -#endif - -ssize_t nxt_event_conn_io_sendbuf(nxt_conn_t *c, nxt_buf_t *b, - size_t limit); - - -nxt_uint_t nxt_sendbuf_mem_coalesce0(nxt_task_t *task, nxt_sendbuf_t *sb, - struct iovec *iov, nxt_uint_t niov_max); -nxt_uint_t nxt_sendbuf_mem_coalesce(nxt_task_t *task, - nxt_sendbuf_coalesce_t *sb); -size_t nxt_sendbuf_file_coalesce(nxt_sendbuf_coalesce_t *sb); - -/* - * Auxiliary nxt_sendbuf_copy_coalesce() interface copies small memory - * buffers into internal buffer before output. It is intended for - * SSL/TLS libraries which lack vector I/O interface yet add noticeable - * overhead to each SSL/TLS record. - */ -ssize_t nxt_sendbuf_copy_coalesce(nxt_conn_t *c, nxt_buf_mem_t *bm, - nxt_buf_t *b, size_t limit); - -nxt_buf_t *nxt_sendbuf_update(nxt_buf_t *b, size_t sent); -nxt_buf_t *nxt_sendbuf_completion(nxt_task_t *task, nxt_work_queue_t *wq, - nxt_buf_t *b); -void nxt_sendbuf_drain(nxt_task_t *task, nxt_work_queue_t *wq, nxt_buf_t *b); - - -#endif /* _NXT_SENDBUF_H_INCLUDED_ */ diff --git a/src/nxt_service.c b/src/nxt_service.c deleted file mode 100644 index cc9f8d89..00000000 --- a/src/nxt_service.c +++ /dev/null @@ -1,165 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static const nxt_service_t nxt_services[] = { - -#if (NXT_HAVE_KQUEUE) - { "engine", "kqueue", &nxt_kqueue_engine }, -#endif - -#if (NXT_HAVE_EPOLL_EDGE) - { "engine", "epoll", &nxt_epoll_edge_engine }, - { "engine", "epoll_edge", &nxt_epoll_edge_engine }, - { "engine", "epoll_level", &nxt_epoll_level_engine }, - -#elif (NXT_HAVE_EPOLL) - { "engine", "epoll", &nxt_epoll_level_engine }, - { "engine", "epoll_level", &nxt_epoll_level_engine }, -#endif - -#if (NXT_HAVE_EVENTPORT) - { "engine", "eventport", &nxt_eventport_engine }, -#endif - -#if (NXT_HAVE_DEVPOLL) - { "engine", "devpoll", &nxt_devpoll_engine }, - { "engine", "/dev/poll", &nxt_devpoll_engine }, -#endif - -#if (NXT_HAVE_POLLSET) - { "engine", "pollset", &nxt_pollset_engine }, -#endif - - { "engine", "poll", &nxt_poll_engine }, - { "engine", "select", &nxt_select_engine }, - -#if (NXT_HAVE_OPENSSL) - { "SSL/TLS", "OpenSSL", &nxt_openssl_lib }, - { "SSL/TLS", "openssl", &nxt_openssl_lib }, -#endif - -#if (NXT_HAVE_GNUTLS) - { "SSL/TLS", "GnuTLS", &nxt_gnutls_lib }, - { "SSL/TLS", "gnutls", &nxt_gnutls_lib }, -#endif - -#if (NXT_HAVE_CYASSL) - { "SSL/TLS", "CyaSSL", &nxt_cyassl_lib }, - { "SSL/TLS", "cyassl", &nxt_cyassl_lib }, -#endif - -}; - - -nxt_array_t * -nxt_services_init(nxt_mp_t *mp) -{ - nxt_uint_t n; - nxt_array_t *services; - nxt_service_t *s; - const nxt_service_t *service; - - services = nxt_array_create(mp, 32, sizeof(nxt_service_t)); - - if (nxt_fast_path(services != NULL)) { - - service = nxt_services; - n = nxt_nitems(nxt_services); - - while (n != 0) { - s = nxt_array_add(services); - if (nxt_slow_path(s == NULL)) { - return NULL; - } - - *s = *service; - - service++; - n--; - } - } - - return services; -} - - -nxt_int_t -nxt_service_add(nxt_array_t *services, const nxt_service_t *service) -{ - nxt_uint_t n; - nxt_service_t *s; - - s = services->elts; - n = services->nelts; - - while (n != 0) { - if (nxt_strcmp(s->type, service->type) != 0) { - goto next; - } - - if (nxt_strcmp(s->name, service->name) != 0) { - goto next; - } - - nxt_thread_log_alert("service \"%s:%s\" is duplicate", - service->type, service->name); - return NXT_ERROR; - - next: - - s++; - n--; - } - - s = nxt_array_add(services); - if (nxt_fast_path(s != NULL)) { - *s = *service; - return NXT_OK; - } - - return NXT_ERROR; -} - - -const void * -nxt_service_get(nxt_array_t *services, const char *type, const char *name) -{ - nxt_uint_t n; - const nxt_service_t *s; - - if (services != NULL) { - s = services->elts; - n = services->nelts; - - } else { - s = nxt_services; - n = nxt_nitems(nxt_services); - } - - while (n != 0) { - if (nxt_strcmp(s->type, type) == 0) { - - if (name == NULL) { - return s->service; - } - - if (nxt_strcmp(s->name, name) == 0) { - return s->service; - } - } - - s++; - n--; - } - - nxt_thread_log_alert("service \"%s%s%s\" not found", - type, (name != NULL) ? ":" : "", name); - - return NULL; -} diff --git a/src/nxt_service.h b/src/nxt_service.h deleted file mode 100644 index c43d5394..00000000 --- a/src/nxt_service.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_SERVICE_H_INCLUDED_ -#define _NXT_SERVICE_H_INCLUDED_ - - -typedef struct { - const char *type; - const char *name; - const void *service; -} nxt_service_t; - - -#define nxt_service_is_module(s) \ - ((s)->type == NULL) - - -NXT_EXPORT nxt_array_t *nxt_services_init(nxt_mp_t *mp); -NXT_EXPORT nxt_int_t nxt_service_add(nxt_array_t *services, - const nxt_service_t *service); -NXT_EXPORT const void *nxt_service_get(nxt_array_t *services, const char *type, - const char *name); - - -#endif /* _NXT_SERVICE_H_INCLUDED_ */ diff --git a/src/nxt_sha1.c b/src/nxt_sha1.c deleted file mode 100644 index 407c5933..00000000 --- a/src/nxt_sha1.c +++ /dev/null @@ -1,295 +0,0 @@ - -/* - * Copyright (C) Maxim Dounin - * Copyright (C) NGINX, Inc. - * - * An internal SHA1 implementation. - */ - - -#include -#include - - -static const u_char *nxt_sha1_body(nxt_sha1_t *ctx, const u_char *data, - size_t size); - - -void -nxt_sha1_init(nxt_sha1_t *ctx) -{ - ctx->a = 0x67452301; - ctx->b = 0xefcdab89; - ctx->c = 0x98badcfe; - ctx->d = 0x10325476; - ctx->e = 0xc3d2e1f0; - - ctx->bytes = 0; -} - - -void -nxt_sha1_update(nxt_sha1_t *ctx, const void *data, size_t size) -{ - size_t used, free; - - used = (size_t) (ctx->bytes & 0x3f); - ctx->bytes += size; - - if (used) { - free = 64 - used; - - if (size < free) { - memcpy(&ctx->buffer[used], data, size); - return; - } - - memcpy(&ctx->buffer[used], data, free); - data = (u_char *) data + free; - size -= free; - (void) nxt_sha1_body(ctx, ctx->buffer, 64); - } - - if (size >= 64) { - data = nxt_sha1_body(ctx, data, size & ~(size_t) 0x3f); - size &= 0x3f; - } - - memcpy(ctx->buffer, data, size); -} - - -void -nxt_sha1_final(u_char result[20], nxt_sha1_t *ctx) -{ - size_t used, free; - - used = (size_t) (ctx->bytes & 0x3f); - - ctx->buffer[used++] = 0x80; - - free = 64 - used; - - if (free < 8) { - nxt_memzero(&ctx->buffer[used], free); - (void) nxt_sha1_body(ctx, ctx->buffer, 64); - used = 0; - free = 64; - } - - nxt_memzero(&ctx->buffer[used], free - 8); - - ctx->bytes <<= 3; - ctx->buffer[56] = (u_char) (ctx->bytes >> 56); - ctx->buffer[57] = (u_char) (ctx->bytes >> 48); - ctx->buffer[58] = (u_char) (ctx->bytes >> 40); - ctx->buffer[59] = (u_char) (ctx->bytes >> 32); - ctx->buffer[60] = (u_char) (ctx->bytes >> 24); - ctx->buffer[61] = (u_char) (ctx->bytes >> 16); - ctx->buffer[62] = (u_char) (ctx->bytes >> 8); - ctx->buffer[63] = (u_char) ctx->bytes; - - (void) nxt_sha1_body(ctx, ctx->buffer, 64); - - result[0] = (u_char) (ctx->a >> 24); - result[1] = (u_char) (ctx->a >> 16); - result[2] = (u_char) (ctx->a >> 8); - result[3] = (u_char) ctx->a; - result[4] = (u_char) (ctx->b >> 24); - result[5] = (u_char) (ctx->b >> 16); - result[6] = (u_char) (ctx->b >> 8); - result[7] = (u_char) ctx->b; - result[8] = (u_char) (ctx->c >> 24); - result[9] = (u_char) (ctx->c >> 16); - result[10] = (u_char) (ctx->c >> 8); - result[11] = (u_char) ctx->c; - result[12] = (u_char) (ctx->d >> 24); - result[13] = (u_char) (ctx->d >> 16); - result[14] = (u_char) (ctx->d >> 8); - result[15] = (u_char) ctx->d; - result[16] = (u_char) (ctx->e >> 24); - result[17] = (u_char) (ctx->e >> 16); - result[18] = (u_char) (ctx->e >> 8); - result[19] = (u_char) ctx->e; - - nxt_memzero(ctx, sizeof(*ctx)); -} - - -/* - * Helper functions. - */ - -#define ROTATE(bits, word) (((word) << (bits)) | ((word) >> (32 - (bits)))) - -#define F1(b, c, d) (((b) & (c)) | ((~(b)) & (d))) -#define F2(b, c, d) ((b) ^ (c) ^ (d)) -#define F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) - -#define STEP(f, a, b, c, d, e, w, t) \ - temp = ROTATE(5, (a)) + f((b), (c), (d)) + (e) + (w) + (t); \ - (e) = (d); \ - (d) = (c); \ - (c) = ROTATE(30, (b)); \ - (b) = (a); \ - (a) = temp; - - -/* - * GET() reads 4 input bytes in big-endian byte order and returns - * them as uint32_t. - */ - -#define GET(n) \ - ( ((uint32_t) p[n * 4 + 3]) \ - | ((uint32_t) p[n * 4 + 2] << 8) \ - | ((uint32_t) p[n * 4 + 1] << 16) \ - | ((uint32_t) p[n * 4] << 24)) - - -/* - * This processes one or more 64-byte data blocks, but does not update - * the bit counters. There are no alignment requirements. - */ - -static const u_char * -nxt_sha1_body(nxt_sha1_t *ctx, const u_char *data, size_t size) -{ - uint32_t a, b, c, d, e, temp; - uint32_t saved_a, saved_b, saved_c, saved_d, saved_e; - uint32_t words[80]; - nxt_uint_t i; - const u_char *p; - - p = data; - - a = ctx->a; - b = ctx->b; - c = ctx->c; - d = ctx->d; - e = ctx->e; - - do { - saved_a = a; - saved_b = b; - saved_c = c; - saved_d = d; - saved_e = e; - - /* Load data block into the words array */ - - for (i = 0; i < 16; i++) { - words[i] = GET(i); - } - - for (i = 16; i < 80; i++) { - words[i] = ROTATE(1, words[i - 3] - ^ words[i - 8] - ^ words[i - 14] - ^ words[i - 16]); - } - - /* Transformations */ - - STEP(F1, a, b, c, d, e, words[0], 0x5a827999); - STEP(F1, a, b, c, d, e, words[1], 0x5a827999); - STEP(F1, a, b, c, d, e, words[2], 0x5a827999); - STEP(F1, a, b, c, d, e, words[3], 0x5a827999); - STEP(F1, a, b, c, d, e, words[4], 0x5a827999); - STEP(F1, a, b, c, d, e, words[5], 0x5a827999); - STEP(F1, a, b, c, d, e, words[6], 0x5a827999); - STEP(F1, a, b, c, d, e, words[7], 0x5a827999); - STEP(F1, a, b, c, d, e, words[8], 0x5a827999); - STEP(F1, a, b, c, d, e, words[9], 0x5a827999); - STEP(F1, a, b, c, d, e, words[10], 0x5a827999); - STEP(F1, a, b, c, d, e, words[11], 0x5a827999); - STEP(F1, a, b, c, d, e, words[12], 0x5a827999); - STEP(F1, a, b, c, d, e, words[13], 0x5a827999); - STEP(F1, a, b, c, d, e, words[14], 0x5a827999); - STEP(F1, a, b, c, d, e, words[15], 0x5a827999); - STEP(F1, a, b, c, d, e, words[16], 0x5a827999); - STEP(F1, a, b, c, d, e, words[17], 0x5a827999); - STEP(F1, a, b, c, d, e, words[18], 0x5a827999); - STEP(F1, a, b, c, d, e, words[19], 0x5a827999); - - STEP(F2, a, b, c, d, e, words[20], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[21], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[22], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[23], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[24], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[25], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[26], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[27], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[28], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[29], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[30], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[31], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[32], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[33], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[34], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[35], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[36], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[37], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[38], 0x6ed9eba1); - STEP(F2, a, b, c, d, e, words[39], 0x6ed9eba1); - - STEP(F3, a, b, c, d, e, words[40], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[41], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[42], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[43], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[44], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[45], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[46], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[47], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[48], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[49], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[50], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[51], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[52], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[53], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[54], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[55], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[56], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[57], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[58], 0x8f1bbcdc); - STEP(F3, a, b, c, d, e, words[59], 0x8f1bbcdc); - - STEP(F2, a, b, c, d, e, words[60], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[61], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[62], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[63], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[64], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[65], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[66], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[67], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[68], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[69], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[70], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[71], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[72], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[73], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[74], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[75], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[76], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[77], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[78], 0xca62c1d6); - STEP(F2, a, b, c, d, e, words[79], 0xca62c1d6); - - a += saved_a; - b += saved_b; - c += saved_c; - d += saved_d; - e += saved_e; - - p += 64; - - } while (size -= 64); - - ctx->a = a; - ctx->b = b; - ctx->c = c; - ctx->d = d; - ctx->e = e; - - return p; -} diff --git a/src/nxt_sha1.h b/src/nxt_sha1.h deleted file mode 100644 index 2816982b..00000000 --- a/src/nxt_sha1.h +++ /dev/null @@ -1,24 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - - -#ifndef _NXT_SHA1_H_INCLUDED_ -#define _NXT_SHA1_H_INCLUDED_ - - -typedef struct { - uint64_t bytes; - uint32_t a, b, c, d, e; - u_char buffer[64]; -} nxt_sha1_t; - - -NXT_EXPORT void nxt_sha1_init(nxt_sha1_t *ctx); -NXT_EXPORT void nxt_sha1_update(nxt_sha1_t *ctx, const void *data, size_t size); -NXT_EXPORT void nxt_sha1_final(u_char result[20], nxt_sha1_t *ctx); - - -#endif /* _NXT_SHA1_H_INCLUDED_ */ diff --git a/src/nxt_signal.c b/src/nxt_signal.c deleted file mode 100644 index 0ab1ba99..00000000 --- a/src/nxt_signal.c +++ /dev/null @@ -1,192 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * Signals are handled only via a main thread event engine work queue. - * There are three ways to route signals to the work queue: - * - * 1) Using signal event notifications if an event facility supports it: - * kqueue and epoll/signalfd. This method is used regardless of thread mode. - * - * 2) Multi-threaded mode: a dedicated signal thread which waits in sigwait() - * and post a signal number to the main thread event engine. - * - * 3) Single-threaded mode: a signal handler which posts a signal number - * to the event engine. - */ - - -static nxt_int_t nxt_signal_action(int signo, void (*handler)(int)); -static void nxt_signal_thread(void *data); - - -nxt_event_signals_t * -nxt_event_engine_signals(const nxt_sig_event_t *sigev) -{ - nxt_event_signals_t *signals; - - signals = nxt_zalloc(sizeof(nxt_event_signals_t)); - if (signals == NULL) { - return NULL; - } - - signals->sigev = sigev; - - if (nxt_signal_action(SIGSYS, SIG_IGN) != NXT_OK) { - goto fail; - } - - if (nxt_signal_action(SIGPIPE, SIG_IGN) != NXT_OK) { - goto fail; - } - - sigemptyset(&signals->sigmask); - - while (sigev->signo != 0) { - sigaddset(&signals->sigmask, sigev->signo); - sigev++; - } - - if (sigprocmask(SIG_BLOCK, &signals->sigmask, NULL) != 0) { - nxt_main_log_alert("sigprocmask(SIG_BLOCK) failed %E", nxt_errno); - goto fail; - } - - return signals; - -fail: - - nxt_free(signals); - - return NULL; -} - - -static nxt_int_t -nxt_signal_action(int signo, void (*handler)(int)) -{ - struct sigaction sa; - - nxt_memzero(&sa, sizeof(struct sigaction)); - sigemptyset(&sa.sa_mask); - sa.sa_handler = handler; - - if (sigaction(signo, &sa, NULL) == 0) { - return NXT_OK; - } - - nxt_main_log_alert("sigaction(%d) failed %E", signo, nxt_errno); - - return NXT_ERROR; -} - - -static void -nxt_signal_handler(int signo) -{ - nxt_thread_t *thr; - - thr = nxt_thread(); - - /* Thread is running in a single context now. */ - thr->time.signal++; - - nxt_thread_time_update(thr); - - nxt_main_log_error(NXT_LOG_INFO, "signal handler: %d", signo); - - nxt_event_engine_signal(thr->engine, signo); - - thr->time.signal--; -} - - -nxt_int_t -nxt_signal_thread_start(nxt_event_engine_t *engine) -{ - nxt_thread_link_t *link; - const nxt_sig_event_t *sigev; - - if (engine->signals->process == nxt_pid) { - return NXT_OK; - } - - if (sigprocmask(SIG_BLOCK, &engine->signals->sigmask, NULL) != 0) { - nxt_main_log_alert("sigprocmask(SIG_BLOCK) failed %E", nxt_errno); - return NXT_ERROR; - } - - /* - * kqueue sets signal handlers to SIG_IGN and sigwait() ignores - * them after the switch of event facility from "kqueue" to "select". - */ - - for (sigev = engine->signals->sigev; sigev->signo != 0; sigev++) { - if (nxt_signal_action(sigev->signo, nxt_signal_handler) != NXT_OK) { - return NXT_ERROR; - } - } - - link = nxt_zalloc(sizeof(nxt_thread_link_t)); - - if (nxt_fast_path(link != NULL)) { - link->start = nxt_signal_thread; - link->work.data = engine; - - if (nxt_thread_create(&engine->signals->thread, link) == NXT_OK) { - engine->signals->process = nxt_pid; - return NXT_OK; - } - } - - return NXT_ERROR; -} - - -static void -nxt_signal_thread(void *data) -{ - int signo; - nxt_err_t err; - nxt_thread_t *thr; - nxt_event_engine_t *engine; - - engine = data; - - thr = nxt_thread(); - - nxt_main_log_debug("signal thread"); - - for ( ;; ) { - err = sigwait(&engine->signals->sigmask, &signo); - - nxt_thread_time_update(thr); - - if (nxt_fast_path(err == 0)) { - nxt_main_log_error(NXT_LOG_INFO, "signo: %d", signo); - - nxt_event_engine_signal(engine, signo); - - } else { - nxt_main_log_alert("sigwait() failed %E", err); - } - } -} - - -void -nxt_signal_thread_stop(nxt_event_engine_t *engine) -{ - nxt_thread_handle_t thread; - - thread = engine->signals->thread; - - nxt_thread_cancel(thread); - nxt_thread_wait(thread); -} diff --git a/src/nxt_signal.h b/src/nxt_signal.h deleted file mode 100644 index bc61eb2f..00000000 --- a/src/nxt_signal.h +++ /dev/null @@ -1,50 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_SIGNAL_H_INCLUDED_ -#define _NXT_SIGNAL_H_INCLUDED_ - - -struct nxt_sig_event_s { - int signo; - nxt_work_handler_t handler; - const char *name; -}; - -#define nxt_event_signal(sig, handler) \ - { sig, handler, #sig } - -#define nxt_event_signal_end \ - { 0, NULL, NULL } - - -typedef struct { - /* Used by epoll and eventport. */ - nxt_work_handler_t handler; - - const nxt_sig_event_t *sigev; - sigset_t sigmask; - - /* Used by the signal thread. */ - nxt_pid_t process; - nxt_thread_handle_t thread; -} nxt_event_signals_t; - - -nxt_event_signals_t *nxt_event_engine_signals(const nxt_sig_event_t *sigev); - -#define nxt_event_engine_signals_start(engine) \ - nxt_signal_thread_start(engine) - -#define nxt_event_engine_signals_stop(engine) \ - nxt_signal_thread_stop(engine) - - -NXT_EXPORT nxt_int_t nxt_signal_thread_start(nxt_event_engine_t *engine); -NXT_EXPORT void nxt_signal_thread_stop(nxt_event_engine_t *engine); - - -#endif /* _NXT_SIGNAL_H_INCLUDED_ */ diff --git a/src/nxt_signal_handlers.c b/src/nxt_signal_handlers.c deleted file mode 100644 index 63b38fab..00000000 --- a/src/nxt_signal_handlers.c +++ /dev/null @@ -1,67 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include - - -static void nxt_signal_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_signal_sigterm_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_signal_sigquit_handler(nxt_task_t *task, void *obj, void *data); - - -const nxt_sig_event_t nxt_process_signals[] = { - nxt_event_signal(SIGHUP, nxt_signal_handler), - nxt_event_signal(SIGINT, nxt_signal_sigterm_handler), - nxt_event_signal(SIGQUIT, nxt_signal_sigquit_handler), - nxt_event_signal(SIGTERM, nxt_signal_sigterm_handler), - nxt_event_signal(SIGCHLD, nxt_signal_handler), - nxt_event_signal(SIGUSR1, nxt_signal_handler), - nxt_event_signal(SIGUSR2, nxt_signal_handler), - nxt_event_signal_end, -}; - - -static void -nxt_signal_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_trace(task, "signal signo:%d (%s) received, ignored", - (int) (uintptr_t) obj, data); -} - - -void -nxt_signal_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_process_quit(task, 0); -} - - -static void -nxt_signal_sigterm_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_debug(task, "sigterm handler signo:%d (%s)", - (int) (uintptr_t) obj, data); - - /* A fast exit. */ - - nxt_runtime_quit(task, 0); -} - - -static void -nxt_signal_sigquit_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_debug(task, "sigquit handler signo:%d (%s)", - (int) (uintptr_t) obj, data); - - /* A graceful exit. */ - - nxt_process_quit(task, 0); -} diff --git a/src/nxt_sockaddr.c b/src/nxt_sockaddr.c deleted file mode 100644 index 32941893..00000000 --- a/src/nxt_sockaddr.c +++ /dev/null @@ -1,975 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -#if (NXT_INET6) -static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end); -#endif - -static nxt_sockaddr_t *nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr); -static nxt_sockaddr_t *nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr); -static nxt_sockaddr_t *nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr); - - -nxt_sockaddr_t * -nxt_sockaddr_cache_alloc(nxt_event_engine_t *engine, nxt_listen_socket_t *ls) -{ - size_t size; - uint8_t hint; - nxt_sockaddr_t *sa; - - hint = NXT_EVENT_ENGINE_NO_MEM_HINT; - size = offsetof(nxt_sockaddr_t, u) + ls->socklen + ls->address_length; - - sa = nxt_event_engine_mem_alloc(engine, &hint, size); - - if (nxt_fast_path(sa != NULL)) { - /* Zero only beginning of structure up to sockaddr_un.sun_path[1]. */ - nxt_memzero(sa, offsetof(nxt_sockaddr_t, u.sockaddr.sa_data[1])); - - sa->cache_hint = hint; - sa->socklen = ls->socklen; - sa->length = ls->address_length; - - sa->type = ls->sockaddr->type; - /* - * Set address family for unspecified Unix domain socket, - * because these sockaddr's are not updated by old BSD systems, - * see comment in nxt_conn_io_accept(). - */ - sa->u.sockaddr.sa_family = ls->sockaddr->u.sockaddr.sa_family; - } - - return sa; -} - - -void -nxt_sockaddr_cache_free(nxt_event_engine_t *engine, nxt_conn_t *c) -{ - nxt_sockaddr_t *sa; - - sa = c->remote; - - nxt_event_engine_mem_free(engine, sa->cache_hint, sa, 0); -} - - -nxt_sockaddr_t * -nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, size_t address_length) -{ - size_t size; - nxt_sockaddr_t *sa; - - size = offsetof(nxt_sockaddr_t, u) + socklen + address_length; - - /* - * The current struct sockaddr's define 32-bit fields at maximum - * and may define 64-bit AF_INET6 fields in the future. Alignment - * of memory allocated by nxt_mp_zalloc() is enough for these fields. - * If 128-bit alignment will be required then nxt_mem_malloc() and - * nxt_memzero() should be used instead. - */ - - sa = nxt_mp_zalloc(mp, size); - - if (nxt_fast_path(sa != NULL)) { - sa->socklen = socklen; - sa->length = address_length; - } - - return sa; -} - - -nxt_sockaddr_t * -nxt_sockaddr_create(nxt_mp_t *mp, struct sockaddr *sockaddr, socklen_t length, - size_t address_length) -{ - size_t size, copy; - nxt_sockaddr_t *sa; - - size = length; - copy = length; - -#if (NXT_HAVE_UNIX_DOMAIN) - - /* - * Unspecified Unix domain sockaddr_un form and length are very - * platform depended (see comment in nxt_socket.h). Here they are - * normalized to the sockaddr_un with single zero byte sun_path[]. - */ - - if (size <= offsetof(struct sockaddr_un, sun_path)) { - /* - * Small socket length means a short unspecified Unix domain - * socket address: - * - * getsockname() and getpeername() on OpenBSD prior to 5.3 - * return zero length and does not update a passed sockaddr - * buffer at all. - * - * Linux returns length equal to 2, i.e. sockaddr_un without - * sun_path[], unix(7): - * - * unnamed: A stream socket that has not been bound - * to a pathname using bind(2) has no name. Likewise, - * the two sockets created by socketpair(2) are unnamed. - * When the address of an unnamed socket is returned by - * getsockname(2), getpeername(2), and accept(2), its - * length is sizeof(sa_family_t), and sun_path should - * not be inspected. - */ - size = offsetof(struct sockaddr_un, sun_path) + 1; - -#if !(NXT_LINUX) - - } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') { - /* - * Omit nonsignificant zeros of the unspecified Unix domain socket - * address. This test is disabled for Linux since Linux abstract - * socket address also starts with zero. However Linux unspecified - * Unix domain socket address is short and is handled above. - */ - size = offsetof(struct sockaddr_un, sun_path) + 1; - copy = size; - -#endif - } - -#endif /* NXT_HAVE_UNIX_DOMAIN */ - - sa = nxt_sockaddr_alloc(mp, size, address_length); - - if (nxt_fast_path(sa != NULL)) { - nxt_memcpy(&sa->u.sockaddr, sockaddr, copy); - -#if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD) - - if (length == 0) { - sa->u.sockaddr.sa_family = AF_UNIX; - } - -#endif - } - - return sa; -} - - -nxt_sockaddr_t * -nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src) -{ - size_t length; - nxt_sockaddr_t *dst; - - length = offsetof(nxt_sockaddr_t, u) + src->socklen; - - dst = nxt_mp_alloc(mp, length); - - if (nxt_fast_path(dst != NULL)) { - nxt_memcpy(dst, src, length); - } - - return dst; -} - - -nxt_sockaddr_t * -nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s) -{ - int ret; - size_t length; - socklen_t socklen; - nxt_sockaddr_buf_t sockaddr; - - socklen = NXT_SOCKADDR_LEN; - - ret = getsockname(s, &sockaddr.buf, &socklen); - - if (nxt_fast_path(ret == 0)) { - - switch (sockaddr.buf.sa_family) { -#if (NXT_INET6) - case AF_INET6: - length = NXT_INET6_ADDR_STR_LEN; - break; -#endif - -#if (NXT_HAVE_UNIX_DOMAIN) - case AF_UNIX: - length = nxt_length("unix:") + socklen; - break; -#endif - - case AF_INET: - length = NXT_INET_ADDR_STR_LEN; - break; - - default: - length = 0; - break; - } - - return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length); - } - - nxt_log(task, NXT_LOG_ERR, "getsockname(%d) failed %E", s, nxt_errno); - - return NULL; -} - - -void -nxt_sockaddr_text(nxt_sockaddr_t *sa) -{ - size_t offset; - u_char *p, *start, *end, *octet; - uint32_t port; - - offset = offsetof(nxt_sockaddr_t, u) + sa->socklen; - sa->start = offset; - sa->port_start = offset; - - start = nxt_pointer_to(sa, offset); - end = start + sa->length; - - switch (sa->u.sockaddr.sa_family) { - - case AF_INET: - sa->address_start = offset; - - octet = (u_char *) &sa->u.sockaddr_in.sin_addr; - - p = nxt_sprintf(start, end, "%ud.%ud.%ud.%ud", - octet[0], octet[1], octet[2], octet[3]); - - sa->address_length = p - start; - sa->port_start += sa->address_length + 1; - - port = sa->u.sockaddr_in.sin_port; - - break; - -#if (NXT_INET6) - - case AF_INET6: - sa->address_start = offset + 1; - - p = start; - *p++ = '['; - - p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); - - sa->address_length = p - (start + 1); - sa->port_start += sa->address_length + 3; - - *p++ = ']'; - - port = sa->u.sockaddr_in6.sin6_port; - - break; - -#endif - -#if (NXT_HAVE_UNIX_DOMAIN) - - case AF_UNIX: - sa->address_start = offset; - - p = (u_char *) sa->u.sockaddr_un.sun_path; - -#if (NXT_LINUX) - - if (p[0] == '\0') { - size_t length; - - /* Linux abstract socket address has no trailing zero. */ - length = sa->socklen - offsetof(struct sockaddr_un, sun_path); - - p = nxt_sprintf(start, end, "unix:@%*s", length - 1, p + 1); - - } else { - p = nxt_sprintf(start, end, "unix:%s", p); - } - -#else /* !(NXT_LINUX) */ - - p = nxt_sprintf(start, end, "unix:%s", p); - -#endif - - sa->address_length = p - start; - sa->port_start += sa->address_length; - sa->length = p - start; - - return; - -#endif /* NXT_HAVE_UNIX_DOMAIN */ - - default: - return; - } - - p = nxt_sprintf(p, end, ":%d", ntohs(port)); - - sa->length = p - start; -} - - -uint32_t -nxt_sockaddr_port_number(nxt_sockaddr_t *sa) -{ - uint32_t port; - - switch (sa->u.sockaddr.sa_family) { - -#if (NXT_INET6) - - case AF_INET6: - port = sa->u.sockaddr_in6.sin6_port; - break; - -#endif - -#if (NXT_HAVE_UNIX_DOMAIN) - - case AF_UNIX: - return 0; - -#endif - - default: - port = sa->u.sockaddr_in.sin_port; - break; - } - - return ntohs((uint16_t) port); -} - - -nxt_bool_t -nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2) -{ - if (sa1->socklen != sa2->socklen) { - return 0; - } - - if (sa1->type != sa2->type) { - return 0; - } - - if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) { - return 0; - } - - /* - * sockaddr struct's cannot be compared in whole since kernel - * may fill some fields in inherited sockaddr struct's. - */ - - switch (sa1->u.sockaddr.sa_family) { - -#if (NXT_INET6) - - case AF_INET6: - if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) { - return 0; - } - - if (memcmp(&sa1->u.sockaddr_in6.sin6_addr, - &sa2->u.sockaddr_in6.sin6_addr, 16) - != 0) - { - return 0; - } - - return 1; - -#endif - -#if (NXT_HAVE_UNIX_DOMAIN) - - case AF_UNIX: - { - size_t length; - - length = sa1->socklen - offsetof(struct sockaddr_un, sun_path); - - if (memcmp(&sa1->u.sockaddr_un.sun_path, - &sa2->u.sockaddr_un.sun_path, length) - != 0) - { - return 0; - } - - return 1; - } - -#endif - - default: /* AF_INET */ - if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) { - return 0; - } - - if (sa1->u.sockaddr_in.sin_addr.s_addr - != sa2->u.sockaddr_in.sin_addr.s_addr) - { - return 0; - } - - return 1; - } -} - - -#if (NXT_INET6) - -static u_char * -nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end) -{ - u_char *p; - size_t zero_groups, last_zero_groups, ipv6_bytes; - nxt_uint_t i, zero_start, last_zero_start; - - const size_t max_inet6_length = - nxt_length("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - - if (buf + max_inet6_length > end) { - return buf; - } - - zero_start = 16; - zero_groups = 0; - last_zero_start = 16; - last_zero_groups = 0; - - for (i = 0; i < 16; i += 2) { - - if (addr[i] == 0 && addr[i + 1] == 0) { - - if (last_zero_groups == 0) { - last_zero_start = i; - } - - last_zero_groups++; - - } else { - if (zero_groups < last_zero_groups) { - zero_groups = last_zero_groups; - zero_start = last_zero_start; - } - - last_zero_groups = 0; - } - } - - if (zero_groups < last_zero_groups) { - zero_groups = last_zero_groups; - zero_start = last_zero_start; - } - - ipv6_bytes = 16; - p = buf; - - if (zero_start == 0) { - - /* IPv4-mapped address */ - if ((zero_groups == 5 && addr[10] == 0xFF && addr[11] == 0xFF) - /* IPv4-compatible address */ - || (zero_groups == 6) - /* not IPv6 loopback address */ - || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1)) - { - ipv6_bytes = 12; - } - - *p++ = ':'; - } - - for (i = 0; i < ipv6_bytes; i += 2) { - - if (i == zero_start) { - /* Output maximum number of consecutive zero groups as "::". */ - i += (zero_groups - 1) * 2; - *p++ = ':'; - continue; - } - - p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]); - - if (i < 14) { - *p++ = ':'; - } - } - - if (ipv6_bytes == 12) { - p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud", - addr[12], addr[13], addr[14], addr[15]); - } - - return p; -} - -#endif - - -nxt_sockaddr_t * -nxt_sockaddr_parse(nxt_mp_t *mp, nxt_str_t *addr) -{ - nxt_sockaddr_t *sa; - - sa = nxt_sockaddr_parse_optport(mp, addr); - - if (sa != NULL - && sa->u.sockaddr.sa_family != AF_UNIX - && nxt_sockaddr_port_number(sa) == 0) - { - nxt_thread_log_error(NXT_LOG_ERR, - "The address \"%V\" must specify a port.", addr); - return NULL; - } - - return sa; -} - - -nxt_sockaddr_t * -nxt_sockaddr_parse_optport(nxt_mp_t *mp, nxt_str_t *addr) -{ - nxt_sockaddr_t *sa; - - if (addr->length == 0) { - nxt_thread_log_error(NXT_LOG_ERR, "socket address cannot be empty"); - return NULL; - } - - if (addr->length > 6 && memcmp(addr->start, "unix:", 5) == 0) { - sa = nxt_sockaddr_unix_parse(mp, addr); - - } else if (addr->start[0] == '[' || nxt_inet6_probe(addr)) { - sa = nxt_sockaddr_inet6_parse(mp, addr); - - } else { - sa = nxt_sockaddr_inet_parse(mp, addr); - } - - if (nxt_fast_path(sa != NULL)) { - nxt_sockaddr_text(sa); - } - - return sa; -} - - -static nxt_sockaddr_t * -nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr) -{ -#if (NXT_HAVE_UNIX_DOMAIN) - size_t length, socklen; - u_char *path; - nxt_sockaddr_t *sa; - - /* - * Actual sockaddr_un length can be lesser or even larger than defined - * struct sockaddr_un length (see comment in nxt_socket.h). So - * limit maximum Unix domain socket address length by defined sun_path[] - * length because some OSes accept addresses twice larger than defined - * struct sockaddr_un. Also reserve space for a trailing zero to avoid - * ambiguity, since many OSes accept Unix domain socket addresses - * without a trailing zero. - */ - const size_t max_len = sizeof(struct sockaddr_un) - - offsetof(struct sockaddr_un, sun_path) - 1; - - /* Cutting "unix:". */ - length = addr->length - 5; - path = addr->start + 5; - - if (length > max_len) { - nxt_thread_log_error(NXT_LOG_ERR, - "unix domain socket \"%V\" name is too long", - addr); - return NULL; - } - - socklen = offsetof(struct sockaddr_un, sun_path) + length + 1; - - /* - * Linux unix(7): - * - * abstract: an abstract socket address is distinguished by the fact - * that sun_path[0] is a null byte ('\0'). The socket's address in - * this namespace is given by the additional bytes in sun_path that - * are covered by the specified length of the address structure. - * (Null bytes in the name have no special significance.) - */ - if (path[0] == '@') { - path[0] = '\0'; - socklen--; -#if !(NXT_LINUX) - nxt_thread_log_error(NXT_LOG_ERR, - "abstract unix domain sockets are not supported"); - return NULL; -#endif - } - - sa = nxt_sockaddr_alloc(mp, socklen, addr->length); - - if (nxt_fast_path(sa != NULL)) { - sa->u.sockaddr_un.sun_family = AF_UNIX; - nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length); - } - - return sa; - -#else /* !(NXT_HAVE_UNIX_DOMAIN) */ - - nxt_thread_log_error(NXT_LOG_ERR, - "unix domain socket \"%V\" is not supported", addr); - - return NULL; - -#endif -} - - -static nxt_sockaddr_t * -nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr) -{ -#if (NXT_INET6) - u_char *p, *start, *end; - size_t length; - nxt_int_t ret, port; - nxt_sockaddr_t *sa; - - if (addr->start[0] == '[') { - length = addr->length - 1; - start = addr->start + 1; - - end = memchr(start, ']', length); - if (nxt_slow_path(end == NULL)) { - return NULL; - } - - p = end + 1; - - } else { - length = addr->length; - start = addr->start; - end = addr->start + addr->length; - p = NULL; - } - - port = 0; - - if (p != NULL) { - length = (start + length) - p; - - if (length < 2 || *p != ':') { - nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"", - addr); - return NULL; - } - - port = nxt_int_parse(p + 1, length - 1); - - if (port < 1 || port > 65535) { - nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr); - return NULL; - } - } - - sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6), - NXT_INET6_ADDR_STR_LEN); - if (nxt_slow_path(sa == NULL)) { - return NULL; - } - - ret = nxt_inet6_addr(&sa->u.sockaddr_in6.sin6_addr, start, end - start); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"", - addr); - return NULL; - } - - sa->u.sockaddr_in6.sin6_family = AF_INET6; - sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port); - - return sa; - -#else /* !(NXT_INET6) */ - - nxt_thread_log_error(NXT_LOG_ERR, "IPv6 socket \"%V\" is not supported", - addr); - return NULL; - -#endif -} - - -static nxt_sockaddr_t * -nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr) -{ - u_char *p; - size_t length; - nxt_int_t port; - in_addr_t inaddr; - nxt_sockaddr_t *sa; - - p = memchr(addr->start, ':', addr->length); - - if (p == NULL) { - length = addr->length; - - } else { - length = p - addr->start; - } - - inaddr = INADDR_ANY; - - if (length != 1 || addr->start[0] != '*') { - inaddr = nxt_inet_addr(addr->start, length); - if (nxt_slow_path(inaddr == INADDR_NONE)) { - nxt_thread_log_error(NXT_LOG_ERR, "invalid address \"%V\"", addr); - return NULL; - } - } - - port = 0; - - if (p != NULL) { - p++; - length = (addr->start + addr->length) - p; - - port = nxt_int_parse(p, length); - - if (port < 1 || port > 65535) { - nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr); - return NULL; - } - } - - sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in), - NXT_INET_ADDR_STR_LEN); - if (nxt_slow_path(sa == NULL)) { - return NULL; - } - - sa->u.sockaddr_in.sin_family = AF_INET; - sa->u.sockaddr_in.sin_addr.s_addr = inaddr; - sa->u.sockaddr_in.sin_port = htons((in_port_t) port); - - return sa; -} - - -in_addr_t -nxt_inet_addr(u_char *buf, size_t length) -{ - u_char c, *end; - in_addr_t addr; - nxt_uint_t digit, octet, dots; - - if (nxt_slow_path(*(buf + length - 1) == '.')) { - return INADDR_NONE; - } - - addr = 0; - octet = 0; - dots = 0; - - end = buf + length; - - while (buf < end) { - - c = *buf++; - - digit = c - '0'; - /* values below '0' become large unsigned integers */ - - if (digit < 10) { - octet = octet * 10 + digit; - continue; - } - - if (c == '.' && octet < 256) { - addr = (addr << 8) + octet; - octet = 0; - dots++; - continue; - } - - return INADDR_NONE; - } - - if (dots == 3 && octet < 256) { - addr = (addr << 8) + octet; - return htonl(addr); - } - - return INADDR_NONE; -} - - -#if (NXT_INET6) - -nxt_int_t -nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length) -{ - u_char c, *addr, *zero_start, *ipv4, *dst, *src, *end; - nxt_uint_t digit, group, nibbles, groups_left; - - if (length == 0) { - return NXT_ERROR; - } - - end = buf + length; - - if (buf[0] == ':') { - buf++; - } - - addr = in6_addr->s6_addr; - zero_start = NULL; - groups_left = 8; - nibbles = 0; - group = 0; - ipv4 = NULL; - - while (buf < end) { - c = *buf++; - - if (c == ':') { - if (nibbles != 0) { - ipv4 = buf; - - *addr++ = (u_char) (group >> 8); - *addr++ = (u_char) (group & 0xFF); - groups_left--; - - if (groups_left != 0) { - nibbles = 0; - group = 0; - continue; - } - - } else { - if (zero_start == NULL) { - ipv4 = buf; - zero_start = addr; - continue; - } - } - - return NXT_ERROR; - } - - if (c == '.' && nibbles != 0) { - - if (groups_left < 2 || ipv4 == NULL) { - return NXT_ERROR; - } - - group = nxt_inet_addr(ipv4, end - ipv4); - if (group == INADDR_NONE) { - return NXT_ERROR; - } - - group = ntohl(group); - - *addr++ = (u_char) ((group >> 24) & 0xFF); - *addr++ = (u_char) ((group >> 16) & 0xFF); - groups_left--; - - /* the low 16-bit are copied below */ - break; - } - - nibbles++; - - if (nibbles > 4) { - return NXT_ERROR; - } - - group <<= 4; - - digit = c - '0'; - /* values below '0' become large unsigned integers */ - - if (digit < 10) { - group += digit; - continue; - } - - c |= 0x20; - digit = c - 'a'; - /* values below 'a' become large unsigned integers */ - - if (digit < 6) { - group += 10 + digit; - continue; - } - - return NXT_ERROR; - } - - if (nibbles == 0 && zero_start == NULL) { - return NXT_ERROR; - } - - *addr++ = (u_char) (group >> 8); - *addr++ = (u_char) (group & 0xFF); - groups_left--; - - if (groups_left != 0) { - - if (zero_start != NULL) { - - /* moving part before consecutive zero groups to the end */ - - groups_left *= 2; - src = addr - 1; - dst = src + groups_left; - - while (src >= zero_start) { - *dst-- = *src--; - } - - nxt_memzero(zero_start, groups_left); - - return NXT_OK; - } - - } else { - if (zero_start == NULL) { - return NXT_OK; - } - } - - return NXT_ERROR; -} - -#endif - - -nxt_bool_t -nxt_inet6_probe(nxt_str_t *str) -{ - u_char *colon, *end; - - colon = memchr(str->start, ':', str->length); - - if (colon != NULL) { - end = str->start + str->length; - colon = memchr(colon + 1, ':', end - (colon + 1)); - } - - return (colon != NULL); -} diff --git a/src/nxt_sockaddr.h b/src/nxt_sockaddr.h deleted file mode 100644 index 0f96f6dd..00000000 --- a/src/nxt_sockaddr.h +++ /dev/null @@ -1,108 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_SOCKADDR_H_INCLUDED_ -#define _NXT_SOCKADDR_H_INCLUDED_ - - -/* - * The nxt_sockaddr_t should be allocated using nxt_sockaddr_alloc() - * with actual "struct sockaddr_..." size: - * nxt_sockaddr_alloc(pool, sizeof(struct sockaddr_in)) - */ - -/* - * A textual sockaddr representation is stored after struct sockaddr union - * and allocated as a whole. - */ - -struct nxt_sockaddr_s { - /* Socket type: SOCKS_STREAM, SOCK_DGRAM, etc. */ - uint8_t type; - /* Size of struct sockaddr. */ - uint8_t socklen; - /* - * Textual sockaddr representation, e.g.: "127.0.0.1:8000", - * "[::1]:8000", and "unix:/path/to/socket". - */ - uint8_t start; - uint8_t length; - /* - * Textual address representation, e.g: "127.0.0.1", "::1", - * and "unix:/path/to/socket". - */ - uint8_t address_start; - uint8_t address_length; - /* - * Textual port representation, e.g. "8000". - * Port length is (start + length) - port_start. - */ - uint8_t port_start; - - /* A cache hist used to place sockaddr into appropriate free list. */ - uint8_t cache_hint; - - union { - struct sockaddr sockaddr; - struct sockaddr_in sockaddr_in; -#if (NXT_INET6) - struct sockaddr_in6 sockaddr_in6; -#endif -#if (NXT_HAVE_UNIX_DOMAIN) - struct sockaddr_un sockaddr_un; -#endif - } u; -}; - - -nxt_sockaddr_t *nxt_sockaddr_cache_alloc(nxt_event_engine_t *engine, - nxt_listen_socket_t *ls); -void nxt_sockaddr_cache_free(nxt_event_engine_t *engine, nxt_conn_t *c); - -NXT_EXPORT nxt_sockaddr_t *nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, - size_t address_length) - NXT_MALLOC_LIKE; -NXT_EXPORT nxt_sockaddr_t *nxt_sockaddr_create(nxt_mp_t *mp, - struct sockaddr *sockaddr, socklen_t socklen, size_t address_length) - NXT_MALLOC_LIKE; -NXT_EXPORT nxt_sockaddr_t *nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src) - NXT_MALLOC_LIKE; -NXT_EXPORT nxt_sockaddr_t *nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, - nxt_socket_t s) - NXT_MALLOC_LIKE; -NXT_EXPORT void nxt_sockaddr_text(nxt_sockaddr_t *sa); - - -NXT_EXPORT uint32_t nxt_sockaddr_port_number(nxt_sockaddr_t *sa); -NXT_EXPORT nxt_bool_t nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, - nxt_sockaddr_t *sa2); -NXT_EXPORT nxt_sockaddr_t *nxt_sockaddr_parse(nxt_mp_t *mp, nxt_str_t *addr); -NXT_EXPORT nxt_sockaddr_t *nxt_sockaddr_parse_optport(nxt_mp_t *mp, - nxt_str_t *addr); -NXT_EXPORT in_addr_t nxt_inet_addr(u_char *buf, size_t len); -#if (NXT_INET6) -NXT_EXPORT nxt_int_t nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, - size_t len); -#endif -NXT_EXPORT nxt_bool_t nxt_inet6_probe(nxt_str_t *addr); - - -#define NXT_INET_ADDR_STR_LEN nxt_length("255.255.255.255:65535") - -#define NXT_INET6_ADDR_STR_LEN \ - nxt_length("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535") - - -#define nxt_sockaddr_size(sa) \ - (offsetof(nxt_sockaddr_t, u) + sa->socklen + sa->length) -#define nxt_sockaddr_start(sa) nxt_pointer_to(sa, (sa)->start) -#define nxt_sockaddr_address(sa) nxt_pointer_to(sa, (sa)->address_start) -#define nxt_sockaddr_port(sa) nxt_pointer_to(sa, (sa)->port_start) -#define nxt_sockaddr_port_length(sa) \ - (((sa)->start + (sa)->length) - (sa)->port_start) - - -#endif /* _NXT_SOCKADDR_H_INCLUDED_ */ diff --git a/src/nxt_socket.c b/src/nxt_socket.c deleted file mode 100644 index 9ac8ecd2..00000000 --- a/src/nxt_socket.c +++ /dev/null @@ -1,360 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static const char *nxt_socket_sockopt_name(nxt_uint_t level, - nxt_uint_t sockopt); - - -nxt_socket_t -nxt_socket_create(nxt_task_t *task, nxt_uint_t domain, nxt_uint_t type, - nxt_uint_t protocol, nxt_uint_t flags) -{ - nxt_socket_t s; - -#if (NXT_HAVE_SOCK_NONBLOCK) - - if (flags & NXT_NONBLOCK) { - type |= SOCK_NONBLOCK; - } - -#endif - - s = socket(domain, type, protocol); - - if (nxt_slow_path(s == -1)) { - nxt_alert(task, "socket(%ui, 0x%uXi, %ui) failed %E", - domain, type, protocol, nxt_socket_errno); - return s; - } - - nxt_debug(task, "socket(): %d", s); - -#if !(NXT_HAVE_SOCK_NONBLOCK) - - if (flags & NXT_NONBLOCK) { - if (nxt_slow_path(nxt_socket_nonblocking(task, s) != NXT_OK)) { - nxt_socket_close(task, s); - return -1; - } - } - -#endif - - return s; -} - - -void -nxt_socket_defer_accept(nxt_task_t *task, nxt_socket_t s, nxt_sockaddr_t *sa) -{ -#if (NXT_HAVE_UNIX_DOMAIN) - - if (sa->u.sockaddr.sa_family == AF_UNIX) { - /* Deferred accept() is not supported on AF_UNIX sockets. */ - return; - } - -#endif - -#ifdef TCP_DEFER_ACCEPT - - /* Defer Linux accept() up to for 1 second. */ - (void) nxt_socket_setsockopt(task, s, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1); - -#endif -} - - -nxt_int_t -nxt_socket_getsockopt(nxt_task_t *task, nxt_socket_t s, nxt_uint_t level, - nxt_uint_t sockopt) -{ - int val; - socklen_t len; - - len = sizeof(val); - - if (nxt_fast_path(getsockopt(s, level, sockopt, &val, &len) == 0)) { - nxt_debug(task, "getsockopt(%d, %ui, %s): %d", - s, level, nxt_socket_sockopt_name(level, sockopt), val); - return val; - } - - nxt_alert(task, "getsockopt(%d, %ui, %s) failed %E", - s, level, nxt_socket_sockopt_name(level, sockopt), - nxt_socket_errno); - - return -1; -} - - -nxt_int_t -nxt_socket_setsockopt(nxt_task_t *task, nxt_socket_t s, nxt_uint_t level, - nxt_uint_t sockopt, int val) -{ - socklen_t len; - - len = sizeof(val); - - if (nxt_fast_path(setsockopt(s, level, sockopt, &val, len) == 0)) { - nxt_debug(task, "setsockopt(%d, %ui, %s): %d", - s, level, nxt_socket_sockopt_name(level, sockopt), val); - return NXT_OK; - } - - nxt_alert(task, "setsockopt(%d, %ui, %s, %d) failed %E", - s, level, nxt_socket_sockopt_name(level, sockopt), val, - nxt_socket_errno); - - return NXT_ERROR; -} - - -static const char * -nxt_socket_sockopt_name(nxt_uint_t level, nxt_uint_t sockopt) -{ - switch (level) { - - case SOL_SOCKET: - switch (sockopt) { - - case SO_SNDBUF: - return "SO_SNDBUF"; - - case SO_RCVBUF: - return "SO_RCVBUF"; - - case SO_REUSEADDR: - return "SO_REUSEADDR"; - - case SO_TYPE: - return "SO_TYPE"; - } - - break; - - case IPPROTO_TCP: - switch (sockopt) { - - case TCP_NODELAY: - return "TCP_NODELAY"; - -#ifdef TCP_DEFER_ACCEPT - case TCP_DEFER_ACCEPT: - return "TCP_DEFER_ACCEPT"; -#endif - } - - break; - -#if (NXT_INET6) - case IPPROTO_IPV6: - - switch (sockopt) { - - case IPV6_V6ONLY: - return "IPV6_V6ONLY"; - } - - break; -#endif - - } - - return ""; -} - - -nxt_int_t -nxt_socket_bind(nxt_task_t *task, nxt_socket_t s, nxt_sockaddr_t *sa) -{ - nxt_debug(task, "bind(%d, %*s)", s, (size_t) sa->length, - nxt_sockaddr_start(sa)); - - if (nxt_fast_path(bind(s, &sa->u.sockaddr, sa->socklen) == 0)) { - return NXT_OK; - } - - nxt_alert(task, "bind(%d, %*s) failed %E", - s, (size_t) sa->length, nxt_sockaddr_start(sa), nxt_socket_errno); - - return NXT_ERROR; -} - - -nxt_int_t -nxt_socket_connect(nxt_task_t *task, nxt_socket_t s, nxt_sockaddr_t *sa) -{ - nxt_err_t err; - nxt_int_t ret; - nxt_uint_t level; - - nxt_debug(task, "connect(%d, %*s)", - s, (size_t) sa->length, nxt_sockaddr_start(sa)); - - if (connect(s, &sa->u.sockaddr, sa->socklen) == 0) { - return NXT_OK; - } - - err = nxt_socket_errno; - - switch (err) { - - case NXT_EINPROGRESS: - nxt_debug(task, "connect(%d, %*s) in progress", - s, (size_t) sa->length, nxt_sockaddr_start(sa)); - return NXT_AGAIN; - - case NXT_ECONNREFUSED: -#if (NXT_LINUX) - case NXT_EAGAIN: - /* - * Linux returns EAGAIN instead of ECONNREFUSED - * for UNIX sockets if a listen queue is full. - */ -#endif - level = NXT_LOG_ERR; - ret = NXT_DECLINED; - break; - - case NXT_ECONNRESET: - case NXT_ENETDOWN: - case NXT_ENETUNREACH: - case NXT_EHOSTDOWN: - case NXT_EHOSTUNREACH: - level = NXT_LOG_ERR; - ret = NXT_ERROR; - break; - - default: - level = NXT_LOG_ALERT; - ret = NXT_ERROR; - } - - nxt_log(task, level, "connect(%d, %*s) failed %E", - s, (size_t) sa->length, nxt_sockaddr_start(sa), err); - - return ret; -} - - -void -nxt_socket_shutdown(nxt_task_t *task, nxt_socket_t s, nxt_uint_t how) -{ - nxt_err_t err; - nxt_uint_t level; - - if (nxt_fast_path(shutdown(s, how) == 0)) { - nxt_debug(task, "shutdown(%d, %ui)", s, how); - return; - } - - err = nxt_socket_errno; - - switch (err) { - - case NXT_ENOTCONN: - level = NXT_LOG_DEBUG; - break; - - case NXT_ECONNRESET: - case NXT_ENETDOWN: - case NXT_ENETUNREACH: - case NXT_EHOSTDOWN: - case NXT_EHOSTUNREACH: - level = NXT_LOG_ERR; - break; - - default: - level = NXT_LOG_ALERT; - } - - nxt_log(task, level, "shutdown(%d, %ui) failed %E", s, how, err); -} - - -void -nxt_socket_close(nxt_task_t *task, nxt_socket_t s) -{ - nxt_err_t err; - nxt_uint_t level; - - if (nxt_fast_path(close(s) == 0)) { - nxt_debug(task, "socket close(%d)", s); - return; - } - - err = nxt_socket_errno; - - switch (err) { - - case NXT_ENOTCONN: - level = NXT_LOG_DEBUG; - break; - - case NXT_ECONNRESET: - case NXT_ENETDOWN: - case NXT_ENETUNREACH: - case NXT_EHOSTDOWN: - case NXT_EHOSTUNREACH: - level = NXT_LOG_ERR; - break; - - default: - level = NXT_LOG_ALERT; - } - - nxt_log(task, level, "socket close(%d) failed %E", s, err); -} - - -nxt_err_t -nxt_socket_error(nxt_socket_t s) -{ - int ret, err; - socklen_t len; - - err = 0; - len = sizeof(int); - /* - * Linux and BSDs return 0 and store a pending error in the err argument; - * Solaris returns -1 and sets the errno. - */ - ret = getsockopt(s, SOL_SOCKET, SO_ERROR, (void *) &err, &len); - - if (nxt_slow_path(ret == -1)) { - err = nxt_errno; - } - - return err; -} - - -nxt_uint_t -nxt_socket_error_level(nxt_err_t err) -{ - switch (err) { - - case NXT_EPIPE: - case NXT_ECONNRESET: - case NXT_ENOTCONN: - case NXT_ETIMEDOUT: - case NXT_ENETDOWN: - case NXT_ENETUNREACH: - case NXT_EHOSTDOWN: - case NXT_EHOSTUNREACH: - return NXT_LOG_INFO; - - case NXT_ECONNREFUSED: - return NXT_LOG_ERR; - - default: - return NXT_LOG_ALERT; - } -} diff --git a/src/nxt_socket.h b/src/nxt_socket.h deleted file mode 100644 index 69b09039..00000000 --- a/src/nxt_socket.h +++ /dev/null @@ -1,128 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_SOCKET_H_INCLUDED_ -#define _NXT_SOCKET_H_INCLUDED_ - - -typedef int nxt_socket_t; - -#define NXT_NONBLOCK 1 - - -/* - * struct sockaddr and struct sockaddr_in are 16 bytes. - * - * struct sockaddr_in6 is: - * 28 bytes on Linux, FreeBSD, MacOSX, NetBSD, OpenBSD, AIX, HP-UX; - * 32 bytes on Solaris. - * - * - * struct sockaddr_un is: - * 94 bytes on HP-UX; - * 106 bytes on FreeBSD, MacOSX, NetBSD, OpenBSD; - * 110 bytes on Linux, Solaris; - * 1025 bytes on AIX. - * - * The real maximum sockaddr_un length however different from defined length: - * OpenBSD can accept and return 105 bytes if address is not - * zero-terminated; - * Linux can accept 110 bytes and return 111 bytes; - * MacOSX and NetBSD can accept and return 255 bytes; - * Solaris can accept 257 bytes and return 258 bytes; - * FreeBSD maximum sockaddr_un length is equal to defined length. - * - * POSIX.1g renamed AF_UNIX to AF_LOCAL, however, Solaris up to 10 - * version lacks AF_LOCAL. AF_UNIX is defined even on Windows although - * struct sockaddr_un is not. - * - * Unix domain socket address without a trailing zero is accepted at least by: - * Linux, FreeBSD, Solaris, MacOSX, NetBSD, and OpenBSD. - * Linux and Solaris add the trailing zero and return sockaddr_un length - * increased by one. Others return sockaddr_un without the trailing zero. - * - * For unspecified Unix domain socket address - * NetBSD returns sockaddr_un length equal to 106 and fills sun_path[] - * with zeros; - * FreeBSD, Solaris, MacOSX, and OpenBSD return sockaddr_un length - * equal to 16 and fill sun_path[] with zeros; - * Linux returns sockaddr_un length equal to 2 without sun_path[]; - * - * 4.4BSD getsockname() and getpeername() returned zero length. - * This behaviour has been inherited by BSD flavours and has been - * eventually changed in NetBSD 1.2, FreeBSD 3.0, and OpenBSD 5.3. - * - * - * struct sockaddr_storage is: - * 128 bytes on Linux, FreeBSD, MacOSX, NetBSD; - * 256 bytes on Solaris, OpenBSD, and HP-UX; - * 1288 bytes on AIX. - * - * struct sockaddr_storage is too large on some platforms - * or less than real maximum struct sockaddr_un length. - */ - -#if (NXT_HAVE_UNIX_DOMAIN) -#define NXT_SOCKADDR_LEN sizeof(struct sockaddr_un) - -#elif (NXT_HAVE_SOCKADDR_IN6) -#define NXT_SOCKADDR_LEN sizeof(struct sockaddr_in6) - -#else -#define NXT_SOCKADDR_LEN sizeof(struct sockaddr_in) -#endif - - -typedef union { - struct sockaddr buf; - uint64_t alignment; - char space[NXT_SOCKADDR_LEN]; -} nxt_sockaddr_buf_t; - - -/* - * MAXHOSTNAMELEN is: - * 64 on Linux; - * 256 on FreeBSD, Solaris, MacOSX, NetBSD, OpenBSD. - */ -#define NXT_MAXHOSTNAMELEN MAXHOSTNAMELEN - - -NXT_EXPORT nxt_socket_t nxt_socket_create(nxt_task_t *task, nxt_uint_t family, - nxt_uint_t type, nxt_uint_t protocol, nxt_uint_t flags); -NXT_EXPORT void nxt_socket_defer_accept(nxt_task_t *task, nxt_socket_t s, - nxt_sockaddr_t *sa); -NXT_EXPORT nxt_int_t nxt_socket_getsockopt(nxt_task_t *task, nxt_socket_t s, - nxt_uint_t level, nxt_uint_t sockopt); -NXT_EXPORT nxt_int_t nxt_socket_setsockopt(nxt_task_t *task, nxt_socket_t s, - nxt_uint_t level, nxt_uint_t sockopt, int val); -NXT_EXPORT nxt_int_t nxt_socket_bind(nxt_task_t *task, nxt_socket_t s, - nxt_sockaddr_t *sa); -NXT_EXPORT nxt_int_t nxt_socket_connect(nxt_task_t *task, nxt_socket_t s, - nxt_sockaddr_t *sa); -NXT_EXPORT void nxt_socket_shutdown(nxt_task_t *task, nxt_socket_t s, - nxt_uint_t how); -NXT_EXPORT void nxt_socket_close(nxt_task_t *task, nxt_socket_t s); -nxt_err_t nxt_socket_error(nxt_socket_t s); -nxt_uint_t nxt_socket_error_level(nxt_err_t err); - -NXT_EXPORT nxt_int_t nxt_socketpair_create(nxt_task_t *task, - nxt_socket_t *pair); -NXT_EXPORT void nxt_socketpair_close(nxt_task_t *task, nxt_socket_t *pair); -NXT_EXPORT ssize_t nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t *fd, - nxt_iobuf_t *iob, nxt_uint_t niob); -NXT_EXPORT ssize_t nxt_socketpair_recv(nxt_fd_event_t *ev, - nxt_iobuf_t *iob, nxt_uint_t niob, void *oob); - - -#define nxt_socket_nonblocking(task, fd) \ - nxt_fd_nonblocking(task, fd) - -#define nxt_socket_blocking(task, fd) \ - nxt_fd_blocking(task, fd) - - -#endif /* _NXT_SOCKET_H_INCLUDED_ */ diff --git a/src/nxt_socket_msg.c b/src/nxt_socket_msg.c deleted file mode 100644 index 3b35ab29..00000000 --- a/src/nxt_socket_msg.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -ssize_t -nxt_sendmsg(nxt_socket_t s, nxt_iobuf_t *iob, nxt_uint_t niob, - const nxt_send_oob_t *oob) -{ - struct msghdr msg; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iob; - msg.msg_iovlen = niob; - /* Flags are cleared just to suppress valgrind warning. */ - msg.msg_flags = 0; - - if (oob != NULL && oob->size != 0) { - msg.msg_control = (void *) oob->buf; - msg.msg_controllen = oob->size; - - } else { - msg.msg_control = NULL; - msg.msg_controllen = 0; - } - - return sendmsg(s, &msg, 0); -} - - -ssize_t -nxt_recvmsg(nxt_socket_t s, nxt_iobuf_t *iob, nxt_uint_t niob, - nxt_recv_oob_t *oob) -{ - ssize_t n; - struct msghdr msg; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iob; - msg.msg_iovlen = niob; - msg.msg_control = oob->buf; - msg.msg_controllen = sizeof(oob->buf); - - n = recvmsg(s, &msg, 0); - - if (nxt_fast_path(n != -1)) { - oob->size = msg.msg_controllen; - } - - return n; -} diff --git a/src/nxt_socket_msg.h b/src/nxt_socket_msg.h deleted file mode 100644 index 81617bd6..00000000 --- a/src/nxt_socket_msg.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_SOCKET_MSG_H_INCLUDED_ -#define _NXT_SOCKET_MSG_H_INCLUDED_ - -#if (NXT_HAVE_UCRED) -#include -#endif - - -#if (NXT_HAVE_UCRED) -#define NXT_CRED_USECMSG 1 -#define NXT_CRED_CMSGTYPE SCM_CREDENTIALS -#define NXT_CRED_GETPID(u) (u->pid) - -typedef struct ucred nxt_socket_cred_t; - -#elif (NXT_HAVE_MSGHDR_CMSGCRED) -#define NXT_CRED_USECMSG 1 -#define NXT_CRED_CMSGTYPE SCM_CREDS -#define NXT_CRED_GETPID(u) (u->cmcred_pid) - -typedef struct cmsgcred nxt_socket_cred_t; -#endif - -#if (NXT_CRED_USECMSG) -#define NXT_OOB_RECV_SIZE \ - (CMSG_SPACE(2 * sizeof(int)) + CMSG_SPACE(sizeof(nxt_socket_cred_t))) -#else -#define NXT_OOB_RECV_SIZE \ - CMSG_SPACE(2 * sizeof(int)) -#endif - -#if (NXT_HAVE_MSGHDR_CMSGCRED) -#define NXT_OOB_SEND_SIZE \ - (CMSG_SPACE(2 * sizeof(int)) + CMSG_SPACE(sizeof(nxt_socket_cred_t))) -#else -#define NXT_OOB_SEND_SIZE \ - CMSG_SPACE(2 * sizeof(int)) -#endif - - -typedef struct { - size_t size; - u_char buf[NXT_OOB_RECV_SIZE]; -} nxt_recv_oob_t; - - -typedef struct { - size_t size; - u_char buf[NXT_OOB_SEND_SIZE]; -} nxt_send_oob_t; - - -/** - * The nxt_sendmsg is a wrapper for sendmsg. - * The oob struct must be initialized using nxt_socket_msg_oob_init(). - */ -NXT_EXPORT ssize_t nxt_sendmsg(nxt_socket_t s, nxt_iobuf_t *iob, - nxt_uint_t niob, const nxt_send_oob_t *oob); - -/** - * The nxt_recvmsg is a wrapper for recvmsg. - * The oob buffer must be consumed by using nxt_socket_msg_oob_get(). - */ -NXT_EXPORT ssize_t nxt_recvmsg(nxt_socket_t s, - nxt_iobuf_t *iob, nxt_uint_t niob, nxt_recv_oob_t *oob); - - -nxt_inline struct cmsghdr * -NXT_CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg) -{ -#if !defined(__GLIBC__) && defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wsign-compare" -#endif - return CMSG_NXTHDR(msgh, cmsg); -#if !defined(__GLIBC__) && defined(__clang__) -#pragma clang diagnostic pop -#endif -} - - -nxt_inline void -nxt_socket_msg_oob_init(nxt_send_oob_t *oob, int *fds) -{ - int nfds; - struct cmsghdr *cmsg; - -#if (NXT_HAVE_MSGHDR_CMSGCRED) - cmsg = (struct cmsghdr *) (oob->buf); - /* - * Fill all padding fields with 0. - * Code in Go 1.11 validate cmsghdr using padding field as part of len. - * See Cmsghdr definition and socketControlMessageHeaderAndData function. - */ - nxt_memzero(cmsg, sizeof(struct cmsghdr)); - - cmsg->cmsg_len = CMSG_LEN(sizeof(nxt_socket_cred_t)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = NXT_CRED_CMSGTYPE; - - oob->size = CMSG_SPACE(sizeof(nxt_socket_cred_t)); - -#else - oob->size = 0; -#endif - - nfds = (fds[0] != -1 ? 1 : 0) + (fds[1] != -1 ? 1 : 0); - - if (nfds == 0) { - return; - } - - cmsg = (struct cmsghdr *) (oob->buf + oob->size); - - nxt_memzero(cmsg, sizeof(struct cmsghdr)); - - cmsg->cmsg_len = CMSG_LEN(nfds * sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - - /* - * nxt_memcpy() is used instead of simple - * *(int *) CMSG_DATA(&cmsg.cm) = fd; - * because GCC 4.4 with -O2/3/s optimization may issue a warning: - * dereferencing type-punned pointer will break strict-aliasing rules - * - * Fortunately, GCC with -O1 compiles this nxt_memcpy() - * in the same simple assignment as in the code above. - */ - nxt_memcpy(CMSG_DATA(cmsg), fds, nfds * sizeof(int)); - - oob->size += CMSG_SPACE(nfds * sizeof(int)); -} - - -nxt_inline nxt_int_t -nxt_socket_msg_oob_get_fds(nxt_recv_oob_t *oob, nxt_fd_t *fd) -{ - size_t size; - struct msghdr msg; - struct cmsghdr *cmsg; - - msg.msg_control = oob->buf; - msg.msg_controllen = oob->size; - - for (cmsg = CMSG_FIRSTHDR(&msg); - cmsg != NULL; - cmsg = NXT_CMSG_NXTHDR(&msg, cmsg)) - { - size = cmsg->cmsg_len - CMSG_LEN(0); - - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - if (nxt_slow_path(size != sizeof(int) && size != 2 * sizeof(int))) { - return NXT_ERROR; - } - - nxt_memcpy(fd, CMSG_DATA(cmsg), size); - - return NXT_OK; - } - } - - return NXT_OK; -} - - -nxt_inline nxt_int_t -nxt_socket_msg_oob_get(nxt_recv_oob_t *oob, nxt_fd_t *fd, nxt_pid_t *pid) -{ - size_t size; - struct msghdr msg; - struct cmsghdr *cmsg; - - if (oob->size == 0) { - return NXT_OK; - } - -#if (NXT_CRED_USECMSG) - *pid = -1; -#endif - - msg.msg_control = oob->buf; - msg.msg_controllen = oob->size; - - for (cmsg = CMSG_FIRSTHDR(&msg); - cmsg != NULL; - cmsg = NXT_CMSG_NXTHDR(&msg, cmsg)) - { - size = cmsg->cmsg_len - CMSG_LEN(0); - - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - if (nxt_slow_path(size != sizeof(int) && size != 2 * sizeof(int))) { - return NXT_ERROR; - } - - nxt_memcpy(fd, CMSG_DATA(cmsg), size); - -#if (!NXT_CRED_USECMSG) - break; -#endif - } - -#if (NXT_CRED_USECMSG) - else if (cmsg->cmsg_level == SOL_SOCKET - && cmsg->cmsg_type == NXT_CRED_CMSGTYPE) - { - nxt_socket_cred_t *creds; - - if (nxt_slow_path(size != sizeof(nxt_socket_cred_t))) { - return NXT_ERROR; - } - - creds = (nxt_socket_cred_t *) CMSG_DATA(cmsg); - *pid = NXT_CRED_GETPID(creds); - } -#endif - } - -#if (NXT_CRED_USECMSG) - /* For platforms supporting credential passing, it's enforced */ - if (nxt_slow_path(*pid == -1)) { - return NXT_ERROR; - } -#endif - - return NXT_OK; -} - - -#endif /* _NXT_SOCKET_MSG_H_INCLUDED_ */ diff --git a/src/nxt_socketpair.c b/src/nxt_socketpair.c deleted file mode 100644 index 45274b78..00000000 --- a/src/nxt_socketpair.c +++ /dev/null @@ -1,187 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include - -/* - * SOCK_SEQPACKET protocol is supported for AF_UNIX in Solaris 8 X/Open - * sockets, Linux 2.6.4, FreeBSD 9.0, NetBSD 6.0, and OpenBSD 5.0. - */ - -/* SOCK_SEQPACKET is disabled to test SOCK_DGRAM on all platforms. */ -#if (0 || NXT_HAVE_AF_UNIX_SOCK_SEQPACKET) -#define NXT_UNIX_SOCKET SOCK_SEQPACKET -#else -#define NXT_UNIX_SOCKET SOCK_DGRAM -#endif - - -nxt_int_t -nxt_socketpair_create(nxt_task_t *task, nxt_socket_t *pair) -{ - if (nxt_slow_path(socketpair(AF_UNIX, NXT_UNIX_SOCKET, 0, pair) != 0)) { - nxt_alert(task, "socketpair() failed %E", nxt_errno); - return NXT_ERROR; - } - - nxt_debug(task, "socketpair(): %d:%d", pair[0], pair[1]); - - if (nxt_slow_path(nxt_socket_nonblocking(task, pair[0]) != NXT_OK)) { - goto fail; - } - - if (nxt_slow_path(fcntl(pair[0], F_SETFD, FD_CLOEXEC) == -1)) { - goto fail; - } - - if (nxt_slow_path(nxt_socket_nonblocking(task, pair[1]) != NXT_OK)) { - goto fail; - } - - if (nxt_slow_path(fcntl(pair[1], F_SETFD, FD_CLOEXEC) == -1)) { - goto fail; - } - -#if NXT_HAVE_SOCKOPT_SO_PASSCRED - int enable_creds = 1; - - if (nxt_slow_path(setsockopt(pair[0], SOL_SOCKET, SO_PASSCRED, - &enable_creds, sizeof(enable_creds)) == -1)) - { - nxt_alert(task, "failed to set SO_PASSCRED %E", nxt_errno); - goto fail; - } - - if (nxt_slow_path(setsockopt(pair[1], SOL_SOCKET, SO_PASSCRED, - &enable_creds, sizeof(enable_creds)) == -1)) - { - nxt_alert(task, "failed to set SO_PASSCRED %E", nxt_errno); - goto fail; - } -#endif - - return NXT_OK; - -fail: - - nxt_socketpair_close(task, pair); - - return NXT_ERROR; -} - - -void -nxt_socketpair_close(nxt_task_t *task, nxt_socket_t *pair) -{ - nxt_socket_close(task, pair[0]); - nxt_socket_close(task, pair[1]); -} - - -ssize_t -nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, - nxt_uint_t niob) -{ - ssize_t n; - nxt_err_t err; - nxt_send_oob_t oob; - - nxt_socket_msg_oob_init(&oob, fd); - - for ( ;; ) { - n = nxt_sendmsg(ev->fd, iob, niob, &oob); - - err = (n == -1) ? nxt_socket_errno : 0; - - nxt_debug(ev->task, "sendmsg(%d, %FD, %FD, %ui): %z", ev->fd, fd[0], - fd[1], niob, n); - - if (n > 0) { - return n; - } - - /* n == -1 */ - - switch (err) { - - case NXT_EAGAIN: - nxt_debug(ev->task, "sendmsg(%d) not ready", ev->fd); - break; - - /* - * Returned (at least on OSX) when trying to send many small messages. - */ - case NXT_ENOBUFS: - nxt_debug(ev->task, "sendmsg(%d) no buffers", ev->fd); - break; - - case NXT_EINTR: - nxt_debug(ev->task, "sendmsg(%d) interrupted", ev->fd); - continue; - - default: - nxt_alert(ev->task, "sendmsg(%d, %FD, %FD, %ui) failed %E", - ev->fd, fd[0], fd[1], niob, err); - - return NXT_ERROR; - } - - ev->write_ready = 0; - - return NXT_AGAIN; - } -} - - -ssize_t -nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_iobuf_t *iob, nxt_uint_t niob, - void *oob) -{ - ssize_t n; - nxt_err_t err; - - for ( ;; ) { - n = nxt_recvmsg(ev->fd, iob, niob, oob); - - err = (n == -1) ? nxt_socket_errno : 0; - - nxt_debug(ev->task, "recvmsg(%d, %ui, %uz): %z", - ev->fd, niob, ((nxt_recv_oob_t *) oob)->size, n); - - if (n > 0) { - return n; - } - - if (n == 0) { - ev->closed = 1; - ev->read_ready = 0; - - return n; - } - - /* n == -1 */ - - switch (err) { - - case NXT_EAGAIN: - nxt_debug(ev->task, "recvmsg(%d) not ready", ev->fd); - ev->read_ready = 0; - - return NXT_AGAIN; - - case NXT_EINTR: - nxt_debug(ev->task, "recvmsg(%d) interrupted", ev->fd); - continue; - - default: - nxt_alert(ev->task, "recvmsg(%d, %ui) failed %E", - ev->fd, niob, err); - - return NXT_ERROR; - } - } -} diff --git a/src/nxt_solaris_sendfilev.c b/src/nxt_solaris_sendfilev.c deleted file mode 100644 index 1b46d099..00000000 --- a/src/nxt_solaris_sendfilev.c +++ /dev/null @@ -1,169 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * sendfilev() has been introduced in Solaris 8 (7/01). - * According to sendfilev(3EXT) it can write to: - * - * a file descriptor to a regular file or to a AF_NCA, AF_INET, or - * AF_INET6 family type SOCK_STREAM socket that is open for writing. - */ - -ssize_t nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t *c, nxt_buf_t *b, - size_t limit); -static size_t nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, - int32_t *nsfv, nxt_bool_t *sync, size_t limit); - - -ssize_t -nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t *c, nxt_buf_t *b, - size_t limit) -{ - size_t sent; - ssize_t n; - int32_t nsfv; - nxt_err_t err; - nxt_off_t size; - nxt_bool_t sync; - sendfilevec_t sfv[NXT_IOBUF_MAX]; - - if (c->sendfile == 0) { - /* AF_UNIX does not support sendfilev(). */ - return nxt_event_conn_io_sendbuf(c, b, limit); - } - - sync = 0; - - size = nxt_solaris_buf_coalesce(b, sfv, &nsfv, &sync, limit); - - nxt_debug(c->socket.task, "sendfilev(%d, %D)", c->socket.fd, nsfv); - - if (nsfv == 0 && sync) { - return 0; - } - - sent = 0; - n = sendfilev(c->socket.fd, sfv, nsfv, &sent); - - err = (n == -1) ? nxt_errno : 0; - - nxt_debug(c->socket.task, "sendfilev(): %d sent:%uz", n, sent); - - if (n == -1) { - switch (err) { - - case NXT_EAGAIN: - c->socket.write_ready = 0; - break; - - case NXT_EINTR: - break; - - default: - c->socket.error = err; - nxt_log(c->socket.task, nxt_socket_error_level(err), - "sendfilev(%d, %D) failed %E", c->socket.fd, nsfv, err); - - return NXT_ERROR; - } - - nxt_debug(c->socket.task, "sendfilev() %E", err); - - return sent; - } - - if ((nxt_off_t) sent < size) { - c->socket.write_ready = 0; - } - - return sent; -} - - -static size_t -nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, int32_t *nsfv, - nxt_bool_t *sync, size_t limit) -{ - size_t size, total; - nxt_fd_t fd, last_fd; - nxt_int_t i; - nxt_off_t pos, last_pos; - - i = -1; - last_fd = -1; - last_pos = 0; - total = 0; - - for (total = 0; b != NULL && total < limit; b = b->next) { - - if (nxt_buf_is_file(b)) { - - fd = b->file->fd; - pos = b->file_pos; - size = b->file_end - pos; - - if (size == 0) { - continue; - } - - if (total + size > limit) { - size = limit - total; - } - - } else if (nxt_buf_is_mem(b)) { - - fd = SFV_FD_SELF; - pos = (uintptr_t) b->mem.pos; - size = b->mem.free - b->mem.pos; - - if (size == 0) { - continue; - } - - if (total + size > limit) { - size = limit - total; - } - - } else { - *sync = 1; - continue; - } - - if (size == 0) { - break; - } - - if (fd != last_fd || pos != last_pos) { - - if (++i >= NXT_IOBUF_MAX) { - goto done; - } - - sfv[i].sfv_fd = fd; - sfv[i].sfv_flag = 0; - sfv[i].sfv_off = pos; - sfv[i].sfv_len = size; - - } else { - sfv[i].sfv_len += size; - } - - total += size; - last_pos = pos + size; - last_fd = fd; - } - - i++; - -done: - - *nsfv = i; - - return total; -} diff --git a/src/nxt_sort.h b/src/nxt_sort.h deleted file mode 100644 index b79d0919..00000000 --- a/src/nxt_sort.h +++ /dev/null @@ -1,14 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_SORT_H_INCLUDED_ -#define _NXT_SORT_H_INCLUDED_ - - -#define nxt_qsort qsort - - -#endif /* _NXT_SORT_H_INCLUDED_ */ diff --git a/src/nxt_source.h b/src/nxt_source.h deleted file mode 100644 index 0b4658dd..00000000 --- a/src/nxt_source.h +++ /dev/null @@ -1,42 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_SOURCE_H_INCLUDED_ -#define _NXT_SOURCE_H_INCLUDED_ - - -/* - * A source handler should store a pointer to a passed source hook, but not - * the hook's values themselves, because a source filter may change the values. - */ -typedef struct { - void *context; - nxt_work_handler_t filter; -} nxt_source_hook_t; - - -typedef void (*nxt_source_handler_t)(void *source_context, - nxt_source_hook_t *query); - - -#define nxt_source_filter(thr, wq, task, next, out) \ - do { \ - if (thr->engine->batch != 0) { \ - nxt_thread_work_queue_add(thr, wq, nxt_source_filter_handler, \ - task, next, out); \ - \ - } else { \ - (next)->filter(task, (next)->context, out); \ - } \ - \ - } while (0) - - -NXT_EXPORT void nxt_source_filter_handler(nxt_task_t *task, void *obj, - void *data); - - -#endif /* _NXT_SOURCE_H_INCLUDED_ */ diff --git a/src/nxt_spinlock.c b/src/nxt_spinlock.c deleted file mode 100644 index 940be724..00000000 --- a/src/nxt_spinlock.c +++ /dev/null @@ -1,112 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * Linux supports pthread spinlocks since glibc 2.3. Spinlock is an - * atomic integer with zero initial value. On i386/amd64 however the - * initial value is one. Spinlock never yields control. - * - * FreeBSD 5.2 and Solaris 10 support pthread spinlocks. Spinlock is a - * structure and uses mutex implementation so it must be initialized by - * by pthread_spin_init() and destroyed by pthread_spin_destroy(). - * - * MacOSX supported OSSpinLockLock(), it was deprecated in 10.12 (Sierra). - * OSSpinLockLock() tries to acquire a lock atomically. If the lock is - * busy, on SMP system it tests the lock 1000 times in a tight loop with - * "pause" instruction. If the lock has been released, OSSpinLockLock() - * tries to acquire it again. On failure it goes again in the tight loop. - * If the lock has not been released during spinning in the loop or - * on UP system, OSSpinLockLock() calls thread_switch() to run 1ms - * with depressed (the lowest) priority. - */ - - -/* It should be adjusted with the "spinlock_count" directive. */ -static nxt_uint_t nxt_spinlock_count = 1000; - - -void -nxt_thread_spin_init(nxt_uint_t ncpu, nxt_uint_t count) -{ - switch (ncpu) { - - case 0: - /* Explicit spinlock count. */ - nxt_spinlock_count = count; - break; - - case 1: - /* Spinning is useless on UP. */ - nxt_spinlock_count = 0; - break; - - default: - /* - * SMP. - * - * TODO: The count should be 10 on a virtualized system - * since virtualized CPUs may share the same physical CPU. - */ - nxt_spinlock_count = 1000; - break; - } -} - - -void -nxt_thread_spin_lock(nxt_thread_spinlock_t *lock) -{ - nxt_uint_t n; - - nxt_thread_log_debug("spin_lock(%p) enter", lock); - - for ( ;; ) { - - again: - - if (nxt_fast_path(nxt_atomic_try_lock(lock))) { - return; - } - - for (n = nxt_spinlock_count; n != 0; n--) { - - nxt_cpu_pause(); - - if (*lock == 0) { - goto again; - } - } - - nxt_thread_yield(); - } -} - - -nxt_bool_t -nxt_thread_spin_trylock(nxt_thread_spinlock_t *lock) -{ - nxt_thread_log_debug("spin_trylock(%p) enter", lock); - - if (nxt_fast_path(nxt_atomic_try_lock(lock))) { - return 1; - } - - nxt_thread_log_debug("spin_trylock(%p) failed", lock); - - return 0; -} - - -void -nxt_thread_spin_unlock(nxt_thread_spinlock_t *lock) -{ - nxt_atomic_release(lock); - - nxt_thread_log_debug("spin_unlock(%p) exit", lock); -} diff --git a/src/nxt_spinlock.h b/src/nxt_spinlock.h deleted file mode 100644 index 28e05445..00000000 --- a/src/nxt_spinlock.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_SPINLOCK_H_INCLUDED_ -#define _NXT_UNIX_SPINLOCK_H_INCLUDED_ - - -typedef nxt_atomic_t nxt_thread_spinlock_t; - -NXT_EXPORT void nxt_thread_spin_init(nxt_uint_t ncpu, nxt_uint_t count); -NXT_EXPORT void nxt_thread_spin_lock(nxt_thread_spinlock_t *lock); -NXT_EXPORT nxt_bool_t nxt_thread_spin_trylock(nxt_thread_spinlock_t *lock); -NXT_EXPORT void nxt_thread_spin_unlock(nxt_thread_spinlock_t *lock); - - -#endif /* _NXT_UNIX_SPINLOCK_H_INCLUDED_ */ diff --git a/src/nxt_sprintf.c b/src/nxt_sprintf.c deleted file mode 100644 index 875f43a5..00000000 --- a/src/nxt_sprintf.c +++ /dev/null @@ -1,724 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -/* - * Supported formats: - * - * %[0][width][x|X]O nxt_off_t - * %[0][width][x|X]T nxt_time_t - * %[0][width][u][x|X]z ssize_t/size_t - * %[0][width][u][x|X]d int/u_int - * %[0][width][u][x|X]l long - * %[0][width|m][u][x|X]i nxt_int_t/nxt_uint_t - * %[0][width][u][x|X]D int32_t/uint32_t - * %[0][width][u][x|X]L int64_t/uint64_t - * %[0][width|m][u][x|X]A nxt_atomic_int_t/nxt_atomic_uint_t - * %[0][width][.width]f double, max valid number fits to %18.15f - * - * %FD nxt_fd_t, int / HANDLE - * %d nxt_socket_t, int - * - * %PI nxt_pid_t, process id - * %PT nxt_tid_t, thread id - * %PF nxt_fid_t, fiber id - * %PH pthread_t handle returned by pthread_self() - * - * %s null-terminated string - * %*s length and string - * %FN nxt_file_name_t * - * - * %M nxt_msec_t - * %N nxt_nsec_t - * %r rlim_t - * %p void * - * %b nxt_bool_t - * %E nxt_err_t - * %V nxt_str_t * - * %Z '\0' - * %n '\n' - * %c char - * %% % - * - * Reserved: - * %t ptrdiff_t - * %S null-terminated wchar string - * %C wchar - * %[0][width][u][x|X]Q int128_t/uint128_t - */ - - -u_char * nxt_cdecl -nxt_sprintf(u_char *buf, u_char *end, const char *fmt, ...) -{ - u_char *p; - va_list args; - - va_start(args, fmt); - p = nxt_vsprintf(buf, end, fmt, args); - va_end(args); - - return p; -} - - -/* - * nxt_sprintf_t is used: - * to pass several parameters of nxt_integer() via single pointer - * and to store little used variables of nxt_vsprintf(). - */ - -typedef struct { - u_char *end; - const u_char *hex; - uint32_t width; - int32_t frac_width; - uint8_t max_width; - u_char padding; -} nxt_sprintf_t; - - -static u_char *nxt_integer(nxt_sprintf_t *spf, u_char *buf, uint64_t ui64); -static u_char *nxt_number(nxt_sprintf_t *spf, u_char *buf, double n); - - -/* A right way of "f == 0.0". */ -#define nxt_double_is_zero(f) \ - (fabs(f) <= FLT_EPSILON) - - -u_char * -nxt_vsprintf(u_char *buf, u_char *end, const char *fmt, va_list args) -{ - int d; - double f, i; - size_t length; - int64_t i64; - uint64_t ui64, frac; - nxt_str_t *v; - nxt_err_t err; - nxt_uint_t scale, n; - nxt_msec_t ms; - nxt_nsec_t ns; - nxt_bool_t sign; - const u_char *p; - nxt_sprintf_t spf; - nxt_file_name_t *fn; - - static const u_char hexadecimal[16] = "0123456789abcdef"; - static const u_char HEXADECIMAL[16] = "0123456789ABCDEF"; - static const u_char nan[] = "[nan]"; - static const u_char null[] = "[null]"; - static const u_char infinity[] = "[infinity]"; - - spf.end = end; - - while (*fmt != '\0' && buf < end) { - - /* - * "buf < end" means that we could copy at least one character: - * a plain character, "%%", "%c", or a minus without test. - */ - - if (*fmt != '%') { - *buf++ = *fmt++; - continue; - } - - fmt++; - - /* Test some often used text formats first. */ - - switch (*fmt) { - - case 'V': - fmt++; - v = va_arg(args, nxt_str_t *); - - if (nxt_fast_path(v != NULL)) { - length = v->length; - p = v->start; - goto copy; - } - - continue; - - case 's': - fmt++; - - p = va_arg(args, const u_char *); - - if (nxt_slow_path(p == NULL)) { - buf = nxt_cpymem(buf, null, nxt_length(null)); - continue; - } - - while (*p != '\0' && buf < end) { - *buf++ = *p++; - } - - continue; - - case '*': - length = va_arg(args, size_t); - - fmt++; - - if (*fmt == 's') { - fmt++; - p = va_arg(args, const u_char *); - - if (nxt_slow_path(p == NULL)) { - buf = nxt_cpymem(buf, null, nxt_length(null)); - continue; - } - - goto copy; - } - - continue; - - default: - break; - } - - spf.hex = NULL; - spf.width = 0; - spf.frac_width = -1; - spf.max_width = 0; - spf.padding = (*fmt == '0') ? '0' : ' '; - - sign = 1; - - i64 = 0; - ui64 = 0; - - while (*fmt >= '0' && *fmt <= '9') { - spf.width = spf.width * 10 + (*fmt++ - '0'); - } - - - for ( ;; ) { - switch (*fmt) { - - case 'u': - sign = 0; - fmt++; - continue; - - case 'm': - spf.max_width = 1; - fmt++; - continue; - - case 'X': - spf.hex = HEXADECIMAL; - sign = 0; - fmt++; - continue; - - case 'x': - spf.hex = hexadecimal; - sign = 0; - fmt++; - continue; - - case '.': - fmt++; - spf.frac_width = 0; - - while (*fmt >= '0' && *fmt <= '9') { - spf.frac_width = spf.frac_width * 10 + *fmt++ - '0'; - } - - break; - - default: - break; - } - - break; - } - - - switch (*fmt) { - - case 'E': - err = va_arg(args, nxt_err_t); - - *buf++ = '('; - spf.hex = NULL; - spf.width = 0; - buf = nxt_integer(&spf, buf, err); - - if (buf < end - 1) { - *buf++ = ':'; - *buf++ = ' '; - } - - buf = nxt_strerror(err, buf, end - buf); - - if (buf < end) { - *buf++ = ')'; - } - - fmt++; - continue; - - case 'O': - i64 = (int64_t) va_arg(args, nxt_off_t); - sign = 1; - goto number; - - case 'T': - i64 = (int64_t) va_arg(args, nxt_time_t); - sign = 1; - goto number; - - case 'M': - ms = (nxt_msec_t) va_arg(args, nxt_msec_t); - if ((nxt_msec_int_t) ms == -1 && spf.hex == NULL) { - i64 = -1; - sign = 1; - } else { - ui64 = (uint64_t) ms; - sign = 0; - } - goto number; - - case 'N': - ns = (nxt_nsec_t) va_arg(args, nxt_nsec_t); - if ((nxt_nsec_int_t) ns == -1) { - i64 = -1; - sign = 1; - } else { - ui64 = (uint64_t) ns; - sign = 0; - } - goto number; - - case 'z': - if (sign) { - i64 = (int64_t) va_arg(args, ssize_t); - } else { - ui64 = (uint64_t) va_arg(args, size_t); - } - goto number; - - case 'i': - if (sign) { - i64 = (int64_t) va_arg(args, nxt_int_t); - } else { - ui64 = (uint64_t) va_arg(args, nxt_uint_t); - } - - if (spf.max_width != 0) { - spf.width = NXT_INT_T_LEN; - } - - goto number; - - case 'd': - if (sign) { - i64 = (int64_t) va_arg(args, int); - } else { - ui64 = (uint64_t) va_arg(args, u_int); - } - goto number; - - case 'l': - if (sign) { - i64 = (int64_t) va_arg(args, long); - } else { - ui64 = (uint64_t) va_arg(args, u_long); - } - goto number; - - case 'D': - if (sign) { - i64 = (int64_t) va_arg(args, int32_t); - } else { - ui64 = (uint64_t) va_arg(args, uint32_t); - } - goto number; - - case 'L': - if (sign) { - i64 = va_arg(args, int64_t); - } else { - ui64 = va_arg(args, uint64_t); - } - goto number; - - case 'A': - if (sign) { - i64 = (int64_t) va_arg(args, nxt_atomic_int_t); - } else { - ui64 = (uint64_t) va_arg(args, nxt_atomic_uint_t); - } - - if (spf.max_width != 0) { - spf.width = NXT_ATOMIC_T_LEN; - } - - goto number; - - case 'b': - ui64 = (uint64_t) va_arg(args, nxt_bool_t); - sign = 0; - goto number; - - case 'f': - fmt++; - - f = va_arg(args, double); - - if (f < 0) { - *buf++ = '-'; - f = -f; - } - - if (nxt_slow_path(isnan(f))) { - p = nan; - length = nxt_length(nan); - - goto copy; - - } else if (nxt_slow_path(isinf(f))) { - p = infinity; - length = nxt_length(infinity); - - goto copy; - } - - (void) modf(f, &i); - frac = 0; - - if (spf.frac_width > 0) { - - scale = 1; - for (n = spf.frac_width; n != 0; n--) { - scale *= 10; - } - - frac = (uint64_t) ((f - i) * scale + 0.5); - - if (frac == scale) { - i += 1; - frac = 0; - } - } - - buf = nxt_number(&spf, buf, i); - - if (spf.frac_width > 0) { - - if (buf < end) { - *buf++ = '.'; - - spf.hex = NULL; - spf.padding = '0'; - spf.width = spf.frac_width; - buf = nxt_integer(&spf, buf, frac); - } - - } else if (spf.frac_width < 0) { - f = modf(f, &i); - - if (!nxt_double_is_zero(f) && buf < end) { - *buf++ = '.'; - - while (!nxt_double_is_zero(f) && buf < end) { - f *= 10; - f = modf(f, &i); - *buf++ = (u_char) i + '0'; - } - } - } - - continue; - - case 'r': - i64 = (int64_t) va_arg(args, rlim_t); - sign = 1; - break; - - case 'p': - ui64 = (uintptr_t) va_arg(args, void *); - sign = 0; - spf.hex = HEXADECIMAL; - /* - * spf.width = NXT_PTR_SIZE * 2; - * spf.padding = '0'; - */ - goto number; - - case 'c': - d = va_arg(args, int); - *buf++ = (u_char) (d & 0xFF); - fmt++; - - continue; - - case 'F': - fmt++; - - switch (*fmt) { - - case 'D': - i64 = (int64_t) va_arg(args, nxt_fd_t); - sign = 1; - - goto number; - - case 'N': - fn = va_arg(args, nxt_file_name_t *); - p = fn; - - while (*p != '\0' && buf < end) { - *buf++ = *p++; - } - - fmt++; - continue; - - default: - continue; - } - - case 'P': - fmt++; - - switch (*fmt) { - - case 'I': - i64 = (int64_t) va_arg(args, nxt_pid_t); - sign = 1; - goto number; - - case 'T': - ui64 = (uint64_t) (uintptr_t) va_arg(args, nxt_tid_t); - sign = 0; - goto number; -#if 0 - case 'F': - ui64 = (uint64_t) va_arg(args, nxt_fid_t); - sign = 0; - goto number; -#endif - case 'H': - ui64 = (uint64_t) (uintptr_t) va_arg(args, pthread_t); - spf.hex = HEXADECIMAL; - sign = 0; - goto number; - - default: - continue; - } - - case 'Z': - *buf++ = '\0'; - fmt++; - continue; - - case 'n': - *buf++ = '\n'; - fmt++; - continue; - - case '%': - *buf++ = '%'; - fmt++; - continue; - - default: - *buf++ = *fmt++; - continue; - } - - number: - - if (sign) { - if (i64 < 0) { - *buf++ = '-'; - ui64 = (uint64_t) -i64; - - } else { - ui64 = (uint64_t) i64; - } - } - - buf = nxt_integer(&spf, buf, ui64); - - fmt++; - continue; - - copy: - - length = nxt_min((size_t) (end - buf), length); - buf = nxt_cpymem(buf, p, length); - continue; - } - - return buf; -} - - -static u_char * -nxt_integer(nxt_sprintf_t *spf, u_char *buf, uint64_t ui64) -{ - u_char *p, *end; - size_t length; - u_char temp[NXT_INT64_T_LEN]; - - p = temp + NXT_INT64_T_LEN; - - if (spf->hex == NULL) { - -#if (NXT_32BIT) - - for ( ;; ) { - u_char *start; - uint32_t ui32; - - /* - * 32-bit platforms usually lack hardware support of 64-bit - * division and remainder operations. For this reason C compiler - * adds calls to the runtime library functions which provides - * these operations. These functions usually have about hundred - * lines of code. - * - * For 32-bit numbers and some constant divisors GCC, Clang and - * other compilers can use inlined multiplications and shifts - * which are faster than division or remainder operations. - * For example, unsigned "ui32 / 10" is compiled to - * - * ((uint64_t) ui32 * 0xCCCCCCCD) >> 35 - * - * So a 64-bit number is split to parts by 10^9. The parts fit - * to 32 bits and are processed separately as 32-bit numbers. A - * number of 64-bit division/remainder operations is significantly - * decreased depending on the 64-bit number's value, it is - * 0 if the 64-bit value is less than 4294967296, - * 1 if the 64-bit value is greater than 4294967295 - * and less than 4294967296000000000, - * 2 otherwise. - */ - - if (ui64 <= 0xFFFFFFFF) { - ui32 = (uint32_t) ui64; - start = NULL; - - } else { - ui32 = (uint32_t) (ui64 % 1000000000); - start = p - 9; - } - - do { - *(--p) = (u_char) (ui32 % 10 + '0'); - ui32 /= 10; - } while (ui32 != 0); - - if (start == NULL) { - break; - } - - /* Add leading zeros of part. */ - - while (p > start) { - *(--p) = '0'; - } - - ui64 /= 1000000000; - } - -#else /* NXT_64BIT */ - - do { - *(--p) = (u_char) (ui64 % 10 + '0'); - ui64 /= 10; - } while (ui64 != 0); - -#endif - - } else { - - do { - *(--p) = spf->hex[ui64 & 0xF]; - ui64 >>= 4; - } while (ui64 != 0); - } - - /* Zero or space padding. */ - - if (spf->width != 0) { - - length = (temp + NXT_INT64_T_LEN) - p; - end = buf + (spf->width - length); - end = nxt_min(end, spf->end); - - while (buf < end) { - *buf++ = spf->padding; - } - } - - /* Number copying. */ - - length = (temp + NXT_INT64_T_LEN) - p; - end = buf + length; - end = nxt_min(end, spf->end); - - while (buf < end) { - *buf++ = *p++; - } - - return buf; -} - - -static u_char * -nxt_number(nxt_sprintf_t *spf, u_char *buf, double n) -{ - u_char *p, *end; - size_t length; - u_char temp[NXT_DOUBLE_LEN]; - - p = temp + NXT_DOUBLE_LEN; - - do { - *(--p) = (u_char) (fmod(n, 10) + '0'); - n = trunc(n / 10); - } while (!nxt_double_is_zero(n)); - - /* Zero or space padding. */ - - if (spf->width != 0) { - length = (temp + NXT_DOUBLE_LEN) - p; - end = buf + (spf->width - length); - end = nxt_min(end, spf->end); - - while (buf < end) { - *buf++ = spf->padding; - } - } - - /* Number copying. */ - - length = (temp + NXT_DOUBLE_LEN) - p; - - end = buf + length; - end = nxt_min(end, spf->end); - - while (buf < end) { - *buf++ = *p++; - } - - return buf; -} diff --git a/src/nxt_sprintf.h b/src/nxt_sprintf.h deleted file mode 100644 index 0a927f71..00000000 --- a/src/nxt_sprintf.h +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_SPRINTF_H_INCLUDED_ -#define _NXT_SPRINTF_H_INCLUDED_ - - -/* STUB */ -#define NXT_DOUBLE_LEN (1 + DBL_MAX_10_EXP) - - -NXT_EXPORT u_char *nxt_cdecl nxt_sprintf(u_char *buf, u_char *end, - const char *fmt, ...); -NXT_EXPORT u_char *nxt_vsprintf(u_char *buf, u_char *end, - const char *fmt, va_list args); - - -#endif /* _NXT_SPRINTF_H_INCLUDED_ */ diff --git a/src/nxt_status.c b/src/nxt_status.c deleted file mode 100644 index f8002e86..00000000 --- a/src/nxt_status.c +++ /dev/null @@ -1,105 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -nxt_conf_value_t * -nxt_status_get(nxt_status_report_t *report, nxt_mp_t *mp) -{ - size_t i; - nxt_str_t name; - nxt_int_t ret; - nxt_status_app_t *app; - nxt_conf_value_t *status, *obj, *apps, *app_obj; - - static nxt_str_t conns_str = nxt_string("connections"); - static nxt_str_t acc_str = nxt_string("accepted"); - static nxt_str_t active_str = nxt_string("active"); - static nxt_str_t idle_str = nxt_string("idle"); - static nxt_str_t closed_str = nxt_string("closed"); - static nxt_str_t reqs_str = nxt_string("requests"); - static nxt_str_t total_str = nxt_string("total"); - static nxt_str_t apps_str = nxt_string("applications"); - static nxt_str_t procs_str = nxt_string("processes"); - static nxt_str_t run_str = nxt_string("running"); - static nxt_str_t start_str = nxt_string("starting"); - - status = nxt_conf_create_object(mp, 3); - if (nxt_slow_path(status == NULL)) { - return NULL; - } - - obj = nxt_conf_create_object(mp, 4); - if (nxt_slow_path(obj == NULL)) { - return NULL; - } - - nxt_conf_set_member(status, &conns_str, obj, 0); - - nxt_conf_set_member_integer(obj, &acc_str, report->accepted_conns, 0); - nxt_conf_set_member_integer(obj, &active_str, report->accepted_conns - - report->closed_conns - - report->idle_conns, 1); - nxt_conf_set_member_integer(obj, &idle_str, report->idle_conns, 2); - nxt_conf_set_member_integer(obj, &closed_str, report->closed_conns, 3); - - obj = nxt_conf_create_object(mp, 1); - if (nxt_slow_path(obj == NULL)) { - return NULL; - } - - nxt_conf_set_member(status, &reqs_str, obj, 1); - - nxt_conf_set_member_integer(obj, &total_str, report->requests, 0); - - apps = nxt_conf_create_object(mp, report->apps_count); - if (nxt_slow_path(apps == NULL)) { - return NULL; - } - - nxt_conf_set_member(status, &apps_str, apps, 2); - - for (i = 0; i < report->apps_count; i++) { - app = &report->apps[i]; - - app_obj = nxt_conf_create_object(mp, 2); - if (nxt_slow_path(app_obj == NULL)) { - return NULL; - } - - name.length = app->name.length; - name.start = nxt_pointer_to(report, (uintptr_t) app->name.start); - - ret = nxt_conf_set_member_dup(apps, mp, &name, app_obj, i); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - obj = nxt_conf_create_object(mp, 3); - if (nxt_slow_path(obj == NULL)) { - return NULL; - } - - nxt_conf_set_member(app_obj, &procs_str, obj, 0); - - nxt_conf_set_member_integer(obj, &run_str, app->processes, 0); - nxt_conf_set_member_integer(obj, &start_str, app->pending_processes, 1); - nxt_conf_set_member_integer(obj, &idle_str, app->idle_processes, 2); - - obj = nxt_conf_create_object(mp, 1); - if (nxt_slow_path(obj == NULL)) { - return NULL; - } - - nxt_conf_set_member(app_obj, &reqs_str, obj, 1); - - nxt_conf_set_member_integer(obj, &active_str, app->active_requests, 0); - } - - return status; -} diff --git a/src/nxt_status.h b/src/nxt_status.h deleted file mode 100644 index a99ac7d0..00000000 --- a/src/nxt_status.h +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_STATUS_H_INCLUDED_ -#define _NXT_STATUS_H_INCLUDED_ - - -typedef struct { - nxt_str_t name; - uint32_t active_requests; - uint32_t pending_processes; - uint32_t processes; - uint32_t idle_processes; -} nxt_status_app_t; - - -typedef struct { - uint64_t accepted_conns; - uint64_t idle_conns; - uint64_t closed_conns; - uint64_t requests; - - size_t apps_count; - nxt_status_app_t apps[]; -} nxt_status_report_t; - - -nxt_conf_value_t *nxt_status_get(nxt_status_report_t *report, nxt_mp_t *mp); - - -#endif /* _NXT_STATUS_H_INCLUDED_ */ diff --git a/src/nxt_string.c b/src/nxt_string.c deleted file mode 100644 index 1ca595a1..00000000 --- a/src/nxt_string.c +++ /dev/null @@ -1,844 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_str_t * -nxt_str_alloc(nxt_mp_t *mp, size_t length) -{ - nxt_str_t *s; - - /* The string start is allocated aligned to be close to nxt_str_t. */ - s = nxt_mp_get(mp, sizeof(nxt_str_t) + length); - - if (nxt_fast_path(s != NULL)) { - s->length = length; - s->start = nxt_pointer_to(s, sizeof(nxt_str_t)); - } - - return s; -} - - -/* - * nxt_str_dup() creates a new string with a copy of a source string. - * If length of the source string is zero, then the new string anyway - * gets a pointer somewhere in mem_pool. - */ - -nxt_str_t * -nxt_str_dup(nxt_mp_t *mp, nxt_str_t *dst, const nxt_str_t *src) -{ - u_char *p; - - if (dst == NULL) { - /* The string start is allocated aligned to be close to nxt_str_t. */ - dst = nxt_mp_get(mp, sizeof(nxt_str_t) + src->length); - if (nxt_slow_path(dst == NULL)) { - return NULL; - } - - p = (u_char *) dst; - p += sizeof(nxt_str_t); - dst->start = p; - - } else { - dst->start = nxt_mp_nget(mp, src->length); - if (nxt_slow_path(dst->start == NULL)) { - return NULL; - } - } - - nxt_memcpy(dst->start, src->start, src->length); - dst->length = src->length; - - return dst; -} - - -/* - * nxt_str_cstrz() creates a C style zero-terminated copy of a source - * nxt_str_t. The function is intended to create strings suitable - * for libc and kernel interfaces so result is pointer to char instead - * of u_char to minimize casts. - */ - -char * -nxt_str_cstrz(nxt_mp_t *mp, const nxt_str_t *src) -{ - char *p, *dst; - - dst = nxt_mp_alloc(mp, src->length + 1); - - if (nxt_fast_path(dst != NULL)) { - p = nxt_cpymem(dst, src->start, src->length); - *p = '\0'; - } - - return dst; -} - - -void -nxt_memcpy_lowcase(u_char *dst, const u_char *src, size_t length) -{ - u_char c; - - while (length != 0) { - c = *src++; - *dst++ = nxt_lowcase(c); - length--; - } -} - - -void -nxt_memcpy_upcase(u_char *dst, const u_char *src, size_t length) -{ - u_char c; - - while (length != 0) { - c = *src++; - *dst++ = nxt_upcase(c); - length--; - } -} - - -u_char * -nxt_cpystr(u_char *dst, const u_char *src) -{ - for ( ;; ) { - *dst = *src; - - if (*dst == '\0') { - break; - } - - dst++; - src++; - } - - return dst; -} - - -u_char * -nxt_cpystrn(u_char *dst, const u_char *src, size_t length) -{ - if (length == 0) { - return dst; - } - - while (--length != 0) { - *dst = *src; - - if (*dst == '\0') { - return dst; - } - - dst++; - src++; - } - - *dst = '\0'; - - return dst; -} - - -nxt_int_t -nxt_strcasecmp(const u_char *s1, const u_char *s2) -{ - u_char c1, c2; - nxt_int_t n; - - for ( ;; ) { - c1 = *s1++; - c2 = *s2++; - - c1 = nxt_lowcase(c1); - c2 = nxt_lowcase(c2); - - n = c1 - c2; - - if (n != 0) { - return n; - } - - if (c1 == 0) { - return 0; - } - } -} - - -nxt_int_t -nxt_strncasecmp(const u_char *s1, const u_char *s2, size_t length) -{ - u_char c1, c2; - nxt_int_t n; - - while (length-- != 0) { - c1 = *s1++; - c2 = *s2++; - - c1 = nxt_lowcase(c1); - c2 = nxt_lowcase(c2); - - n = c1 - c2; - - if (n != 0) { - return n; - } - - if (c1 == 0) { - return 0; - } - } - - return 0; -} - - -nxt_int_t -nxt_memcasecmp(const void *p1, const void *p2, size_t length) -{ - u_char c1, c2; - nxt_int_t n; - const u_char *s1, *s2; - - s1 = p1; - s2 = p2; - - while (length-- != 0) { - c1 = *s1++; - c2 = *s2++; - - c1 = nxt_lowcase(c1); - c2 = nxt_lowcase(c2); - - n = c1 - c2; - - if (n != 0) { - return n; - } - } - - return 0; -} - - -/* - * nxt_memstrn() is intended for search of static substring "ss" - * with known length "length" in string "s" limited by parameter "end". - * Zeros are ignored in both strings. - */ - -u_char * -nxt_memstrn(const u_char *s, const u_char *end, const char *ss, size_t length) -{ - u_char c1, c2, *s2; - - s2 = (u_char *) ss; - c2 = *s2++; - length--; - - while (s < end) { - c1 = *s++; - - if (c1 == c2) { - - if (s + length > end) { - return NULL; - } - - if (memcmp(s, s2, length) == 0) { - return (u_char *) s - 1; - } - } - } - - return NULL; -} - - -/* - * nxt_strcasestrn() is intended for caseless search of static substring - * "ss" with known length "length" in string "s" limited by parameter "end". - * Zeros are ignored in both strings. - */ - -u_char * -nxt_memcasestrn(const u_char *s, const u_char *end, const char *ss, - size_t length) -{ - u_char c1, c2, *s2; - - s2 = (u_char *) ss; - c2 = *s2++; - c2 = nxt_lowcase(c2); - length--; - - while (s < end) { - c1 = *s++; - c1 = nxt_lowcase(c1); - - if (c1 == c2) { - - if (s + length > end) { - return NULL; - } - - if (nxt_memcasecmp(s, s2, length) == 0) { - return (u_char *) s - 1; - } - } - } - - return NULL; -} - - -/* - * nxt_rstrstrn() is intended to search for static substring "ss" - * with known length "length" in string "s" limited by parameter "end" - * in reverse order. Zeros are ignored in both strings. - */ - -u_char * -nxt_rmemstrn(const u_char *s, const u_char *end, const char *ss, size_t length) -{ - u_char c1, c2; - const u_char *s1, *s2; - - s1 = end - length; - s2 = (u_char *) ss; - c2 = *s2++; - length--; - - while (s < s1) { - c1 = *s1; - - if (c1 == c2) { - if (memcmp(s1 + 1, s2, length) == 0) { - return (u_char *) s1; - } - } - - s1--; - } - - return NULL; -} - - -size_t -nxt_str_strip(const u_char *start, u_char *end) -{ - u_char *p; - - for (p = end - 1; p >= start; p--) { - if (*p != '\r' && *p != '\n') { - break; - } - } - - return (p + 1) - start; -} - - -nxt_int_t -nxt_strverscmp(const u_char *s1, const u_char *s2) -{ - u_char c1, c2; - nxt_int_t diff; - - enum { - st_str = 0, - st_num, - st_zero, - st_frac, - } state; - - state = st_str; - - for ( ;; ) { - c1 = *s1++; - c2 = *s2++; - - diff = c1 - c2; - - if (diff != 0) { - break; - } - - if (c1 == '\0') { - return 0; - } - - if (!nxt_isdigit(c1)) { - state = st_str; - continue; - } - - if (state == st_str) { - state = (c1 != '0') ? st_num : st_zero; - continue; - } - - if (state == st_zero && c1 != '0') { - state = st_frac; - continue; - } - } - - switch (state) { - - case st_str: - - if ((u_char) (c1 - '1') > 8 || (u_char) (c2 - '1') > 8) { - return diff; - } - - c1 = *s1++; - c2 = *s2++; - - /* Fall through. */ - - case st_num: - - while (nxt_isdigit(c1) && nxt_isdigit(c2)) { - c1 = *s1++; - c2 = *s2++; - } - - if (nxt_isdigit(c1)) { - return 1; - } - - if (nxt_isdigit(c2)) { - return -1; - } - - return diff; - - case st_zero: - - if (c1 == '0' || c2 == '\0') { - return -1; - } - - if (c2 == '0' || c1 == '\0') { - return 1; - } - - /* Fall through. */ - - case st_frac: - default: - return diff; - } -} - - -nxt_bool_t -nxt_strvers_match(u_char *version, u_char *prefix, size_t length) -{ - u_char next, last; - - if (length == 0) { - return 1; - } - - if (nxt_strncmp(version, prefix, length) == 0) { - - next = version[length]; - - if (next == '\0') { - return 1; - } - - last = version[length - 1]; - - if (nxt_isdigit(last) != nxt_isdigit(next)) { - /* This is a version part boundary. */ - return 1; - } - } - - return 0; -} - - -const uint8_t nxt_hex2int[256] - nxt_aligned(32) = -{ - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 16, 16, 16, 16, 16, - 16, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -}; - - -static const uint32_t nxt_uri_escape[] = { - 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - - /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0xd000002d, /* 1101 0000 0000 0000 0000 0000 0010 1101 */ - - /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ - - /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ - - 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ -}; - - -u_char * -nxt_decode_uri(u_char *dst, u_char *src, size_t length) -{ - u_char *end, ch; - uint8_t d0, d1; - - nxt_prefetch(&nxt_hex2int['0']); - - end = src + length; - - while (src < end) { - ch = *src++; - - if (ch == '%') { - if (nxt_slow_path(end - src < 2)) { - return NULL; - } - - d0 = nxt_hex2int[*src++]; - d1 = nxt_hex2int[*src++]; - - if (nxt_slow_path((d0 | d1) >= 16)) { - return NULL; - } - - ch = (d0 << 4) + d1; - } - - *dst++ = ch; - } - - return dst; -} - - -u_char * -nxt_decode_uri_plus(u_char *dst, u_char *src, size_t length) -{ - u_char *end, ch; - uint8_t d0, d1; - - nxt_prefetch(&nxt_hex2int['0']); - - end = src + length; - - while (src < end) { - ch = *src++; - - switch (ch) { - case '%': - if (nxt_slow_path(end - src < 2)) { - return NULL; - } - - d0 = nxt_hex2int[*src++]; - d1 = nxt_hex2int[*src++]; - - if (nxt_slow_path((d0 | d1) >= 16)) { - return NULL; - } - - ch = (d0 << 4) + d1; - break; - - case '+': - ch = ' '; - break; - } - - *dst++ = ch; - } - - return dst; -} - - -uintptr_t -nxt_encode_uri(u_char *dst, u_char *src, size_t length) -{ - u_char *end; - nxt_uint_t n; - - static const u_char hex[16] = "0123456789ABCDEF"; - - end = src + length; - - if (dst == NULL) { - - /* Find the number of the characters to be escaped. */ - - n = 0; - - while (src < end) { - - if (nxt_uri_escape[*src >> 5] & (1U << (*src & 0x1f))) { - n++; - } - - src++; - } - - return (uintptr_t) n; - } - - while (src < end) { - - if (nxt_uri_escape[*src >> 5] & (1U << (*src & 0x1f))) { - *dst++ = '%'; - *dst++ = hex[*src >> 4]; - *dst++ = hex[*src & 0xf]; - - } else { - *dst++ = *src; - } - - src++; - } - - return (uintptr_t) dst; -} - - -uintptr_t -nxt_encode_complex_uri(u_char *dst, u_char *src, size_t length) -{ - u_char *reserved, *end, ch; - nxt_uint_t n; - - static const u_char hex[16] = "0123456789ABCDEF"; - - reserved = (u_char *) "?#\0"; - - end = src + length; - - if (dst == NULL) { - - /* Find the number of the characters to be escaped. */ - - n = 0; - - while (src < end) { - ch = *src++; - - if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) { - if (ch == reserved[0]) { - reserved++; - continue; - } - - if (ch == reserved[1]) { - reserved += 2; - continue; - } - - n++; - } - } - - return (uintptr_t) n; - } - - while (src < end) { - ch = *src++; - - if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) { - if (ch == reserved[0]) { - reserved++; - - } else if (ch == reserved[1]) { - reserved += 2; - - } else { - *dst++ = '%'; - *dst++ = hex[ch >> 4]; - *dst++ = hex[ch & 0xf]; - continue; - } - } - - *dst++ = ch; - } - - return (uintptr_t) dst; -} - - -nxt_bool_t -nxt_is_complex_uri_encoded(u_char *src, size_t length) -{ - u_char *reserved, *end, ch; - uint8_t d0, d1; - - reserved = (u_char *) "?#\0"; - - for (end = src + length; src < end; src++) { - ch = *src; - - if (nxt_uri_escape[ch >> 5] & (1U << (ch & 0x1f))) { - if (ch == '%') { - if (end - src < 2) { - return 0; - } - - d0 = nxt_hex2int[*++src]; - d1 = nxt_hex2int[*++src]; - - if ((d0 | d1) >= 16) { - return 0; - } - - continue; - } - - if (ch == reserved[0]) { - reserved++; - continue; - } - - if (ch == reserved[1]) { - reserved += 2; - continue; - } - - return 0; - } - } - - return 1; -} - - -ssize_t -nxt_base64_decode(u_char *dst, u_char *src, size_t length) -{ - u_char *end, *p; - size_t pad; - uint8_t v1, v2, v3, v4; - - static const uint8_t decode[] = { - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77, - 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77, - 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77, - - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 - }; - - end = src + length; - pad = (4 - (length % 4)) % 4; - - if (dst == NULL) { - if (pad > 2) { - return NXT_ERROR; - } - - while (src < end) { - if (decode[*src] != 77) { - src++; - continue; - } - - if (pad == 0) { - pad = end - src; - - if ((pad == 1 || (pad == 2 && src[1] == '=')) && src[0] == '=') - { - break; - } - } - - return NXT_ERROR; - } - - return (length + 3) / 4 * 3 - pad; - } - - nxt_assert(length != 0); - - if (pad == 0) { - pad = (end[-1] == '=') + (end[-2] == '='); - end -= (pad + 3) & 4; - - } else { - end -= 4 - pad; - } - - p = dst; - - while (src < end) { - v1 = decode[src[0]]; - v2 = decode[src[1]]; - v3 = decode[src[2]]; - v4 = decode[src[3]]; - - *p++ = (v1 << 2 | v2 >> 4); - *p++ = (v2 << 4 | v3 >> 2); - *p++ = (v3 << 6 | v4); - - src += 4; - } - - if (pad > 0) { - v1 = decode[src[0]]; - v2 = decode[src[1]]; - - *p++ = (v1 << 2 | v2 >> 4); - - if (pad == 1) { - v3 = decode[src[2]]; - *p++ = (v2 << 4 | v3 >> 2); - } - } - - return (p - dst); -} diff --git a/src/nxt_string.h b/src/nxt_string.h deleted file mode 100644 index 18ea5490..00000000 --- a/src/nxt_string.h +++ /dev/null @@ -1,167 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_STRING_H_INCLUDED_ -#define _NXT_STRING_H_INCLUDED_ - - -#define nxt_lowcase(c) \ - (u_char) ((c >= 'A' && c <= 'Z') ? c | 0x20 : c) - -#define nxt_upcase(c) \ - (u_char) ((c >= 'a' && c <= 'z') ? c & ~0x20 : c) - -#define nxt_isdigit(c) \ - ((u_char) ((c) - '0') <= 9) - -#define nxt_strtod(s, endptr) \ - strtod((char *) s, (char **) endptr) - - -#define nxt_strlen(s) \ - strlen((char *) s) - - -#define nxt_strdup(s) \ - strdup((char *) s) - - -#define nxt_strchr(buf, delim) \ - (u_char *) strchr((char *) buf, delim) - - -#define nxt_memzero(buf, length) \ - (void) memset(buf, 0, length) - - -#define nxt_memset(buf, c, length) \ - (void) memset(buf, c, length) - - -#define nxt_memcpy(dst, src, length) \ - (void) memcpy(dst, src, length) - - -NXT_EXPORT void nxt_memcpy_lowcase(u_char *dst, const u_char *src, - size_t length); -NXT_EXPORT void nxt_memcpy_upcase(u_char *dst, const u_char *src, - size_t length); - - -/* - * nxt_cpymem() is an inline function but not a macro to - * eliminate possible double evaluation of length "length". - */ -nxt_inline void * -nxt_cpymem(void *dst, const void *src, size_t length) -{ - return ((u_char *) memcpy(dst, src, length)) + length; -} - - -#define nxt_memmove(dst, src, length) \ - (void) memmove(dst, src, length) - - -#define nxt_strcmp(s1, s2) \ - strcmp((char *) s1, (char *) s2) - - -#define nxt_strncmp(s1, s2, length) \ - strncmp((char *) s1, (char *) s2, length) - - -NXT_EXPORT u_char *nxt_cpystr(u_char *dst, const u_char *src); -NXT_EXPORT u_char *nxt_cpystrn(u_char *dst, const u_char *src, size_t length); -NXT_EXPORT nxt_int_t nxt_strcasecmp(const u_char *s1, const u_char *s2); -NXT_EXPORT nxt_int_t nxt_strncasecmp(const u_char *s1, const u_char *s2, - size_t length); -NXT_EXPORT nxt_int_t nxt_memcasecmp(const void *p1, const void *p2, - size_t length); - -NXT_EXPORT u_char *nxt_memstrn(const u_char *s, const u_char *end, - const char *ss, size_t length); -NXT_EXPORT u_char *nxt_memcasestrn(const u_char *s, const u_char *end, - const char *ss, size_t length); -NXT_EXPORT u_char *nxt_rmemstrn(const u_char *s, const u_char *end, - const char *ss, size_t length); -NXT_EXPORT size_t nxt_str_strip(const u_char *start, u_char *end); - - -typedef struct { - size_t length; - u_char *start; -} nxt_str_t; - - -#define nxt_string(str) { nxt_length(str), (u_char *) str } -#define nxt_string_zero(str) { sizeof(str), (u_char *) str } -#define nxt_null_string { 0, NULL } - - -#define nxt_str_set(str, text) \ - do { \ - (str)->length = nxt_length(text); \ - (str)->start = (u_char *) text; \ - } while (0) - - -#define nxt_str_null(str) \ - do { \ - (str)->length = 0; \ - (str)->start = NULL; \ - } while (0) - - -NXT_EXPORT nxt_str_t *nxt_str_alloc(nxt_mp_t *mp, size_t length); -NXT_EXPORT nxt_str_t *nxt_str_dup(nxt_mp_t *mp, nxt_str_t *dst, - const nxt_str_t *src); -NXT_EXPORT char *nxt_str_cstrz(nxt_mp_t *mp, const nxt_str_t *src); - - -#define nxt_strstr_eq(s1, s2) \ - (((s1)->length == (s2)->length) \ - && (memcmp((s1)->start, (s2)->start, (s1)->length) == 0)) - - -#define nxt_strcasestr_eq(s1, s2) \ - (((s1)->length == (s2)->length) \ - && (nxt_memcasecmp((s1)->start, (s2)->start, (s1)->length) == 0)) - - -#define nxt_str_eq(s, p, _length) \ - (((s)->length == _length) && (memcmp((s)->start, p, _length) == 0)) - - -#define nxt_str_start(s, p, _length) \ - (((s)->length >= _length) && (memcmp((s)->start, p, _length) == 0)) - - -#define nxt_strchr_eq(s, c) \ - (((s)->length == 1) && ((s)->start[0] == c)) - - -#define nxt_strchr_start(s, c) \ - (((s)->length != 0) && ((s)->start[0] == c)) - - -NXT_EXPORT nxt_int_t nxt_strverscmp(const u_char *s1, const u_char *s2); -NXT_EXPORT nxt_bool_t nxt_strvers_match(u_char *version, u_char *prefix, - size_t length); - -NXT_EXPORT u_char *nxt_decode_uri(u_char *dst, u_char *src, size_t length); -NXT_EXPORT u_char *nxt_decode_uri_plus(u_char *dst, u_char *src, size_t length); -NXT_EXPORT uintptr_t nxt_encode_uri(u_char *dst, u_char *src, size_t length); -NXT_EXPORT uintptr_t nxt_encode_complex_uri(u_char *dst, u_char *src, - size_t length); -NXT_EXPORT nxt_bool_t nxt_is_complex_uri_encoded(u_char *s, size_t length); - -NXT_EXPORT ssize_t nxt_base64_decode(u_char *dst, u_char *src, size_t length); - -extern const uint8_t nxt_hex2int[256]; - - -#endif /* _NXT_STRING_H_INCLUDED_ */ diff --git a/src/nxt_test_build.c b/src/nxt_test_build.c deleted file mode 100644 index aefd8c13..00000000 --- a/src/nxt_test_build.c +++ /dev/null @@ -1,153 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - - -#include - - -#if (NXT_TEST_BUILD_EPOLL) - -int -epoll_create(int size) -{ - return -1; -} - - -int -epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) -{ - return -1; -} - - -int -epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout) -{ - return -1; -} - -int -eventfd(u_int initval, int flags) -{ - return -1; -} - - -int -signalfd(int fd, const sigset_t *mask, int flags) -{ - return -1; -} - - -int -accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) -{ - return -1; -} - -#endif - - -#if (NXT_TEST_BUILD_EVENTPORT) - -int -port_create(void) -{ - return -1; -} - - -int -port_associate(int port, int source, uintptr_t object, int events, void *user) -{ - return -1; -} - - -int -port_dissociate(int port, int source, uintptr_t object) -{ - return -1; -} - - -int -port_send(int port, int events, void *user) -{ - return -1; -} - - -int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget, - const timespec_t *timeout) -{ - return -1; -} - -#endif - - -#if (NXT_TEST_BUILD_POLLSET) - -pollset_t -pollset_create(int maxfd) -{ - return -1; -} - - -int -pollset_destroy(pollset_t ps) -{ - return -1; -} - - -int -pollset_query(pollset_t ps, struct pollfd *pollfd_query) -{ - return -1; -} - - -int -pollset_ctl(pollset_t ps, struct poll_ctl *pollctl_array, int array_length) -{ - return -1; -} - - -int -pollset_poll(pollset_t ps, struct pollfd *polldata_array, int array_length, - int timeout) -{ - return -1; -} - -#endif - - -#if (NXT_TEST_BUILD_SOLARIS_SENDFILEV) - -ssize_t sendfilev(int fd, const struct sendfilevec *vec, - int sfvcnt, size_t *xferred) -{ - return -1; -} - -#endif - - -#if (NXT_TEST_BUILD_AIX_SEND_FILE) - -ssize_t send_file(int *s, struct sf_parms *sf_iobuf, uint_t flags) -{ - return -1; -} - -#endif diff --git a/src/nxt_test_build.h b/src/nxt_test_build.h deleted file mode 100644 index 6513e748..00000000 --- a/src/nxt_test_build.h +++ /dev/null @@ -1,274 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - - -#ifndef _NXT_UNIX_TEST_BUILD_H_INCLUDED_ -#define _NXT_UNIX_TEST_BUILD_H_INCLUDED_ - - -#if (NXT_TEST_BUILD_EPOLL) - -#define NXT_HAVE_EPOLL 1 -#define NXT_HAVE_EPOLL_EDGE 1 -#define NXT_HAVE_EVENTFD 1 -#define NXT_HAVE_SIGNALFD 1 -#define NXT_HAVE_ACCEPT4 1 - -/* Linux epoll declarations */ - -#define EPOLLIN 0x00000001 -#define EPOLLPRI 0x00000002 -#define EPOLLOUT 0x00000004 -#define EPOLLERR 0x00000008 -#define EPOLLHUP 0x00000010 -#define EPOLLRDNORM 0x00000040 -#define EPOLLRDBAND 0x00000080 -#define EPOLLWRNORM 00000x0100 -#define EPOLLWRBAND 0x00000200 -#define EPOLLMSG 0x00000400 -#define EPOLLRDHUP 0x00002000 - -#define EPOLLET 0x80000000 -#define EPOLLONESHOT 0x40000000 - -#define EPOLL_CTL_ADD 1 -#define EPOLL_CTL_DEL 2 -#define EPOLL_CTL_MOD 3 - -#define EFD_SEMAPHORE 1 -#define EFD_NONBLOCK 04000 - - -typedef union epoll_data { - void *ptr; - int fd; - uint32_t u32; - uint64_t u64; -} epoll_data_t; - - -struct epoll_event { - uint32_t events; - epoll_data_t data; -}; - - -struct signalfd_siginfo { - uint32_t ssi_signo; /* Signal number */ - int32_t ssi_errno; /* Error number (unused) */ - int32_t ssi_code; /* Signal code */ - uint32_t ssi_pid; /* PID of sender */ - uint32_t ssi_uid; /* Real UID of sender */ - int32_t ssi_fd; /* File descriptor (SIGIO) */ - uint32_t ssi_tid; /* Kernel timer ID (POSIX timers) */ - uint32_t ssi_band; /* Band event (SIGIO) */ - uint32_t ssi_overrun; /* POSIX timer overrun count */ - uint32_t ssi_trapno; /* Trap number that caused signal */ - int32_t ssi_status; /* Exit status or signal (SIGCHLD) */ - int32_t ssi_int; /* Integer sent by sigqueue(2) */ - uint64_t ssi_ptr; /* Pointer sent by sigqueue(2) */ - uint64_t ssi_utime; /* User CPU time consumed (SIGCHLD) */ - uint64_t ssi_stime; /* System CPU time consumed (SIGCHLD) */ - uint64_t ssi_addr; /* Address that generated signal - (for hardware-generated signals) */ - uint8_t pad[8]; /* Pad size to 128 bytes (allow for - additional fields in the future) */ -}; - - -int epoll_create(int size); -int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); -int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout); - -int eventfd(u_int initval, int flags); -int signalfd(int fd, const sigset_t *mask, int flags); - -#define SOCK_NONBLOCK 04000 - -int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); - -#endif - - -#if (NXT_TEST_BUILD_EVENTPORT) - -#include - -#define NXT_HAVE_EVENTPORT 1 - -#define ushort_t u_short -#define uint_t u_int - -/* Solaris eventport declarations */ - -#define PORT_SOURCE_AIO 1 -#define PORT_SOURCE_TIMER 2 -#define PORT_SOURCE_USER 3 -#define PORT_SOURCE_FD 4 -#define PORT_SOURCE_ALERT 5 -#define PORT_SOURCE_MQ 6 -#define PORT_SOURCE_FILE 7 - -#ifndef ETIME -#define ETIME 62 -#endif - - -typedef struct { - int portev_events; /* event data is source specific */ - ushort_t portev_source; /* event source */ - ushort_t portev_pad; /* port internal use */ - uintptr_t portev_object; /* source specific object */ - void *portev_user; /* user cookie */ -} port_event_t; - - -typedef struct timespec timespec_t; -typedef struct timespec timestruc_t; - - -typedef struct file_obj { - timestruc_t fo_atime; /* Access time from stat(2) */ - timestruc_t fo_mtime; /* Modification time from stat(2) */ - timestruc_t fo_ctime; /* Change time from stat(2) */ - uintptr_t fo_pad[3]; /* For future expansion */ - char *fo_name; /* Null terminated file name */ -} file_obj_t; - - -int port_create(void); -int port_associate(int port, int source, uintptr_t object, int events, - void *user); -int port_dissociate(int port, int source, uintptr_t object); -int port_send(int port, int events, void *user); -int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget, - const timespec_t *timeout); - -#endif - - -#if (NXT_TEST_BUILD_DEVPOLL) - -#define NXT_HAVE_DEVPOLL 1 - -#include -#include - -/* Solaris /dev/poll declarations */ - -#define POLLREMOVE 0x0800 -#define DP_POLL 0xD001 -#define DP_ISPOLLED 0xD002 - - -struct dvpoll { - struct pollfd *dp_fds; - int dp_nfds; - int dp_timeout; -}; - -#endif - - -#if (NXT_TEST_BUILD_POLLSET) - -#define NXT_HAVE_POLLSET 1 - -#include - -/* AIX pollset declarations */ - -#define PS_ADD 0x0 -#define PS_MOD 0x1 -#define PS_DELETE 0x2 - - -typedef int pollset_t; - -struct poll_ctl { - short cmd; - short events; - int fd; -}; - - -pollset_t pollset_create(int maxfd); -int pollset_destroy(pollset_t ps); -int pollset_query(pollset_t ps, struct pollfd *pollfd_query); -int pollset_ctl(pollset_t ps, struct poll_ctl *pollctl_array, int array_length); -int pollset_poll(pollset_t ps, struct pollfd *polldata_array, int array_length, - int timeout); - -#endif - - -#if (NXT_TEST_BUILD_FREEBSD_SENDFILE || NXT_TEST_BUILD_MACOSX_SENDFILE) - -#if !(NXT_FREEBSD) && !(NXT_MACOSX) - -struct sf_hdtr { - struct iovec *headers; - int hdr_cnt; - struct iovec *trailers; - int trl_cnt; -}; - -#endif - -#endif - - -#if (NXT_TEST_BUILD_SOLARIS_SENDFILEV) - -/* Solaris declarations */ - -typedef struct sendfilevec { - int sfv_fd; - u_int sfv_flag; - off_t sfv_off; - size_t sfv_len; -} sendfilevec_t; - -#define SFV_FD_SELF -2 - -ssize_t sendfilev(int fd, const struct sendfilevec *vec, int sfvcnt, - size_t *xferred); - -#endif - - -#if (NXT_TEST_BUILD_AIX_SEND_FILE) - -#ifndef uint_t -#define uint_t u_int -#endif - -struct sf_parms { - void *header_data; - uint_t header_length; - - int file_descriptor; - uint64_t file_size; - uint64_t file_offset; - int64_t file_bytes; - - void *trailer_data; - uint_t trailer_length; - - uint64_t bytes_sent; -}; - -#define SF_CLOSE 0x00000001 /* close the socket after completion */ -#define SF_REUSE 0x00000002 /* reuse socket. not supported */ -#define SF_DONT_CACHE 0x00000004 /* don't apply network buffer cache */ -#define SF_SYNC_CACHE 0x00000008 /* sync/update network buffer cache */ - -ssize_t send_file(int *s, struct sf_parms *sf_iobuf, uint_t flags); - -#endif - - -#endif /* _NXT_UNIX_TEST_BUILD_H_INCLUDED_ */ diff --git a/src/nxt_thread.c b/src/nxt_thread.c deleted file mode 100644 index f3804719..00000000 --- a/src/nxt_thread.c +++ /dev/null @@ -1,267 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static void *nxt_thread_trampoline(void *data); -static void nxt_thread_time_cleanup(void *data); - - -#if (NXT_HAVE_PTHREAD_SPECIFIC_DATA) - -static void nxt_thread_key_dtor(void *data); - - -void -nxt_thread_init_data(nxt_thread_specific_data_t tsd) -{ - void *p; - nxt_err_t err; - pthread_key_t key; - - while ((nxt_atomic_int_t) tsd->key < 0) { - /* - * Atomic allocation of a key number. - * -1 means an uninitialized key, - * -2 is the initializing lock to assure the single value for the key. - */ - if (nxt_atomic_cmp_set(&tsd->key, -1, -2)) { - - err = pthread_key_create(&key, nxt_thread_key_dtor); - if (err != 0) { - nxt_main_log_alert("pthread_key_create() failed %E", err); - goto fail; - } - - tsd->key = (nxt_atomic_t) key; - - nxt_main_log_debug("pthread_key_create(): %A", tsd->key); - } - } - - if (pthread_getspecific((pthread_key_t) tsd->key) != NULL) { - return; - } - - p = nxt_zalloc(tsd->size); - if (p == NULL) { - goto fail; - } - - err = pthread_setspecific((pthread_key_t) tsd->key, p); - if (err == 0) { - return; - } - - nxt_main_log_alert("pthread_setspecific(%A) failed %E", tsd->key, err); - -fail: - - pthread_exit(NULL); - nxt_unreachable(); -} - - -static void -nxt_thread_key_dtor(void *data) -{ - nxt_main_log_debug("pthread key dtor: %p", data); - - nxt_free(data); -} - -#endif - - -nxt_int_t -nxt_thread_create(nxt_thread_handle_t *handle, nxt_thread_link_t *link) -{ - nxt_err_t err; - - err = pthread_create(handle, NULL, nxt_thread_trampoline, link); - - if (nxt_fast_path(err == 0)) { - nxt_thread_log_debug("pthread_create(): %PH", *handle); - - return NXT_OK; - } - - nxt_thread_log_alert("pthread_create() failed %E", err); - - nxt_free(link); - - return NXT_ERROR; -} - - -static void * -nxt_thread_trampoline(void *data) -{ - nxt_thread_t *thr; - nxt_thread_link_t *link; - nxt_thread_start_t start; - - link = data; - - thr = nxt_thread_init(); - - nxt_log_debug(thr->log, "thread trampoline: %PH", thr->handle); - - pthread_cleanup_push(nxt_thread_time_cleanup, thr); - - start = link->start; - data = link->work.data; - - if (link->work.handler != NULL) { - thr->link = link; - - } else { - nxt_free(link); - } - - start(data); - - /* - * nxt_thread_time_cleanup() should be called only if a thread - * would be canceled, so ignore it here because nxt_thread_exit() - * calls nxt_thread_time_free() as well. - */ - pthread_cleanup_pop(0); - - nxt_thread_exit(thr); - nxt_unreachable(); - return NULL; -} - - -nxt_thread_t * -nxt_thread_init(void) -{ - nxt_thread_t *thr; - - nxt_thread_init_data(nxt_thread_context); - - thr = nxt_thread(); - - if (thr->log == NULL) { - thr->log = &nxt_main_log; - thr->handle = nxt_thread_handle(); - - /* - * Threads are never preempted by asynchronous signals, since - * the signals are processed synchronously by dedicated thread. - */ - thr->time.signal = -1; - - nxt_thread_time_update(thr); - } - - nxt_random_init(&thr->random); - - return thr; -} - - -static void -nxt_thread_time_cleanup(void *data) -{ - nxt_thread_t *thr; - - thr = data; - - nxt_log_debug(thr->log, "thread time cleanup"); - - nxt_thread_time_free(thr); -} - - -void -nxt_thread_exit(nxt_thread_t *thr) -{ - nxt_thread_link_t *link; - nxt_event_engine_t *engine; - - nxt_log_debug(thr->log, "thread exit"); - - link = thr->link; - thr->link = NULL; - - if (link != NULL) { - /* - * link->work.handler is already set to an exit handler, - * and link->work.task is already set to the correct engine->task. - * The link should be freed by the exit handler. - */ - link->work.obj = (void *) (uintptr_t) thr->handle; - engine = nxt_container_of(link->work.task, nxt_event_engine_t, task); - - nxt_event_engine_post(engine, &link->work); - } - - nxt_thread_time_free(thr); - - pthread_exit(NULL); - nxt_unreachable(); -} - - -void -nxt_thread_cancel(nxt_thread_handle_t handle) -{ - nxt_err_t err; - - nxt_thread_log_debug("thread cancel: %PH", handle); - - err = pthread_cancel(handle); - - if (err != 0) { - nxt_main_log_alert("pthread_cancel(%PH) failed %E", handle, err); - } -} - - -void -nxt_thread_wait(nxt_thread_handle_t handle) -{ - nxt_err_t err; - - nxt_thread_log_debug("thread wait: %PH", handle); - - err = pthread_join(handle, NULL); - - if (err != 0) { - nxt_main_log_alert("pthread_join(%PH) failed %E", handle, err); - } -} - - -nxt_tid_t -nxt_thread_tid(nxt_thread_t *thr) -{ -#if (NXT_HAVE_THREAD_STORAGE_CLASS) - - if (nxt_slow_path(thr->tid == 0)) { - thr->tid = nxt_thread_get_tid(); - } - - return thr->tid; - -#else - - if (nxt_fast_path(thr != NULL)) { - - if (nxt_slow_path(thr->tid == 0)) { - thr->tid = nxt_thread_get_tid(); - } - - return thr->tid; - } - - return nxt_thread_get_tid(); - -#endif -} diff --git a/src/nxt_thread.h b/src/nxt_thread.h deleted file mode 100644 index 53b2d8c0..00000000 --- a/src/nxt_thread.h +++ /dev/null @@ -1,163 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_THREAD_H_INCLUDED_ -#define _NXT_UNIX_THREAD_H_INCLUDED_ - - -/* - * Thread Specific Data - * - * The interface unifies two TSD implementations: the __thread storage - * class and pthread specific data. It works also in non-threaded mode. - * The interface is optimized for the __thread storage class and non-threaded - * mode, since the __thread storage is faster and is supported in modern - * versions of Linux, FreeBSD, Solaris, and MacOSX. Pthread specific data - * is considered as a fallback option. - * - * The underlining interfaces are different: pthread data must be allocated - * by hand and may be accessed only by using pointers whereas __thread data - * allocation is transparent and it is accessed directly. - * - * pthread_getspecific() is usually faster than pthread_setspecific() - * (much faster on MacOSX), so there is no nxt_thread_set_data() interface - * for this reason. It is better to store frequently alterable thread - * log pointer in nxt_thread_t, but not in a dedicated key. - */ - -#if (NXT_HAVE_THREAD_STORAGE_CLASS) - -#define nxt_thread_extern_data(type, tsd) \ - NXT_EXPORT extern __thread type tsd - -#define nxt_thread_declare_data(type, tsd) \ - __thread type tsd - -#define nxt_thread_init_data(tsd) - -#define nxt_thread_get_data(tsd) \ - &tsd - - -#else /* NXT_HAVE_PTHREAD_SPECIFIC_DATA */ - -/* - * nxt_thread_get_data() is used as - * p = nxt_thread_get_data(tsd), - * but the tsd address is actually required. This could be resolved by macro - * #define nxt_thread_get_data(tsd) nxt_thread_get_data_addr(&tsd) - * or by definition nxt_thread_specific_data_t as an array. - * - * On Linux and Solaris pthread_key_t is unsigned integer. - * On FreeBSD, NetBSD, OpenBSD, and HP-UX pthread_key_t is integer. - * On MacOSX and AIX pthread_key_t is unsigned long integer. - * On Cygwin pthread_key_t is pointer to void. - */ - -typedef struct { - nxt_atomic_t key; - size_t size; -} nxt_thread_specific_data_t[1]; - - -#define nxt_thread_extern_data(type, tsd) \ - NXT_EXPORT extern nxt_thread_specific_data_t tsd - -#define nxt_thread_declare_data(type, tsd) \ - nxt_thread_specific_data_t tsd = { { (nxt_atomic_int_t) -1, sizeof(type) } } - -NXT_EXPORT void nxt_thread_init_data(nxt_thread_specific_data_t tsd); - -#define nxt_thread_get_data(tsd) \ - pthread_getspecific((pthread_key_t) tsd->key) - -#endif - - -typedef void (*nxt_thread_start_t)(void *data); - -typedef struct { - nxt_thread_start_t start; - nxt_event_engine_t *engine; - nxt_work_t work; -} nxt_thread_link_t; - - -NXT_EXPORT nxt_int_t nxt_thread_create(nxt_thread_handle_t *handle, - nxt_thread_link_t *link); -NXT_EXPORT nxt_thread_t *nxt_thread_init(void); -NXT_EXPORT void nxt_thread_exit(nxt_thread_t *thr); -NXT_EXPORT void nxt_thread_cancel(nxt_thread_handle_t handle); -NXT_EXPORT void nxt_thread_wait(nxt_thread_handle_t handle); - - -#define nxt_thread_handle() \ - pthread_self() - - -typedef pthread_mutex_t nxt_thread_mutex_t; - -NXT_EXPORT nxt_int_t nxt_thread_mutex_create(nxt_thread_mutex_t *mtx); -NXT_EXPORT void nxt_thread_mutex_destroy(nxt_thread_mutex_t *mtx); -NXT_EXPORT nxt_int_t nxt_thread_mutex_lock(nxt_thread_mutex_t *mtx); -NXT_EXPORT nxt_bool_t nxt_thread_mutex_trylock(nxt_thread_mutex_t *mtx); -NXT_EXPORT nxt_int_t nxt_thread_mutex_unlock(nxt_thread_mutex_t *mtx); - - -typedef pthread_cond_t nxt_thread_cond_t; - -NXT_EXPORT nxt_int_t nxt_thread_cond_create(nxt_thread_cond_t *cond); -NXT_EXPORT void nxt_thread_cond_destroy(nxt_thread_cond_t *cond); -NXT_EXPORT nxt_int_t nxt_thread_cond_signal(nxt_thread_cond_t *cond); -NXT_EXPORT nxt_err_t nxt_thread_cond_wait(nxt_thread_cond_t *cond, - nxt_thread_mutex_t *mtx, nxt_nsec_t timeout); - - -#if (NXT_HAVE_PTHREAD_YIELD) -#define nxt_thread_yield() \ - pthread_yield() - -#elif (NXT_HAVE_PTHREAD_YIELD_NP) -#define nxt_thread_yield() \ - pthread_yield_np() - -#else -#define nxt_thread_yield() \ - nxt_sched_yield() - -#endif - - -struct nxt_thread_s { - nxt_log_t *log; - nxt_log_t main_log; - - nxt_task_t *task; - - nxt_tid_t tid; - nxt_thread_handle_t handle; - nxt_thread_link_t *link; - nxt_thread_pool_t *thread_pool; - - nxt_thread_time_t time; - - nxt_runtime_t *runtime; - nxt_event_engine_t *engine; - void *data; - -#if 0 - /* - * Although pointer to a current fiber should be a property of - * engine->fibers, its placement here eliminates 2 memory accesses. - */ - nxt_fiber_t *fiber; -#endif - - nxt_random_t random; -}; - - -#endif /* _NXT_UNIX_THREAD_H_INCLUDED_ */ diff --git a/src/nxt_thread_cond.c b/src/nxt_thread_cond.c deleted file mode 100644 index fcd108e4..00000000 --- a/src/nxt_thread_cond.c +++ /dev/null @@ -1,107 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_int_t -nxt_thread_cond_create(nxt_thread_cond_t *cond) -{ - nxt_err_t err; - - err = pthread_cond_init(cond, NULL); - if (err == 0) { - nxt_thread_log_debug("pthread_cond_init(%p)", cond); - return NXT_OK; - } - - nxt_thread_log_alert("pthread_cond_init() failed %E", err); - return NXT_ERROR; -} - - -void -nxt_thread_cond_destroy(nxt_thread_cond_t *cond) -{ - nxt_err_t err; - - err = pthread_cond_destroy(cond); - if (err != 0) { - nxt_thread_log_alert("pthread_cond_destroy() failed %E", err); - } - - nxt_thread_log_debug("pthread_cond_destroy(%p)", cond); -} - - -nxt_int_t -nxt_thread_cond_signal(nxt_thread_cond_t *cond) -{ - nxt_err_t err; - - err = pthread_cond_signal(cond); - if (nxt_fast_path(err == 0)) { - nxt_thread_log_debug("pthread_cond_signal(%p)", cond); - return NXT_OK; - } - - nxt_thread_log_alert("pthread_cond_signal() failed %E", err); - - return NXT_ERROR; -} - - -nxt_err_t -nxt_thread_cond_wait(nxt_thread_cond_t *cond, nxt_thread_mutex_t *mtx, - nxt_nsec_t timeout) -{ - nxt_err_t err; - nxt_nsec_t ns; - nxt_thread_t *thr; - nxt_realtime_t *now; - struct timespec ts; - - thr = nxt_thread(); - - if (timeout == NXT_INFINITE_NSEC) { - nxt_log_debug(thr->log, "pthread_cond_wait(%p) enter", cond); - - err = pthread_cond_wait(cond, mtx); - - nxt_thread_time_update(thr); - - if (nxt_fast_path(err == 0)) { - nxt_log_debug(thr->log, "pthread_cond_wait(%p) exit", cond); - return 0; - } - - nxt_log_alert(thr->log, "pthread_cond_wait() failed %E", err); - - } else { - nxt_log_debug(thr->log, "pthread_cond_timedwait(%p, %N) enter", - cond, timeout); - - now = nxt_thread_realtime(thr); - - ns = now->nsec + timeout; - ts.tv_sec = now->sec + ns / 1000000000; - ts.tv_nsec = ns % 1000000000; - - err = pthread_cond_timedwait(cond, mtx, &ts); - - nxt_thread_time_update(thr); - - if (nxt_fast_path(err == 0 || err == NXT_ETIMEDOUT)) { - nxt_log_debug(thr->log, "pthread_cond_timedwait(%p) exit: %d", - cond, err); - return err; - } - - nxt_log_alert(thr->log, "pthread_cond_timedwait() failed %E", err); - } - - return NXT_ERROR; -} diff --git a/src/nxt_thread_id.h b/src/nxt_thread_id.h deleted file mode 100644 index 764c9934..00000000 --- a/src/nxt_thread_id.h +++ /dev/null @@ -1,189 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_THREAD_ID_H_INCLUDED_ -#define _NXT_UNIX_THREAD_ID_H_INCLUDED_ - - -#if (NXT_LINUX) - -/* - * Linux thread id is a pid of thread created by clone(2), - * glibc does not provide a wrapper for gettid(). - */ - -typedef pid_t nxt_tid_t; - -nxt_inline nxt_tid_t -nxt_thread_get_tid(void) -{ - return syscall(SYS_gettid); -} - -#elif (NXT_FREEBSD) - -/* - * FreeBSD 9.0 provides pthread_getthreadid_np(), here is its - * emulation. Kernel thread id is the first field of struct pthread. - * Although kernel exports a thread id as long type, lwpid_t is 32bit. - * Thread id is a number above 100,000. - */ - -typedef uint32_t nxt_tid_t; - -nxt_inline nxt_tid_t -nxt_thread_get_tid(void) -{ - return (uint32_t) (*(long *) pthread_self()); -} - -#elif (NXT_SOLARIS) - -/* Solaris pthread_t are numbers starting with 1. */ - -typedef pthread_t nxt_tid_t; - -nxt_inline nxt_tid_t -nxt_thread_get_tid(void) -{ - return pthread_self(); -} - -#elif (NXT_MACOSX) - -/* - * MacOSX thread has two thread ids: - * - * 1) MacOSX 10.6 (Snow Leoprad) has pthread_threadid_np() returning - * an uint64_t value, which is obtained using the __thread_selfid() - * syscall. It is a number above 300,000. - */ - -typedef uint64_t nxt_tid_t; - -nxt_inline nxt_tid_t -nxt_thread_get_tid(void) -{ - uint64_t tid; - - (void) pthread_threadid_np(NULL, &tid); - return tid; -} - -/* - * 2) Kernel thread mach_port_t returned by pthread_mach_thread_np(). - * It is a number in range 100-100,000. - * - * return pthread_mach_thread_np(pthread_self()); - */ - -#elif (NXT_OPENBSD) - -typedef pid_t nxt_tid_t; - -/* OpenBSD 3.9 getthrid(). */ - -nxt_inline nxt_tid_t -nxt_thread_get_tid(void) -{ - return getthrid(); -} - -#elif (NXT_AIX) - -/* - * pthread_self() in main thread returns 1. - * pthread_self() in other threads returns 258, 515, etc. - * - * pthread_getthrds_np(PTHRDSINFO_QUERY_TID) returns kernel tid - * shown in "ps -ef -m -o THREAD" output. - */ - -typedef tid_t nxt_tid_t; - -nxt_inline nxt_tid_t -nxt_thread_get_tid(void) -{ - int err, size; - pthread_t pt; - struct __pthrdsinfo ti; - - size = 0; - pt = pthread_self(); - - err = pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_TID, &ti, - sizeof(struct __pthrdsinfo), NULL, size); - - if (nxt_fast_path(err == 0)) { - return ti.__pi_tid; - } - - nxt_main_log_alert("pthread_getthrds_np(PTHRDSINFO_QUERY_TID) failed %E", - err); - return 0; -} - -/* - * AIX pthread_getunique_np() returns thread unique number starting with 1. - * OS/400 and i5/OS have pthread_getthreadid_np(), but AIX lacks their - * counterpart. - * - * - * int tid; - * pthread_t pt; - * - * pt = pthread_self(); - * pthread_getunique_np(&pt, &tid); - * return tid; - */ - -#elif (NXT_HPUX) - -/* HP-UX pthread_t are numbers starting with 1. */ - -typedef pthread_t nxt_tid_t; - -nxt_inline nxt_tid_t -nxt_thread_get_tid(void) -{ - return pthread_self(); -} - -#else - -typedef pthread_t nxt_tid_t; - -nxt_inline nxt_tid_t -nxt_thread_get_tid(void) -{ - return pthread_self(); -} - -#endif - - -NXT_EXPORT nxt_tid_t nxt_thread_tid(nxt_thread_t *thr); - - -/* - * On Linux pthread_t is unsigned long integer. - * On FreeBSD, MacOSX, NetBSD, and OpenBSD pthread_t is pointer to a struct. - * On Solaris and AIX pthread_t is unsigned integer. - * On HP-UX pthread_t is int. - * On Cygwin pthread_t is pointer to void. - * On z/OS pthread_t is "struct { char __[0x08]; }". - */ -typedef pthread_t nxt_thread_handle_t; - - -#define nxt_thread_handle_clear(th) \ - th = (pthread_t) 0 - -#define nxt_thread_handle_equal(th0, th1) \ - pthread_equal(th0, th1) - - -#endif /* _NXT_UNIX_THREAD_ID_H_INCLUDED_ */ diff --git a/src/nxt_thread_log.h b/src/nxt_thread_log.h deleted file mode 100644 index 214098ff..00000000 --- a/src/nxt_thread_log.h +++ /dev/null @@ -1,61 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_THREAD_LOG_H_INCLUDED_ -#define _NXT_THREAD_LOG_H_INCLUDED_ - - -#define nxt_thread_log_alert(...) \ - do { \ - nxt_thread_t *_thr = nxt_thread(); \ - \ - nxt_log_alert(_thr->log, __VA_ARGS__); \ - \ - } while (0) - - -#define nxt_thread_log_error(_level, ...) \ - do { \ - nxt_thread_t *_thr = nxt_thread(); \ - \ - nxt_log_error(_level, _thr->log, __VA_ARGS__); \ - \ - } while (0) - - -#if (NXT_DEBUG) - -#define nxt_thread_log_debug(...) \ - do { \ - nxt_thread_t *_thr = nxt_thread(); \ - \ - nxt_log_debug(_thr->log, __VA_ARGS__); \ - \ - } while (0) - - -#define nxt_thread_debug(thr) \ - nxt_thread_t *thr = nxt_thread() - -#else - -#define nxt_thread_log_debug(...) -#define nxt_thread_debug(thr) - -#endif - - -nxt_inline nxt_log_t * -nxt_thread_log(void) -{ - nxt_thread_t *thr; - - thr = nxt_thread(); - return thr->log; -} - - -#endif /* _NXT_THREAD_LOG_H_INCLUDED_ */ diff --git a/src/nxt_thread_mutex.c b/src/nxt_thread_mutex.c deleted file mode 100644 index 472a69f0..00000000 --- a/src/nxt_thread_mutex.c +++ /dev/null @@ -1,192 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * All modern pthread mutex implementations try to acquire a lock atomically - * in userland before going to sleep in kernel. Some spins on SMP systems - * before the sleeping. - * - * In Solaris since version 8 all mutex types spin before sleeping. - * The default spin count is 1000. It can be overridden using - * _THREAD_ADAPTIVE_SPIN=100 environment variable. - * - * In MacOSX all mutex types spin to acquire a lock protecting a mutex's - * internals. If the mutex is busy, thread calls Mach semaphore_wait(). - * - * - * PTHREAD_MUTEX_NORMAL lacks deadlock detection and is the fastest - * mutex type. - * - * Linux: No spinning. The internal name PTHREAD_MUTEX_TIMED_NP - * remains from the times when pthread_mutex_timedlock() was - * non-standard extension. Alias name: PTHREAD_MUTEX_FAST_NP. - * FreeBSD: No spinning. - * - * - * PTHREAD_MUTEX_ERRORCHECK is usually as fast as PTHREAD_MUTEX_NORMAL - * yet has lightweight deadlock detection. - * - * Linux: No spinning. The internal name: PTHREAD_MUTEX_ERRORCHECK_NP. - * FreeBSD: No spinning. - * - * - * PTHREAD_MUTEX_RECURSIVE allows recursive locking. - * - * Linux: No spinning. The internal name: PTHREAD_MUTEX_RECURSIVE_NP. - * FreeBSD: No spinning. - * - * - * PTHREAD_MUTEX_ADAPTIVE_NP spins on SMP systems before sleeping. - * - * Linux: No deadlock detection. Dynamically changes a spin count - * for each mutex from 10 to 100 based on spin count taken - * previously. - * - * FreeBSD: Deadlock detection. The default spin count is 2000. - * It can be overriden using LIBPTHREAD_SPINLOOPS environment - * variable or by pthread_mutex_setspinloops_np(). If a lock - * is still busy, sched_yield() can be called on both UP and - * SMP systems. The default yield loop count is zero, but it - * can be set by LIBPTHREAD_YIELDLOOPS environment variable or - * by pthread_mutex_setyieldloops_np(). sched_yield() moves - * a thread to the end of CPU scheduler run queue and this is - * cheaper than removing the thread from the queue and sleeping. - * - * Solaris: No PTHREAD_MUTEX_ADAPTIVE_NP . - * MacOSX: No PTHREAD_MUTEX_ADAPTIVE_NP. - * - * - * PTHREAD_MUTEX_ELISION_NP is a Linux extension to elide locks using - * Intel Restricted Transactional Memory. It is the most suitable for - * rwlock pattern access because it allows simultaneous reads without lock. - * Supported since glibc 2.18. - * - * - * PTHREAD_MUTEX_DEFAULT is default mutex type. - * - * Linux: PTHREAD_MUTEX_NORMAL. - * FreeBSD: PTHREAD_MUTEX_ERRORCHECK. - * Solaris: PTHREAD_MUTEX_NORMAL. - * MacOSX: PTHREAD_MUTEX_NORMAL. - */ - - -nxt_int_t -nxt_thread_mutex_create(nxt_thread_mutex_t *mtx) -{ - nxt_err_t err; - pthread_mutexattr_t attr; - - err = pthread_mutexattr_init(&attr); - if (err != 0) { - nxt_thread_log_alert("pthread_mutexattr_init() failed %E", err); - return NXT_ERROR; - } - - err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); - if (err != 0) { - nxt_thread_log_alert("pthread_mutexattr_settype" - "(PTHREAD_MUTEX_ERRORCHECK) failed %E", err); - return NXT_ERROR; - } - - err = pthread_mutex_init(mtx, &attr); - if (err != 0) { - nxt_thread_log_alert("pthread_mutex_init() failed %E", err); - return NXT_ERROR; - } - - err = pthread_mutexattr_destroy(&attr); - if (err != 0) { - nxt_thread_log_alert("pthread_mutexattr_destroy() failed %E", err); - } - - nxt_thread_log_debug("pthread_mutex_init(%p)", mtx); - - return NXT_OK; -} - - -void -nxt_thread_mutex_destroy(nxt_thread_mutex_t *mtx) -{ - nxt_err_t err; - - err = pthread_mutex_destroy(mtx); - if (nxt_slow_path(err != 0)) { - nxt_thread_log_alert("pthread_mutex_destroy() failed %E", err); - } - - nxt_thread_log_debug("pthread_mutex_destroy(%p)", mtx); -} - - -nxt_int_t -nxt_thread_mutex_lock(nxt_thread_mutex_t *mtx) -{ - nxt_err_t err; - - nxt_thread_log_debug("pthread_mutex_lock(%p) enter", mtx); - - err = pthread_mutex_lock(mtx); - if (nxt_fast_path(err == 0)) { - return NXT_OK; - } - - nxt_thread_log_alert("pthread_mutex_lock() failed %E", err); - - return NXT_ERROR; -} - - -nxt_bool_t -nxt_thread_mutex_trylock(nxt_thread_mutex_t *mtx) -{ - nxt_err_t err; - - nxt_thread_debug(thr); - - nxt_log_debug(thr->log, "pthread_mutex_trylock(%p) enter", mtx); - - err = pthread_mutex_trylock(mtx); - if (nxt_fast_path(err == 0)) { - return 1; - } - - if (err == NXT_EBUSY) { - nxt_log_debug(thr->log, "pthread_mutex_trylock(%p) failed", mtx); - - } else { - nxt_thread_log_alert("pthread_mutex_trylock() failed %E", err); - } - - return 0; -} - - -nxt_int_t -nxt_thread_mutex_unlock(nxt_thread_mutex_t *mtx) -{ - nxt_err_t err; - nxt_thread_t *thr; - - err = pthread_mutex_unlock(mtx); - - thr = nxt_thread(); - nxt_thread_time_update(thr); - - if (nxt_fast_path(err == 0)) { - nxt_log_debug(thr->log, "pthread_mutex_unlock(%p) exit", mtx); - return NXT_OK; - } - - nxt_log_alert(thr->log, "pthread_mutex_unlock() failed %E", err); - - return NXT_ERROR; -} diff --git a/src/nxt_thread_pool.c b/src/nxt_thread_pool.c deleted file mode 100644 index 0be2ddc0..00000000 --- a/src/nxt_thread_pool.c +++ /dev/null @@ -1,310 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -static nxt_int_t nxt_thread_pool_init(nxt_thread_pool_t *tp); -static void nxt_thread_pool_exit(nxt_task_t *task, void *obj, void *data); -static void nxt_thread_pool_start(void *ctx); -static void nxt_thread_pool_loop(void *ctx); -static void nxt_thread_pool_wait(nxt_thread_pool_t *tp); - - -nxt_thread_pool_t * -nxt_thread_pool_create(nxt_uint_t max_threads, nxt_nsec_t timeout, - nxt_thread_pool_init_t init, nxt_event_engine_t *engine, - nxt_work_handler_t exit) -{ - nxt_thread_pool_t *tp; - - tp = nxt_zalloc(sizeof(nxt_thread_pool_t)); - if (tp == NULL) { - return NULL; - } - - tp->max_threads = max_threads; - tp->timeout = timeout; - tp->engine = engine; - tp->task.thread = engine->task.thread; - tp->task.log = engine->task.log; - tp->init = init; - tp->exit = exit; - - return tp; -} - - -nxt_int_t -nxt_thread_pool_post(nxt_thread_pool_t *tp, nxt_work_t *work) -{ - nxt_thread_log_debug("thread pool post"); - - if (nxt_slow_path(nxt_thread_pool_init(tp) != NXT_OK)) { - return NXT_ERROR; - } - - nxt_locked_work_queue_add(&tp->work_queue, work); - - (void) nxt_sem_post(&tp->sem); - - return NXT_OK; -} - - -static nxt_int_t -nxt_thread_pool_init(nxt_thread_pool_t *tp) -{ - nxt_int_t ret; - nxt_thread_link_t *link; - nxt_thread_handle_t handle; - - if (nxt_fast_path(tp->ready)) { - return NXT_OK; - } - - if (tp->max_threads == 0) { - /* The pool is being destroyed. */ - return NXT_ERROR; - } - - nxt_thread_spin_lock(&tp->work_queue.lock); - - ret = NXT_OK; - - if (!tp->ready) { - - nxt_thread_log_debug("thread pool init"); - - (void) nxt_atomic_fetch_add(&tp->threads, 1); - - if (nxt_fast_path(nxt_sem_init(&tp->sem, 0) == NXT_OK)) { - - link = nxt_zalloc(sizeof(nxt_thread_link_t)); - - if (nxt_fast_path(link != NULL)) { - link->start = nxt_thread_pool_start; - link->work.data = tp; - - if (nxt_thread_create(&handle, link) == NXT_OK) { - tp->ready = 1; - goto done; - } - } - - nxt_sem_destroy(&tp->sem); - } - - (void) nxt_atomic_fetch_add(&tp->threads, -1); - - ret = NXT_ERROR; - } - -done: - - nxt_thread_spin_unlock(&tp->work_queue.lock); - - return ret; -} - - -static void -nxt_thread_pool_start(void *ctx) -{ - nxt_thread_t *thr; - nxt_thread_pool_t *tp; - - tp = ctx; - thr = nxt_thread(); - - tp->main = thr->handle; - tp->task.thread = thr; - - nxt_thread_pool_loop(ctx); -} - - -static void -nxt_thread_pool_loop(void *ctx) -{ - void *obj, *data; - nxt_task_t *task; - nxt_thread_t *thr; - nxt_thread_pool_t *tp; - nxt_work_handler_t handler; - - tp = ctx; - thr = nxt_thread(); - - if (tp->init != NULL) { - tp->init(); - } - - for ( ;; ) { - nxt_thread_pool_wait(tp); - - handler = nxt_locked_work_queue_pop(&tp->work_queue, &task, &obj, - &data); - - if (nxt_fast_path(handler != NULL)) { - task->thread = thr; - - nxt_log_debug(thr->log, "locked work queue"); - - handler(task, obj, data); - } - - thr->log = &nxt_main_log; - } -} - - -static void -nxt_thread_pool_wait(nxt_thread_pool_t *tp) -{ - nxt_err_t err; - nxt_thread_t *thr; - nxt_atomic_uint_t waiting, threads; - nxt_thread_link_t *link; - nxt_thread_handle_t handle; - - thr = nxt_thread(); - - nxt_log_debug(thr->log, "thread pool wait"); - - (void) nxt_atomic_fetch_add(&tp->waiting, 1); - - for ( ;; ) { - err = nxt_sem_wait(&tp->sem, tp->timeout); - - if (err == 0) { - waiting = nxt_atomic_fetch_add(&tp->waiting, -1); - break; - } - - if (err == NXT_ETIMEDOUT) { - if (nxt_thread_handle_equal(thr->handle, tp->main)) { - continue; - } - } - - (void) nxt_atomic_fetch_add(&tp->waiting, -1); - (void) nxt_atomic_fetch_add(&tp->threads, -1); - - nxt_thread_exit(thr); - nxt_unreachable(); - } - - nxt_log_debug(thr->log, "thread pool awake, waiting: %A", waiting); - - if (waiting > 1) { - return; - } - - do { - threads = tp->threads; - - if (threads >= tp->max_threads) { - return; - } - - } while (!nxt_atomic_cmp_set(&tp->threads, threads, threads + 1)); - - link = nxt_zalloc(sizeof(nxt_thread_link_t)); - - if (nxt_fast_path(link != NULL)) { - link->start = nxt_thread_pool_loop; - link->work.data = tp; - - if (nxt_thread_create(&handle, link) != NXT_OK) { - (void) nxt_atomic_fetch_add(&tp->threads, -1); - } - } -} - - -void -nxt_thread_pool_destroy(nxt_thread_pool_t *tp) -{ - nxt_thread_t *thr; - - thr = nxt_thread(); - - nxt_log_debug(thr->log, "thread pool destroy: %A", tp->ready); - - if (!tp->ready) { - nxt_work_queue_add(&thr->engine->fast_work_queue, tp->exit, - &tp->engine->task, tp, NULL); - return; - } - - if (tp->max_threads != 0) { - /* Disable new threads creation and mark a pool as being destroyed. */ - tp->max_threads = 0; - - nxt_work_set(&tp->work, nxt_thread_pool_exit, &tp->task, tp, NULL); - - nxt_thread_pool_post(tp, &tp->work); - } -} - - -/* - * A thread handle (pthread_t) is either pointer or integer, so it can be - * passed as work handler pointer "data" argument. To convert void pointer - * to pthread_t and vice versa the source argument should be cast first to - * uintptr_t type and then to the destination type. - * - * If the handle would be a struct it should be stored in thread pool and - * the thread pool must be freed in the thread pool exit procedure after - * the last thread of pool will exit. - */ - -static void -nxt_thread_pool_exit(nxt_task_t *task, void *obj, void *data) -{ - nxt_thread_t *thread; - nxt_thread_pool_t *tp; - nxt_atomic_uint_t threads; - nxt_thread_handle_t handle; - - tp = obj; - thread = task->thread; - - nxt_debug(task, "thread pool exit"); - - if (data != NULL) { - handle = (nxt_thread_handle_t) (uintptr_t) data; - nxt_thread_wait(handle); - } - - threads = nxt_atomic_fetch_add(&tp->threads, -1); - - nxt_debug(task, "thread pool threads: %A", threads); - - if (threads > 1) { - nxt_work_set(&tp->work, nxt_thread_pool_exit, &tp->task, tp, - (void *) (uintptr_t) thread->handle); - - nxt_thread_pool_post(tp, &tp->work); - - } else { - nxt_debug(task, "thread pool destroy"); - - nxt_sem_destroy(&tp->sem); - - nxt_work_set(&tp->work, tp->exit, &tp->engine->task, tp, - (void *) (uintptr_t) thread->handle); - - nxt_event_engine_post(tp->engine, &tp->work); - - /* The "tp" memory should be freed by tp->exit handler. */ - } - - nxt_thread_exit(thread); - - nxt_unreachable(); -} diff --git a/src/nxt_thread_pool.h b/src/nxt_thread_pool.h deleted file mode 100644 index 750b98f8..00000000 --- a/src/nxt_thread_pool.h +++ /dev/null @@ -1,44 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_THREAD_POOL_H_INCLUDED_ -#define _NXT_UNIX_THREAD_POOL_H_INCLUDED_ - - -typedef void (*nxt_thread_pool_init_t)(void); - - -struct nxt_thread_pool_s { - nxt_atomic_t ready; - nxt_atomic_t waiting; - nxt_atomic_t threads; - nxt_uint_t max_threads; - - nxt_sem_t sem; - nxt_nsec_t timeout; - - nxt_work_t work; - nxt_task_t task; - - nxt_locked_work_queue_t work_queue; - - nxt_thread_handle_t main; - - nxt_event_engine_t *engine; - nxt_thread_pool_init_t init; - nxt_work_handler_t exit; -}; - - -NXT_EXPORT nxt_thread_pool_t *nxt_thread_pool_create(nxt_uint_t max_threads, - nxt_nsec_t timeout, nxt_thread_pool_init_t init, - nxt_event_engine_t *engine, nxt_work_handler_t exit); -NXT_EXPORT void nxt_thread_pool_destroy(nxt_thread_pool_t *tp); -NXT_EXPORT nxt_int_t nxt_thread_pool_post(nxt_thread_pool_t *tp, - nxt_work_t *work); - - -#endif /* _NXT_UNIX_THREAD_POOL_H_INCLUDED_ */ diff --git a/src/nxt_thread_time.c b/src/nxt_thread_time.c deleted file mode 100644 index d084af0a..00000000 --- a/src/nxt_thread_time.c +++ /dev/null @@ -1,432 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * Each thread keeps several time representations in its thread local - * storage: - * the monotonic time in nanoseconds since unspecified point in the past, - * the real time in seconds and nanoseconds since the Epoch, - * the local time and GMT time structs, - * and various user-defined text representations of local and GMT times. - * - * The monotonic time is used mainly by engine timers and is updated after - * a kernel operation which can block for unpredictable duration like event - * polling. Besides getting the monotonic time is generally faster than - * getting the real time, so the monotonic time is also used for milestones - * to update cached real time seconds and, if debug log enabled, milliseconds. - * As a result, the cached real time is updated at most one time per second - * or millisecond respectively. If there is a signal event support or in - * multi-threaded mode, then the cached real time and local time structs - * are updated only on demand. In single-threaded mode without the signal - * event support the cached real and local time are updated synchronously - * with the monotonic time update. GMT time structs and text representations - * are always updated only on demand. - */ - - -static void nxt_time_thread(void *data); -static void nxt_thread_time_shared(nxt_monotonic_time_t *now); -static void nxt_thread_realtime_update(nxt_thread_t *thr, - nxt_monotonic_time_t *now); -static u_char *nxt_thread_time_string_no_cache(nxt_thread_t *thr, - nxt_time_string_t *ts, u_char *buf); -static nxt_atomic_uint_t nxt_thread_time_string_slot(nxt_time_string_t *ts); -static nxt_time_string_cache_t *nxt_thread_time_string_cache(nxt_thread_t *thr, - nxt_atomic_uint_t slot); - - -static nxt_atomic_int_t nxt_gmtoff; -static nxt_bool_t nxt_use_shared_time = 0; -static volatile nxt_monotonic_time_t nxt_shared_time; - - -void -nxt_thread_time_update(nxt_thread_t *thr) -{ - if (nxt_use_shared_time) { - nxt_thread_time_shared(&thr->time.now); - - } else { - nxt_monotonic_time(&thr->time.now); - } -} - - -void -nxt_thread_time_free(nxt_thread_t *thr) -{ - nxt_uint_t i; - nxt_time_string_cache_t *tsc; - - tsc = thr->time.strings; - - if (tsc) { - thr->time.no_cache = 1; - - for (i = 0; i < thr->time.nstrings; i++) { - nxt_free(tsc[i].string.start); - } - - nxt_free(tsc); - thr->time.strings = NULL; - } -} - - -void -nxt_time_thread_start(nxt_msec_t interval) -{ - nxt_thread_link_t *link; - nxt_thread_handle_t handle; - - link = nxt_zalloc(sizeof(nxt_thread_link_t)); - - if (nxt_fast_path(link != NULL)) { - link->start = nxt_time_thread; - link->work.data = (void *) (uintptr_t) interval; - - (void) nxt_thread_create(&handle, link); - } -} - - -static void -nxt_time_thread(void *data) -{ - nxt_nsec_t interval, rest; - nxt_thread_t *thr; - nxt_monotonic_time_t now; - - interval = (uintptr_t) data; - interval *= 1000000; - - thr = nxt_thread(); - /* - * The time thread is never preempted by asynchronous signals, since - * the signals are processed synchronously by dedicated thread. - */ - thr->time.signal = -1; - - nxt_log_debug(thr->log, "time thread"); - - nxt_memzero(&now, sizeof(nxt_monotonic_time_t)); - - nxt_monotonic_time(&now); - nxt_thread_realtime_update(thr, &now); - - nxt_shared_time = now; - nxt_use_shared_time = 1; - - for ( ;; ) { - rest = 1000000000 - now.realtime.nsec; - - nxt_nanosleep(nxt_min(interval, rest)); - - nxt_monotonic_time(&now); - nxt_thread_realtime_update(thr, &now); - - nxt_shared_time = now; - -#if 0 - thr->time.now = now; - nxt_log_debug(thr->log, "time thread"); -#endif - -#if 0 - if (nxt_exiting) { - nxt_use_shared_time = 0; - return; - } -#endif - } -} - - -static void -nxt_thread_time_shared(nxt_monotonic_time_t *now) -{ - nxt_uint_t n; - nxt_time_t t; - nxt_nsec_t m, u; - - /* Lock-free thread time update. */ - - for ( ;; ) { - *now = nxt_shared_time; - - t = nxt_shared_time.realtime.sec; - n = nxt_shared_time.realtime.nsec; - m = nxt_shared_time.monotonic; - u = nxt_shared_time.update; - - if (now->realtime.sec == t && now->realtime.nsec == n - && now->monotonic == m && now->update == u) - { - return; - } - } -} - - -nxt_time_t -nxt_thread_time(nxt_thread_t *thr) -{ - nxt_thread_realtime_update(thr, &thr->time.now); - - return thr->time.now.realtime.sec; -} - - -nxt_realtime_t * -nxt_thread_realtime(nxt_thread_t *thr) -{ - nxt_thread_realtime_update(thr, &thr->time.now); - - return &thr->time.now.realtime; -} - - -static void -nxt_thread_realtime_update(nxt_thread_t *thr, nxt_monotonic_time_t *now) -{ - nxt_nsec_t delta; - -#if (NXT_DEBUG) - - if (nxt_slow_path(thr->log->level == NXT_LOG_DEBUG || nxt_debug)) { - - if (now->monotonic >= now->update) { - nxt_realtime(&now->realtime); - - delta = 1000000 - now->realtime.nsec % 1000000; - now->update = now->monotonic + delta; - } - - return; - } - -#endif - - if (now->monotonic >= now->update) { - nxt_realtime(&now->realtime); - - delta = 1000000000 - now->realtime.nsec; - now->update = now->monotonic + delta; - } -} - - -u_char * -nxt_thread_time_string(nxt_thread_t *thr, nxt_time_string_t *ts, u_char *buf) -{ - u_char *p; - struct tm *tm; - nxt_time_t s; - nxt_bool_t update; - nxt_atomic_uint_t slot; - nxt_time_string_cache_t *tsc; - - if (nxt_slow_path(thr == NULL || thr->time.no_cache)) { - return nxt_thread_time_string_no_cache(thr, ts, buf); - } - - slot = nxt_thread_time_string_slot(ts); - - tsc = nxt_thread_time_string_cache(thr, slot); - if (tsc == NULL) { - return buf; - } - - if (thr->time.signal < 0) { - /* - * Lazy real time update: - * signal event support or multi-threaded mode. - */ - nxt_thread_realtime_update(thr, &thr->time.now); - } - - s = thr->time.now.realtime.sec; - - update = (s != tsc->last); - -#if (NXT_DEBUG) - - if (ts->msec == NXT_THREAD_TIME_MSEC - && (nxt_slow_path(thr->log->level == NXT_LOG_DEBUG || nxt_debug))) - { - nxt_msec_t ms; - - ms = thr->time.now.realtime.nsec / 1000000; - update |= (ms != tsc->last_msec); - tsc->last_msec = ms; - } - -#endif - - if (nxt_slow_path(update)) { - - if (ts->timezone == NXT_THREAD_TIME_LOCAL) { - - tm = &thr->time.localtime; - - if (nxt_slow_path(s != thr->time.last_localtime)) { - - if (thr->time.signal < 0) { - /* - * Lazy local time update: - * signal event support or multi-threaded mode. - */ - nxt_localtime(s, &thr->time.localtime); - thr->time.last_localtime = s; - - } else { - /* - * "thr->time.signal >= 0" means that a thread may be - * interrupted by a signal handler. Since localtime() - * cannot be safely called in a signal context, the - * thread's thr->time.localtime must be updated regularly - * by nxt_thread_time_update() in non-signal context. - * Stale timestamp means that nxt_thread_time_string() - * is being called in a signal context, so here is - * Async-Signal-Safe localtime() emulation using the - * latest cached GMT offset. - * - * The timestamp is not set here intentionally to update - * thr->time.localtime later in non-signal context. The - * real previously cached thr->localtime is used because - * Linux and Solaris strftime() depend on tm.tm_isdst - * and tm.tm_gmtoff fields. - */ - nxt_gmtime(s + nxt_timezone(tm), tm); - } - } - - } else { - tm = &thr->time.gmtime; - - if (nxt_slow_path(s != thr->time.last_gmtime)) { - nxt_gmtime(s, tm); - thr->time.last_gmtime = s; - } - - } - - p = tsc->string.start; - - if (nxt_slow_path(p == NULL)) { - - thr->time.no_cache = 1; - p = nxt_zalloc(ts->size); - thr->time.no_cache = 0; - - if (p == NULL) { - return buf; - } - - tsc->string.start = p; - } - - p = ts->handler(p, &thr->time.now.realtime, tm, ts->size, ts->format); - - tsc->string.length = p - tsc->string.start; - - if (nxt_slow_path(tsc->string.length == 0)) { - return buf; - } - - tsc->last = s; - } - - return nxt_cpymem(buf, tsc->string.start, tsc->string.length); -} - - -static u_char * -nxt_thread_time_string_no_cache(nxt_thread_t *thr, nxt_time_string_t *ts, - u_char *buf) -{ - struct tm tm; - nxt_realtime_t now; - - nxt_realtime(&now); - - if (ts->timezone == NXT_THREAD_TIME_LOCAL) { - - if (thr == NULL || thr->time.signal <= 0) { - /* Non-signal context */ - nxt_localtime(now.sec, &tm); - - } else { - nxt_gmtime(now.sec + nxt_gmtoff, &tm); - } - - } else { - nxt_gmtime(now.sec, &tm); - } - - return ts->handler(buf, &now, &tm, ts->size, ts->format); -} - - -static nxt_atomic_uint_t -nxt_thread_time_string_slot(nxt_time_string_t *ts) -{ - static nxt_atomic_t slot; - - while (nxt_slow_path((nxt_atomic_int_t) ts->slot < 0)) { - /* - * Atomic allocation of a slot number. - * -1 means an uninitialized slot, - * -2 is the initializing lock to assure the single value for the slot. - */ - if (nxt_atomic_cmp_set(&ts->slot, -1, -2)) { - ts->slot = nxt_atomic_fetch_add(&slot, 1); - - /* No "break" here since it adds only dispensable "jmp". */ - } - } - - return (nxt_atomic_uint_t) ts->slot; -} - - -static nxt_time_string_cache_t * -nxt_thread_time_string_cache(nxt_thread_t *thr, nxt_atomic_uint_t slot) -{ - size_t size; - nxt_atomic_uint_t i, nstrings; - nxt_time_string_cache_t *tsc; - - if (nxt_fast_path(slot < thr->time.nstrings)) { - tsc = &thr->time.strings[slot]; - nxt_prefetch(tsc->string.start); - return tsc; - } - - nstrings = slot + 1; - size = nstrings * sizeof(nxt_time_string_cache_t); - - thr->time.no_cache = 1; - tsc = nxt_realloc(thr->time.strings, size); - thr->time.no_cache = 0; - - if (tsc == NULL) { - return NULL; - } - - for (i = thr->time.nstrings; i < nstrings; i++) { - tsc[i].last = -1; - tsc[i].string.start = NULL; - } - - thr->time.strings = tsc; - thr->time.nstrings = nstrings; - - return &tsc[slot]; -} diff --git a/src/nxt_thread_time.h b/src/nxt_thread_time.h deleted file mode 100644 index 77eaea49..00000000 --- a/src/nxt_thread_time.h +++ /dev/null @@ -1,92 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_THREAD_TIME_H_INCLUDED_ -#define _NXT_THREAD_TIME_H_INCLUDED_ - - -#define NXT_THREAD_TIME_LOCAL 0 -#define NXT_THREAD_TIME_GMT 1 - -#define NXT_THREAD_TIME_SEC 0 -#define NXT_THREAD_TIME_MSEC 1 - - -typedef struct { - nxt_atomic_t slot; - u_char *(*handler)(u_char *buf, nxt_realtime_t *now, - struct tm *tm, size_t size, - const char *format); - const char *format; - size_t size; - - uint8_t timezone; /* 1 bit */ - uint8_t msec; /* 1 bit */ -} nxt_time_string_t; - - -typedef struct { - nxt_time_t last; -#if (NXT_DEBUG) - nxt_msec_t last_msec; -#endif - nxt_str_t string; -} nxt_time_string_cache_t; - - -typedef struct { - nxt_monotonic_time_t now; - - nxt_time_t last_gmtime; - nxt_time_t last_localtime; - struct tm gmtime; - struct tm localtime; - - uint32_t no_cache; /* 1 bit */ - - /* - * The flag indicating a signal state of a thread. - * It is used to handle local time of the thread: - * -1 means that the thread never runs in a signal context; - * 0 means that the thread may run in a signal context but not now; - * >0 means that the thread runs in a signal context right now. - */ - nxt_atomic_int_t signal; - - nxt_atomic_uint_t nstrings; - nxt_time_string_cache_t *strings; -} nxt_thread_time_t; - - -NXT_EXPORT void nxt_thread_time_update(nxt_thread_t *thr); -void nxt_thread_time_free(nxt_thread_t *thr); -NXT_EXPORT nxt_time_t nxt_thread_time(nxt_thread_t *thr); -NXT_EXPORT nxt_realtime_t *nxt_thread_realtime(nxt_thread_t *thr); -NXT_EXPORT u_char *nxt_thread_time_string(nxt_thread_t *thr, - nxt_time_string_t *ts, u_char *buf); -void nxt_time_thread_start(nxt_msec_t interval); - - -#define nxt_thread_monotonic_time(thr) \ - (thr)->time.now.monotonic - - -#if (NXT_DEBUG) - -#define nxt_thread_time_debug_update(thr) \ - nxt_thread_time_update(thr) - -#else - -#define nxt_thread_time_debug_update(thr) - -#endif - - -NXT_EXPORT void nxt_gmtime(nxt_time_t s, struct tm *tm); - - -#endif /* _NXT_THREAD_TIME_H_INCLUDED_ */ diff --git a/src/nxt_time.c b/src/nxt_time.c deleted file mode 100644 index dfead51c..00000000 --- a/src/nxt_time.c +++ /dev/null @@ -1,365 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* OS-specific real, monotonic, and local times and timezone update. */ - - -/* Real time. */ - -#if (NXT_HAVE_CLOCK_REALTIME_COARSE) - -/* - * Linux clock_gettime() resides on the vDSO page. Linux 2.6.32 - * clock_gettime(CLOCK_REALTIME_COARSE) uses only cached values and does - * not read TSC or HPET so it has the kernel jiffy precision (1ms by default) - * and it is several times faster than clock_gettime(CLOCK_REALTIME). - */ - -void -nxt_realtime(nxt_realtime_t *now) -{ - struct timespec ts; - - (void) clock_gettime(CLOCK_REALTIME_COARSE, &ts); - - now->sec = (nxt_time_t) ts.tv_sec; - now->nsec = ts.tv_nsec; -} - - -#elif (NXT_HAVE_CLOCK_REALTIME_FAST) - -/* - * FreeBSD 7.0 specific clock_gettime(CLOCK_REALTIME_FAST) may be - * 5-30 times faster than clock_gettime(CLOCK_REALTIME) depending - * on kern.timecounter.hardware. The clock has a precision of 1/HZ - * seconds (HZ is 1000 on modern platforms, thus 1ms precision). - * FreeBSD 9.2 clock_gettime() resides on the vDSO page and reads - * TSC. clock_gettime(CLOCK_REALTIME_FAST) is the same as - * clock_gettime(CLOCK_REALTIME). - */ - -void -nxt_realtime(nxt_realtime_t *now) -{ - struct timespec ts; - - (void) clock_gettime(CLOCK_REALTIME_FAST, &ts); - - now->sec = (nxt_time_t) ts.tv_sec; - now->nsec = ts.tv_nsec; -} - - -#elif (NXT_HAVE_CLOCK_REALTIME && !(NXT_HPUX)) - -/* - * clock_gettime(CLOCK_REALTIME) is supported by Linux, FreeBSD 3.0, - * Solaris 8, NetBSD 1.3, and AIX. HP-UX supports it too, however, - * it is implemented through a call to gettimeofday(). Linux - * clock_gettime(CLOCK_REALTIME) resides on the vDSO page and reads - * TSC or HPET. FreeBSD 9.2 clock_gettime(CLOCK_REALTIME) resides - * on the vDSO page and reads TSC. - */ - -void -nxt_realtime(nxt_realtime_t *now) -{ - struct timespec ts; - - (void) clock_gettime(CLOCK_REALTIME, &ts); - - now->sec = (nxt_time_t) ts.tv_sec; - now->nsec = ts.tv_nsec; -} - - -#else - -/* MacOSX, HP-UX. */ - -void -nxt_realtime(nxt_realtime_t *now) -{ - struct timeval tv; - - (void) gettimeofday(&tv, NULL); - - now->sec = (nxt_time_t) tv.tv_sec; - now->nsec = tv.tv_usec * 1000; -} - -#endif - - -/* Monotonic time. */ - -#if (NXT_HAVE_CLOCK_MONOTONIC_COARSE) - -/* - * Linux clock_gettime() resides on the vDSO page. Linux 2.6.32 - * clock_gettime(CLOCK_MONOTONIC_COARSE) uses only cached values and does - * not read TSC or HPET so it has the kernel jiffy precision (1ms by default) - * and it is several times faster than clock_gettime(CLOCK_MONOTONIC). - */ - -void -nxt_monotonic_time(nxt_monotonic_time_t *now) -{ - struct timespec ts; - - (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); - - now->monotonic = (nxt_nsec_t) ts.tv_sec * 1000000000 + ts.tv_nsec; -} - - -#elif (NXT_HAVE_CLOCK_MONOTONIC_FAST) - -/* - * FreeBSD 7.0 specific clock_gettime(CLOCK_MONOTONIC_FAST) may be - * 5-30 times faster than clock_gettime(CLOCK_MONOTONIC) depending - * on kern.timecounter.hardware. The clock has a precision of 1/HZ - * seconds (HZ is 1000 on modern platforms, thus 1ms precision). - * FreeBSD 9.2 clock_gettime() resides on the vDSO page and reads - * TSC. clock_gettime(CLOCK_MONOTONIC_FAST) is the same as - * clock_gettime(CLOCK_MONOTONIC). - */ - -void -nxt_monotonic_time(nxt_monotonic_time_t *now) -{ - struct timespec ts; - - (void) clock_gettime(CLOCK_MONOTONIC_FAST, &ts); - - now->monotonic = (nxt_nsec_t) ts.tv_sec * 1000000000 + ts.tv_nsec; -} - - -#elif (NXT_HAVE_HG_GETHRTIME) - -/* - * HP-UX 11.31 provides fast hg_gethrtime() which uses a chunk of memory - * shared between userspace application and the kernel, and was introduced - * by Project Mercury ("HG"). - */ - -void -nxt_monotonic_time(nxt_monotonic_time_t *now) -{ - now->monotonic = (nxt_nsec_t) hg_gethrtime(); -} - - -#elif (NXT_SOLARIS || NXT_HPUX) - -/* - * Solaris gethrtime(), clock_gettime(CLOCK_REALTIME), and gettimeofday() - * use a fast systrap whereas clock_gettime(CLOCK_MONOTONIC) and other - * clock_gettime()s use normal systrap. However, the difference is - * negligible on x86_64. - * - * HP-UX lacks clock_gettime(CLOCK_MONOTONIC) but has lightweight - * system call gethrtime(). - */ - -void -nxt_monotonic_time(nxt_monotonic_time_t *now) -{ - now->monotonic = (nxt_nsec_t) gethrtime(); -} - - -#elif (NXT_HAVE_CLOCK_MONOTONIC) - -/* - * clock_gettime(CLOCK_MONOTONIC) is supported by Linux, FreeBSD 5.0, - * Solaris 8, NetBSD 1.6, and AIX. Linux clock_gettime(CLOCK_MONOTONIC) - * resides on the vDSO page and reads TSC or HPET. FreeBSD 9.2 - * clock_gettime(CLOCK_MONOTONIC) resides on the vDSO page and reads TSC. - */ - -void -nxt_monotonic_time(nxt_monotonic_time_t *now) -{ - struct timespec ts; - - (void) clock_gettime(CLOCK_MONOTONIC, &ts); - - now->monotonic = (nxt_nsec_t) ts.tv_sec * 1000000000 + ts.tv_nsec; -} - - -#elif (NXT_MACOSX) - -/* - * MacOSX does not support clock_gettime(), but mach_absolute_time() returns - * monotonic ticks. To get nanoseconds the ticks should be multiplied then - * divided by numerator/denominator returned by mach_timebase_info(), however - * on modern MacOSX they are 1/1. On PowerPC MacOSX these values were - * 1000000000/33333335 or 1000000000/25000000, on iOS 4+ they were 125/3, - * and on iOS 3 they were 1000000000/24000000. - */ - -void -nxt_monotonic_time(nxt_monotonic_time_t *now) -{ - now->monotonic = mach_absolute_time(); -} - - -#else - -void -nxt_monotonic_time(nxt_monotonic_time_t *now) -{ - nxt_nsec_t current; - nxt_nsec_int_t delta; - struct timeval tv; - - (void) gettimeofday(&tv, NULL); - - now->realtime.sec = (nxt_time_t) tv.tv_sec; - now->realtime.nsec = tv.tv_usec * 1000; - - /* - * Monotonic time emulation using gettimeofday() - * for platforms which lack monotonic time. - */ - - current = (nxt_nsec_t) tv.tv_sec * 1000000000 + tv.tv_usec * 1000; - delta = current - now->previous; - now->previous = current; - - if (delta > 0) { - now->monotonic += delta; - - } else { - /* The time went backward. */ - now->monotonic++; - } - - /* - * Eliminate subsequent gettimeofday() call - * in nxt_thread_realtime_update(). - */ - now->update = now->monotonic + 1; -} - -#endif - - -/* Local time. */ - -#if (NXT_HAVE_LOCALTIME_R) - -void -nxt_localtime(nxt_time_t s, struct tm *tm) -{ - time_t _s; - - _s = (time_t) s; - (void) localtime_r(&_s, tm); -} - - -#else - -void -nxt_localtime(nxt_time_t s, struct tm *tm) -{ - time_t _s; - struct tm *_tm; - - _s = (time_t) s; - _tm = localtime(&_s); - *tm = *_tm; -} - -#endif - - -/* Timezone update. */ - -#if (NXT_LINUX) - -/* - * Linux glibc does not test /etc/localtime change - * in localtime_r(), but tests in localtime(). - */ - -void -nxt_timezone_update(void) -{ - time_t s; - - s = time(NULL); - (void) localtime(&s); -} - - -#elif (NXT_FREEBSD) - -/* - * FreeBSD libc does not test /etc/localtime change, but it can be - * worked around by calling tzset() with TZ and then without TZ - * to update timezone. This trick should work since FreeBSD 2.1.0. - */ - -void -nxt_timezone_update(void) -{ - if (getenv("TZ") != NULL) { - return; - } - - /* The libc uses /etc/localtime if TZ is not set. */ - - (void) putenv((char *) "TZ=UTC"); - tzset(); - - (void) unsetenv("TZ"); - tzset(); -} - - -#elif (NXT_SOLARIS) - -/* - * Solaris 10, patch 142909-17 introduced tzreload(8): - * - * The tzreload command notifies active (running) processes to reread - * timezone information. The timezone information is cached in each - * process, absent a tzreload command, is never reread until a process - * is restarted. In response to a tzreload command, active processes - * reread the current timezone information at the next call to ctime(3C) - * and mktime(3C). By default, the tzreload notification is sent to - * the processes within the current zone. - */ - -void -nxt_timezone_update(void) -{ - time_t s; - - s = time(NULL); - (void) ctime(&s); -} - - -#else - -void -nxt_timezone_update(void) -{ - return; -} - -#endif diff --git a/src/nxt_time.h b/src/nxt_time.h deleted file mode 100644 index 9617b3d4..00000000 --- a/src/nxt_time.h +++ /dev/null @@ -1,107 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIX_TIME_H_INCLUDED_ -#define _NXT_UNIX_TIME_H_INCLUDED_ - - -typedef uint64_t nxt_nsec_t; -typedef int64_t nxt_nsec_int_t; -#define NXT_INFINITE_NSEC ((nxt_nsec_t) -1) - - -typedef struct { - nxt_time_t sec; - nxt_uint_t nsec; -} nxt_realtime_t; - - -/* - * nxt_monotonic_time_t includes nxt_realtime_t to eliminate - * surplus gettimeofday() call on platform without monotonic time. - */ - -typedef struct { - nxt_realtime_t realtime; - nxt_nsec_t monotonic; - nxt_nsec_t update; - -#if !(NXT_HAVE_CLOCK_MONOTONIC || NXT_SOLARIS || NXT_HPUX || NXT_MACOSX) - nxt_nsec_t previous; -#endif -} nxt_monotonic_time_t; - - -NXT_EXPORT void nxt_realtime(nxt_realtime_t *now); -NXT_EXPORT void nxt_monotonic_time(nxt_monotonic_time_t *now); -NXT_EXPORT void nxt_localtime(nxt_time_t s, struct tm *tm); -NXT_EXPORT void nxt_timezone_update(void); - -/* - * Both localtime() and localtime_r() are not Async-Signal-Safe, therefore, - * they can not be used in signal handlers. Since Daylight Saving Time (DST) - * state changes no more than twice a year, a simple workaround is to use - * a previously cached GMT offset value and nxt_gmtime(): - * - * nxt_gmtime(GMT seconds + GMT offset, tm); - * - * GMT offset with account of current DST state can be obtained only - * using localtime()'s struct tm because: - * - * 1) gettimeofday() does not return GMT offset at almost all platforms. - * MacOSX returns a value cached after the first localtime() call. - * AIX returns GMT offset without account of DST state and indicates - * only that timezone has DST, but does not indicate current DST state. - * - * 2) There are the "timezone" and "daylight" variables on Linux, Solaris, - * HP-UX, IRIX, and other systems. The "daylight" variable indicates - * only that timezone has DST, but does not indicate current DST state. - * - * 3) Solaris and IRIX have the "altzone" variable which contains GMT offset - * for timezone with DST applied, but without account of DST state. - * - * 4) There is the "struct tm.tm_gmtoff" field on BSD systems and modern Linux. - * This field contains GMT offset with account of DST state. - * - * 5) The "struct tm.tm_isdst" field returned by localtime() indicates - * current DST state on all platforms. This field may have three values: - * positive means DST in effect, zero means DST is not in effect, and - * negative means DST state is unknown. - */ - -#if (NXT_HAVE_TM_GMTOFF) - -#define nxt_timezone(tm) \ - ((tm)->tm_gmtoff) - -#elif (NXT_HAVE_ALTZONE) - -#define nxt_timezone(tm) \ - (-(((tm)->tm_isdst > 0) ? altzone : timezone)) - -#else - -#define nxt_timezone(tm) \ - (-(((tm)->tm_isdst > 0) ? timezone + 3600 : timezone)) - -#endif - - -typedef uint32_t nxt_msec_t; -typedef int32_t nxt_msec_int_t; -#define NXT_INFINITE_MSEC ((nxt_msec_t) -1) - - -/* - * Since nxt_msec_t values are stored just in 32 bits, they overflow - * every 49 days. This signed subtraction takes into account that overflow. - * "nxt_msec_diff(m1, m2) < 0" means that m1 is lesser than m2. - */ -#define nxt_msec_diff(m1, m2) \ - ((int32_t) ((m1) - (m2))) - - -#endif /* _NXT_UNIX_TIME_H_INCLUDED_ */ diff --git a/src/nxt_time_parse.c b/src/nxt_time_parse.c deleted file mode 100644 index 63620b09..00000000 --- a/src/nxt_time_parse.c +++ /dev/null @@ -1,489 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * nxt_time_parse() parses a time string given in RFC822, RFC850, or ISOC - * formats and returns nxt_time_t value >= 0 on success or -1 on failure. - */ - -nxt_time_t -nxt_time_parse(const u_char *p, size_t len) -{ - size_t n; - u_char c; - uint64_t s; - nxt_int_t yr, month, day, hour, min, sec; - nxt_uint_t year, days; - const u_char *end; - - static const nxt_int_t mday[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - - enum { - RFC822 = 0, /* "Mon, 28 Sep 1970 12:00:00" */ - RFC850, /* "Monday, 28-Sep-70 12:00:00" */ - ISOC, /* "Mon Sep 28 12:00:00 1970" */ - } fmt; - - fmt = RFC822; - end = p + len; - - while (p < end) { - c = *p++; - - if (c == ',') { - break; - } - - if (c == ' ') { - fmt = ISOC; - break; - } - } - - while (p < end) { - if (*p != ' ') { - break; - } - - p++; - } - - if (nxt_slow_path(p + 18 > end)) { - /* Lesser than RFC850 "28-Sep-70 12:00:00" length. */ - return -1; - } - - day = 0; - - if (fmt != ISOC) { - day = nxt_int_parse(p, 2); - if (nxt_slow_path(day <= 0)) { - return -1; - } - p += 2; - - if (*p == ' ') { - if (nxt_slow_path(p + 18 > end)) { - /* Lesser than RFC822 " Sep 1970 12:00:00" length. */ - return -1; - } - - /* RFC822 */ - - } else if (*p == '-') { - fmt = RFC850; - - } else { - return -1; - } - - p++; - } - - switch (*p) { - - case 'J': - month = p[1] == 'a' ? 0 : p[2] == 'n' ? 5 : 6; - break; - - case 'F': - month = 1; - break; - - case 'M': - month = p[2] == 'r' ? 2 : 4; - break; - - case 'A': - month = p[1] == 'p' ? 3 : 7; - break; - - case 'S': - month = 8; - break; - - case 'O': - month = 9; - break; - - case 'N': - month = 10; - break; - - case 'D': - month = 11; - break; - - default: - return -1; - } - - p += 3; - yr = 0; - - switch (fmt) { - - case RFC822: - if (nxt_slow_path(*p++ != ' ')) { - return -1; - } - - yr = nxt_int_parse(p, 4); - if (nxt_slow_path(yr <= 0)) { - return -1; - } - p += 4; - - break; - - case RFC850: - if (nxt_slow_path(*p++ != '-')) { - return -1; - } - - yr = nxt_int_parse(p, 2); - if (nxt_slow_path(yr <= 0)) { - return -1; - } - p += 2; - - yr += (yr < 70) ? 2000 : 1900; - - break; - - default: /* ISOC */ - if (nxt_slow_path(*p++ != ' ')) { - return -1; - } - - if (p[0] != ' ') { - n = 2; - - if (p[1] == ' ') { - n = 1; - } - - } else { - p++; - n = 1; - } - - day = nxt_int_parse(p, n); - if (nxt_slow_path(day <= 0)) { - return -1; - } - p += n; - - if (nxt_slow_path(p + 14 > end)) { - /* Lesser than ISOC " 12:00:00 1970" length. */ - return -1; - } - - break; - } - - if (nxt_slow_path(*p++ != ' ')) { - return -1; - } - - hour = nxt_int_parse(p, 2); - if (nxt_slow_path(hour < 0)) { - return -1; - } - p += 2; - - if (nxt_slow_path(*p++ != ':')) { - return -1; - } - - min = nxt_int_parse(p, 2); - if (nxt_slow_path(min < 0)) { - return -1; - } - p += 2; - - if (nxt_slow_path(*p++ != ':')) { - return -1; - } - - sec = nxt_int_parse(p, 2); - if (nxt_slow_path(sec < 0)) { - return -1; - } - - if (fmt == ISOC) { - p += 2; - - if (nxt_slow_path(*p++ != ' ')) { - return -1; - } - - yr = nxt_int_parse(p, 4); - if (nxt_slow_path(yr < 0)) { - return -1; - } - } - - if (nxt_slow_path(hour > 23 || min > 59 || sec > 59)) { - return -1; - } - - year = yr; - - if (day == 29 && month == 1) { - - if (nxt_slow_path((year & 3) != 0)) { - /* Not a leap year. */ - return -1; - } - - if (nxt_slow_path((year % 100 == 0) && (year % 400) != 0)) { - /* Not a leap year. */ - return -1; - } - - } else if (nxt_slow_path(day > mday[(nxt_uint_t) month])) { - return -1; - } - - /* - * Shift new year to March 1 and start months - * from 1 (not 0), as required for Gauss' formula. - */ - - if (--month <= 0) { - month += 12; - year -= 1; - } - - /* Gauss' formula for Gregorian days since March 1, 1 BCE. */ - - /* Days in years including leap years since March 1, 1 BCE. */ - days = 365 * year + year / 4 - year / 100 + year / 400 - - /* Days before the month. */ - + 367 * (nxt_uint_t) month / 12 - 30 - - /* Days before the day. */ - + (nxt_uint_t) day - 1; - - /* - * 719527 days were between March 1, 1 BCE and March 1, 1970, - * 31 and 28 days were in January and February 1970. - */ - days = days - 719527 + 31 + 28; - - s = (uint64_t) days * 86400 - + (nxt_uint_t) hour * 3600 - + (nxt_uint_t) min * 60 - + (nxt_uint_t) sec; - -#if (NXT_TIME_T_SIZE <= 4) - - /* Y2038 */ - - if (nxt_slow_path(s > 0x7FFFFFFF)) { - return -1; - } - -#endif - - return (nxt_time_t) s; -} - - -/* - * nxt_term_parse() parses term string given in format "200", "10m", - * or "1d 1h" and returns nxt_int_t value >= 0 on success, -1 on failure, - * and -2 on overflow. The maximum valid value is 2^31 - 1 or about - * 68 years in seconds or about 24 days in milliseconds. - */ - -nxt_int_t -nxt_term_parse(const u_char *p, size_t len, nxt_bool_t seconds) -{ - u_char c, ch; - nxt_uint_t val, term, scale, max; - const u_char *end; - - enum { - st_first_digit = 0, - st_digit, - st_letter, - st_space, - } state; - - enum { - st_start = 0, - st_year, - st_month, - st_week, - st_day, - st_hour, - st_min, - st_sec, - st_msec, - st_last, - } step; - - val = 0; - term = 0; - state = st_first_digit; - step = seconds ? st_start : st_month; - - end = p + len; - - while (p < end) { - - ch = *p++; - - if (state == st_space) { - - if (ch == ' ') { - continue; - } - - state = st_first_digit; - } - - if (state != st_letter) { - - /* Values below '0' become >= 208. */ - c = ch - '0'; - - if (c <= 9) { - val = val * 10 + c; - state = st_digit; - continue; - } - - if (state == st_first_digit) { - return -1; - } - - state = st_letter; - } - - switch (ch) { - - case 'y': - if (step > st_start) { - return -1; - } - step = st_year; - max = NXT_INT32_T_MAX / (365 * 24 * 60 * 60); - scale = 365 * 24 * 60 * 60; - break; - - case 'M': - if (step >= st_month) { - return -1; - } - step = st_month; - max = NXT_INT32_T_MAX / (30 * 24 * 60 * 60); - scale = 30 * 24 * 60 * 60; - break; - - case 'w': - if (step >= st_week) { - return -1; - } - step = st_week; - max = NXT_INT32_T_MAX / (7 * 24 * 60 * 60); - scale = 7 * 24 * 60 * 60; - break; - - case 'd': - if (step >= st_day) { - return -1; - } - step = st_day; - max = NXT_INT32_T_MAX / (24 * 60 * 60); - scale = 24 * 60 * 60; - break; - - case 'h': - if (step >= st_hour) { - return -1; - } - step = st_hour; - max = NXT_INT32_T_MAX / (60 * 60); - scale = 60 * 60; - break; - - case 'm': - if (p < end && *p == 's') { - if (seconds || step >= st_msec) { - return -1; - } - p++; - step = st_msec; - max = NXT_INT32_T_MAX; - scale = 1; - break; - } - - if (step >= st_min) { - return -1; - } - step = st_min; - max = NXT_INT32_T_MAX / 60; - scale = 60; - break; - - case 's': - if (step >= st_sec) { - return -1; - } - step = st_sec; - max = NXT_INT32_T_MAX; - scale = 1; - break; - - case ' ': - if (step >= st_sec) { - return -1; - } - step = st_last; - max = NXT_INT32_T_MAX; - scale = 1; - break; - - default: - return -1; - } - - if (!seconds && step != st_msec) { - scale *= 1000; - max /= 1000; - } - - if (val > max) { - return -2; - } - - term += val * scale; - - if (term > NXT_INT32_T_MAX) { - return -2; - } - - val = 0; - - state = st_space; - } - - if (!seconds) { - val *= 1000; - } - - return term + val; -} diff --git a/src/nxt_timer.c b/src/nxt_timer.c deleted file mode 100644 index cb94b77c..00000000 --- a/src/nxt_timer.c +++ /dev/null @@ -1,344 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * Timer operations are batched in the changes array to improve instruction - * and data cache locality of rbtree operations. - * - * nxt_timer_add() adds or modify a timer. - * - * nxt_timer_disable() disables a timer. - * - * nxt_timer_delete() deletes a timer. It returns 1 if there are pending - * changes in the changes array or 0 otherwise. - */ - -static intptr_t nxt_timer_rbtree_compare(nxt_rbtree_node_t *node1, - nxt_rbtree_node_t *node2); -static void nxt_timer_change(nxt_event_engine_t *engine, nxt_timer_t *timer, - nxt_timer_operation_t change, nxt_msec_t time); -static void nxt_timer_changes_commit(nxt_event_engine_t *engine); -static void nxt_timer_handler(nxt_task_t *task, void *obj, void *data); - - -nxt_int_t -nxt_timers_init(nxt_timers_t *timers, nxt_uint_t mchanges) -{ - nxt_rbtree_init(&timers->tree, nxt_timer_rbtree_compare); - - if (mchanges > NXT_TIMER_MAX_CHANGES) { - mchanges = NXT_TIMER_MAX_CHANGES; - } - - timers->mchanges = mchanges; - - timers->changes = nxt_malloc(sizeof(nxt_timer_change_t) * mchanges); - - if (nxt_fast_path(timers->changes != NULL)) { - return NXT_OK; - } - - return NXT_ERROR; -} - - -static intptr_t -nxt_timer_rbtree_compare(nxt_rbtree_node_t *node1, nxt_rbtree_node_t *node2) -{ - nxt_timer_t *timer1, *timer2; - - timer1 = (nxt_timer_t *) node1; - timer2 = (nxt_timer_t *) node2; - - /* - * Timer values are distributed in small range, usually several minutes - * and overflow every 49 days if nxt_msec_t is stored in 32 bits. - * This signed comparison takes into account that overflow. - */ - /* timer1->time < timer2->time */ - return nxt_msec_diff(timer1->time , timer2->time); -} - - -void -nxt_timer_add(nxt_event_engine_t *engine, nxt_timer_t *timer, - nxt_msec_t timeout) -{ - int32_t diff; - uint32_t time; - - time = engine->timers.now + timeout; - - nxt_debug(timer->task, "timer add: %M±%d %M:%M", - timer->time, timer->bias, timeout, time); - - timer->enabled = 1; - - if (nxt_timer_is_in_tree(timer)) { - - diff = nxt_msec_diff(time, timer->time); - /* - * Use the previous timer if difference between it and the - * new timer is within bias: this decreases number of rbtree - * operations for fast connections. - */ - if (nxt_abs(diff) <= timer->bias) { - nxt_debug(timer->task, "timer previous: %M±%d", - time, timer->bias); - - nxt_timer_change(engine, timer, NXT_TIMER_NOPE, 0); - return; - } - } - - nxt_timer_change(engine, timer, NXT_TIMER_ADD, time); -} - - -nxt_bool_t -nxt_timer_delete(nxt_event_engine_t *engine, nxt_timer_t *timer) -{ - nxt_debug(timer->task, "timer delete: %M±%d", - timer->time, timer->bias); - - timer->enabled = 0; - - if (nxt_timer_is_in_tree(timer)) { - - nxt_timer_change(engine, timer, NXT_TIMER_DELETE, 0); - - return 1; - } - - nxt_timer_change(engine, timer, NXT_TIMER_NOPE, 0); - - return (timer->queued || timer->change != NXT_TIMER_NO_CHANGE); -} - - -static void -nxt_timer_change(nxt_event_engine_t *engine, nxt_timer_t *timer, - nxt_timer_operation_t change, nxt_msec_t time) -{ - nxt_timers_t *timers; - nxt_timer_change_t *ch; - - timers = &engine->timers; - - if (timer->change == NXT_TIMER_NO_CHANGE) { - - if (change == NXT_TIMER_NOPE) { - return; - } - - if (timers->nchanges >= timers->mchanges) { - nxt_timer_changes_commit(engine); - } - - timers->nchanges++; - timer->change = timers->nchanges; - } - - nxt_debug(timer->task, "timer change: %M±%d:%d", - time, timer->bias, change); - - ch = &timers->changes[timer->change - 1]; - - ch->change = change; - ch->time = time; - ch->timer = timer; -} - - -static void -nxt_timer_changes_commit(nxt_event_engine_t *engine) -{ - nxt_timer_t *timer; - nxt_timers_t *timers; - nxt_timer_change_t *ch, *end, *add, *add_end; - - timers = &engine->timers; - - nxt_debug(&engine->task, "timers changes: %ui", timers->nchanges); - - ch = timers->changes; - end = ch + timers->nchanges; - - add = ch; - add_end = add; - - while (ch < end) { - timer = ch->timer; - - switch (ch->change) { - - case NXT_TIMER_NOPE: - break; - - case NXT_TIMER_ADD: - - timer->time = ch->time; - - add_end->timer = timer; - add_end++; - - if (!nxt_timer_is_in_tree(timer)) { - break; - } - - /* Fall through. */ - - case NXT_TIMER_DELETE: - nxt_debug(timer->task, "timer rbtree delete: %M±%d", - timer->time, timer->bias); - - nxt_rbtree_delete(&timers->tree, &timer->node); - nxt_timer_in_tree_clear(timer); - - break; - } - - timer->change = NXT_TIMER_NO_CHANGE; - - ch++; - } - - while (add < add_end) { - timer = add->timer; - - nxt_debug(timer->task, "timer rbtree insert: %M±%d", - timer->time, timer->bias); - - nxt_rbtree_insert(&timers->tree, &timer->node); - nxt_timer_in_tree_set(timer); - - add++; - } - - timers->nchanges = 0; -} - - -nxt_msec_t -nxt_timer_find(nxt_event_engine_t *engine) -{ - int32_t delta; - nxt_msec_t time; - nxt_timer_t *timer; - nxt_timers_t *timers; - nxt_rbtree_t *tree; - nxt_rbtree_node_t *node, *next; - - timers = &engine->timers; - - if (timers->nchanges != 0) { - nxt_timer_changes_commit(engine); - } - - tree = &timers->tree; - - for (node = nxt_rbtree_min(tree); - nxt_rbtree_is_there_successor(tree, node); - node = next) - { - next = nxt_rbtree_node_successor(tree, node); - - timer = (nxt_timer_t *) node; - - /* - * Disabled timers are not deleted here since the minimum active - * timer may be larger than a disabled timer, but event poll may - * return much earlier and the disabled timer can be reactivated. - */ - - if (timer->enabled) { - time = timer->time; - timers->minimum = time - timer->bias; - - nxt_debug(timer->task, "timer found minimum: %M±%d:%M", - time, timer->bias, timers->now); - - delta = nxt_msec_diff(time, timers->now); - - return (nxt_msec_t) nxt_max(delta, 0); - } - } - - /* Set minimum time one day ahead. */ - timers->minimum = timers->now + 24 * 60 * 60 * 1000; - - return NXT_INFINITE_MSEC; -} - - -void -nxt_timer_expire(nxt_event_engine_t *engine, nxt_msec_t now) -{ - nxt_timer_t *timer; - nxt_timers_t *timers; - nxt_rbtree_t *tree; - nxt_rbtree_node_t *node, *next; - - timers = &engine->timers; - timers->now = now; - - nxt_debug(&engine->task, "timer expire minimum: %M:%M", - timers->minimum, now); - - /* timers->minimum > now */ - if (nxt_msec_diff(timers->minimum , now) > 0) { - return; - } - - tree = &timers->tree; - - for (node = nxt_rbtree_min(tree); - nxt_rbtree_is_there_successor(tree, node); - node = next) - { - timer = (nxt_timer_t *) node; - - /* timer->time > now + timer->bias */ - if (nxt_msec_diff(timer->time , now) > (int32_t) timer->bias) { - return; - } - - next = nxt_rbtree_node_successor(tree, node); - - nxt_debug(timer->task, "timer expire delete: %M±%d", - timer->time, timer->bias); - - nxt_rbtree_delete(tree, &timer->node); - nxt_timer_in_tree_clear(timer); - - if (timer->enabled) { - timer->queued = 1; - - nxt_work_queue_add(timer->work_queue, nxt_timer_handler, - timer->task, timer, NULL); - } - } -} - - -static void -nxt_timer_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_timer_t *timer; - - timer = obj; - - timer->queued = 0; - - if (timer->enabled && timer->change == NXT_TIMER_NO_CHANGE) { - timer->enabled = 0; - - timer->handler(task, timer, NULL); - } -} diff --git a/src/nxt_timer.h b/src/nxt_timer.h deleted file mode 100644 index 3ccff848..00000000 --- a/src/nxt_timer.h +++ /dev/null @@ -1,113 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_TIMER_H_INCLUDED_ -#define _NXT_TIMER_H_INCLUDED_ - - -/* Valid values are between 0ms to 255ms. */ -#define NXT_TIMER_DEFAULT_BIAS 50 -//#define NXT_TIMER_DEFAULT_BIAS 0 - - -/* - * The nxt_timer_t structure can hold up to 14 bits of change index, - * but 0 reserved for NXT_TIMER_NO_CHANGE. - */ -#define NXT_TIMER_MAX_CHANGES 16383 -#define NXT_TIMER_NO_CHANGE 0 - - -typedef struct { - /* The rbtree node must be the first field. */ - NXT_RBTREE_NODE (node); - - uint8_t bias; - - uint16_t change:14; - uint16_t enabled:1; - uint16_t queued:1; - - nxt_msec_t time; - - nxt_work_queue_t *work_queue; - nxt_work_handler_t handler; - - nxt_task_t *task; - nxt_log_t *log; -} nxt_timer_t; - - -#define NXT_TIMER { NXT_RBTREE_NODE_INIT, 0, NXT_TIMER_NO_CHANGE, \ - 0, 0, 0, NULL, NULL, NULL, NULL } - - -typedef enum { - NXT_TIMER_NOPE = 0, - NXT_TIMER_ADD, - NXT_TIMER_DELETE, -} nxt_timer_operation_t; - - -typedef struct { - nxt_timer_operation_t change:8; - nxt_msec_t time; - nxt_timer_t *timer; -} nxt_timer_change_t; - - -typedef struct { - nxt_rbtree_t tree; - - /* An overflown milliseconds counter. */ - nxt_msec_t now; - nxt_msec_t minimum; - - nxt_uint_t mchanges; - nxt_uint_t nchanges; - - nxt_timer_change_t *changes; -} nxt_timers_t; - - -#define nxt_timer_data(obj, type, timer) \ - nxt_container_of(obj, type, timer) - - -/* - * When timer resides in rbtree all links of its node are not NULL. - * A parent link is the nearst to other timer flags. - */ - -#define nxt_timer_is_in_tree(timer) \ - ((timer)->node.parent != NULL) - -#define nxt_timer_in_tree_set(timer) - /* Noop, because rbtree insertion sets a node's parent link. */ - -#define nxt_timer_in_tree_clear(timer) \ - (timer)->node.parent = NULL - - -nxt_int_t nxt_timers_init(nxt_timers_t *timers, nxt_uint_t mchanges); -nxt_msec_t nxt_timer_find(nxt_event_engine_t *engine); -void nxt_timer_expire(nxt_event_engine_t *engine, nxt_msec_t now); - -NXT_EXPORT void nxt_timer_add(nxt_event_engine_t *engine, nxt_timer_t *timer, - nxt_msec_t timeout); -NXT_EXPORT nxt_bool_t nxt_timer_delete(nxt_event_engine_t *engine, - nxt_timer_t *timer); - -nxt_inline void -nxt_timer_disable(nxt_event_engine_t *engine, nxt_timer_t *timer) -{ - nxt_debug(timer->task, "timer disable: %M", timer->time); - - timer->enabled = 0; -} - - -#endif /* _NXT_TIMER_H_INCLUDED_ */ diff --git a/src/nxt_tls.h b/src/nxt_tls.h deleted file mode 100644 index 0667ade3..00000000 --- a/src/nxt_tls.h +++ /dev/null @@ -1,116 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_TLS_H_INCLUDED_ -#define _NXT_TLS_H_INCLUDED_ - - -#include - - -/* - * The SSL/TLS libraries lack vector I/O interface yet add noticeable - * overhead to each SSL/TLS record so buffering allows to decrease the - * overhead. The typical overhead size is about 30 bytes, however, TLS - * supports also random padding up to 255 bytes. The maximum SSLv3/TLS - * record size is 16K. However, large records increase decryption latency. - * 4K is good compromise between 1-6% of SSL/TLS overhead and the latency. - * 4K buffer allows to send one SSL/TLS record (4096-bytes data and up to - * 224-bytes overhead) in three 1440-bytes TCP/IPv4 packets with timestamps - * and compatible with tunnels. - */ - -#define NXT_TLS_BUFFER_SIZE 4096 - - -typedef struct nxt_tls_conf_s nxt_tls_conf_t; -typedef struct nxt_tls_bundle_conf_s nxt_tls_bundle_conf_t; -typedef struct nxt_tls_init_s nxt_tls_init_t; -typedef struct nxt_tls_ticket_s nxt_tls_ticket_t; -typedef struct nxt_tls_tickets_s nxt_tls_tickets_t; - -typedef struct { - nxt_int_t (*library_init)(nxt_task_t *task); - void (*library_free)(nxt_task_t *task); - - nxt_int_t (*server_init)(nxt_task_t *task, nxt_mp_t *mp, - nxt_tls_init_t *tls_init, - nxt_bool_t last); - void (*server_free)(nxt_task_t *task, - nxt_tls_conf_t *conf); -} nxt_tls_lib_t; - - -typedef struct { - nxt_tls_bundle_conf_t *bundle; - - nxt_str_t name; -} nxt_tls_bundle_hash_item_t; - - -struct nxt_tls_bundle_conf_s { - void *ctx; - - nxt_fd_t chain_file; - nxt_str_t name; - - nxt_tls_bundle_conf_t *next; -}; - - -struct nxt_tls_conf_s { - nxt_tls_bundle_conf_t *bundle; - nxt_lvlhsh_t bundle_hash; - - nxt_tls_tickets_t *tickets; - - void (*conn_init)(nxt_task_t *task, - nxt_tls_conf_t *conf, nxt_conn_t *c); - - const nxt_tls_lib_t *lib; - - char *ciphers; - - char *ca_certificate; - - size_t buffer_size; - - uint8_t no_wait_shutdown; /* 1 bit */ -}; - - -struct nxt_tls_init_s { - size_t cache_size; - nxt_time_t timeout; - nxt_conf_value_t *conf_cmds; - nxt_conf_value_t *tickets_conf; - - nxt_tls_conf_t *conf; -}; - - -#if (NXT_HAVE_OPENSSL) -extern const nxt_tls_lib_t nxt_openssl_lib; - -void nxt_cdecl nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level, - const char *fmt, ...); -u_char *nxt_openssl_copy_error(u_char *p, u_char *end); -#endif - -#if (NXT_HAVE_GNUTLS) -extern const nxt_tls_lib_t nxt_gnutls_lib; -#endif - -#if (NXT_HAVE_CYASSL) -extern const nxt_tls_lib_t nxt_cyassl_lib; -#endif - -#if (NXT_HAVE_POLARSSL) -extern const nxt_tls_lib_t nxt_polar_lib; -#endif - - -#endif /* _NXT_TLS_H_INCLUDED_ */ diff --git a/src/nxt_tstr.c b/src/nxt_tstr.c deleted file mode 100644 index edf6860a..00000000 --- a/src/nxt_tstr.c +++ /dev/null @@ -1,343 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - - -typedef enum { - NXT_TSTR_CONST = 0, - NXT_TSTR_VAR, -#if (NXT_HAVE_NJS) - NXT_TSTR_JS, -#endif -} nxt_tstr_type_t; - - -struct nxt_tstr_s { - nxt_str_t str; - - union { - nxt_var_t *var; -#if (NXT_HAVE_NJS) - nxt_js_t *js; -#endif - } u; - - nxt_tstr_flags_t flags; - nxt_tstr_type_t type; -}; - - -struct nxt_tstr_query_s { - nxt_mp_t *pool; - - nxt_tstr_state_t *state; - nxt_tstr_cache_t *cache; - - nxt_uint_t waiting; - nxt_uint_t failed; /* 1 bit */ - - void *ctx; - void *data; - - nxt_work_handler_t ready; - nxt_work_handler_t error; -}; - - -#define nxt_tstr_is_js(str) \ - nxt_strchr_start(str, '`') - - -nxt_tstr_state_t * -nxt_tstr_state_new(nxt_mp_t *mp, nxt_bool_t test) -{ - nxt_tstr_state_t *state; - - state = nxt_mp_get(mp, sizeof(nxt_tstr_state_t)); - if (nxt_slow_path(state == NULL)) { - return NULL; - } - - state->pool = mp; - state->test = test; - - state->var_refs = nxt_array_create(mp, 4, sizeof(nxt_var_ref_t)); - if (nxt_slow_path(state->var_refs == NULL)) { - return NULL; - } - -#if (NXT_HAVE_NJS) - state->jcf = nxt_js_conf_new(mp, test); - if (nxt_slow_path(state->jcf == NULL)) { - return NULL; - } -#endif - - return state; -} - - -nxt_tstr_t * -nxt_tstr_compile(nxt_tstr_state_t *state, nxt_str_t *str, - nxt_tstr_flags_t flags) -{ - u_char *p; - nxt_tstr_t *tstr; - nxt_bool_t strz; - - strz = (flags & NXT_TSTR_STRZ) != 0; - - tstr = nxt_mp_get(state->pool, sizeof(nxt_tstr_t)); - if (nxt_slow_path(tstr == NULL)) { - return NULL; - } - - tstr->str.length = str->length + strz; - - tstr->str.start = nxt_mp_nget(state->pool, tstr->str.length); - if (nxt_slow_path(tstr->str.start == NULL)) { - return NULL; - } - - p = nxt_cpymem(tstr->str.start, str->start, str->length); - - if (strz) { - *p = '\0'; - } - - tstr->flags = flags; - - if (nxt_tstr_is_js(str)) { - -#if (NXT_HAVE_NJS) - - nxt_str_t tpl; - - tstr->type = NXT_TSTR_JS; - - nxt_tstr_str(tstr, &tpl); - - tstr->u.js = nxt_js_add_tpl(state->jcf, &tpl, strz); - if (nxt_slow_path(tstr->u.js == NULL)) { - return NULL; - } - -#endif - - } else { - p = memchr(str->start, '$', str->length); - - if (p != NULL) { - tstr->type = NXT_TSTR_VAR; - - tstr->u.var = nxt_var_compile(state, &tstr->str); - if (nxt_slow_path(tstr->u.var == NULL)) { - return NULL; - } - - } else { - tstr->type = NXT_TSTR_CONST; - } - } - - return tstr; -} - - -nxt_int_t -nxt_tstr_test(nxt_tstr_state_t *state, nxt_str_t *str, u_char *error) -{ - u_char *p; - - if (nxt_tstr_is_js(str)) { -#if (NXT_HAVE_NJS) - return nxt_js_test(state->jcf, str, error); - -#else - nxt_sprintf(error, error + NXT_MAX_ERROR_STR, - "Unit is built without support of njs: " - "\"--njs\" ./configure option is missing."); - return NXT_ERROR; -#endif - - } else { - p = memchr(str->start, '$', str->length); - - if (p != NULL) { - return nxt_var_test(state, str, error); - } - } - - return NXT_OK; -} - - -nxt_int_t -nxt_tstr_state_done(nxt_tstr_state_t *state, u_char *error) -{ -#if (NXT_HAVE_NJS) - if (!state->test) { - nxt_int_t ret; - - ret = nxt_js_compile(state->jcf); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } -#endif - - return NXT_OK; -} - - -void -nxt_tstr_state_release(nxt_tstr_state_t *state) -{ -#if (NXT_HAVE_NJS) - nxt_js_conf_release(state->jcf); -#endif -} - - -nxt_bool_t -nxt_tstr_is_const(nxt_tstr_t *tstr) -{ - return (tstr->type == NXT_TSTR_CONST); -} - - -void -nxt_tstr_str(nxt_tstr_t *tstr, nxt_str_t *str) -{ - *str = tstr->str; - - if (tstr->flags & NXT_TSTR_STRZ) { - str->length--; - } -} - - -nxt_int_t -nxt_tstr_query_init(nxt_tstr_query_t **query_p, nxt_tstr_state_t *state, - nxt_tstr_cache_t *cache, void *ctx, nxt_mp_t *mp) -{ - nxt_tstr_query_t *query; - - query = *query_p; - - if (*query_p == NULL) { - query = nxt_mp_zget(mp, sizeof(nxt_tstr_query_t)); - if (nxt_slow_path(query == NULL)) { - return NXT_ERROR; - } - } - - query->pool = mp; - query->state = state; - query->cache = cache; - query->ctx = ctx; - - *query_p = query; - - return NXT_OK; -} - - -void -nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, nxt_tstr_t *tstr, - nxt_str_t *val) -{ - nxt_int_t ret; - - if (nxt_tstr_is_const(tstr)) { - nxt_tstr_str(tstr, val); - return; - } - - if (nxt_slow_path(query->failed)) { - return; - } - - if (tstr->type == NXT_TSTR_VAR) { - ret = nxt_var_interpreter(task, query->state, &query->cache->var, - tstr->u.var, val, query->ctx, - tstr->flags & NXT_TSTR_LOGGING); - - if (nxt_slow_path(ret != NXT_OK)) { - query->failed = 1; - return; - } - - } else { -#if (NXT_HAVE_NJS) - ret = nxt_js_call(task, query->state->jcf, &query->cache->js, - tstr->u.js, val, query->ctx); - - if (nxt_slow_path(ret != NXT_OK)) { - query->failed = 1; - return; - } -#endif - } - - if (tstr->flags & NXT_TSTR_STRZ) { - val->length--; - } - -#if (NXT_DEBUG) - nxt_str_t str; - - nxt_tstr_str(tstr, &str); - - nxt_debug(task, "tstr query: \"%V\", result: \"%V\"", &str, val); -#endif -} - - -nxt_bool_t -nxt_tstr_query_failed(nxt_tstr_query_t *query) -{ - return query->failed; -} - - -void -nxt_tstr_query_resolve(nxt_task_t *task, nxt_tstr_query_t *query, void *data, - nxt_work_handler_t ready, nxt_work_handler_t error) -{ - query->data = data; - query->ready = ready; - query->error = error; - - if (query->waiting == 0) { - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - query->failed ? query->error : query->ready, - task, query->ctx, query->data); - } -} - - -void -nxt_tstr_query_handle(nxt_task_t *task, nxt_tstr_query_t *query, - nxt_bool_t failed) -{ - query->failed |= failed; - - if (--query->waiting == 0) { - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - query->failed ? query->error : query->ready, - task, query->ctx, query->data); - } -} - - -void -nxt_tstr_query_release(nxt_tstr_query_t *query) -{ -#if (NXT_HAVE_NJS) - nxt_js_release(&query->cache->js); -#endif -} diff --git a/src/nxt_tstr.h b/src/nxt_tstr.h deleted file mode 100644 index 3e842f81..00000000 --- a/src/nxt_tstr.h +++ /dev/null @@ -1,82 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_TSTR_H_INCLUDED_ -#define _NXT_TSTR_H_INCLUDED_ - - -#include - -typedef struct nxt_tstr_s nxt_tstr_t; -typedef struct nxt_tstr_query_s nxt_tstr_query_t; - - -struct nxt_tstr_state_s { - nxt_mp_t *pool; - nxt_array_t *var_refs; -#if (NXT_HAVE_NJS) - nxt_js_conf_t *jcf; -#endif - uint8_t test; /* 1 bit */ -}; - - -typedef struct { - nxt_var_cache_t var; -#if (NXT_HAVE_NJS) - nxt_js_cache_t js; -#endif -} nxt_tstr_cache_t; - - -typedef enum { - NXT_TSTR_STRZ = 1 << 0, - NXT_TSTR_LOGGING = 1 << 1, -} nxt_tstr_flags_t; - - -nxt_tstr_state_t *nxt_tstr_state_new(nxt_mp_t *mp, nxt_bool_t test); -nxt_tstr_t *nxt_tstr_compile(nxt_tstr_state_t *state, nxt_str_t *str, - nxt_tstr_flags_t flags); -nxt_int_t nxt_tstr_test(nxt_tstr_state_t *state, nxt_str_t *str, u_char *error); -nxt_int_t nxt_tstr_state_done(nxt_tstr_state_t *state, u_char *error); -void nxt_tstr_state_release(nxt_tstr_state_t *state); - -nxt_bool_t nxt_tstr_is_const(nxt_tstr_t *tstr); -void nxt_tstr_str(nxt_tstr_t *tstr, nxt_str_t *str); - -nxt_int_t nxt_tstr_query_init(nxt_tstr_query_t **query_p, - nxt_tstr_state_t *state, nxt_tstr_cache_t *cache, void *ctx, - nxt_mp_t *mp); -void nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, nxt_tstr_t *tstr, - nxt_str_t *val); -nxt_bool_t nxt_tstr_query_failed(nxt_tstr_query_t *query); -void nxt_tstr_query_resolve(nxt_task_t *task, nxt_tstr_query_t *query, - void *data, nxt_work_handler_t ready, nxt_work_handler_t error); -void nxt_tstr_query_handle(nxt_task_t *task, nxt_tstr_query_t *query, - nxt_bool_t failed); -void nxt_tstr_query_release(nxt_tstr_query_t *query); - - -nxt_inline nxt_bool_t -nxt_is_tstr(nxt_str_t *str) -{ - u_char *p; - - p = memchr(str->start, '`', str->length); - if (p != NULL) { - return 1; - } - - p = memchr(str->start, '$', str->length); - if (p != NULL) { - return 1; - } - - return 0; -} - - -#endif /* _NXT_TSTR_H_INCLUDED_ */ diff --git a/src/nxt_types.h b/src/nxt_types.h deleted file mode 100644 index 03e9c187..00000000 --- a/src/nxt_types.h +++ /dev/null @@ -1,151 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_TYPES_H_INCLUDED_ -#define _NXT_TYPES_H_INCLUDED_ - - -/* - * nxt_int_t corresponds to the most efficient integer type, - * an architecture word. It is usually the long type, - * but on Win64 the long is int32_t, so pointer size suits better. - * nxt_int_t must be no less than int32_t. - */ - -#if (__amd64__) -/* - * AMD64 64-bit multiplication and division operations - * are slower and 64-bit instructions are longer. - */ -#define NXT_INT_T_SIZE 4 -typedef int nxt_int_t; -typedef u_int nxt_uint_t; - -#else -#define NXT_INT_T_SIZE NXT_PTR_SIZE -typedef intptr_t nxt_int_t; -typedef uintptr_t nxt_uint_t; -#endif - - -typedef nxt_uint_t nxt_bool_t; - - -/* - * nxt_off_t corresponds to OS's off_t, a file offset type. - * Although Linux, Solaris, and HP-UX define both off_t and off64_t, - * setting _FILE_OFFSET_BITS to 64 defines off_t as off64_t. - */ -typedef off_t nxt_off_t; - - -/* - * nxt_time_t corresponds to OS's time_t, time in seconds. nxt_time_t is - * a signed integer. OS's time_t may be an integer or real-floating type, - * though it is usually a signed 32-bit or 64-bit integer depending on - * platform bit count. There are however exceptions, e.g., time_t is: - * 32-bit on 64-bit NetBSD prior to 6.0 version; - * 64-bit on 32-bit NetBSD 6.0; - * 32-bit on 64-bit OpenBSD; - * 64-bit in Linux x32 ABI; - * 64-bit in 32-bit Visual Studio C++ 2005. - */ -#if (NXT_QNX) -/* - * QNX defines time_t as uint32_t. - * Y2038 fix: "typedef int64_t nxt_time_t". - */ -typedef int32_t nxt_time_t; - -#else -/* Y2038, if time_t is 32-bit integer. */ -typedef time_t nxt_time_t; -#endif - - -#if (NXT_PTR_SIZE == 8) -#define NXT_64BIT 1 -#define NXT_32BIT 0 - -#else -#define NXT_64BIT 0 -#define NXT_32BIT 1 -#endif - - -#define NXT_INT64_T_LEN nxt_length("-9223372036854775808") -#define NXT_INT32_T_LEN nxt_length("-2147483648") - -#define NXT_INT64_T_HEXLEN nxt_length("FFFFFFFFFFFFFFFF") -#define NXT_INT32_T_HEXLEN nxt_length("FFFFFFFF") - -#define NXT_INT64_T_MAX 0x7FFFFFFFFFFFFFFFLL -#define NXT_INT32_T_MAX 0x7FFFFFFF - - -#if (NXT_INT_T_SIZE == 8) -#define NXT_INT_T_LEN NXT_INT64_T_LEN -#define NXT_INT_T_HEXLEN NXT_INT64_T_HEXLEN -#define NXT_INT_T_MAX NXT_INT64_T_MAX - -#else -#define NXT_INT_T_LEN NXT_INT32_T_LEN -#define NXT_INT_T_HEXLEN NXT_INT32_T_HEXLEN -#define NXT_INT_T_MAX NXT_INT32_T_MAX -#endif - - -#if (NXT_64BIT) -#define NXT_ATOMIC_T_LEN NXT_INT64_T_LEN -#define NXT_ATOMIC_T_HEXLEN NXT_INT64_T_HEXLEN -#define NXT_ATOMIC_T_MAX NXT_INT64_T_MAX - -#else -#define NXT_ATOMIC_T_LEN NXT_INT32_T_LEN -#define NXT_ATOMIC_T_HEXLEN NXT_INT32_T_HEXLEN -#define NXT_ATOMIC_T_MAX NXT_INT32_T_MAX -#endif - - -#if (NXT_OFF_T_SIZE == 8) -typedef uint64_t nxt_uoff_t; -#define NXT_OFF_T_LEN NXT_INT64_T_LEN -#define NXT_OFF_T_HEXLEN NXT_INT64_T_HEXLEN -#define NXT_OFF_T_MAX NXT_INT64_T_MAX - -#else -typedef uint32_t nxt_uoff_t; -#define NXT_OFF_T_LEN NXT_INT32_T_LEN -#define NXT_OFF_T_HEXLEN NXT_INT32_T_HEXLEN -#define NXT_OFF_T_MAX NXT_INT32_T_MAX -#endif - - -#if (NXT_SIZE_T_SIZE == 8) -#define NXT_SIZE_T_LEN NXT_INT64_T_LEN -#define NXT_SIZE_T_HEXLEN NXT_INT64_T_HEXLEN -#define NXT_SIZE_T_MAX NXT_INT64_T_MAX - -#else -#define NXT_SIZE_T_LEN NXT_INT32_T_LEN -#define NXT_SIZE_T_HEXLEN NXT_INT32_T_HEXLEN -#define NXT_SIZE_T_MAX NXT_INT32_T_MAX -#endif - - -#if (NXT_TIME_T_SIZE == 8) -#define NXT_TIME_T_LEN NXT_INT64_T_LEN -#define NXT_TIME_T_HEXLEN NXT_INT64_T_HEXLEN -#define NXT_TIME_T_MAX NXT_INT64_T_MAX - -#else -#define NXT_TIME_T_LEN NXT_INT32_T_LEN -#define NXT_TIME_T_HEXLEN NXT_INT32_T_HEXLEN -#define NXT_TIME_T_MAX NXT_INT32_T_MAX -#endif - - -#endif /* _NXT_TYPES_H_INCLUDED_ */ diff --git a/src/nxt_unicode_lowcase.h b/src/nxt_unicode_lowcase.h deleted file mode 100644 index 2f25ab69..00000000 --- a/src/nxt_unicode_lowcase.h +++ /dev/null @@ -1,1043 +0,0 @@ - -/* - * 26 128-bytes blocks, 521 pointers. - * 14920 bytes on 32-bit platforms, 17000 bytes on 64-bit platforms. - */ - -#define NXT_UNICODE_MAX_LOWCASE 0x10427 - -#define NXT_UNICODE_BLOCK_SIZE 128 - - -static const uint32_t nxt_unicode_block_000[128] nxt_aligned(64) = { - 0x00000, 0x00001, 0x00002, 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, - 0x00008, 0x00009, 0x0000A, 0x0000B, 0x0000C, 0x0000D, 0x0000E, 0x0000F, - 0x00010, 0x00011, 0x00012, 0x00013, 0x00014, 0x00015, 0x00016, 0x00017, - 0x00018, 0x00019, 0x0001A, 0x0001B, 0x0001C, 0x0001D, 0x0001E, 0x0001F, - 0x00020, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027, - 0x00028, 0x00029, 0x0002A, 0x0002B, 0x0002C, 0x0002D, 0x0002E, 0x0002F, - 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, - 0x00038, 0x00039, 0x0003A, 0x0003B, 0x0003C, 0x0003D, 0x0003E, 0x0003F, - 0x00040, 0x00061, 0x00062, 0x00063, 0x00064, 0x00065, 0x00066, 0x00067, - 0x00068, 0x00069, 0x0006A, 0x0006B, 0x0006C, 0x0006D, 0x0006E, 0x0006F, - 0x00070, 0x00071, 0x00072, 0x00073, 0x00074, 0x00075, 0x00076, 0x00077, - 0x00078, 0x00079, 0x0007A, 0x0005B, 0x0005C, 0x0005D, 0x0005E, 0x0005F, - 0x00060, 0x00061, 0x00062, 0x00063, 0x00064, 0x00065, 0x00066, 0x00067, - 0x00068, 0x00069, 0x0006A, 0x0006B, 0x0006C, 0x0006D, 0x0006E, 0x0006F, - 0x00070, 0x00071, 0x00072, 0x00073, 0x00074, 0x00075, 0x00076, 0x00077, - 0x00078, 0x00079, 0x0007A, 0x0007B, 0x0007C, 0x0007D, 0x0007E, 0x0007F, -}; - - -static const uint32_t nxt_unicode_block_001[128] nxt_aligned(64) = { - 0x00080, 0x00081, 0x00082, 0x00083, 0x00084, 0x00085, 0x00086, 0x00087, - 0x00088, 0x00089, 0x0008A, 0x0008B, 0x0008C, 0x0008D, 0x0008E, 0x0008F, - 0x00090, 0x00091, 0x00092, 0x00093, 0x00094, 0x00095, 0x00096, 0x00097, - 0x00098, 0x00099, 0x0009A, 0x0009B, 0x0009C, 0x0009D, 0x0009E, 0x0009F, - 0x000A0, 0x000A1, 0x000A2, 0x000A3, 0x000A4, 0x000A5, 0x000A6, 0x000A7, - 0x000A8, 0x000A9, 0x000AA, 0x000AB, 0x000AC, 0x000AD, 0x000AE, 0x000AF, - 0x000B0, 0x000B1, 0x000B2, 0x000B3, 0x000B4, 0x003BC, 0x000B6, 0x000B7, - 0x000B8, 0x000B9, 0x000BA, 0x000BB, 0x000BC, 0x000BD, 0x000BE, 0x000BF, - 0x000E0, 0x000E1, 0x000E2, 0x000E3, 0x000E4, 0x000E5, 0x000E6, 0x000E7, - 0x000E8, 0x000E9, 0x000EA, 0x000EB, 0x000EC, 0x000ED, 0x000EE, 0x000EF, - 0x000F0, 0x000F1, 0x000F2, 0x000F3, 0x000F4, 0x000F5, 0x000F6, 0x000D7, - 0x000F8, 0x000F9, 0x000FA, 0x000FB, 0x000FC, 0x000FD, 0x000FE, 0x000DF, - 0x000E0, 0x000E1, 0x000E2, 0x000E3, 0x000E4, 0x000E5, 0x000E6, 0x000E7, - 0x000E8, 0x000E9, 0x000EA, 0x000EB, 0x000EC, 0x000ED, 0x000EE, 0x000EF, - 0x000F0, 0x000F1, 0x000F2, 0x000F3, 0x000F4, 0x000F5, 0x000F6, 0x000F7, - 0x000F8, 0x000F9, 0x000FA, 0x000FB, 0x000FC, 0x000FD, 0x000FE, 0x000FF, -}; - - -static const uint32_t nxt_unicode_block_002[128] nxt_aligned(64) = { - 0x00101, 0x00101, 0x00103, 0x00103, 0x00105, 0x00105, 0x00107, 0x00107, - 0x00109, 0x00109, 0x0010B, 0x0010B, 0x0010D, 0x0010D, 0x0010F, 0x0010F, - 0x00111, 0x00111, 0x00113, 0x00113, 0x00115, 0x00115, 0x00117, 0x00117, - 0x00119, 0x00119, 0x0011B, 0x0011B, 0x0011D, 0x0011D, 0x0011F, 0x0011F, - 0x00121, 0x00121, 0x00123, 0x00123, 0x00125, 0x00125, 0x00127, 0x00127, - 0x00129, 0x00129, 0x0012B, 0x0012B, 0x0012D, 0x0012D, 0x0012F, 0x0012F, - 0x00130, 0x00131, 0x00133, 0x00133, 0x00135, 0x00135, 0x00137, 0x00137, - 0x00138, 0x0013A, 0x0013A, 0x0013C, 0x0013C, 0x0013E, 0x0013E, 0x00140, - 0x00140, 0x00142, 0x00142, 0x00144, 0x00144, 0x00146, 0x00146, 0x00148, - 0x00148, 0x00149, 0x0014B, 0x0014B, 0x0014D, 0x0014D, 0x0014F, 0x0014F, - 0x00151, 0x00151, 0x00153, 0x00153, 0x00155, 0x00155, 0x00157, 0x00157, - 0x00159, 0x00159, 0x0015B, 0x0015B, 0x0015D, 0x0015D, 0x0015F, 0x0015F, - 0x00161, 0x00161, 0x00163, 0x00163, 0x00165, 0x00165, 0x00167, 0x00167, - 0x00169, 0x00169, 0x0016B, 0x0016B, 0x0016D, 0x0016D, 0x0016F, 0x0016F, - 0x00171, 0x00171, 0x00173, 0x00173, 0x00175, 0x00175, 0x00177, 0x00177, - 0x000FF, 0x0017A, 0x0017A, 0x0017C, 0x0017C, 0x0017E, 0x0017E, 0x00073, -}; - - -static const uint32_t nxt_unicode_block_003[128] nxt_aligned(64) = { - 0x00180, 0x00253, 0x00183, 0x00183, 0x00185, 0x00185, 0x00254, 0x00188, - 0x00188, 0x00256, 0x00257, 0x0018C, 0x0018C, 0x0018D, 0x001DD, 0x00259, - 0x0025B, 0x00192, 0x00192, 0x00260, 0x00263, 0x00195, 0x00269, 0x00268, - 0x00199, 0x00199, 0x0019A, 0x0019B, 0x0026F, 0x00272, 0x0019E, 0x00275, - 0x001A1, 0x001A1, 0x001A3, 0x001A3, 0x001A5, 0x001A5, 0x00280, 0x001A8, - 0x001A8, 0x00283, 0x001AA, 0x001AB, 0x001AD, 0x001AD, 0x00288, 0x001B0, - 0x001B0, 0x0028A, 0x0028B, 0x001B4, 0x001B4, 0x001B6, 0x001B6, 0x00292, - 0x001B9, 0x001B9, 0x001BA, 0x001BB, 0x001BD, 0x001BD, 0x001BE, 0x001BF, - 0x001C0, 0x001C1, 0x001C2, 0x001C3, 0x001C6, 0x001C6, 0x001C6, 0x001C9, - 0x001C9, 0x001C9, 0x001CC, 0x001CC, 0x001CC, 0x001CE, 0x001CE, 0x001D0, - 0x001D0, 0x001D2, 0x001D2, 0x001D4, 0x001D4, 0x001D6, 0x001D6, 0x001D8, - 0x001D8, 0x001DA, 0x001DA, 0x001DC, 0x001DC, 0x001DD, 0x001DF, 0x001DF, - 0x001E1, 0x001E1, 0x001E3, 0x001E3, 0x001E5, 0x001E5, 0x001E7, 0x001E7, - 0x001E9, 0x001E9, 0x001EB, 0x001EB, 0x001ED, 0x001ED, 0x001EF, 0x001EF, - 0x001F0, 0x001F3, 0x001F3, 0x001F3, 0x001F5, 0x001F5, 0x00195, 0x001BF, - 0x001F9, 0x001F9, 0x001FB, 0x001FB, 0x001FD, 0x001FD, 0x001FF, 0x001FF, -}; - - -static const uint32_t nxt_unicode_block_004[128] nxt_aligned(64) = { - 0x00201, 0x00201, 0x00203, 0x00203, 0x00205, 0x00205, 0x00207, 0x00207, - 0x00209, 0x00209, 0x0020B, 0x0020B, 0x0020D, 0x0020D, 0x0020F, 0x0020F, - 0x00211, 0x00211, 0x00213, 0x00213, 0x00215, 0x00215, 0x00217, 0x00217, - 0x00219, 0x00219, 0x0021B, 0x0021B, 0x0021D, 0x0021D, 0x0021F, 0x0021F, - 0x0019E, 0x00221, 0x00223, 0x00223, 0x00225, 0x00225, 0x00227, 0x00227, - 0x00229, 0x00229, 0x0022B, 0x0022B, 0x0022D, 0x0022D, 0x0022F, 0x0022F, - 0x00231, 0x00231, 0x00233, 0x00233, 0x00234, 0x00235, 0x00236, 0x00237, - 0x00238, 0x00239, 0x02C65, 0x0023C, 0x0023C, 0x0019A, 0x02C66, 0x0023F, - 0x00240, 0x00242, 0x00242, 0x00180, 0x00289, 0x0028C, 0x00247, 0x00247, - 0x00249, 0x00249, 0x0024B, 0x0024B, 0x0024D, 0x0024D, 0x0024F, 0x0024F, - 0x00250, 0x00251, 0x00252, 0x00253, 0x00254, 0x00255, 0x00256, 0x00257, - 0x00258, 0x00259, 0x0025A, 0x0025B, 0x0025C, 0x0025D, 0x0025E, 0x0025F, - 0x00260, 0x00261, 0x00262, 0x00263, 0x00264, 0x00265, 0x00266, 0x00267, - 0x00268, 0x00269, 0x0026A, 0x0026B, 0x0026C, 0x0026D, 0x0026E, 0x0026F, - 0x00270, 0x00271, 0x00272, 0x00273, 0x00274, 0x00275, 0x00276, 0x00277, - 0x00278, 0x00279, 0x0027A, 0x0027B, 0x0027C, 0x0027D, 0x0027E, 0x0027F, -}; - - -static const uint32_t nxt_unicode_block_006[128] nxt_aligned(64) = { - 0x00300, 0x00301, 0x00302, 0x00303, 0x00304, 0x00305, 0x00306, 0x00307, - 0x00308, 0x00309, 0x0030A, 0x0030B, 0x0030C, 0x0030D, 0x0030E, 0x0030F, - 0x00310, 0x00311, 0x00312, 0x00313, 0x00314, 0x00315, 0x00316, 0x00317, - 0x00318, 0x00319, 0x0031A, 0x0031B, 0x0031C, 0x0031D, 0x0031E, 0x0031F, - 0x00320, 0x00321, 0x00322, 0x00323, 0x00324, 0x00325, 0x00326, 0x00327, - 0x00328, 0x00329, 0x0032A, 0x0032B, 0x0032C, 0x0032D, 0x0032E, 0x0032F, - 0x00330, 0x00331, 0x00332, 0x00333, 0x00334, 0x00335, 0x00336, 0x00337, - 0x00338, 0x00339, 0x0033A, 0x0033B, 0x0033C, 0x0033D, 0x0033E, 0x0033F, - 0x00340, 0x00341, 0x00342, 0x00343, 0x00344, 0x003B9, 0x00346, 0x00347, - 0x00348, 0x00349, 0x0034A, 0x0034B, 0x0034C, 0x0034D, 0x0034E, 0x0034F, - 0x00350, 0x00351, 0x00352, 0x00353, 0x00354, 0x00355, 0x00356, 0x00357, - 0x00358, 0x00359, 0x0035A, 0x0035B, 0x0035C, 0x0035D, 0x0035E, 0x0035F, - 0x00360, 0x00361, 0x00362, 0x00363, 0x00364, 0x00365, 0x00366, 0x00367, - 0x00368, 0x00369, 0x0036A, 0x0036B, 0x0036C, 0x0036D, 0x0036E, 0x0036F, - 0x00371, 0x00371, 0x00373, 0x00373, 0x00374, 0x00375, 0x00377, 0x00377, - 0x00378, 0x00379, 0x0037A, 0x0037B, 0x0037C, 0x0037D, 0x0037E, 0x0037F, -}; - - -static const uint32_t nxt_unicode_block_007[128] nxt_aligned(64) = { - 0x00380, 0x00381, 0x00382, 0x00383, 0x00384, 0x00385, 0x003AC, 0x00387, - 0x003AD, 0x003AE, 0x003AF, 0x0038B, 0x003CC, 0x0038D, 0x003CD, 0x003CE, - 0x00390, 0x003B1, 0x003B2, 0x003B3, 0x003B4, 0x003B5, 0x003B6, 0x003B7, - 0x003B8, 0x003B9, 0x003BA, 0x003BB, 0x003BC, 0x003BD, 0x003BE, 0x003BF, - 0x003C0, 0x003C1, 0x003A2, 0x003C3, 0x003C4, 0x003C5, 0x003C6, 0x003C7, - 0x003C8, 0x003C9, 0x003CA, 0x003CB, 0x003AC, 0x003AD, 0x003AE, 0x003AF, - 0x003B0, 0x003B1, 0x003B2, 0x003B3, 0x003B4, 0x003B5, 0x003B6, 0x003B7, - 0x003B8, 0x003B9, 0x003BA, 0x003BB, 0x003BC, 0x003BD, 0x003BE, 0x003BF, - 0x003C0, 0x003C1, 0x003C3, 0x003C3, 0x003C4, 0x003C5, 0x003C6, 0x003C7, - 0x003C8, 0x003C9, 0x003CA, 0x003CB, 0x003CC, 0x003CD, 0x003CE, 0x003D7, - 0x003B2, 0x003B8, 0x003D2, 0x003D3, 0x003D4, 0x003C6, 0x003C0, 0x003D7, - 0x003D9, 0x003D9, 0x003DB, 0x003DB, 0x003DD, 0x003DD, 0x003DF, 0x003DF, - 0x003E1, 0x003E1, 0x003E3, 0x003E3, 0x003E5, 0x003E5, 0x003E7, 0x003E7, - 0x003E9, 0x003E9, 0x003EB, 0x003EB, 0x003ED, 0x003ED, 0x003EF, 0x003EF, - 0x003BA, 0x003C1, 0x003F2, 0x003F3, 0x003B8, 0x003B5, 0x003F6, 0x003F8, - 0x003F8, 0x003F2, 0x003FB, 0x003FB, 0x003FC, 0x0037B, 0x0037C, 0x0037D, -}; - - -static const uint32_t nxt_unicode_block_008[128] nxt_aligned(64) = { - 0x00450, 0x00451, 0x00452, 0x00453, 0x00454, 0x00455, 0x00456, 0x00457, - 0x00458, 0x00459, 0x0045A, 0x0045B, 0x0045C, 0x0045D, 0x0045E, 0x0045F, - 0x00430, 0x00431, 0x00432, 0x00433, 0x00434, 0x00435, 0x00436, 0x00437, - 0x00438, 0x00439, 0x0043A, 0x0043B, 0x0043C, 0x0043D, 0x0043E, 0x0043F, - 0x00440, 0x00441, 0x00442, 0x00443, 0x00444, 0x00445, 0x00446, 0x00447, - 0x00448, 0x00449, 0x0044A, 0x0044B, 0x0044C, 0x0044D, 0x0044E, 0x0044F, - 0x00430, 0x00431, 0x00432, 0x00433, 0x00434, 0x00435, 0x00436, 0x00437, - 0x00438, 0x00439, 0x0043A, 0x0043B, 0x0043C, 0x0043D, 0x0043E, 0x0043F, - 0x00440, 0x00441, 0x00442, 0x00443, 0x00444, 0x00445, 0x00446, 0x00447, - 0x00448, 0x00449, 0x0044A, 0x0044B, 0x0044C, 0x0044D, 0x0044E, 0x0044F, - 0x00450, 0x00451, 0x00452, 0x00453, 0x00454, 0x00455, 0x00456, 0x00457, - 0x00458, 0x00459, 0x0045A, 0x0045B, 0x0045C, 0x0045D, 0x0045E, 0x0045F, - 0x00461, 0x00461, 0x00463, 0x00463, 0x00465, 0x00465, 0x00467, 0x00467, - 0x00469, 0x00469, 0x0046B, 0x0046B, 0x0046D, 0x0046D, 0x0046F, 0x0046F, - 0x00471, 0x00471, 0x00473, 0x00473, 0x00475, 0x00475, 0x00477, 0x00477, - 0x00479, 0x00479, 0x0047B, 0x0047B, 0x0047D, 0x0047D, 0x0047F, 0x0047F, -}; - - -static const uint32_t nxt_unicode_block_009[128] nxt_aligned(64) = { - 0x00481, 0x00481, 0x00482, 0x00483, 0x00484, 0x00485, 0x00486, 0x00487, - 0x00488, 0x00489, 0x0048B, 0x0048B, 0x0048D, 0x0048D, 0x0048F, 0x0048F, - 0x00491, 0x00491, 0x00493, 0x00493, 0x00495, 0x00495, 0x00497, 0x00497, - 0x00499, 0x00499, 0x0049B, 0x0049B, 0x0049D, 0x0049D, 0x0049F, 0x0049F, - 0x004A1, 0x004A1, 0x004A3, 0x004A3, 0x004A5, 0x004A5, 0x004A7, 0x004A7, - 0x004A9, 0x004A9, 0x004AB, 0x004AB, 0x004AD, 0x004AD, 0x004AF, 0x004AF, - 0x004B1, 0x004B1, 0x004B3, 0x004B3, 0x004B5, 0x004B5, 0x004B7, 0x004B7, - 0x004B9, 0x004B9, 0x004BB, 0x004BB, 0x004BD, 0x004BD, 0x004BF, 0x004BF, - 0x004CF, 0x004C2, 0x004C2, 0x004C4, 0x004C4, 0x004C6, 0x004C6, 0x004C8, - 0x004C8, 0x004CA, 0x004CA, 0x004CC, 0x004CC, 0x004CE, 0x004CE, 0x004CF, - 0x004D1, 0x004D1, 0x004D3, 0x004D3, 0x004D5, 0x004D5, 0x004D7, 0x004D7, - 0x004D9, 0x004D9, 0x004DB, 0x004DB, 0x004DD, 0x004DD, 0x004DF, 0x004DF, - 0x004E1, 0x004E1, 0x004E3, 0x004E3, 0x004E5, 0x004E5, 0x004E7, 0x004E7, - 0x004E9, 0x004E9, 0x004EB, 0x004EB, 0x004ED, 0x004ED, 0x004EF, 0x004EF, - 0x004F1, 0x004F1, 0x004F3, 0x004F3, 0x004F5, 0x004F5, 0x004F7, 0x004F7, - 0x004F9, 0x004F9, 0x004FB, 0x004FB, 0x004FD, 0x004FD, 0x004FF, 0x004FF, -}; - - -static const uint32_t nxt_unicode_block_00a[128] nxt_aligned(64) = { - 0x00501, 0x00501, 0x00503, 0x00503, 0x00505, 0x00505, 0x00507, 0x00507, - 0x00509, 0x00509, 0x0050B, 0x0050B, 0x0050D, 0x0050D, 0x0050F, 0x0050F, - 0x00511, 0x00511, 0x00513, 0x00513, 0x00515, 0x00515, 0x00517, 0x00517, - 0x00519, 0x00519, 0x0051B, 0x0051B, 0x0051D, 0x0051D, 0x0051F, 0x0051F, - 0x00521, 0x00521, 0x00523, 0x00523, 0x00525, 0x00525, 0x00527, 0x00527, - 0x00528, 0x00529, 0x0052A, 0x0052B, 0x0052C, 0x0052D, 0x0052E, 0x0052F, - 0x00530, 0x00561, 0x00562, 0x00563, 0x00564, 0x00565, 0x00566, 0x00567, - 0x00568, 0x00569, 0x0056A, 0x0056B, 0x0056C, 0x0056D, 0x0056E, 0x0056F, - 0x00570, 0x00571, 0x00572, 0x00573, 0x00574, 0x00575, 0x00576, 0x00577, - 0x00578, 0x00579, 0x0057A, 0x0057B, 0x0057C, 0x0057D, 0x0057E, 0x0057F, - 0x00580, 0x00581, 0x00582, 0x00583, 0x00584, 0x00585, 0x00586, 0x00557, - 0x00558, 0x00559, 0x0055A, 0x0055B, 0x0055C, 0x0055D, 0x0055E, 0x0055F, - 0x00560, 0x00561, 0x00562, 0x00563, 0x00564, 0x00565, 0x00566, 0x00567, - 0x00568, 0x00569, 0x0056A, 0x0056B, 0x0056C, 0x0056D, 0x0056E, 0x0056F, - 0x00570, 0x00571, 0x00572, 0x00573, 0x00574, 0x00575, 0x00576, 0x00577, - 0x00578, 0x00579, 0x0057A, 0x0057B, 0x0057C, 0x0057D, 0x0057E, 0x0057F, -}; - - -static const uint32_t nxt_unicode_block_021[128] nxt_aligned(64) = { - 0x01080, 0x01081, 0x01082, 0x01083, 0x01084, 0x01085, 0x01086, 0x01087, - 0x01088, 0x01089, 0x0108A, 0x0108B, 0x0108C, 0x0108D, 0x0108E, 0x0108F, - 0x01090, 0x01091, 0x01092, 0x01093, 0x01094, 0x01095, 0x01096, 0x01097, - 0x01098, 0x01099, 0x0109A, 0x0109B, 0x0109C, 0x0109D, 0x0109E, 0x0109F, - 0x02D00, 0x02D01, 0x02D02, 0x02D03, 0x02D04, 0x02D05, 0x02D06, 0x02D07, - 0x02D08, 0x02D09, 0x02D0A, 0x02D0B, 0x02D0C, 0x02D0D, 0x02D0E, 0x02D0F, - 0x02D10, 0x02D11, 0x02D12, 0x02D13, 0x02D14, 0x02D15, 0x02D16, 0x02D17, - 0x02D18, 0x02D19, 0x02D1A, 0x02D1B, 0x02D1C, 0x02D1D, 0x02D1E, 0x02D1F, - 0x02D20, 0x02D21, 0x02D22, 0x02D23, 0x02D24, 0x02D25, 0x010C6, 0x02D27, - 0x010C8, 0x010C9, 0x010CA, 0x010CB, 0x010CC, 0x02D2D, 0x010CE, 0x010CF, - 0x010D0, 0x010D1, 0x010D2, 0x010D3, 0x010D4, 0x010D5, 0x010D6, 0x010D7, - 0x010D8, 0x010D9, 0x010DA, 0x010DB, 0x010DC, 0x010DD, 0x010DE, 0x010DF, - 0x010E0, 0x010E1, 0x010E2, 0x010E3, 0x010E4, 0x010E5, 0x010E6, 0x010E7, - 0x010E8, 0x010E9, 0x010EA, 0x010EB, 0x010EC, 0x010ED, 0x010EE, 0x010EF, - 0x010F0, 0x010F1, 0x010F2, 0x010F3, 0x010F4, 0x010F5, 0x010F6, 0x010F7, - 0x010F8, 0x010F9, 0x010FA, 0x010FB, 0x010FC, 0x010FD, 0x010FE, 0x010FF, -}; - - -static const uint32_t nxt_unicode_block_03c[128] nxt_aligned(64) = { - 0x01E01, 0x01E01, 0x01E03, 0x01E03, 0x01E05, 0x01E05, 0x01E07, 0x01E07, - 0x01E09, 0x01E09, 0x01E0B, 0x01E0B, 0x01E0D, 0x01E0D, 0x01E0F, 0x01E0F, - 0x01E11, 0x01E11, 0x01E13, 0x01E13, 0x01E15, 0x01E15, 0x01E17, 0x01E17, - 0x01E19, 0x01E19, 0x01E1B, 0x01E1B, 0x01E1D, 0x01E1D, 0x01E1F, 0x01E1F, - 0x01E21, 0x01E21, 0x01E23, 0x01E23, 0x01E25, 0x01E25, 0x01E27, 0x01E27, - 0x01E29, 0x01E29, 0x01E2B, 0x01E2B, 0x01E2D, 0x01E2D, 0x01E2F, 0x01E2F, - 0x01E31, 0x01E31, 0x01E33, 0x01E33, 0x01E35, 0x01E35, 0x01E37, 0x01E37, - 0x01E39, 0x01E39, 0x01E3B, 0x01E3B, 0x01E3D, 0x01E3D, 0x01E3F, 0x01E3F, - 0x01E41, 0x01E41, 0x01E43, 0x01E43, 0x01E45, 0x01E45, 0x01E47, 0x01E47, - 0x01E49, 0x01E49, 0x01E4B, 0x01E4B, 0x01E4D, 0x01E4D, 0x01E4F, 0x01E4F, - 0x01E51, 0x01E51, 0x01E53, 0x01E53, 0x01E55, 0x01E55, 0x01E57, 0x01E57, - 0x01E59, 0x01E59, 0x01E5B, 0x01E5B, 0x01E5D, 0x01E5D, 0x01E5F, 0x01E5F, - 0x01E61, 0x01E61, 0x01E63, 0x01E63, 0x01E65, 0x01E65, 0x01E67, 0x01E67, - 0x01E69, 0x01E69, 0x01E6B, 0x01E6B, 0x01E6D, 0x01E6D, 0x01E6F, 0x01E6F, - 0x01E71, 0x01E71, 0x01E73, 0x01E73, 0x01E75, 0x01E75, 0x01E77, 0x01E77, - 0x01E79, 0x01E79, 0x01E7B, 0x01E7B, 0x01E7D, 0x01E7D, 0x01E7F, 0x01E7F, -}; - - -static const uint32_t nxt_unicode_block_03d[128] nxt_aligned(64) = { - 0x01E81, 0x01E81, 0x01E83, 0x01E83, 0x01E85, 0x01E85, 0x01E87, 0x01E87, - 0x01E89, 0x01E89, 0x01E8B, 0x01E8B, 0x01E8D, 0x01E8D, 0x01E8F, 0x01E8F, - 0x01E91, 0x01E91, 0x01E93, 0x01E93, 0x01E95, 0x01E95, 0x01E96, 0x01E97, - 0x01E98, 0x01E99, 0x01E9A, 0x01E61, 0x01E9C, 0x01E9D, 0x000DF, 0x01E9F, - 0x01EA1, 0x01EA1, 0x01EA3, 0x01EA3, 0x01EA5, 0x01EA5, 0x01EA7, 0x01EA7, - 0x01EA9, 0x01EA9, 0x01EAB, 0x01EAB, 0x01EAD, 0x01EAD, 0x01EAF, 0x01EAF, - 0x01EB1, 0x01EB1, 0x01EB3, 0x01EB3, 0x01EB5, 0x01EB5, 0x01EB7, 0x01EB7, - 0x01EB9, 0x01EB9, 0x01EBB, 0x01EBB, 0x01EBD, 0x01EBD, 0x01EBF, 0x01EBF, - 0x01EC1, 0x01EC1, 0x01EC3, 0x01EC3, 0x01EC5, 0x01EC5, 0x01EC7, 0x01EC7, - 0x01EC9, 0x01EC9, 0x01ECB, 0x01ECB, 0x01ECD, 0x01ECD, 0x01ECF, 0x01ECF, - 0x01ED1, 0x01ED1, 0x01ED3, 0x01ED3, 0x01ED5, 0x01ED5, 0x01ED7, 0x01ED7, - 0x01ED9, 0x01ED9, 0x01EDB, 0x01EDB, 0x01EDD, 0x01EDD, 0x01EDF, 0x01EDF, - 0x01EE1, 0x01EE1, 0x01EE3, 0x01EE3, 0x01EE5, 0x01EE5, 0x01EE7, 0x01EE7, - 0x01EE9, 0x01EE9, 0x01EEB, 0x01EEB, 0x01EED, 0x01EED, 0x01EEF, 0x01EEF, - 0x01EF1, 0x01EF1, 0x01EF3, 0x01EF3, 0x01EF5, 0x01EF5, 0x01EF7, 0x01EF7, - 0x01EF9, 0x01EF9, 0x01EFB, 0x01EFB, 0x01EFD, 0x01EFD, 0x01EFF, 0x01EFF, -}; - - -static const uint32_t nxt_unicode_block_03e[128] nxt_aligned(64) = { - 0x01F00, 0x01F01, 0x01F02, 0x01F03, 0x01F04, 0x01F05, 0x01F06, 0x01F07, - 0x01F00, 0x01F01, 0x01F02, 0x01F03, 0x01F04, 0x01F05, 0x01F06, 0x01F07, - 0x01F10, 0x01F11, 0x01F12, 0x01F13, 0x01F14, 0x01F15, 0x01F16, 0x01F17, - 0x01F10, 0x01F11, 0x01F12, 0x01F13, 0x01F14, 0x01F15, 0x01F1E, 0x01F1F, - 0x01F20, 0x01F21, 0x01F22, 0x01F23, 0x01F24, 0x01F25, 0x01F26, 0x01F27, - 0x01F20, 0x01F21, 0x01F22, 0x01F23, 0x01F24, 0x01F25, 0x01F26, 0x01F27, - 0x01F30, 0x01F31, 0x01F32, 0x01F33, 0x01F34, 0x01F35, 0x01F36, 0x01F37, - 0x01F30, 0x01F31, 0x01F32, 0x01F33, 0x01F34, 0x01F35, 0x01F36, 0x01F37, - 0x01F40, 0x01F41, 0x01F42, 0x01F43, 0x01F44, 0x01F45, 0x01F46, 0x01F47, - 0x01F40, 0x01F41, 0x01F42, 0x01F43, 0x01F44, 0x01F45, 0x01F4E, 0x01F4F, - 0x01F50, 0x01F51, 0x01F52, 0x01F53, 0x01F54, 0x01F55, 0x01F56, 0x01F57, - 0x01F58, 0x01F51, 0x01F5A, 0x01F53, 0x01F5C, 0x01F55, 0x01F5E, 0x01F57, - 0x01F60, 0x01F61, 0x01F62, 0x01F63, 0x01F64, 0x01F65, 0x01F66, 0x01F67, - 0x01F60, 0x01F61, 0x01F62, 0x01F63, 0x01F64, 0x01F65, 0x01F66, 0x01F67, - 0x01F70, 0x01F71, 0x01F72, 0x01F73, 0x01F74, 0x01F75, 0x01F76, 0x01F77, - 0x01F78, 0x01F79, 0x01F7A, 0x01F7B, 0x01F7C, 0x01F7D, 0x01F7E, 0x01F7F, -}; - - -static const uint32_t nxt_unicode_block_03f[128] nxt_aligned(64) = { - 0x01F80, 0x01F81, 0x01F82, 0x01F83, 0x01F84, 0x01F85, 0x01F86, 0x01F87, - 0x01F80, 0x01F81, 0x01F82, 0x01F83, 0x01F84, 0x01F85, 0x01F86, 0x01F87, - 0x01F90, 0x01F91, 0x01F92, 0x01F93, 0x01F94, 0x01F95, 0x01F96, 0x01F97, - 0x01F90, 0x01F91, 0x01F92, 0x01F93, 0x01F94, 0x01F95, 0x01F96, 0x01F97, - 0x01FA0, 0x01FA1, 0x01FA2, 0x01FA3, 0x01FA4, 0x01FA5, 0x01FA6, 0x01FA7, - 0x01FA0, 0x01FA1, 0x01FA2, 0x01FA3, 0x01FA4, 0x01FA5, 0x01FA6, 0x01FA7, - 0x01FB0, 0x01FB1, 0x01FB2, 0x01FB3, 0x01FB4, 0x01FB5, 0x01FB6, 0x01FB7, - 0x01FB0, 0x01FB1, 0x01F70, 0x01F71, 0x01FB3, 0x01FBD, 0x003B9, 0x01FBF, - 0x01FC0, 0x01FC1, 0x01FC2, 0x01FC3, 0x01FC4, 0x01FC5, 0x01FC6, 0x01FC7, - 0x01F72, 0x01F73, 0x01F74, 0x01F75, 0x01FC3, 0x01FCD, 0x01FCE, 0x01FCF, - 0x01FD0, 0x01FD1, 0x01FD2, 0x01FD3, 0x01FD4, 0x01FD5, 0x01FD6, 0x01FD7, - 0x01FD0, 0x01FD1, 0x01F76, 0x01F77, 0x01FDC, 0x01FDD, 0x01FDE, 0x01FDF, - 0x01FE0, 0x01FE1, 0x01FE2, 0x01FE3, 0x01FE4, 0x01FE5, 0x01FE6, 0x01FE7, - 0x01FE0, 0x01FE1, 0x01F7A, 0x01F7B, 0x01FE5, 0x01FED, 0x01FEE, 0x01FEF, - 0x01FF0, 0x01FF1, 0x01FF2, 0x01FF3, 0x01FF4, 0x01FF5, 0x01FF6, 0x01FF7, - 0x01F78, 0x01F79, 0x01F7C, 0x01F7D, 0x01FF3, 0x01FFD, 0x01FFE, 0x01FFF, -}; - - -static const uint32_t nxt_unicode_block_042[128] nxt_aligned(64) = { - 0x02100, 0x02101, 0x02102, 0x02103, 0x02104, 0x02105, 0x02106, 0x02107, - 0x02108, 0x02109, 0x0210A, 0x0210B, 0x0210C, 0x0210D, 0x0210E, 0x0210F, - 0x02110, 0x02111, 0x02112, 0x02113, 0x02114, 0x02115, 0x02116, 0x02117, - 0x02118, 0x02119, 0x0211A, 0x0211B, 0x0211C, 0x0211D, 0x0211E, 0x0211F, - 0x02120, 0x02121, 0x02122, 0x02123, 0x02124, 0x02125, 0x003C9, 0x02127, - 0x02128, 0x02129, 0x0006B, 0x000E5, 0x0212C, 0x0212D, 0x0212E, 0x0212F, - 0x02130, 0x02131, 0x0214E, 0x02133, 0x02134, 0x02135, 0x02136, 0x02137, - 0x02138, 0x02139, 0x0213A, 0x0213B, 0x0213C, 0x0213D, 0x0213E, 0x0213F, - 0x02140, 0x02141, 0x02142, 0x02143, 0x02144, 0x02145, 0x02146, 0x02147, - 0x02148, 0x02149, 0x0214A, 0x0214B, 0x0214C, 0x0214D, 0x0214E, 0x0214F, - 0x02150, 0x02151, 0x02152, 0x02153, 0x02154, 0x02155, 0x02156, 0x02157, - 0x02158, 0x02159, 0x0215A, 0x0215B, 0x0215C, 0x0215D, 0x0215E, 0x0215F, - 0x02170, 0x02171, 0x02172, 0x02173, 0x02174, 0x02175, 0x02176, 0x02177, - 0x02178, 0x02179, 0x0217A, 0x0217B, 0x0217C, 0x0217D, 0x0217E, 0x0217F, - 0x02170, 0x02171, 0x02172, 0x02173, 0x02174, 0x02175, 0x02176, 0x02177, - 0x02178, 0x02179, 0x0217A, 0x0217B, 0x0217C, 0x0217D, 0x0217E, 0x0217F, -}; - - -static const uint32_t nxt_unicode_block_043[128] nxt_aligned(64) = { - 0x02180, 0x02181, 0x02182, 0x02184, 0x02184, 0x02185, 0x02186, 0x02187, - 0x02188, 0x02189, 0x0218A, 0x0218B, 0x0218C, 0x0218D, 0x0218E, 0x0218F, - 0x02190, 0x02191, 0x02192, 0x02193, 0x02194, 0x02195, 0x02196, 0x02197, - 0x02198, 0x02199, 0x0219A, 0x0219B, 0x0219C, 0x0219D, 0x0219E, 0x0219F, - 0x021A0, 0x021A1, 0x021A2, 0x021A3, 0x021A4, 0x021A5, 0x021A6, 0x021A7, - 0x021A8, 0x021A9, 0x021AA, 0x021AB, 0x021AC, 0x021AD, 0x021AE, 0x021AF, - 0x021B0, 0x021B1, 0x021B2, 0x021B3, 0x021B4, 0x021B5, 0x021B6, 0x021B7, - 0x021B8, 0x021B9, 0x021BA, 0x021BB, 0x021BC, 0x021BD, 0x021BE, 0x021BF, - 0x021C0, 0x021C1, 0x021C2, 0x021C3, 0x021C4, 0x021C5, 0x021C6, 0x021C7, - 0x021C8, 0x021C9, 0x021CA, 0x021CB, 0x021CC, 0x021CD, 0x021CE, 0x021CF, - 0x021D0, 0x021D1, 0x021D2, 0x021D3, 0x021D4, 0x021D5, 0x021D6, 0x021D7, - 0x021D8, 0x021D9, 0x021DA, 0x021DB, 0x021DC, 0x021DD, 0x021DE, 0x021DF, - 0x021E0, 0x021E1, 0x021E2, 0x021E3, 0x021E4, 0x021E5, 0x021E6, 0x021E7, - 0x021E8, 0x021E9, 0x021EA, 0x021EB, 0x021EC, 0x021ED, 0x021EE, 0x021EF, - 0x021F0, 0x021F1, 0x021F2, 0x021F3, 0x021F4, 0x021F5, 0x021F6, 0x021F7, - 0x021F8, 0x021F9, 0x021FA, 0x021FB, 0x021FC, 0x021FD, 0x021FE, 0x021FF, -}; - - -static const uint32_t nxt_unicode_block_049[128] nxt_aligned(64) = { - 0x02480, 0x02481, 0x02482, 0x02483, 0x02484, 0x02485, 0x02486, 0x02487, - 0x02488, 0x02489, 0x0248A, 0x0248B, 0x0248C, 0x0248D, 0x0248E, 0x0248F, - 0x02490, 0x02491, 0x02492, 0x02493, 0x02494, 0x02495, 0x02496, 0x02497, - 0x02498, 0x02499, 0x0249A, 0x0249B, 0x0249C, 0x0249D, 0x0249E, 0x0249F, - 0x024A0, 0x024A1, 0x024A2, 0x024A3, 0x024A4, 0x024A5, 0x024A6, 0x024A7, - 0x024A8, 0x024A9, 0x024AA, 0x024AB, 0x024AC, 0x024AD, 0x024AE, 0x024AF, - 0x024B0, 0x024B1, 0x024B2, 0x024B3, 0x024B4, 0x024B5, 0x024D0, 0x024D1, - 0x024D2, 0x024D3, 0x024D4, 0x024D5, 0x024D6, 0x024D7, 0x024D8, 0x024D9, - 0x024DA, 0x024DB, 0x024DC, 0x024DD, 0x024DE, 0x024DF, 0x024E0, 0x024E1, - 0x024E2, 0x024E3, 0x024E4, 0x024E5, 0x024E6, 0x024E7, 0x024E8, 0x024E9, - 0x024D0, 0x024D1, 0x024D2, 0x024D3, 0x024D4, 0x024D5, 0x024D6, 0x024D7, - 0x024D8, 0x024D9, 0x024DA, 0x024DB, 0x024DC, 0x024DD, 0x024DE, 0x024DF, - 0x024E0, 0x024E1, 0x024E2, 0x024E3, 0x024E4, 0x024E5, 0x024E6, 0x024E7, - 0x024E8, 0x024E9, 0x024EA, 0x024EB, 0x024EC, 0x024ED, 0x024EE, 0x024EF, - 0x024F0, 0x024F1, 0x024F2, 0x024F3, 0x024F4, 0x024F5, 0x024F6, 0x024F7, - 0x024F8, 0x024F9, 0x024FA, 0x024FB, 0x024FC, 0x024FD, 0x024FE, 0x024FF, -}; - - -static const uint32_t nxt_unicode_block_058[128] nxt_aligned(64) = { - 0x02C30, 0x02C31, 0x02C32, 0x02C33, 0x02C34, 0x02C35, 0x02C36, 0x02C37, - 0x02C38, 0x02C39, 0x02C3A, 0x02C3B, 0x02C3C, 0x02C3D, 0x02C3E, 0x02C3F, - 0x02C40, 0x02C41, 0x02C42, 0x02C43, 0x02C44, 0x02C45, 0x02C46, 0x02C47, - 0x02C48, 0x02C49, 0x02C4A, 0x02C4B, 0x02C4C, 0x02C4D, 0x02C4E, 0x02C4F, - 0x02C50, 0x02C51, 0x02C52, 0x02C53, 0x02C54, 0x02C55, 0x02C56, 0x02C57, - 0x02C58, 0x02C59, 0x02C5A, 0x02C5B, 0x02C5C, 0x02C5D, 0x02C5E, 0x02C2F, - 0x02C30, 0x02C31, 0x02C32, 0x02C33, 0x02C34, 0x02C35, 0x02C36, 0x02C37, - 0x02C38, 0x02C39, 0x02C3A, 0x02C3B, 0x02C3C, 0x02C3D, 0x02C3E, 0x02C3F, - 0x02C40, 0x02C41, 0x02C42, 0x02C43, 0x02C44, 0x02C45, 0x02C46, 0x02C47, - 0x02C48, 0x02C49, 0x02C4A, 0x02C4B, 0x02C4C, 0x02C4D, 0x02C4E, 0x02C4F, - 0x02C50, 0x02C51, 0x02C52, 0x02C53, 0x02C54, 0x02C55, 0x02C56, 0x02C57, - 0x02C58, 0x02C59, 0x02C5A, 0x02C5B, 0x02C5C, 0x02C5D, 0x02C5E, 0x02C5F, - 0x02C61, 0x02C61, 0x0026B, 0x01D7D, 0x0027D, 0x02C65, 0x02C66, 0x02C68, - 0x02C68, 0x02C6A, 0x02C6A, 0x02C6C, 0x02C6C, 0x00251, 0x00271, 0x00250, - 0x00252, 0x02C71, 0x02C73, 0x02C73, 0x02C74, 0x02C76, 0x02C76, 0x02C77, - 0x02C78, 0x02C79, 0x02C7A, 0x02C7B, 0x02C7C, 0x02C7D, 0x0023F, 0x00240, -}; - - -static const uint32_t nxt_unicode_block_059[128] nxt_aligned(64) = { - 0x02C81, 0x02C81, 0x02C83, 0x02C83, 0x02C85, 0x02C85, 0x02C87, 0x02C87, - 0x02C89, 0x02C89, 0x02C8B, 0x02C8B, 0x02C8D, 0x02C8D, 0x02C8F, 0x02C8F, - 0x02C91, 0x02C91, 0x02C93, 0x02C93, 0x02C95, 0x02C95, 0x02C97, 0x02C97, - 0x02C99, 0x02C99, 0x02C9B, 0x02C9B, 0x02C9D, 0x02C9D, 0x02C9F, 0x02C9F, - 0x02CA1, 0x02CA1, 0x02CA3, 0x02CA3, 0x02CA5, 0x02CA5, 0x02CA7, 0x02CA7, - 0x02CA9, 0x02CA9, 0x02CAB, 0x02CAB, 0x02CAD, 0x02CAD, 0x02CAF, 0x02CAF, - 0x02CB1, 0x02CB1, 0x02CB3, 0x02CB3, 0x02CB5, 0x02CB5, 0x02CB7, 0x02CB7, - 0x02CB9, 0x02CB9, 0x02CBB, 0x02CBB, 0x02CBD, 0x02CBD, 0x02CBF, 0x02CBF, - 0x02CC1, 0x02CC1, 0x02CC3, 0x02CC3, 0x02CC5, 0x02CC5, 0x02CC7, 0x02CC7, - 0x02CC9, 0x02CC9, 0x02CCB, 0x02CCB, 0x02CCD, 0x02CCD, 0x02CCF, 0x02CCF, - 0x02CD1, 0x02CD1, 0x02CD3, 0x02CD3, 0x02CD5, 0x02CD5, 0x02CD7, 0x02CD7, - 0x02CD9, 0x02CD9, 0x02CDB, 0x02CDB, 0x02CDD, 0x02CDD, 0x02CDF, 0x02CDF, - 0x02CE1, 0x02CE1, 0x02CE3, 0x02CE3, 0x02CE4, 0x02CE5, 0x02CE6, 0x02CE7, - 0x02CE8, 0x02CE9, 0x02CEA, 0x02CEC, 0x02CEC, 0x02CEE, 0x02CEE, 0x02CEF, - 0x02CF0, 0x02CF1, 0x02CF3, 0x02CF3, 0x02CF4, 0x02CF5, 0x02CF6, 0x02CF7, - 0x02CF8, 0x02CF9, 0x02CFA, 0x02CFB, 0x02CFC, 0x02CFD, 0x02CFE, 0x02CFF, -}; - - -static const uint32_t nxt_unicode_block_14c[128] nxt_aligned(64) = { - 0x0A600, 0x0A601, 0x0A602, 0x0A603, 0x0A604, 0x0A605, 0x0A606, 0x0A607, - 0x0A608, 0x0A609, 0x0A60A, 0x0A60B, 0x0A60C, 0x0A60D, 0x0A60E, 0x0A60F, - 0x0A610, 0x0A611, 0x0A612, 0x0A613, 0x0A614, 0x0A615, 0x0A616, 0x0A617, - 0x0A618, 0x0A619, 0x0A61A, 0x0A61B, 0x0A61C, 0x0A61D, 0x0A61E, 0x0A61F, - 0x0A620, 0x0A621, 0x0A622, 0x0A623, 0x0A624, 0x0A625, 0x0A626, 0x0A627, - 0x0A628, 0x0A629, 0x0A62A, 0x0A62B, 0x0A62C, 0x0A62D, 0x0A62E, 0x0A62F, - 0x0A630, 0x0A631, 0x0A632, 0x0A633, 0x0A634, 0x0A635, 0x0A636, 0x0A637, - 0x0A638, 0x0A639, 0x0A63A, 0x0A63B, 0x0A63C, 0x0A63D, 0x0A63E, 0x0A63F, - 0x0A641, 0x0A641, 0x0A643, 0x0A643, 0x0A645, 0x0A645, 0x0A647, 0x0A647, - 0x0A649, 0x0A649, 0x0A64B, 0x0A64B, 0x0A64D, 0x0A64D, 0x0A64F, 0x0A64F, - 0x0A651, 0x0A651, 0x0A653, 0x0A653, 0x0A655, 0x0A655, 0x0A657, 0x0A657, - 0x0A659, 0x0A659, 0x0A65B, 0x0A65B, 0x0A65D, 0x0A65D, 0x0A65F, 0x0A65F, - 0x0A661, 0x0A661, 0x0A663, 0x0A663, 0x0A665, 0x0A665, 0x0A667, 0x0A667, - 0x0A669, 0x0A669, 0x0A66B, 0x0A66B, 0x0A66D, 0x0A66D, 0x0A66E, 0x0A66F, - 0x0A670, 0x0A671, 0x0A672, 0x0A673, 0x0A674, 0x0A675, 0x0A676, 0x0A677, - 0x0A678, 0x0A679, 0x0A67A, 0x0A67B, 0x0A67C, 0x0A67D, 0x0A67E, 0x0A67F, -}; - - -static const uint32_t nxt_unicode_block_14d[128] nxt_aligned(64) = { - 0x0A681, 0x0A681, 0x0A683, 0x0A683, 0x0A685, 0x0A685, 0x0A687, 0x0A687, - 0x0A689, 0x0A689, 0x0A68B, 0x0A68B, 0x0A68D, 0x0A68D, 0x0A68F, 0x0A68F, - 0x0A691, 0x0A691, 0x0A693, 0x0A693, 0x0A695, 0x0A695, 0x0A697, 0x0A697, - 0x0A698, 0x0A699, 0x0A69A, 0x0A69B, 0x0A69C, 0x0A69D, 0x0A69E, 0x0A69F, - 0x0A6A0, 0x0A6A1, 0x0A6A2, 0x0A6A3, 0x0A6A4, 0x0A6A5, 0x0A6A6, 0x0A6A7, - 0x0A6A8, 0x0A6A9, 0x0A6AA, 0x0A6AB, 0x0A6AC, 0x0A6AD, 0x0A6AE, 0x0A6AF, - 0x0A6B0, 0x0A6B1, 0x0A6B2, 0x0A6B3, 0x0A6B4, 0x0A6B5, 0x0A6B6, 0x0A6B7, - 0x0A6B8, 0x0A6B9, 0x0A6BA, 0x0A6BB, 0x0A6BC, 0x0A6BD, 0x0A6BE, 0x0A6BF, - 0x0A6C0, 0x0A6C1, 0x0A6C2, 0x0A6C3, 0x0A6C4, 0x0A6C5, 0x0A6C6, 0x0A6C7, - 0x0A6C8, 0x0A6C9, 0x0A6CA, 0x0A6CB, 0x0A6CC, 0x0A6CD, 0x0A6CE, 0x0A6CF, - 0x0A6D0, 0x0A6D1, 0x0A6D2, 0x0A6D3, 0x0A6D4, 0x0A6D5, 0x0A6D6, 0x0A6D7, - 0x0A6D8, 0x0A6D9, 0x0A6DA, 0x0A6DB, 0x0A6DC, 0x0A6DD, 0x0A6DE, 0x0A6DF, - 0x0A6E0, 0x0A6E1, 0x0A6E2, 0x0A6E3, 0x0A6E4, 0x0A6E5, 0x0A6E6, 0x0A6E7, - 0x0A6E8, 0x0A6E9, 0x0A6EA, 0x0A6EB, 0x0A6EC, 0x0A6ED, 0x0A6EE, 0x0A6EF, - 0x0A6F0, 0x0A6F1, 0x0A6F2, 0x0A6F3, 0x0A6F4, 0x0A6F5, 0x0A6F6, 0x0A6F7, - 0x0A6F8, 0x0A6F9, 0x0A6FA, 0x0A6FB, 0x0A6FC, 0x0A6FD, 0x0A6FE, 0x0A6FF, -}; - - -static const uint32_t nxt_unicode_block_14e[128] nxt_aligned(64) = { - 0x0A700, 0x0A701, 0x0A702, 0x0A703, 0x0A704, 0x0A705, 0x0A706, 0x0A707, - 0x0A708, 0x0A709, 0x0A70A, 0x0A70B, 0x0A70C, 0x0A70D, 0x0A70E, 0x0A70F, - 0x0A710, 0x0A711, 0x0A712, 0x0A713, 0x0A714, 0x0A715, 0x0A716, 0x0A717, - 0x0A718, 0x0A719, 0x0A71A, 0x0A71B, 0x0A71C, 0x0A71D, 0x0A71E, 0x0A71F, - 0x0A720, 0x0A721, 0x0A723, 0x0A723, 0x0A725, 0x0A725, 0x0A727, 0x0A727, - 0x0A729, 0x0A729, 0x0A72B, 0x0A72B, 0x0A72D, 0x0A72D, 0x0A72F, 0x0A72F, - 0x0A730, 0x0A731, 0x0A733, 0x0A733, 0x0A735, 0x0A735, 0x0A737, 0x0A737, - 0x0A739, 0x0A739, 0x0A73B, 0x0A73B, 0x0A73D, 0x0A73D, 0x0A73F, 0x0A73F, - 0x0A741, 0x0A741, 0x0A743, 0x0A743, 0x0A745, 0x0A745, 0x0A747, 0x0A747, - 0x0A749, 0x0A749, 0x0A74B, 0x0A74B, 0x0A74D, 0x0A74D, 0x0A74F, 0x0A74F, - 0x0A751, 0x0A751, 0x0A753, 0x0A753, 0x0A755, 0x0A755, 0x0A757, 0x0A757, - 0x0A759, 0x0A759, 0x0A75B, 0x0A75B, 0x0A75D, 0x0A75D, 0x0A75F, 0x0A75F, - 0x0A761, 0x0A761, 0x0A763, 0x0A763, 0x0A765, 0x0A765, 0x0A767, 0x0A767, - 0x0A769, 0x0A769, 0x0A76B, 0x0A76B, 0x0A76D, 0x0A76D, 0x0A76F, 0x0A76F, - 0x0A770, 0x0A771, 0x0A772, 0x0A773, 0x0A774, 0x0A775, 0x0A776, 0x0A777, - 0x0A778, 0x0A77A, 0x0A77A, 0x0A77C, 0x0A77C, 0x01D79, 0x0A77F, 0x0A77F, -}; - - -static const uint32_t nxt_unicode_block_14f[128] nxt_aligned(64) = { - 0x0A781, 0x0A781, 0x0A783, 0x0A783, 0x0A785, 0x0A785, 0x0A787, 0x0A787, - 0x0A788, 0x0A789, 0x0A78A, 0x0A78C, 0x0A78C, 0x00265, 0x0A78E, 0x0A78F, - 0x0A791, 0x0A791, 0x0A793, 0x0A793, 0x0A794, 0x0A795, 0x0A796, 0x0A797, - 0x0A798, 0x0A799, 0x0A79A, 0x0A79B, 0x0A79C, 0x0A79D, 0x0A79E, 0x0A79F, - 0x0A7A1, 0x0A7A1, 0x0A7A3, 0x0A7A3, 0x0A7A5, 0x0A7A5, 0x0A7A7, 0x0A7A7, - 0x0A7A9, 0x0A7A9, 0x00266, 0x0A7AB, 0x0A7AC, 0x0A7AD, 0x0A7AE, 0x0A7AF, - 0x0A7B0, 0x0A7B1, 0x0A7B2, 0x0A7B3, 0x0A7B4, 0x0A7B5, 0x0A7B6, 0x0A7B7, - 0x0A7B8, 0x0A7B9, 0x0A7BA, 0x0A7BB, 0x0A7BC, 0x0A7BD, 0x0A7BE, 0x0A7BF, - 0x0A7C0, 0x0A7C1, 0x0A7C2, 0x0A7C3, 0x0A7C4, 0x0A7C5, 0x0A7C6, 0x0A7C7, - 0x0A7C8, 0x0A7C9, 0x0A7CA, 0x0A7CB, 0x0A7CC, 0x0A7CD, 0x0A7CE, 0x0A7CF, - 0x0A7D0, 0x0A7D1, 0x0A7D2, 0x0A7D3, 0x0A7D4, 0x0A7D5, 0x0A7D6, 0x0A7D7, - 0x0A7D8, 0x0A7D9, 0x0A7DA, 0x0A7DB, 0x0A7DC, 0x0A7DD, 0x0A7DE, 0x0A7DF, - 0x0A7E0, 0x0A7E1, 0x0A7E2, 0x0A7E3, 0x0A7E4, 0x0A7E5, 0x0A7E6, 0x0A7E7, - 0x0A7E8, 0x0A7E9, 0x0A7EA, 0x0A7EB, 0x0A7EC, 0x0A7ED, 0x0A7EE, 0x0A7EF, - 0x0A7F0, 0x0A7F1, 0x0A7F2, 0x0A7F3, 0x0A7F4, 0x0A7F5, 0x0A7F6, 0x0A7F7, - 0x0A7F8, 0x0A7F9, 0x0A7FA, 0x0A7FB, 0x0A7FC, 0x0A7FD, 0x0A7FE, 0x0A7FF, -}; - - -static const uint32_t nxt_unicode_block_1fe[128] nxt_aligned(64) = { - 0x0FF00, 0x0FF01, 0x0FF02, 0x0FF03, 0x0FF04, 0x0FF05, 0x0FF06, 0x0FF07, - 0x0FF08, 0x0FF09, 0x0FF0A, 0x0FF0B, 0x0FF0C, 0x0FF0D, 0x0FF0E, 0x0FF0F, - 0x0FF10, 0x0FF11, 0x0FF12, 0x0FF13, 0x0FF14, 0x0FF15, 0x0FF16, 0x0FF17, - 0x0FF18, 0x0FF19, 0x0FF1A, 0x0FF1B, 0x0FF1C, 0x0FF1D, 0x0FF1E, 0x0FF1F, - 0x0FF20, 0x0FF41, 0x0FF42, 0x0FF43, 0x0FF44, 0x0FF45, 0x0FF46, 0x0FF47, - 0x0FF48, 0x0FF49, 0x0FF4A, 0x0FF4B, 0x0FF4C, 0x0FF4D, 0x0FF4E, 0x0FF4F, - 0x0FF50, 0x0FF51, 0x0FF52, 0x0FF53, 0x0FF54, 0x0FF55, 0x0FF56, 0x0FF57, - 0x0FF58, 0x0FF59, 0x0FF5A, 0x0FF3B, 0x0FF3C, 0x0FF3D, 0x0FF3E, 0x0FF3F, - 0x0FF40, 0x0FF41, 0x0FF42, 0x0FF43, 0x0FF44, 0x0FF45, 0x0FF46, 0x0FF47, - 0x0FF48, 0x0FF49, 0x0FF4A, 0x0FF4B, 0x0FF4C, 0x0FF4D, 0x0FF4E, 0x0FF4F, - 0x0FF50, 0x0FF51, 0x0FF52, 0x0FF53, 0x0FF54, 0x0FF55, 0x0FF56, 0x0FF57, - 0x0FF58, 0x0FF59, 0x0FF5A, 0x0FF5B, 0x0FF5C, 0x0FF5D, 0x0FF5E, 0x0FF5F, - 0x0FF60, 0x0FF61, 0x0FF62, 0x0FF63, 0x0FF64, 0x0FF65, 0x0FF66, 0x0FF67, - 0x0FF68, 0x0FF69, 0x0FF6A, 0x0FF6B, 0x0FF6C, 0x0FF6D, 0x0FF6E, 0x0FF6F, - 0x0FF70, 0x0FF71, 0x0FF72, 0x0FF73, 0x0FF74, 0x0FF75, 0x0FF76, 0x0FF77, - 0x0FF78, 0x0FF79, 0x0FF7A, 0x0FF7B, 0x0FF7C, 0x0FF7D, 0x0FF7E, 0x0FF7F, -}; - - -static const uint32_t nxt_unicode_block_208[40] nxt_aligned(64) = { - 0x10428, 0x10429, 0x1042A, 0x1042B, 0x1042C, 0x1042D, 0x1042E, 0x1042F, - 0x10430, 0x10431, 0x10432, 0x10433, 0x10434, 0x10435, 0x10436, 0x10437, - 0x10438, 0x10439, 0x1043A, 0x1043B, 0x1043C, 0x1043D, 0x1043E, 0x1043F, - 0x10440, 0x10441, 0x10442, 0x10443, 0x10444, 0x10445, 0x10446, 0x10447, - 0x10448, 0x10449, 0x1044A, 0x1044B, 0x1044C, 0x1044D, 0x1044E, 0x1044F, -}; - - -static const uint32_t *nxt_unicode_blocks[] nxt_aligned(64) = { - nxt_unicode_block_000, - nxt_unicode_block_001, - nxt_unicode_block_002, - nxt_unicode_block_003, - nxt_unicode_block_004, - NULL, - nxt_unicode_block_006, - nxt_unicode_block_007, - nxt_unicode_block_008, - nxt_unicode_block_009, - nxt_unicode_block_00a, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - nxt_unicode_block_021, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - nxt_unicode_block_03c, - nxt_unicode_block_03d, - nxt_unicode_block_03e, - nxt_unicode_block_03f, - NULL, - NULL, - nxt_unicode_block_042, - nxt_unicode_block_043, - NULL, - NULL, - NULL, - NULL, - NULL, - nxt_unicode_block_049, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - nxt_unicode_block_058, - nxt_unicode_block_059, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - nxt_unicode_block_14c, - nxt_unicode_block_14d, - nxt_unicode_block_14e, - nxt_unicode_block_14f, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - nxt_unicode_block_1fe, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - nxt_unicode_block_208, -}; diff --git a/src/nxt_unicode_lowcase.pl b/src/nxt_unicode_lowcase.pl deleted file mode 100644 index abf64965..00000000 --- a/src/nxt_unicode_lowcase.pl +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; - -# BLOCK_SIZE should be 128, 256, 512, etc. The value 128 provides -# the minimum memory footprint for both 32-bit and 64-bit platforms. -use constant BLOCK_SIZE => 128; - -my %lowcase; -my %blocks; -my $max_block = 0; -my $max_lowcase = 0; - -while (<>) { - if (/^(\w+); (C|S); (\w+);/) { - my ($symbol, $folding) = (hex $1, hex $3); - $lowcase{$symbol} = $folding; - $blocks{int($symbol / BLOCK_SIZE)} = 1; - - if ($max_lowcase < $symbol) { - $max_lowcase = $symbol; - } - } -} - - -my $last_block_size = $max_lowcase % BLOCK_SIZE + 1; - - -for my $block (sort { $a <=> $b } keys %blocks) { - if ($max_block < $block) { - $max_block = $block; - } -} - - -my $blocks = scalar keys %blocks; - -printf("\n/*\n" . - " * %d %s-bytes blocks, %d pointers.\n" . - " * %d bytes on 32-bit platforms, %d bytes on 64-bit platforms.\n" . - " */\n\n", - $blocks, BLOCK_SIZE, $max_block + 1, - ($blocks - 1) * BLOCK_SIZE * 4 + $last_block_size + $max_block * 4, - ($blocks - 1) * BLOCK_SIZE * 4 + $last_block_size+ $max_block * 8); - -printf("#define NXT_UNICODE_MAX_LOWCASE 0x%05x\n\n", $max_lowcase); -printf("#define NXT_UNICODE_BLOCK_SIZE %d\n\n\n", BLOCK_SIZE); - - -for my $block (sort { $a <=> $b } keys %blocks) { - my $block_size = ($block != $max_block) ? BLOCK_SIZE : $last_block_size; - - print "static const uint32_t "; - printf("nxt_unicode_block_%03x[%d] nxt_aligned(64) = {", - $block, $block_size); - - for my $c (0 .. $block_size - 1) { - printf "\n " if $c % 8 == 0; - - my $n = $block * BLOCK_SIZE + $c; - - if (exists $lowcase{$n}) { - printf(" 0x%05x,", $lowcase{$n}); - - } else { - #print " .......,"; - printf(" 0x%05x,", $n); - } - } - - print "\n};\n\n\n"; -} - - -print "static const uint32_t *nxt_unicode_blocks[] nxt_aligned(64) = {\n"; - -for my $block (0 .. $max_block) { - if (exists($blocks{$block})) { - printf(" nxt_unicode_block_%03x,\n", $block); - - } else { - print " NULL,\n"; - } -} - -print "};\n"; diff --git a/src/nxt_unicode_macosx_lowcase.h b/src/nxt_unicode_macosx_lowcase.h deleted file mode 100644 index d0cc1518..00000000 --- a/src/nxt_unicode_macosx_lowcase.h +++ /dev/null @@ -1,816 +0,0 @@ - -/* - * 15 128-bytes blocks, 511 pointers. - * 9267 bytes on 32-bit platforms, 11307 bytes on 64-bit platforms. - */ - -#define NXT_UNICODE_MAX_LOWCASE 0x0FF3A - -#define NXT_UNICODE_BLOCK_SIZE 128 - - -static const uint32_t nxt_unicode_block_000[128] nxt_aligned(64) = { - 0x00000, 0x00001, 0x00002, 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, - 0x00008, 0x00009, 0x0000A, 0x0000B, 0x0000C, 0x0000D, 0x0000E, 0x0000F, - 0x00010, 0x00011, 0x00012, 0x00013, 0x00014, 0x00015, 0x00016, 0x00017, - 0x00018, 0x00019, 0x0001A, 0x0001B, 0x0001C, 0x0001D, 0x0001E, 0x0001F, - 0x00020, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027, - 0x00028, 0x00029, 0x0002A, 0x0002B, 0x0002C, 0x0002D, 0x0002E, 0x0002F, - 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, - 0x00038, 0x00039, 0x0003A, 0x0003B, 0x0003C, 0x0003D, 0x0003E, 0x0003F, - 0x00040, 0x00061, 0x00062, 0x00063, 0x00064, 0x00065, 0x00066, 0x00067, - 0x00068, 0x00069, 0x0006A, 0x0006B, 0x0006C, 0x0006D, 0x0006E, 0x0006F, - 0x00070, 0x00071, 0x00072, 0x00073, 0x00074, 0x00075, 0x00076, 0x00077, - 0x00078, 0x00079, 0x0007A, 0x0005B, 0x0005C, 0x0005D, 0x0005E, 0x0005F, - 0x00060, 0x00061, 0x00062, 0x00063, 0x00064, 0x00065, 0x00066, 0x00067, - 0x00068, 0x00069, 0x0006A, 0x0006B, 0x0006C, 0x0006D, 0x0006E, 0x0006F, - 0x00070, 0x00071, 0x00072, 0x00073, 0x00074, 0x00075, 0x00076, 0x00077, - 0x00078, 0x00079, 0x0007A, 0x0007B, 0x0007C, 0x0007D, 0x0007E, 0x0007F, -}; - - -static const uint32_t nxt_unicode_block_001[128] nxt_aligned(64) = { - 0x00080, 0x00081, 0x00082, 0x00083, 0x00084, 0x00085, 0x00086, 0x00087, - 0x00088, 0x00089, 0x0008A, 0x0008B, 0x0008C, 0x0008D, 0x0008E, 0x0008F, - 0x00090, 0x00091, 0x00092, 0x00093, 0x00094, 0x00095, 0x00096, 0x00097, - 0x00098, 0x00099, 0x0009A, 0x0009B, 0x0009C, 0x0009D, 0x0009E, 0x0009F, - 0x000A0, 0x000A1, 0x000A2, 0x000A3, 0x000A4, 0x000A5, 0x000A6, 0x000A7, - 0x000A8, 0x000A9, 0x000AA, 0x000AB, 0x000AC, 0x000AD, 0x000AE, 0x000AF, - 0x000B0, 0x000B1, 0x000B2, 0x000B3, 0x000B4, 0x000B5, 0x000B6, 0x000B7, - 0x000B8, 0x000B9, 0x000BA, 0x000BB, 0x000BC, 0x000BD, 0x000BE, 0x000BF, - 0x000E0, 0x000E1, 0x000E2, 0x000E3, 0x000E4, 0x000E5, 0x000E6, 0x000E7, - 0x000E8, 0x000E9, 0x000EA, 0x000EB, 0x000EC, 0x000ED, 0x000EE, 0x000EF, - 0x000F0, 0x000F1, 0x000F2, 0x000F3, 0x000F4, 0x000F5, 0x000F6, 0x000D7, - 0x000F8, 0x000F9, 0x000FA, 0x000FB, 0x000FC, 0x000FD, 0x000FE, 0x000DF, - 0x000E0, 0x000E1, 0x000E2, 0x000E3, 0x000E4, 0x000E5, 0x000E6, 0x000E7, - 0x000E8, 0x000E9, 0x000EA, 0x000EB, 0x000EC, 0x000ED, 0x000EE, 0x000EF, - 0x000F0, 0x000F1, 0x000F2, 0x000F3, 0x000F4, 0x000F5, 0x000F6, 0x000F7, - 0x000F8, 0x000F9, 0x000FA, 0x000FB, 0x000FC, 0x000FD, 0x000FE, 0x000FF, -}; - - -static const uint32_t nxt_unicode_block_002[128] nxt_aligned(64) = { - 0x00101, 0x00101, 0x00103, 0x00103, 0x00105, 0x00105, 0x00107, 0x00107, - 0x00109, 0x00109, 0x0010B, 0x0010B, 0x0010D, 0x0010D, 0x0010F, 0x0010F, - 0x00111, 0x00111, 0x00113, 0x00113, 0x00115, 0x00115, 0x00117, 0x00117, - 0x00119, 0x00119, 0x0011B, 0x0011B, 0x0011D, 0x0011D, 0x0011F, 0x0011F, - 0x00121, 0x00121, 0x00123, 0x00123, 0x00125, 0x00125, 0x00127, 0x00127, - 0x00129, 0x00129, 0x0012B, 0x0012B, 0x0012D, 0x0012D, 0x0012F, 0x0012F, - 0x00130, 0x00131, 0x00133, 0x00133, 0x00135, 0x00135, 0x00137, 0x00137, - 0x00138, 0x0013A, 0x0013A, 0x0013C, 0x0013C, 0x0013E, 0x0013E, 0x00140, - 0x00140, 0x00142, 0x00142, 0x00144, 0x00144, 0x00146, 0x00146, 0x00148, - 0x00148, 0x00149, 0x0014B, 0x0014B, 0x0014D, 0x0014D, 0x0014F, 0x0014F, - 0x00151, 0x00151, 0x00153, 0x00153, 0x00155, 0x00155, 0x00157, 0x00157, - 0x00159, 0x00159, 0x0015B, 0x0015B, 0x0015D, 0x0015D, 0x0015F, 0x0015F, - 0x00161, 0x00161, 0x00163, 0x00163, 0x00165, 0x00165, 0x00167, 0x00167, - 0x00169, 0x00169, 0x0016B, 0x0016B, 0x0016D, 0x0016D, 0x0016F, 0x0016F, - 0x00171, 0x00171, 0x00173, 0x00173, 0x00175, 0x00175, 0x00177, 0x00177, - 0x000FF, 0x0017A, 0x0017A, 0x0017C, 0x0017C, 0x0017E, 0x0017E, 0x0017F, -}; - - -static const uint32_t nxt_unicode_block_003[128] nxt_aligned(64) = { - 0x00180, 0x00253, 0x00183, 0x00183, 0x00185, 0x00185, 0x00254, 0x00188, - 0x00188, 0x00256, 0x00257, 0x0018C, 0x0018C, 0x0018D, 0x001DD, 0x00259, - 0x0025B, 0x00192, 0x00192, 0x00260, 0x00263, 0x00195, 0x00269, 0x00268, - 0x00199, 0x00199, 0x0019A, 0x0019B, 0x0026F, 0x00272, 0x0019E, 0x00275, - 0x001A1, 0x001A1, 0x001A3, 0x001A3, 0x001A5, 0x001A5, 0x001A6, 0x001A8, - 0x001A8, 0x00283, 0x001AA, 0x001AB, 0x001AD, 0x001AD, 0x00288, 0x001B0, - 0x001B0, 0x0028A, 0x0028B, 0x001B4, 0x001B4, 0x001B6, 0x001B6, 0x00292, - 0x001B9, 0x001B9, 0x001BA, 0x001BB, 0x001BD, 0x001BD, 0x001BE, 0x001BF, - 0x001C0, 0x001C1, 0x001C2, 0x001C3, 0x001C6, 0x001C6, 0x001C6, 0x001C9, - 0x001C9, 0x001C9, 0x001CC, 0x001CC, 0x001CC, 0x001CE, 0x001CE, 0x001D0, - 0x001D0, 0x001D2, 0x001D2, 0x001D4, 0x001D4, 0x001D6, 0x001D6, 0x001D8, - 0x001D8, 0x001DA, 0x001DA, 0x001DC, 0x001DC, 0x001DD, 0x001DF, 0x001DF, - 0x001E1, 0x001E1, 0x001E3, 0x001E3, 0x001E5, 0x001E5, 0x001E7, 0x001E7, - 0x001E9, 0x001E9, 0x001EB, 0x001EB, 0x001ED, 0x001ED, 0x001EF, 0x001EF, - 0x001F0, 0x001F3, 0x001F3, 0x001F3, 0x001F5, 0x001F5, 0x001F6, 0x001F7, - 0x001F9, 0x001F9, 0x001FB, 0x001FB, 0x001FD, 0x001FD, 0x001FF, 0x001FF, -}; - - -static const uint32_t nxt_unicode_block_004[128] nxt_aligned(64) = { - 0x00201, 0x00201, 0x00203, 0x00203, 0x00205, 0x00205, 0x00207, 0x00207, - 0x00209, 0x00209, 0x0020B, 0x0020B, 0x0020D, 0x0020D, 0x0020F, 0x0020F, - 0x00211, 0x00211, 0x00213, 0x00213, 0x00215, 0x00215, 0x00217, 0x00217, - 0x00219, 0x00219, 0x0021B, 0x0021B, 0x0021C, 0x0021D, 0x0021F, 0x0021F, - 0x00220, 0x00221, 0x00222, 0x00223, 0x00224, 0x00225, 0x00227, 0x00227, - 0x00229, 0x00229, 0x0022B, 0x0022B, 0x0022D, 0x0022D, 0x0022F, 0x0022F, - 0x00231, 0x00231, 0x00233, 0x00233, 0x00234, 0x00235, 0x00236, 0x00237, - 0x00238, 0x00239, 0x0023A, 0x0023B, 0x0023C, 0x0023D, 0x0023E, 0x0023F, - 0x00240, 0x00241, 0x00242, 0x00243, 0x00244, 0x00245, 0x00246, 0x00247, - 0x00248, 0x00249, 0x0024A, 0x0024B, 0x0024C, 0x0024D, 0x0024E, 0x0024F, - 0x00250, 0x00251, 0x00252, 0x00253, 0x00254, 0x00255, 0x00256, 0x00257, - 0x00258, 0x00259, 0x0025A, 0x0025B, 0x0025C, 0x0025D, 0x0025E, 0x0025F, - 0x00260, 0x00261, 0x00262, 0x00263, 0x00264, 0x00265, 0x00266, 0x00267, - 0x00268, 0x00269, 0x0026A, 0x0026B, 0x0026C, 0x0026D, 0x0026E, 0x0026F, - 0x00270, 0x00271, 0x00272, 0x00273, 0x00274, 0x00275, 0x00276, 0x00277, - 0x00278, 0x00279, 0x0027A, 0x0027B, 0x0027C, 0x0027D, 0x0027E, 0x0027F, -}; - - -static const uint32_t nxt_unicode_block_007[128] nxt_aligned(64) = { - 0x00380, 0x00381, 0x00382, 0x00383, 0x00384, 0x00385, 0x003AC, 0x00387, - 0x003AD, 0x003AE, 0x003AF, 0x0038B, 0x003CC, 0x0038D, 0x003CD, 0x003CE, - 0x00390, 0x003B1, 0x003B2, 0x003B3, 0x003B4, 0x003B5, 0x003B6, 0x003B7, - 0x003B8, 0x003B9, 0x003BA, 0x003BB, 0x003BC, 0x003BD, 0x003BE, 0x003BF, - 0x003C0, 0x003C1, 0x003A2, 0x003C3, 0x003C4, 0x003C5, 0x003C6, 0x003C7, - 0x003C8, 0x003C9, 0x003CA, 0x003CB, 0x003AC, 0x003AD, 0x003AE, 0x003AF, - 0x003B0, 0x003B1, 0x003B2, 0x003B3, 0x003B4, 0x003B5, 0x003B6, 0x003B7, - 0x003B8, 0x003B9, 0x003BA, 0x003BB, 0x003BC, 0x003BD, 0x003BE, 0x003BF, - 0x003C0, 0x003C1, 0x003C2, 0x003C3, 0x003C4, 0x003C5, 0x003C6, 0x003C7, - 0x003C8, 0x003C9, 0x003CA, 0x003CB, 0x003CC, 0x003CD, 0x003CE, 0x003CF, - 0x003D0, 0x003D1, 0x003D2, 0x003D3, 0x003D4, 0x003D5, 0x003D6, 0x003D7, - 0x003D8, 0x003D9, 0x003DA, 0x003DB, 0x003DC, 0x003DD, 0x003DE, 0x003DF, - 0x003E0, 0x003E1, 0x003E3, 0x003E3, 0x003E5, 0x003E5, 0x003E7, 0x003E7, - 0x003E9, 0x003E9, 0x003EB, 0x003EB, 0x003ED, 0x003ED, 0x003EF, 0x003EF, - 0x003F0, 0x003F1, 0x003F2, 0x003F3, 0x003F4, 0x003F5, 0x003F6, 0x003F7, - 0x003F8, 0x003F9, 0x003FA, 0x003FB, 0x003FC, 0x003FD, 0x003FE, 0x003FF, -}; - - -static const uint32_t nxt_unicode_block_008[128] nxt_aligned(64) = { - 0x00450, 0x00451, 0x00452, 0x00453, 0x00454, 0x00455, 0x00456, 0x00457, - 0x00458, 0x00459, 0x0045A, 0x0045B, 0x0045C, 0x0045D, 0x0045E, 0x0045F, - 0x00430, 0x00431, 0x00432, 0x00433, 0x00434, 0x00435, 0x00436, 0x00437, - 0x00438, 0x00439, 0x0043A, 0x0043B, 0x0043C, 0x0043D, 0x0043E, 0x0043F, - 0x00440, 0x00441, 0x00442, 0x00443, 0x00444, 0x00445, 0x00446, 0x00447, - 0x00448, 0x00449, 0x0044A, 0x0044B, 0x0044C, 0x0044D, 0x0044E, 0x0044F, - 0x00430, 0x00431, 0x00432, 0x00433, 0x00434, 0x00435, 0x00436, 0x00437, - 0x00438, 0x00439, 0x0043A, 0x0043B, 0x0043C, 0x0043D, 0x0043E, 0x0043F, - 0x00440, 0x00441, 0x00442, 0x00443, 0x00444, 0x00445, 0x00446, 0x00447, - 0x00448, 0x00449, 0x0044A, 0x0044B, 0x0044C, 0x0044D, 0x0044E, 0x0044F, - 0x00450, 0x00451, 0x00452, 0x00453, 0x00454, 0x00455, 0x00456, 0x00457, - 0x00458, 0x00459, 0x0045A, 0x0045B, 0x0045C, 0x0045D, 0x0045E, 0x0045F, - 0x00461, 0x00461, 0x00463, 0x00463, 0x00465, 0x00465, 0x00467, 0x00467, - 0x00469, 0x00469, 0x0046B, 0x0046B, 0x0046D, 0x0046D, 0x0046F, 0x0046F, - 0x00471, 0x00471, 0x00473, 0x00473, 0x00475, 0x00475, 0x00477, 0x00477, - 0x00479, 0x00479, 0x0047B, 0x0047B, 0x0047D, 0x0047D, 0x0047F, 0x0047F, -}; - - -static const uint32_t nxt_unicode_block_009[128] nxt_aligned(64) = { - 0x00481, 0x00481, 0x00482, 0x00483, 0x00484, 0x00485, 0x00486, 0x00487, - 0x00488, 0x00489, 0x0048A, 0x0048B, 0x0048C, 0x0048D, 0x0048E, 0x0048F, - 0x00491, 0x00491, 0x00493, 0x00493, 0x00495, 0x00495, 0x00497, 0x00497, - 0x00499, 0x00499, 0x0049B, 0x0049B, 0x0049D, 0x0049D, 0x0049F, 0x0049F, - 0x004A1, 0x004A1, 0x004A3, 0x004A3, 0x004A5, 0x004A5, 0x004A7, 0x004A7, - 0x004A9, 0x004A9, 0x004AB, 0x004AB, 0x004AD, 0x004AD, 0x004AF, 0x004AF, - 0x004B1, 0x004B1, 0x004B3, 0x004B3, 0x004B5, 0x004B5, 0x004B7, 0x004B7, - 0x004B9, 0x004B9, 0x004BB, 0x004BB, 0x004BD, 0x004BD, 0x004BF, 0x004BF, - 0x004C0, 0x004C2, 0x004C2, 0x004C4, 0x004C4, 0x004C5, 0x004C6, 0x004C8, - 0x004C8, 0x004C9, 0x004CA, 0x004CC, 0x004CC, 0x004CD, 0x004CE, 0x004CF, - 0x004D1, 0x004D1, 0x004D3, 0x004D3, 0x004D4, 0x004D5, 0x004D7, 0x004D7, - 0x004D8, 0x004D9, 0x004DA, 0x004DB, 0x004DD, 0x004DD, 0x004DF, 0x004DF, - 0x004E0, 0x004E1, 0x004E3, 0x004E3, 0x004E5, 0x004E5, 0x004E7, 0x004E7, - 0x004E8, 0x004E9, 0x004EA, 0x004EB, 0x004ED, 0x004ED, 0x004EF, 0x004EF, - 0x004F1, 0x004F1, 0x004F3, 0x004F3, 0x004F5, 0x004F5, 0x004F6, 0x004F7, - 0x004F9, 0x004F9, 0x004FA, 0x004FB, 0x004FC, 0x004FD, 0x004FE, 0x004FF, -}; - - -static const uint32_t nxt_unicode_block_00a[128] nxt_aligned(64) = { - 0x00500, 0x00501, 0x00502, 0x00503, 0x00504, 0x00505, 0x00506, 0x00507, - 0x00508, 0x00509, 0x0050A, 0x0050B, 0x0050C, 0x0050D, 0x0050E, 0x0050F, - 0x00510, 0x00511, 0x00512, 0x00513, 0x00514, 0x00515, 0x00516, 0x00517, - 0x00518, 0x00519, 0x0051A, 0x0051B, 0x0051C, 0x0051D, 0x0051E, 0x0051F, - 0x00520, 0x00521, 0x00522, 0x00523, 0x00524, 0x00525, 0x00526, 0x00527, - 0x00528, 0x00529, 0x0052A, 0x0052B, 0x0052C, 0x0052D, 0x0052E, 0x0052F, - 0x00530, 0x00561, 0x00562, 0x00563, 0x00564, 0x00565, 0x00566, 0x00567, - 0x00568, 0x00569, 0x0056A, 0x0056B, 0x0056C, 0x0056D, 0x0056E, 0x0056F, - 0x00570, 0x00571, 0x00572, 0x00573, 0x00574, 0x00575, 0x00576, 0x00577, - 0x00578, 0x00579, 0x0057A, 0x0057B, 0x0057C, 0x0057D, 0x0057E, 0x0057F, - 0x00580, 0x00581, 0x00582, 0x00583, 0x00584, 0x00585, 0x00586, 0x00557, - 0x00558, 0x00559, 0x0055A, 0x0055B, 0x0055C, 0x0055D, 0x0055E, 0x0055F, - 0x00560, 0x00561, 0x00562, 0x00563, 0x00564, 0x00565, 0x00566, 0x00567, - 0x00568, 0x00569, 0x0056A, 0x0056B, 0x0056C, 0x0056D, 0x0056E, 0x0056F, - 0x00570, 0x00571, 0x00572, 0x00573, 0x00574, 0x00575, 0x00576, 0x00577, - 0x00578, 0x00579, 0x0057A, 0x0057B, 0x0057C, 0x0057D, 0x0057E, 0x0057F, -}; - - -static const uint32_t nxt_unicode_block_03c[128] nxt_aligned(64) = { - 0x01E01, 0x01E01, 0x01E03, 0x01E03, 0x01E05, 0x01E05, 0x01E07, 0x01E07, - 0x01E09, 0x01E09, 0x01E0B, 0x01E0B, 0x01E0D, 0x01E0D, 0x01E0F, 0x01E0F, - 0x01E11, 0x01E11, 0x01E13, 0x01E13, 0x01E15, 0x01E15, 0x01E17, 0x01E17, - 0x01E19, 0x01E19, 0x01E1B, 0x01E1B, 0x01E1D, 0x01E1D, 0x01E1F, 0x01E1F, - 0x01E21, 0x01E21, 0x01E23, 0x01E23, 0x01E25, 0x01E25, 0x01E27, 0x01E27, - 0x01E29, 0x01E29, 0x01E2B, 0x01E2B, 0x01E2D, 0x01E2D, 0x01E2F, 0x01E2F, - 0x01E31, 0x01E31, 0x01E33, 0x01E33, 0x01E35, 0x01E35, 0x01E37, 0x01E37, - 0x01E39, 0x01E39, 0x01E3B, 0x01E3B, 0x01E3D, 0x01E3D, 0x01E3F, 0x01E3F, - 0x01E41, 0x01E41, 0x01E43, 0x01E43, 0x01E45, 0x01E45, 0x01E47, 0x01E47, - 0x01E49, 0x01E49, 0x01E4B, 0x01E4B, 0x01E4D, 0x01E4D, 0x01E4F, 0x01E4F, - 0x01E51, 0x01E51, 0x01E53, 0x01E53, 0x01E55, 0x01E55, 0x01E57, 0x01E57, - 0x01E59, 0x01E59, 0x01E5B, 0x01E5B, 0x01E5D, 0x01E5D, 0x01E5F, 0x01E5F, - 0x01E61, 0x01E61, 0x01E63, 0x01E63, 0x01E65, 0x01E65, 0x01E67, 0x01E67, - 0x01E69, 0x01E69, 0x01E6B, 0x01E6B, 0x01E6D, 0x01E6D, 0x01E6F, 0x01E6F, - 0x01E71, 0x01E71, 0x01E73, 0x01E73, 0x01E75, 0x01E75, 0x01E77, 0x01E77, - 0x01E79, 0x01E79, 0x01E7B, 0x01E7B, 0x01E7D, 0x01E7D, 0x01E7F, 0x01E7F, -}; - - -static const uint32_t nxt_unicode_block_03d[128] nxt_aligned(64) = { - 0x01E81, 0x01E81, 0x01E83, 0x01E83, 0x01E85, 0x01E85, 0x01E87, 0x01E87, - 0x01E89, 0x01E89, 0x01E8B, 0x01E8B, 0x01E8D, 0x01E8D, 0x01E8F, 0x01E8F, - 0x01E91, 0x01E91, 0x01E93, 0x01E93, 0x01E95, 0x01E95, 0x01E96, 0x01E97, - 0x01E98, 0x01E99, 0x01E9A, 0x01E9B, 0x01E9C, 0x01E9D, 0x01E9E, 0x01E9F, - 0x01EA1, 0x01EA1, 0x01EA3, 0x01EA3, 0x01EA5, 0x01EA5, 0x01EA7, 0x01EA7, - 0x01EA9, 0x01EA9, 0x01EAB, 0x01EAB, 0x01EAD, 0x01EAD, 0x01EAF, 0x01EAF, - 0x01EB1, 0x01EB1, 0x01EB3, 0x01EB3, 0x01EB5, 0x01EB5, 0x01EB7, 0x01EB7, - 0x01EB9, 0x01EB9, 0x01EBB, 0x01EBB, 0x01EBD, 0x01EBD, 0x01EBF, 0x01EBF, - 0x01EC1, 0x01EC1, 0x01EC3, 0x01EC3, 0x01EC5, 0x01EC5, 0x01EC7, 0x01EC7, - 0x01EC9, 0x01EC9, 0x01ECB, 0x01ECB, 0x01ECD, 0x01ECD, 0x01ECF, 0x01ECF, - 0x01ED1, 0x01ED1, 0x01ED3, 0x01ED3, 0x01ED5, 0x01ED5, 0x01ED7, 0x01ED7, - 0x01ED9, 0x01ED9, 0x01EDB, 0x01EDB, 0x01EDD, 0x01EDD, 0x01EDF, 0x01EDF, - 0x01EE1, 0x01EE1, 0x01EE3, 0x01EE3, 0x01EE5, 0x01EE5, 0x01EE7, 0x01EE7, - 0x01EE9, 0x01EE9, 0x01EEB, 0x01EEB, 0x01EED, 0x01EED, 0x01EEF, 0x01EEF, - 0x01EF1, 0x01EF1, 0x01EF3, 0x01EF3, 0x01EF5, 0x01EF5, 0x01EF7, 0x01EF7, - 0x01EF9, 0x01EF9, 0x01EFA, 0x01EFB, 0x01EFC, 0x01EFD, 0x01EFE, 0x01EFF, -}; - - -static const uint32_t nxt_unicode_block_03e[128] nxt_aligned(64) = { - 0x01F00, 0x01F01, 0x01F02, 0x01F03, 0x01F04, 0x01F05, 0x01F06, 0x01F07, - 0x01F00, 0x01F01, 0x01F02, 0x01F03, 0x01F04, 0x01F05, 0x01F06, 0x01F07, - 0x01F10, 0x01F11, 0x01F12, 0x01F13, 0x01F14, 0x01F15, 0x01F16, 0x01F17, - 0x01F10, 0x01F11, 0x01F12, 0x01F13, 0x01F14, 0x01F15, 0x01F1E, 0x01F1F, - 0x01F20, 0x01F21, 0x01F22, 0x01F23, 0x01F24, 0x01F25, 0x01F26, 0x01F27, - 0x01F20, 0x01F21, 0x01F22, 0x01F23, 0x01F24, 0x01F25, 0x01F26, 0x01F27, - 0x01F30, 0x01F31, 0x01F32, 0x01F33, 0x01F34, 0x01F35, 0x01F36, 0x01F37, - 0x01F30, 0x01F31, 0x01F32, 0x01F33, 0x01F34, 0x01F35, 0x01F36, 0x01F37, - 0x01F40, 0x01F41, 0x01F42, 0x01F43, 0x01F44, 0x01F45, 0x01F46, 0x01F47, - 0x01F40, 0x01F41, 0x01F42, 0x01F43, 0x01F44, 0x01F45, 0x01F4E, 0x01F4F, - 0x01F50, 0x01F51, 0x01F52, 0x01F53, 0x01F54, 0x01F55, 0x01F56, 0x01F57, - 0x01F58, 0x01F51, 0x01F5A, 0x01F53, 0x01F5C, 0x01F55, 0x01F5E, 0x01F57, - 0x01F60, 0x01F61, 0x01F62, 0x01F63, 0x01F64, 0x01F65, 0x01F66, 0x01F67, - 0x01F60, 0x01F61, 0x01F62, 0x01F63, 0x01F64, 0x01F65, 0x01F66, 0x01F67, - 0x01F70, 0x01F71, 0x01F72, 0x01F73, 0x01F74, 0x01F75, 0x01F76, 0x01F77, - 0x01F78, 0x01F79, 0x01F7A, 0x01F7B, 0x01F7C, 0x01F7D, 0x01F7E, 0x01F7F, -}; - - -static const uint32_t nxt_unicode_block_03f[128] nxt_aligned(64) = { - 0x01F80, 0x01F81, 0x01F82, 0x01F83, 0x01F84, 0x01F85, 0x01F86, 0x01F87, - 0x01F80, 0x01F81, 0x01F82, 0x01F83, 0x01F84, 0x01F85, 0x01F86, 0x01F87, - 0x01F90, 0x01F91, 0x01F92, 0x01F93, 0x01F94, 0x01F95, 0x01F96, 0x01F97, - 0x01F90, 0x01F91, 0x01F92, 0x01F93, 0x01F94, 0x01F95, 0x01F96, 0x01F97, - 0x01FA0, 0x01FA1, 0x01FA2, 0x01FA3, 0x01FA4, 0x01FA5, 0x01FA6, 0x01FA7, - 0x01FA0, 0x01FA1, 0x01FA2, 0x01FA3, 0x01FA4, 0x01FA5, 0x01FA6, 0x01FA7, - 0x01FB0, 0x01FB1, 0x01FB2, 0x01FB3, 0x01FB4, 0x01FB5, 0x01FB6, 0x01FB7, - 0x01FB0, 0x01FB1, 0x01F70, 0x01F71, 0x01FB3, 0x01FBD, 0x003B9, 0x01FBF, - 0x01FC0, 0x01FC1, 0x01FC2, 0x01FC3, 0x01FC4, 0x01FC5, 0x01FC6, 0x01FC7, - 0x01F72, 0x01F73, 0x01F74, 0x01F75, 0x01FC3, 0x01FCD, 0x01FCE, 0x01FCF, - 0x01FD0, 0x01FD1, 0x01FD2, 0x01FD3, 0x01FD4, 0x01FD5, 0x01FD6, 0x01FD7, - 0x01FD0, 0x01FD1, 0x01F76, 0x01F77, 0x01FDC, 0x01FDD, 0x01FDE, 0x01FDF, - 0x01FE0, 0x01FE1, 0x01FE2, 0x01FE3, 0x01FE4, 0x01FE5, 0x01FE6, 0x01FE7, - 0x01FE0, 0x01FE1, 0x01F7A, 0x01F7B, 0x01FE5, 0x01FED, 0x01FEE, 0x01FEF, - 0x01FF0, 0x01FF1, 0x01FF2, 0x01FF3, 0x01FF4, 0x01FF5, 0x01FF6, 0x01FF7, - 0x01F78, 0x01F79, 0x01F7C, 0x01F7D, 0x01FF3, 0x01FFD, 0x01FFE, 0x01FFF, -}; - - -static const uint32_t nxt_unicode_block_042[128] nxt_aligned(64) = { - 0x02100, 0x02101, 0x02102, 0x02103, 0x02104, 0x02105, 0x02106, 0x02107, - 0x02108, 0x02109, 0x0210A, 0x0210B, 0x0210C, 0x0210D, 0x0210E, 0x0210F, - 0x02110, 0x02111, 0x02112, 0x02113, 0x02114, 0x02115, 0x02116, 0x02117, - 0x02118, 0x02119, 0x0211A, 0x0211B, 0x0211C, 0x0211D, 0x0211E, 0x0211F, - 0x02120, 0x02121, 0x02122, 0x02123, 0x02124, 0x02125, 0x02126, 0x02127, - 0x02128, 0x02129, 0x0212A, 0x0212B, 0x0212C, 0x0212D, 0x0212E, 0x0212F, - 0x02130, 0x02131, 0x02132, 0x02133, 0x02134, 0x02135, 0x02136, 0x02137, - 0x02138, 0x02139, 0x0213A, 0x0213B, 0x0213C, 0x0213D, 0x0213E, 0x0213F, - 0x02140, 0x02141, 0x02142, 0x02143, 0x02144, 0x02145, 0x02146, 0x02147, - 0x02148, 0x02149, 0x0214A, 0x0214B, 0x0214C, 0x0214D, 0x0214E, 0x0214F, - 0x02150, 0x02151, 0x02152, 0x02153, 0x02154, 0x02155, 0x02156, 0x02157, - 0x02158, 0x02159, 0x0215A, 0x0215B, 0x0215C, 0x0215D, 0x0215E, 0x0215F, - 0x02170, 0x02171, 0x02172, 0x02173, 0x02174, 0x02175, 0x02176, 0x02177, - 0x02178, 0x02179, 0x0217A, 0x0217B, 0x0217C, 0x0217D, 0x0217E, 0x0217F, - 0x02170, 0x02171, 0x02172, 0x02173, 0x02174, 0x02175, 0x02176, 0x02177, - 0x02178, 0x02179, 0x0217A, 0x0217B, 0x0217C, 0x0217D, 0x0217E, 0x0217F, -}; - - -static const uint32_t nxt_unicode_block_1fe[59] nxt_aligned(64) = { - 0x0FF00, 0x0FF01, 0x0FF02, 0x0FF03, 0x0FF04, 0x0FF05, 0x0FF06, 0x0FF07, - 0x0FF08, 0x0FF09, 0x0FF0A, 0x0FF0B, 0x0FF0C, 0x0FF0D, 0x0FF0E, 0x0FF0F, - 0x0FF10, 0x0FF11, 0x0FF12, 0x0FF13, 0x0FF14, 0x0FF15, 0x0FF16, 0x0FF17, - 0x0FF18, 0x0FF19, 0x0FF1A, 0x0FF1B, 0x0FF1C, 0x0FF1D, 0x0FF1E, 0x0FF1F, - 0x0FF20, 0x0FF41, 0x0FF42, 0x0FF43, 0x0FF44, 0x0FF45, 0x0FF46, 0x0FF47, - 0x0FF48, 0x0FF49, 0x0FF4A, 0x0FF4B, 0x0FF4C, 0x0FF4D, 0x0FF4E, 0x0FF4F, - 0x0FF50, 0x0FF51, 0x0FF52, 0x0FF53, 0x0FF54, 0x0FF55, 0x0FF56, 0x0FF57, - 0x0FF58, 0x0FF59, 0x0FF5A, -}; - - -static const uint32_t *nxt_unicode_blocks[] nxt_aligned(64) = { - nxt_unicode_block_000, - nxt_unicode_block_001, - nxt_unicode_block_002, - nxt_unicode_block_003, - nxt_unicode_block_004, - NULL, - NULL, - nxt_unicode_block_007, - nxt_unicode_block_008, - nxt_unicode_block_009, - nxt_unicode_block_00a, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - nxt_unicode_block_03c, - nxt_unicode_block_03d, - nxt_unicode_block_03e, - nxt_unicode_block_03f, - NULL, - NULL, - nxt_unicode_block_042, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - nxt_unicode_block_1fe, -}; diff --git a/src/nxt_unit.c b/src/nxt_unit.c deleted file mode 100644 index b6291b2d..00000000 --- a/src/nxt_unit.c +++ /dev/null @@ -1,6802 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include "nxt_main.h" -#include "nxt_port_memory_int.h" -#include "nxt_socket_msg.h" -#include "nxt_port_queue.h" -#include "nxt_app_queue.h" - -#include "nxt_unit.h" -#include "nxt_unit_request.h" -#include "nxt_unit_response.h" -#include "nxt_unit_websocket.h" - -#include "nxt_websocket.h" - -#if (NXT_HAVE_MEMFD_CREATE) -#include -#endif - -#define NXT_UNIT_MAX_PLAIN_SIZE 1024 -#define NXT_UNIT_LOCAL_BUF_SIZE \ - (NXT_UNIT_MAX_PLAIN_SIZE + sizeof(nxt_port_msg_t)) - -enum { - NXT_QUIT_NORMAL = 0, - NXT_QUIT_GRACEFUL = 1, -}; - -typedef struct nxt_unit_impl_s nxt_unit_impl_t; -typedef struct nxt_unit_mmap_s nxt_unit_mmap_t; -typedef struct nxt_unit_mmaps_s nxt_unit_mmaps_t; -typedef struct nxt_unit_process_s nxt_unit_process_t; -typedef struct nxt_unit_mmap_buf_s nxt_unit_mmap_buf_t; -typedef struct nxt_unit_recv_msg_s nxt_unit_recv_msg_t; -typedef struct nxt_unit_read_buf_s nxt_unit_read_buf_t; -typedef struct nxt_unit_ctx_impl_s nxt_unit_ctx_impl_t; -typedef struct nxt_unit_port_impl_s nxt_unit_port_impl_t; -typedef struct nxt_unit_request_info_impl_s nxt_unit_request_info_impl_t; -typedef struct nxt_unit_websocket_frame_impl_s nxt_unit_websocket_frame_impl_t; - -static nxt_unit_impl_t *nxt_unit_create(nxt_unit_init_t *init); -static int nxt_unit_ctx_init(nxt_unit_impl_t *lib, - nxt_unit_ctx_impl_t *ctx_impl, void *data); -nxt_inline void nxt_unit_ctx_use(nxt_unit_ctx_t *ctx); -nxt_inline void nxt_unit_ctx_release(nxt_unit_ctx_t *ctx); -nxt_inline void nxt_unit_lib_use(nxt_unit_impl_t *lib); -nxt_inline void nxt_unit_lib_release(nxt_unit_impl_t *lib); -nxt_inline void nxt_unit_mmap_buf_insert(nxt_unit_mmap_buf_t **head, - nxt_unit_mmap_buf_t *mmap_buf); -nxt_inline void nxt_unit_mmap_buf_insert_tail(nxt_unit_mmap_buf_t **prev, - nxt_unit_mmap_buf_t *mmap_buf); -nxt_inline void nxt_unit_mmap_buf_unlink(nxt_unit_mmap_buf_t *mmap_buf); -static int nxt_unit_read_env(nxt_unit_port_t *ready_port, - nxt_unit_port_t *router_port, nxt_unit_port_t *read_port, - int *shared_port_fd, int *shared_queue_fd, - int *log_fd, uint32_t *stream, uint32_t *shm_limit, - uint32_t *request_limit); -static int nxt_unit_ready(nxt_unit_ctx_t *ctx, int ready_fd, uint32_t stream, - int queue_fd); -static int nxt_unit_process_msg(nxt_unit_ctx_t *ctx, nxt_unit_read_buf_t *rbuf, - nxt_unit_request_info_t **preq); -static int nxt_unit_process_new_port(nxt_unit_ctx_t *ctx, - nxt_unit_recv_msg_t *recv_msg); -static int nxt_unit_ctx_ready(nxt_unit_ctx_t *ctx); -static int nxt_unit_process_req_headers(nxt_unit_ctx_t *ctx, - nxt_unit_recv_msg_t *recv_msg, nxt_unit_request_info_t **preq); -static int nxt_unit_process_req_body(nxt_unit_ctx_t *ctx, - nxt_unit_recv_msg_t *recv_msg); -static int nxt_unit_request_check_response_port(nxt_unit_request_info_t *req, - nxt_unit_port_id_t *port_id); -static int nxt_unit_send_req_headers_ack(nxt_unit_request_info_t *req); -static int nxt_unit_process_websocket(nxt_unit_ctx_t *ctx, - nxt_unit_recv_msg_t *recv_msg); -static int nxt_unit_process_shm_ack(nxt_unit_ctx_t *ctx); -static nxt_unit_request_info_impl_t *nxt_unit_request_info_get( - nxt_unit_ctx_t *ctx); -static void nxt_unit_request_info_release(nxt_unit_request_info_t *req); -static void nxt_unit_request_info_free(nxt_unit_request_info_impl_t *req); -static nxt_unit_websocket_frame_impl_t *nxt_unit_websocket_frame_get( - nxt_unit_ctx_t *ctx); -static void nxt_unit_websocket_frame_release(nxt_unit_websocket_frame_t *ws); -static void nxt_unit_websocket_frame_free(nxt_unit_ctx_t *ctx, - nxt_unit_websocket_frame_impl_t *ws); -static nxt_unit_mmap_buf_t *nxt_unit_mmap_buf_get(nxt_unit_ctx_t *ctx); -static void nxt_unit_mmap_buf_release(nxt_unit_mmap_buf_t *mmap_buf); -static int nxt_unit_mmap_buf_send(nxt_unit_request_info_t *req, - nxt_unit_mmap_buf_t *mmap_buf, int last); -static void nxt_unit_mmap_buf_free(nxt_unit_mmap_buf_t *mmap_buf); -static void nxt_unit_free_outgoing_buf(nxt_unit_mmap_buf_t *mmap_buf); -static nxt_unit_read_buf_t *nxt_unit_read_buf_get(nxt_unit_ctx_t *ctx); -static nxt_unit_read_buf_t *nxt_unit_read_buf_get_impl( - nxt_unit_ctx_impl_t *ctx_impl); -static void nxt_unit_read_buf_release(nxt_unit_ctx_t *ctx, - nxt_unit_read_buf_t *rbuf); -static nxt_unit_mmap_buf_t *nxt_unit_request_preread( - nxt_unit_request_info_t *req, size_t size); -static ssize_t nxt_unit_buf_read(nxt_unit_buf_t **b, uint64_t *len, void *dst, - size_t size); -static nxt_port_mmap_header_t *nxt_unit_mmap_get(nxt_unit_ctx_t *ctx, - nxt_unit_port_t *port, nxt_chunk_id_t *c, int *n, int min_n); -static int nxt_unit_send_oosm(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port); -static int nxt_unit_wait_shm_ack(nxt_unit_ctx_t *ctx); -static nxt_unit_mmap_t *nxt_unit_mmap_at(nxt_unit_mmaps_t *mmaps, uint32_t i); -static nxt_port_mmap_header_t *nxt_unit_new_mmap(nxt_unit_ctx_t *ctx, - nxt_unit_port_t *port, int n); -static int nxt_unit_shm_open(nxt_unit_ctx_t *ctx, size_t size); -static int nxt_unit_send_mmap(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - int fd); -static int nxt_unit_get_outgoing_buf(nxt_unit_ctx_t *ctx, - nxt_unit_port_t *port, uint32_t size, - uint32_t min_size, nxt_unit_mmap_buf_t *mmap_buf, char *local_buf); -static int nxt_unit_incoming_mmap(nxt_unit_ctx_t *ctx, pid_t pid, int fd); - -static void nxt_unit_awake_ctx(nxt_unit_ctx_t *ctx, - nxt_unit_ctx_impl_t *ctx_impl); -static int nxt_unit_mmaps_init(nxt_unit_mmaps_t *mmaps); -nxt_inline void nxt_unit_process_use(nxt_unit_process_t *process); -nxt_inline void nxt_unit_process_release(nxt_unit_process_t *process); -static void nxt_unit_mmaps_destroy(nxt_unit_mmaps_t *mmaps); -static int nxt_unit_check_rbuf_mmap(nxt_unit_ctx_t *ctx, - nxt_unit_mmaps_t *mmaps, pid_t pid, uint32_t id, - nxt_port_mmap_header_t **hdr, nxt_unit_read_buf_t *rbuf); -static int nxt_unit_mmap_read(nxt_unit_ctx_t *ctx, - nxt_unit_recv_msg_t *recv_msg, nxt_unit_read_buf_t *rbuf); -static int nxt_unit_get_mmap(nxt_unit_ctx_t *ctx, pid_t pid, uint32_t id); -static void nxt_unit_mmap_release(nxt_unit_ctx_t *ctx, - nxt_port_mmap_header_t *hdr, void *start, uint32_t size); -static int nxt_unit_send_shm_ack(nxt_unit_ctx_t *ctx, pid_t pid); - -static nxt_unit_process_t *nxt_unit_process_get(nxt_unit_ctx_t *ctx, pid_t pid); -static nxt_unit_process_t *nxt_unit_process_find(nxt_unit_impl_t *lib, - pid_t pid, int remove); -static nxt_unit_process_t *nxt_unit_process_pop_first(nxt_unit_impl_t *lib); -static int nxt_unit_run_once_impl(nxt_unit_ctx_t *ctx); -static int nxt_unit_read_buf(nxt_unit_ctx_t *ctx, nxt_unit_read_buf_t *rbuf); -static int nxt_unit_chk_ready(nxt_unit_ctx_t *ctx); -static int nxt_unit_process_pending_rbuf(nxt_unit_ctx_t *ctx); -static void nxt_unit_process_ready_req(nxt_unit_ctx_t *ctx); -nxt_inline int nxt_unit_is_read_queue(nxt_unit_read_buf_t *rbuf); -nxt_inline int nxt_unit_is_read_socket(nxt_unit_read_buf_t *rbuf); -nxt_inline int nxt_unit_is_shm_ack(nxt_unit_read_buf_t *rbuf); -nxt_inline int nxt_unit_is_quit(nxt_unit_read_buf_t *rbuf); -static int nxt_unit_process_port_msg_impl(nxt_unit_ctx_t *ctx, - nxt_unit_port_t *port); -static void nxt_unit_ctx_free(nxt_unit_ctx_impl_t *ctx_impl); -static nxt_unit_port_t *nxt_unit_create_port(nxt_unit_ctx_t *ctx); - -static int nxt_unit_send_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *dst, - nxt_unit_port_t *port, int queue_fd); - -nxt_inline void nxt_unit_port_use(nxt_unit_port_t *port); -nxt_inline void nxt_unit_port_release(nxt_unit_port_t *port); -static nxt_unit_port_t *nxt_unit_add_port(nxt_unit_ctx_t *ctx, - nxt_unit_port_t *port, void *queue); -static void nxt_unit_process_awaiting_req(nxt_unit_ctx_t *ctx, - nxt_queue_t *awaiting_req); -static void nxt_unit_remove_port(nxt_unit_impl_t *lib, nxt_unit_ctx_t *ctx, - nxt_unit_port_id_t *port_id); -static nxt_unit_port_t *nxt_unit_remove_port_unsafe(nxt_unit_impl_t *lib, - nxt_unit_port_id_t *port_id); -static void nxt_unit_remove_pid(nxt_unit_impl_t *lib, pid_t pid); -static void nxt_unit_remove_process(nxt_unit_impl_t *lib, - nxt_unit_process_t *process); -static void nxt_unit_quit(nxt_unit_ctx_t *ctx, uint8_t quit_param); -static int nxt_unit_get_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id); -static ssize_t nxt_unit_port_send(nxt_unit_ctx_t *ctx, - nxt_unit_port_t *port, const void *buf, size_t buf_size, - const nxt_send_oob_t *oob); -static ssize_t nxt_unit_sendmsg(nxt_unit_ctx_t *ctx, int fd, - const void *buf, size_t buf_size, const nxt_send_oob_t *oob); -static int nxt_unit_ctx_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - nxt_unit_read_buf_t *rbuf); -nxt_inline void nxt_unit_rbuf_cpy(nxt_unit_read_buf_t *dst, - nxt_unit_read_buf_t *src); -static int nxt_unit_shared_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - nxt_unit_read_buf_t *rbuf); -static int nxt_unit_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - nxt_unit_read_buf_t *rbuf); -static int nxt_unit_port_queue_recv(nxt_unit_port_t *port, - nxt_unit_read_buf_t *rbuf); -static int nxt_unit_app_queue_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - nxt_unit_read_buf_t *rbuf); -nxt_inline int nxt_unit_close(int fd); -static int nxt_unit_fd_blocking(int fd); - -static int nxt_unit_port_hash_add(nxt_lvlhsh_t *port_hash, - nxt_unit_port_t *port); -static nxt_unit_port_t *nxt_unit_port_hash_find(nxt_lvlhsh_t *port_hash, - nxt_unit_port_id_t *port_id, int remove); - -static int nxt_unit_request_hash_add(nxt_unit_ctx_t *ctx, - nxt_unit_request_info_t *req); -static nxt_unit_request_info_t *nxt_unit_request_hash_find( - nxt_unit_ctx_t *ctx, uint32_t stream, int remove); - -static char * nxt_unit_snprint_prefix(char *p, char *end, pid_t pid, - int level); -static void *nxt_unit_lvlhsh_alloc(void *data, size_t size); -static void nxt_unit_lvlhsh_free(void *data, void *p); -static int nxt_unit_memcasecmp(const void *p1, const void *p2, size_t length); - - -struct nxt_unit_mmap_buf_s { - nxt_unit_buf_t buf; - - nxt_unit_mmap_buf_t *next; - nxt_unit_mmap_buf_t **prev; - - nxt_port_mmap_header_t *hdr; - nxt_unit_request_info_t *req; - nxt_unit_ctx_impl_t *ctx_impl; - char *free_ptr; - char *plain_ptr; -}; - - -struct nxt_unit_recv_msg_s { - uint32_t stream; - nxt_pid_t pid; - nxt_port_id_t reply_port; - - uint8_t last; /* 1 bit */ - uint8_t mmap; /* 1 bit */ - - void *start; - uint32_t size; - - int fd[2]; - - nxt_unit_mmap_buf_t *incoming_buf; -}; - - -typedef enum { - NXT_UNIT_RS_START = 0, - NXT_UNIT_RS_RESPONSE_INIT, - NXT_UNIT_RS_RESPONSE_HAS_CONTENT, - NXT_UNIT_RS_RESPONSE_SENT, - NXT_UNIT_RS_RELEASED, -} nxt_unit_req_state_t; - - -struct nxt_unit_request_info_impl_s { - nxt_unit_request_info_t req; - - uint32_t stream; - - nxt_unit_mmap_buf_t *outgoing_buf; - nxt_unit_mmap_buf_t *incoming_buf; - - nxt_unit_req_state_t state; - uint8_t websocket; - uint8_t in_hash; - - /* for nxt_unit_ctx_impl_t.free_req or active_req */ - nxt_queue_link_t link; - /* for nxt_unit_port_impl_t.awaiting_req */ - nxt_queue_link_t port_wait_link; - - char extra_data[]; -}; - - -struct nxt_unit_websocket_frame_impl_s { - nxt_unit_websocket_frame_t ws; - - nxt_unit_mmap_buf_t *buf; - - nxt_queue_link_t link; - - nxt_unit_ctx_impl_t *ctx_impl; -}; - - -struct nxt_unit_read_buf_s { - nxt_queue_link_t link; - nxt_unit_ctx_impl_t *ctx_impl; - ssize_t size; - nxt_recv_oob_t oob; - char buf[16384]; -}; - - -struct nxt_unit_ctx_impl_s { - nxt_unit_ctx_t ctx; - - nxt_atomic_t use_count; - nxt_atomic_t wait_items; - - pthread_mutex_t mutex; - - nxt_unit_port_t *read_port; - - nxt_queue_link_t link; - - nxt_unit_mmap_buf_t *free_buf; - - /* of nxt_unit_request_info_impl_t */ - nxt_queue_t free_req; - - /* of nxt_unit_websocket_frame_impl_t */ - nxt_queue_t free_ws; - - /* of nxt_unit_request_info_impl_t */ - nxt_queue_t active_req; - - /* of nxt_unit_request_info_impl_t */ - nxt_lvlhsh_t requests; - - /* of nxt_unit_request_info_impl_t */ - nxt_queue_t ready_req; - - /* of nxt_unit_read_buf_t */ - nxt_queue_t pending_rbuf; - - /* of nxt_unit_read_buf_t */ - nxt_queue_t free_rbuf; - - uint8_t online; /* 1 bit */ - uint8_t ready; /* 1 bit */ - uint8_t quit_param; - - nxt_unit_mmap_buf_t ctx_buf[2]; - nxt_unit_read_buf_t ctx_read_buf; - - nxt_unit_request_info_impl_t req; -}; - - -struct nxt_unit_mmap_s { - nxt_port_mmap_header_t *hdr; - pthread_t src_thread; - - /* of nxt_unit_read_buf_t */ - nxt_queue_t awaiting_rbuf; -}; - - -struct nxt_unit_mmaps_s { - pthread_mutex_t mutex; - uint32_t size; - uint32_t cap; - nxt_atomic_t allocated_chunks; - nxt_unit_mmap_t *elts; -}; - - -struct nxt_unit_impl_s { - nxt_unit_t unit; - nxt_unit_callbacks_t callbacks; - - nxt_atomic_t use_count; - nxt_atomic_t request_count; - - uint32_t request_data_size; - uint32_t shm_mmap_limit; - uint32_t request_limit; - - pthread_mutex_t mutex; - - nxt_lvlhsh_t processes; /* of nxt_unit_process_t */ - nxt_lvlhsh_t ports; /* of nxt_unit_port_impl_t */ - - nxt_unit_port_t *router_port; - nxt_unit_port_t *shared_port; - - nxt_queue_t contexts; /* of nxt_unit_ctx_impl_t */ - - nxt_unit_mmaps_t incoming; - nxt_unit_mmaps_t outgoing; - - pid_t pid; - int log_fd; - - nxt_unit_ctx_impl_t main_ctx; -}; - - -struct nxt_unit_port_impl_s { - nxt_unit_port_t port; - - nxt_atomic_t use_count; - - /* for nxt_unit_process_t.ports */ - nxt_queue_link_t link; - nxt_unit_process_t *process; - - /* of nxt_unit_request_info_impl_t */ - nxt_queue_t awaiting_req; - - int ready; - - void *queue; - - int from_socket; - nxt_unit_read_buf_t *socket_rbuf; -}; - - -struct nxt_unit_process_s { - pid_t pid; - - nxt_queue_t ports; /* of nxt_unit_port_impl_t */ - - nxt_unit_impl_t *lib; - - nxt_atomic_t use_count; - - uint32_t next_port_id; -}; - - -/* Explicitly using 32 bit types to avoid possible alignment. */ -typedef struct { - int32_t pid; - uint32_t id; -} nxt_unit_port_hash_id_t; - - -static pid_t nxt_unit_pid; - - -nxt_unit_ctx_t * -nxt_unit_init(nxt_unit_init_t *init) -{ - int rc, queue_fd, shared_queue_fd; - void *mem; - uint32_t ready_stream, shm_limit, request_limit; - nxt_unit_ctx_t *ctx; - nxt_unit_impl_t *lib; - nxt_unit_port_t ready_port, router_port, read_port, shared_port; - - nxt_unit_pid = getpid(); - - lib = nxt_unit_create(init); - if (nxt_slow_path(lib == NULL)) { - return NULL; - } - - queue_fd = -1; - mem = MAP_FAILED; - shared_port.out_fd = -1; - shared_port.data = NULL; - - if (init->ready_port.id.pid != 0 - && init->ready_stream != 0 - && init->read_port.id.pid != 0) - { - ready_port = init->ready_port; - ready_stream = init->ready_stream; - router_port = init->router_port; - read_port = init->read_port; - lib->log_fd = init->log_fd; - - nxt_unit_port_id_init(&ready_port.id, ready_port.id.pid, - ready_port.id.id); - nxt_unit_port_id_init(&router_port.id, router_port.id.pid, - router_port.id.id); - nxt_unit_port_id_init(&read_port.id, read_port.id.pid, - read_port.id.id); - - shared_port.in_fd = init->shared_port_fd; - shared_queue_fd = init->shared_queue_fd; - - } else { - rc = nxt_unit_read_env(&ready_port, &router_port, &read_port, - &shared_port.in_fd, &shared_queue_fd, - &lib->log_fd, &ready_stream, &shm_limit, - &request_limit); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - lib->shm_mmap_limit = (shm_limit + PORT_MMAP_DATA_SIZE - 1) - / PORT_MMAP_DATA_SIZE; - lib->request_limit = request_limit; - } - - if (nxt_slow_path(lib->shm_mmap_limit < 1)) { - lib->shm_mmap_limit = 1; - } - - lib->pid = read_port.id.pid; - nxt_unit_pid = lib->pid; - - ctx = &lib->main_ctx.ctx; - - rc = nxt_unit_fd_blocking(router_port.out_fd); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - lib->router_port = nxt_unit_add_port(ctx, &router_port, NULL); - if (nxt_slow_path(lib->router_port == NULL)) { - nxt_unit_alert(NULL, "failed to add router_port"); - - goto fail; - } - - queue_fd = nxt_unit_shm_open(ctx, sizeof(nxt_port_queue_t)); - if (nxt_slow_path(queue_fd == -1)) { - goto fail; - } - - mem = mmap(NULL, sizeof(nxt_port_queue_t), - PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0); - if (nxt_slow_path(mem == MAP_FAILED)) { - nxt_unit_alert(ctx, "mmap(%d) failed: %s (%d)", queue_fd, - strerror(errno), errno); - - goto fail; - } - - nxt_port_queue_init(mem); - - rc = nxt_unit_fd_blocking(read_port.in_fd); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - lib->main_ctx.read_port = nxt_unit_add_port(ctx, &read_port, mem); - if (nxt_slow_path(lib->main_ctx.read_port == NULL)) { - nxt_unit_alert(NULL, "failed to add read_port"); - - goto fail; - } - - rc = nxt_unit_fd_blocking(ready_port.out_fd); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - nxt_unit_port_id_init(&shared_port.id, read_port.id.pid, - NXT_UNIT_SHARED_PORT_ID); - - mem = mmap(NULL, sizeof(nxt_app_queue_t), PROT_READ | PROT_WRITE, - MAP_SHARED, shared_queue_fd, 0); - if (nxt_slow_path(mem == MAP_FAILED)) { - nxt_unit_alert(ctx, "mmap(%d) failed: %s (%d)", shared_queue_fd, - strerror(errno), errno); - - goto fail; - } - - nxt_unit_close(shared_queue_fd); - - lib->shared_port = nxt_unit_add_port(ctx, &shared_port, mem); - if (nxt_slow_path(lib->shared_port == NULL)) { - nxt_unit_alert(NULL, "failed to add shared_port"); - - goto fail; - } - - rc = nxt_unit_ready(ctx, ready_port.out_fd, ready_stream, queue_fd); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_alert(NULL, "failed to send READY message"); - - goto fail; - } - - nxt_unit_close(ready_port.out_fd); - nxt_unit_close(queue_fd); - - return ctx; - -fail: - - if (mem != MAP_FAILED) { - munmap(mem, sizeof(nxt_port_queue_t)); - } - - if (queue_fd != -1) { - nxt_unit_close(queue_fd); - } - - nxt_unit_ctx_release(&lib->main_ctx.ctx); - - return NULL; -} - - -static nxt_unit_impl_t * -nxt_unit_create(nxt_unit_init_t *init) -{ - int rc; - nxt_unit_impl_t *lib; - - if (nxt_slow_path(init->callbacks.request_handler == NULL)) { - nxt_unit_alert(NULL, "request_handler is NULL"); - - return NULL; - } - - lib = nxt_unit_malloc(NULL, - sizeof(nxt_unit_impl_t) + init->request_data_size); - if (nxt_slow_path(lib == NULL)) { - nxt_unit_alert(NULL, "failed to allocate unit struct"); - - return NULL; - } - - rc = pthread_mutex_init(&lib->mutex, NULL); - if (nxt_slow_path(rc != 0)) { - nxt_unit_alert(NULL, "failed to initialize mutex (%d)", rc); - - goto out_unit_free; - } - - lib->unit.data = init->data; - lib->callbacks = init->callbacks; - - lib->request_data_size = init->request_data_size; - lib->shm_mmap_limit = (init->shm_limit + PORT_MMAP_DATA_SIZE - 1) - / PORT_MMAP_DATA_SIZE; - lib->request_limit = init->request_limit; - - lib->processes.slot = NULL; - lib->ports.slot = NULL; - - lib->log_fd = STDERR_FILENO; - - nxt_queue_init(&lib->contexts); - - lib->use_count = 0; - lib->request_count = 0; - lib->router_port = NULL; - lib->shared_port = NULL; - - rc = nxt_unit_ctx_init(lib, &lib->main_ctx, init->ctx_data); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto out_mutex_destroy; - } - - rc = nxt_unit_mmaps_init(&lib->incoming); - if (nxt_slow_path(rc != 0)) { - nxt_unit_alert(NULL, "failed to initialize mutex (%d)", rc); - - goto out_ctx_free; - } - - rc = nxt_unit_mmaps_init(&lib->outgoing); - if (nxt_slow_path(rc != 0)) { - nxt_unit_alert(NULL, "failed to initialize mutex (%d)", rc); - - goto out_mmaps_destroy; - } - - return lib; - -out_mmaps_destroy: - nxt_unit_mmaps_destroy(&lib->incoming); - -out_ctx_free: - nxt_unit_ctx_free(&lib->main_ctx); - -out_mutex_destroy: - pthread_mutex_destroy(&lib->mutex); - -out_unit_free: - nxt_unit_free(NULL, lib); - - return NULL; -} - - -static int -nxt_unit_ctx_init(nxt_unit_impl_t *lib, nxt_unit_ctx_impl_t *ctx_impl, - void *data) -{ - int rc; - - ctx_impl->ctx.data = data; - ctx_impl->ctx.unit = &lib->unit; - - rc = pthread_mutex_init(&ctx_impl->mutex, NULL); - if (nxt_slow_path(rc != 0)) { - nxt_unit_alert(NULL, "failed to initialize mutex (%d)", rc); - - return NXT_UNIT_ERROR; - } - - nxt_unit_lib_use(lib); - - pthread_mutex_lock(&lib->mutex); - - nxt_queue_insert_tail(&lib->contexts, &ctx_impl->link); - - pthread_mutex_unlock(&lib->mutex); - - ctx_impl->use_count = 1; - ctx_impl->wait_items = 0; - ctx_impl->online = 1; - ctx_impl->ready = 0; - ctx_impl->quit_param = NXT_QUIT_GRACEFUL; - - nxt_queue_init(&ctx_impl->free_req); - nxt_queue_init(&ctx_impl->free_ws); - nxt_queue_init(&ctx_impl->active_req); - nxt_queue_init(&ctx_impl->ready_req); - nxt_queue_init(&ctx_impl->pending_rbuf); - nxt_queue_init(&ctx_impl->free_rbuf); - - ctx_impl->free_buf = NULL; - nxt_unit_mmap_buf_insert(&ctx_impl->free_buf, &ctx_impl->ctx_buf[1]); - nxt_unit_mmap_buf_insert(&ctx_impl->free_buf, &ctx_impl->ctx_buf[0]); - - nxt_queue_insert_tail(&ctx_impl->free_req, &ctx_impl->req.link); - nxt_queue_insert_tail(&ctx_impl->free_rbuf, &ctx_impl->ctx_read_buf.link); - - ctx_impl->ctx_read_buf.ctx_impl = ctx_impl; - - ctx_impl->req.req.ctx = &ctx_impl->ctx; - ctx_impl->req.req.unit = &lib->unit; - - ctx_impl->read_port = NULL; - ctx_impl->requests.slot = 0; - - return NXT_UNIT_OK; -} - - -nxt_inline void -nxt_unit_ctx_use(nxt_unit_ctx_t *ctx) -{ - nxt_unit_ctx_impl_t *ctx_impl; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - nxt_atomic_fetch_add(&ctx_impl->use_count, 1); -} - - -nxt_inline void -nxt_unit_ctx_release(nxt_unit_ctx_t *ctx) -{ - long c; - nxt_unit_ctx_impl_t *ctx_impl; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - c = nxt_atomic_fetch_add(&ctx_impl->use_count, -1); - - if (c == 1) { - nxt_unit_ctx_free(ctx_impl); - } -} - - -nxt_inline void -nxt_unit_lib_use(nxt_unit_impl_t *lib) -{ - nxt_atomic_fetch_add(&lib->use_count, 1); -} - - -nxt_inline void -nxt_unit_lib_release(nxt_unit_impl_t *lib) -{ - long c; - nxt_unit_process_t *process; - - c = nxt_atomic_fetch_add(&lib->use_count, -1); - - if (c == 1) { - for ( ;; ) { - pthread_mutex_lock(&lib->mutex); - - process = nxt_unit_process_pop_first(lib); - if (process == NULL) { - pthread_mutex_unlock(&lib->mutex); - - break; - } - - nxt_unit_remove_process(lib, process); - } - - pthread_mutex_destroy(&lib->mutex); - - if (nxt_fast_path(lib->router_port != NULL)) { - nxt_unit_port_release(lib->router_port); - } - - if (nxt_fast_path(lib->shared_port != NULL)) { - nxt_unit_port_release(lib->shared_port); - } - - nxt_unit_mmaps_destroy(&lib->incoming); - nxt_unit_mmaps_destroy(&lib->outgoing); - - nxt_unit_free(NULL, lib); - } -} - - -nxt_inline void -nxt_unit_mmap_buf_insert(nxt_unit_mmap_buf_t **head, - nxt_unit_mmap_buf_t *mmap_buf) -{ - mmap_buf->next = *head; - - if (mmap_buf->next != NULL) { - mmap_buf->next->prev = &mmap_buf->next; - } - - *head = mmap_buf; - mmap_buf->prev = head; -} - - -nxt_inline void -nxt_unit_mmap_buf_insert_tail(nxt_unit_mmap_buf_t **prev, - nxt_unit_mmap_buf_t *mmap_buf) -{ - while (*prev != NULL) { - prev = &(*prev)->next; - } - - nxt_unit_mmap_buf_insert(prev, mmap_buf); -} - - -nxt_inline void -nxt_unit_mmap_buf_unlink(nxt_unit_mmap_buf_t *mmap_buf) -{ - nxt_unit_mmap_buf_t **prev; - - prev = mmap_buf->prev; - - if (mmap_buf->next != NULL) { - mmap_buf->next->prev = prev; - } - - if (prev != NULL) { - *prev = mmap_buf->next; - } -} - - -static int -nxt_unit_read_env(nxt_unit_port_t *ready_port, nxt_unit_port_t *router_port, - nxt_unit_port_t *read_port, int *shared_port_fd, int *shared_queue_fd, - int *log_fd, uint32_t *stream, - uint32_t *shm_limit, uint32_t *request_limit) -{ - int rc; - int ready_fd, router_fd, read_in_fd, read_out_fd; - char *unit_init, *version_end, *vars; - size_t version_length; - int64_t ready_pid, router_pid, read_pid; - uint32_t ready_stream, router_id, ready_id, read_id; - - unit_init = getenv(NXT_UNIT_INIT_ENV); - if (nxt_slow_path(unit_init == NULL)) { - nxt_unit_alert(NULL, "%s is not in the current environment", - NXT_UNIT_INIT_ENV); - - return NXT_UNIT_ERROR; - } - - version_end = strchr(unit_init, ';'); - if (nxt_slow_path(version_end == NULL)) { - nxt_unit_alert(NULL, "Unit version not found in %s=\"%s\"", - NXT_UNIT_INIT_ENV, unit_init); - - return NXT_UNIT_ERROR; - } - - version_length = version_end - unit_init; - - rc = version_length != nxt_length(NXT_VERSION) - || memcmp(unit_init, NXT_VERSION, nxt_length(NXT_VERSION)); - - if (nxt_slow_path(rc != 0)) { - nxt_unit_alert(NULL, "versions mismatch: the Unit daemon has version " - "%.*s, while the app was compiled with libunit %s", - (int) version_length, unit_init, NXT_VERSION); - - return NXT_UNIT_ERROR; - } - - vars = version_end + 1; - - rc = sscanf(vars, - "%"PRIu32";" - "%"PRId64",%"PRIu32",%d;" - "%"PRId64",%"PRIu32",%d;" - "%"PRId64",%"PRIu32",%d,%d;" - "%d,%d;" - "%d,%"PRIu32",%"PRIu32, - &ready_stream, - &ready_pid, &ready_id, &ready_fd, - &router_pid, &router_id, &router_fd, - &read_pid, &read_id, &read_in_fd, &read_out_fd, - shared_port_fd, shared_queue_fd, - log_fd, shm_limit, request_limit); - - if (nxt_slow_path(rc == EOF)) { - nxt_unit_alert(NULL, "sscanf(%s) failed: %s (%d) for %s env", - vars, strerror(errno), errno, NXT_UNIT_INIT_ENV); - - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(rc != 16)) { - nxt_unit_alert(NULL, "invalid number of variables in %s env: " - "found %d of %d in %s", NXT_UNIT_INIT_ENV, rc, 16, vars); - - return NXT_UNIT_ERROR; - } - - nxt_unit_debug(NULL, "%s='%s'", NXT_UNIT_INIT_ENV, unit_init); - - nxt_unit_port_id_init(&ready_port->id, (pid_t) ready_pid, ready_id); - - ready_port->in_fd = -1; - ready_port->out_fd = ready_fd; - ready_port->data = NULL; - - nxt_unit_port_id_init(&router_port->id, (pid_t) router_pid, router_id); - - router_port->in_fd = -1; - router_port->out_fd = router_fd; - router_port->data = NULL; - - nxt_unit_port_id_init(&read_port->id, (pid_t) read_pid, read_id); - - read_port->in_fd = read_in_fd; - read_port->out_fd = read_out_fd; - read_port->data = NULL; - - *stream = ready_stream; - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_ready(nxt_unit_ctx_t *ctx, int ready_fd, uint32_t stream, int queue_fd) -{ - ssize_t res; - nxt_send_oob_t oob; - nxt_port_msg_t msg; - nxt_unit_impl_t *lib; - int fds[2] = {queue_fd, -1}; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - msg.stream = stream; - msg.pid = lib->pid; - msg.reply_port = 0; - msg.type = _NXT_PORT_MSG_PROCESS_READY; - msg.last = 1; - msg.mmap = 0; - msg.nf = 0; - msg.mf = 0; - - nxt_socket_msg_oob_init(&oob, fds); - - res = nxt_unit_sendmsg(ctx, ready_fd, &msg, sizeof(msg), &oob); - if (res != sizeof(msg)) { - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_process_msg(nxt_unit_ctx_t *ctx, nxt_unit_read_buf_t *rbuf, - nxt_unit_request_info_t **preq) -{ - int rc; - pid_t pid; - uint8_t quit_param; - nxt_port_msg_t *port_msg; - nxt_unit_impl_t *lib; - nxt_unit_recv_msg_t recv_msg; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - recv_msg.incoming_buf = NULL; - recv_msg.fd[0] = -1; - recv_msg.fd[1] = -1; - - rc = nxt_socket_msg_oob_get_fds(&rbuf->oob, recv_msg.fd); - if (nxt_slow_path(rc != NXT_OK)) { - nxt_unit_alert(ctx, "failed to receive file descriptor over cmsg"); - rc = NXT_UNIT_ERROR; - goto done; - } - - if (nxt_slow_path(rbuf->size < (ssize_t) sizeof(nxt_port_msg_t))) { - if (nxt_slow_path(rbuf->size == 0)) { - nxt_unit_debug(ctx, "read port closed"); - - nxt_unit_quit(ctx, NXT_QUIT_GRACEFUL); - rc = NXT_UNIT_OK; - goto done; - } - - nxt_unit_alert(ctx, "message too small (%d bytes)", (int) rbuf->size); - - rc = NXT_UNIT_ERROR; - goto done; - } - - port_msg = (nxt_port_msg_t *) rbuf->buf; - - nxt_unit_debug(ctx, "#%"PRIu32": process message %d fd[0] %d fd[1] %d", - port_msg->stream, (int) port_msg->type, - recv_msg.fd[0], recv_msg.fd[1]); - - recv_msg.stream = port_msg->stream; - recv_msg.pid = port_msg->pid; - recv_msg.reply_port = port_msg->reply_port; - recv_msg.last = port_msg->last; - recv_msg.mmap = port_msg->mmap; - - recv_msg.start = port_msg + 1; - recv_msg.size = rbuf->size - sizeof(nxt_port_msg_t); - - if (nxt_slow_path(port_msg->type >= NXT_PORT_MSG_MAX)) { - nxt_unit_alert(ctx, "#%"PRIu32": unknown message type (%d)", - port_msg->stream, (int) port_msg->type); - rc = NXT_UNIT_ERROR; - goto done; - } - - /* Fragmentation is unsupported. */ - if (nxt_slow_path(port_msg->nf != 0 || port_msg->mf != 0)) { - nxt_unit_alert(ctx, "#%"PRIu32": fragmented message type (%d)", - port_msg->stream, (int) port_msg->type); - rc = NXT_UNIT_ERROR; - goto done; - } - - if (port_msg->mmap) { - rc = nxt_unit_mmap_read(ctx, &recv_msg, rbuf); - - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - if (rc == NXT_UNIT_AGAIN) { - recv_msg.fd[0] = -1; - recv_msg.fd[1] = -1; - } - - goto done; - } - } - - switch (port_msg->type) { - - case _NXT_PORT_MSG_RPC_READY: - rc = NXT_UNIT_OK; - break; - - case _NXT_PORT_MSG_QUIT: - if (recv_msg.size == sizeof(quit_param)) { - memcpy(&quit_param, recv_msg.start, sizeof(quit_param)); - - } else { - quit_param = NXT_QUIT_NORMAL; - } - - nxt_unit_debug(ctx, "#%"PRIu32": %squit", port_msg->stream, - (quit_param == NXT_QUIT_GRACEFUL ? "graceful " : "")); - - nxt_unit_quit(ctx, quit_param); - - rc = NXT_UNIT_OK; - break; - - case _NXT_PORT_MSG_NEW_PORT: - rc = nxt_unit_process_new_port(ctx, &recv_msg); - break; - - case _NXT_PORT_MSG_PORT_ACK: - rc = nxt_unit_ctx_ready(ctx); - break; - - case _NXT_PORT_MSG_CHANGE_FILE: - nxt_unit_debug(ctx, "#%"PRIu32": change_file: fd %d", - port_msg->stream, recv_msg.fd[0]); - - if (dup2(recv_msg.fd[0], lib->log_fd) == -1) { - nxt_unit_alert(ctx, "#%"PRIu32": dup2(%d, %d) failed: %s (%d)", - port_msg->stream, recv_msg.fd[0], lib->log_fd, - strerror(errno), errno); - - rc = NXT_UNIT_ERROR; - goto done; - } - - rc = NXT_UNIT_OK; - break; - - case _NXT_PORT_MSG_MMAP: - if (nxt_slow_path(recv_msg.fd[0] < 0)) { - nxt_unit_alert(ctx, "#%"PRIu32": invalid fd %d for mmap", - port_msg->stream, recv_msg.fd[0]); - - rc = NXT_UNIT_ERROR; - goto done; - } - - rc = nxt_unit_incoming_mmap(ctx, port_msg->pid, recv_msg.fd[0]); - break; - - case _NXT_PORT_MSG_REQ_HEADERS: - rc = nxt_unit_process_req_headers(ctx, &recv_msg, preq); - break; - - case _NXT_PORT_MSG_REQ_BODY: - rc = nxt_unit_process_req_body(ctx, &recv_msg); - break; - - case _NXT_PORT_MSG_WEBSOCKET: - rc = nxt_unit_process_websocket(ctx, &recv_msg); - break; - - case _NXT_PORT_MSG_REMOVE_PID: - if (nxt_slow_path(recv_msg.size != sizeof(pid))) { - nxt_unit_alert(ctx, "#%"PRIu32": remove_pid: invalid message size " - "(%d != %d)", port_msg->stream, (int) recv_msg.size, - (int) sizeof(pid)); - - rc = NXT_UNIT_ERROR; - goto done; - } - - memcpy(&pid, recv_msg.start, sizeof(pid)); - - nxt_unit_debug(ctx, "#%"PRIu32": remove_pid: %d", - port_msg->stream, (int) pid); - - nxt_unit_remove_pid(lib, pid); - - rc = NXT_UNIT_OK; - break; - - case _NXT_PORT_MSG_SHM_ACK: - rc = nxt_unit_process_shm_ack(ctx); - break; - - default: - nxt_unit_alert(ctx, "#%"PRIu32": ignore message type: %d", - port_msg->stream, (int) port_msg->type); - - rc = NXT_UNIT_ERROR; - goto done; - } - -done: - - if (recv_msg.fd[0] != -1) { - nxt_unit_close(recv_msg.fd[0]); - } - - if (recv_msg.fd[1] != -1) { - nxt_unit_close(recv_msg.fd[1]); - } - - while (recv_msg.incoming_buf != NULL) { - nxt_unit_mmap_buf_free(recv_msg.incoming_buf); - } - - if (nxt_fast_path(rc != NXT_UNIT_AGAIN)) { -#if (NXT_DEBUG) - memset(rbuf->buf, 0xAC, rbuf->size); -#endif - nxt_unit_read_buf_release(ctx, rbuf); - } - - return rc; -} - - -static int -nxt_unit_process_new_port(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg) -{ - void *mem; - nxt_unit_port_t new_port, *port; - nxt_port_msg_new_port_t *new_port_msg; - - if (nxt_slow_path(recv_msg->size != sizeof(nxt_port_msg_new_port_t))) { - nxt_unit_warn(ctx, "#%"PRIu32": new_port: " - "invalid message size (%d)", - recv_msg->stream, (int) recv_msg->size); - - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(recv_msg->fd[0] < 0)) { - nxt_unit_alert(ctx, "#%"PRIu32": invalid fd %d for new port", - recv_msg->stream, recv_msg->fd[0]); - - return NXT_UNIT_ERROR; - } - - new_port_msg = recv_msg->start; - - nxt_unit_debug(ctx, "#%"PRIu32": new_port: port{%d,%d} fd[0] %d fd[1] %d", - recv_msg->stream, (int) new_port_msg->pid, - (int) new_port_msg->id, recv_msg->fd[0], recv_msg->fd[1]); - - if (nxt_slow_path(nxt_unit_fd_blocking(recv_msg->fd[0]) != NXT_UNIT_OK)) { - return NXT_UNIT_ERROR; - } - - nxt_unit_port_id_init(&new_port.id, new_port_msg->pid, new_port_msg->id); - - new_port.in_fd = -1; - new_port.out_fd = recv_msg->fd[0]; - - mem = mmap(NULL, sizeof(nxt_port_queue_t), PROT_READ | PROT_WRITE, - MAP_SHARED, recv_msg->fd[1], 0); - - if (nxt_slow_path(mem == MAP_FAILED)) { - nxt_unit_alert(ctx, "mmap(%d) failed: %s (%d)", recv_msg->fd[1], - strerror(errno), errno); - - return NXT_UNIT_ERROR; - } - - new_port.data = NULL; - - recv_msg->fd[0] = -1; - - port = nxt_unit_add_port(ctx, &new_port, mem); - if (nxt_slow_path(port == NULL)) { - return NXT_UNIT_ERROR; - } - - nxt_unit_port_release(port); - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_ctx_ready(nxt_unit_ctx_t *ctx) -{ - nxt_unit_impl_t *lib; - nxt_unit_ctx_impl_t *ctx_impl; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - if (nxt_slow_path(ctx_impl->ready)) { - return NXT_UNIT_OK; - } - - ctx_impl->ready = 1; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - /* Call ready_handler() only for main context. */ - if (&lib->main_ctx == ctx_impl && lib->callbacks.ready_handler != NULL) { - return lib->callbacks.ready_handler(ctx); - } - - if (&lib->main_ctx != ctx_impl) { - /* Check if the main context is already stopped or quit. */ - if (nxt_slow_path(!lib->main_ctx.ready)) { - ctx_impl->ready = 0; - - nxt_unit_quit(ctx, lib->main_ctx.quit_param); - - return NXT_UNIT_OK; - } - - if (lib->callbacks.add_port != NULL) { - lib->callbacks.add_port(ctx, lib->shared_port); - } - } - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_process_req_headers(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg, - nxt_unit_request_info_t **preq) -{ - int res; - nxt_unit_impl_t *lib; - nxt_unit_port_id_t port_id; - nxt_unit_request_t *r; - nxt_unit_mmap_buf_t *b; - nxt_unit_request_info_t *req; - nxt_unit_request_info_impl_t *req_impl; - - if (nxt_slow_path(recv_msg->mmap == 0)) { - nxt_unit_warn(ctx, "#%"PRIu32": data is not in shared memory", - recv_msg->stream); - - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(recv_msg->size < sizeof(nxt_unit_request_t))) { - nxt_unit_warn(ctx, "#%"PRIu32": data too short: %d while at least " - "%d expected", recv_msg->stream, (int) recv_msg->size, - (int) sizeof(nxt_unit_request_t)); - - return NXT_UNIT_ERROR; - } - - req_impl = nxt_unit_request_info_get(ctx); - if (nxt_slow_path(req_impl == NULL)) { - nxt_unit_warn(ctx, "#%"PRIu32": request info allocation failed", - recv_msg->stream); - - return NXT_UNIT_ERROR; - } - - req = &req_impl->req; - - req->request = recv_msg->start; - - b = recv_msg->incoming_buf; - - req->request_buf = &b->buf; - req->response = NULL; - req->response_buf = NULL; - - r = req->request; - - req->content_length = r->content_length; - - req->content_buf = req->request_buf; - req->content_buf->free = nxt_unit_sptr_get(&r->preread_content); - - req_impl->stream = recv_msg->stream; - - req_impl->outgoing_buf = NULL; - - for (b = recv_msg->incoming_buf; b != NULL; b = b->next) { - b->req = req; - } - - /* "Move" incoming buffer list to req_impl. */ - req_impl->incoming_buf = recv_msg->incoming_buf; - req_impl->incoming_buf->prev = &req_impl->incoming_buf; - recv_msg->incoming_buf = NULL; - - req->content_fd = recv_msg->fd[0]; - recv_msg->fd[0] = -1; - - req->response_max_fields = 0; - req_impl->state = NXT_UNIT_RS_START; - req_impl->websocket = 0; - req_impl->in_hash = 0; - - nxt_unit_debug(ctx, "#%"PRIu32": %.*s %.*s (%d)", recv_msg->stream, - (int) r->method_length, - (char *) nxt_unit_sptr_get(&r->method), - (int) r->target_length, - (char *) nxt_unit_sptr_get(&r->target), - (int) r->content_length); - - nxt_unit_port_id_init(&port_id, recv_msg->pid, recv_msg->reply_port); - - res = nxt_unit_request_check_response_port(req, &port_id); - if (nxt_slow_path(res == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - - if (nxt_fast_path(res == NXT_UNIT_OK)) { - res = nxt_unit_send_req_headers_ack(req); - if (nxt_slow_path(res == NXT_UNIT_ERROR)) { - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - return NXT_UNIT_ERROR; - } - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - if (req->content_length - > (uint64_t) (req->content_buf->end - req->content_buf->free)) - { - res = nxt_unit_request_hash_add(ctx, req); - if (nxt_slow_path(res != NXT_UNIT_OK)) { - nxt_unit_req_warn(req, "failed to add request to hash"); - - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - return NXT_UNIT_ERROR; - } - - /* - * If application have separate data handler, we may start - * request processing and process data when it is arrived. - */ - if (lib->callbacks.data_handler == NULL) { - return NXT_UNIT_OK; - } - } - - if (preq == NULL) { - lib->callbacks.request_handler(req); - - } else { - *preq = req; - } - } - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_process_req_body(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg) -{ - uint64_t l; - nxt_unit_impl_t *lib; - nxt_unit_mmap_buf_t *b; - nxt_unit_request_info_t *req; - - req = nxt_unit_request_hash_find(ctx, recv_msg->stream, recv_msg->last); - if (req == NULL) { - return NXT_UNIT_OK; - } - - l = req->content_buf->end - req->content_buf->free; - - for (b = recv_msg->incoming_buf; b != NULL; b = b->next) { - b->req = req; - l += b->buf.end - b->buf.free; - } - - if (recv_msg->incoming_buf != NULL) { - b = nxt_container_of(req->content_buf, nxt_unit_mmap_buf_t, buf); - - while (b->next != NULL) { - b = b->next; - } - - /* "Move" incoming buffer list to req_impl. */ - b->next = recv_msg->incoming_buf; - b->next->prev = &b->next; - - recv_msg->incoming_buf = NULL; - } - - req->content_fd = recv_msg->fd[0]; - recv_msg->fd[0] = -1; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - if (lib->callbacks.data_handler != NULL) { - lib->callbacks.data_handler(req); - - return NXT_UNIT_OK; - } - - if (req->content_fd != -1 || l == req->content_length) { - lib->callbacks.request_handler(req); - } - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_request_check_response_port(nxt_unit_request_info_t *req, - nxt_unit_port_id_t *port_id) -{ - int res; - nxt_unit_ctx_t *ctx; - nxt_unit_impl_t *lib; - nxt_unit_port_t *port; - nxt_unit_process_t *process; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_port_impl_t *port_impl; - nxt_unit_request_info_impl_t *req_impl; - - ctx = req->ctx; - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - pthread_mutex_lock(&lib->mutex); - - port = nxt_unit_port_hash_find(&lib->ports, port_id, 0); - port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - - if (nxt_fast_path(port != NULL)) { - req->response_port = port; - - if (nxt_fast_path(port_impl->ready)) { - pthread_mutex_unlock(&lib->mutex); - - nxt_unit_debug(ctx, "check_response_port: found port{%d,%d}", - (int) port->id.pid, (int) port->id.id); - - return NXT_UNIT_OK; - } - - nxt_unit_debug(ctx, "check_response_port: " - "port{%d,%d} already requested", - (int) port->id.pid, (int) port->id.id); - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - nxt_queue_insert_tail(&port_impl->awaiting_req, - &req_impl->port_wait_link); - - pthread_mutex_unlock(&lib->mutex); - - nxt_atomic_fetch_add(&ctx_impl->wait_items, 1); - - return NXT_UNIT_AGAIN; - } - - port_impl = nxt_unit_malloc(ctx, sizeof(nxt_unit_port_impl_t)); - if (nxt_slow_path(port_impl == NULL)) { - nxt_unit_alert(ctx, "check_response_port: malloc(%d) failed", - (int) sizeof(nxt_unit_port_impl_t)); - - pthread_mutex_unlock(&lib->mutex); - - return NXT_UNIT_ERROR; - } - - port = &port_impl->port; - - port->id = *port_id; - port->in_fd = -1; - port->out_fd = -1; - port->data = NULL; - - res = nxt_unit_port_hash_add(&lib->ports, port); - if (nxt_slow_path(res != NXT_UNIT_OK)) { - nxt_unit_alert(ctx, "check_response_port: %d,%d hash_add failed", - port->id.pid, port->id.id); - - pthread_mutex_unlock(&lib->mutex); - - nxt_unit_free(ctx, port); - - return NXT_UNIT_ERROR; - } - - process = nxt_unit_process_find(lib, port_id->pid, 0); - if (nxt_slow_path(process == NULL)) { - nxt_unit_alert(ctx, "check_response_port: process %d not found", - port->id.pid); - - nxt_unit_port_hash_find(&lib->ports, port_id, 1); - - pthread_mutex_unlock(&lib->mutex); - - nxt_unit_free(ctx, port); - - return NXT_UNIT_ERROR; - } - - nxt_queue_insert_tail(&process->ports, &port_impl->link); - - port_impl->process = process; - port_impl->queue = NULL; - port_impl->from_socket = 0; - port_impl->socket_rbuf = NULL; - - nxt_queue_init(&port_impl->awaiting_req); - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - nxt_queue_insert_tail(&port_impl->awaiting_req, &req_impl->port_wait_link); - - port_impl->use_count = 2; - port_impl->ready = 0; - - req->response_port = port; - - pthread_mutex_unlock(&lib->mutex); - - res = nxt_unit_get_port(ctx, port_id); - if (nxt_slow_path(res == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - - nxt_atomic_fetch_add(&ctx_impl->wait_items, 1); - - return NXT_UNIT_AGAIN; -} - - -static int -nxt_unit_send_req_headers_ack(nxt_unit_request_info_t *req) -{ - ssize_t res; - nxt_port_msg_t msg; - nxt_unit_impl_t *lib; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_request_info_impl_t *req_impl; - - lib = nxt_container_of(req->ctx->unit, nxt_unit_impl_t, unit); - ctx_impl = nxt_container_of(req->ctx, nxt_unit_ctx_impl_t, ctx); - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - memset(&msg, 0, sizeof(nxt_port_msg_t)); - - msg.stream = req_impl->stream; - msg.pid = lib->pid; - msg.reply_port = ctx_impl->read_port->id.id; - msg.type = _NXT_PORT_MSG_REQ_HEADERS_ACK; - - res = nxt_unit_port_send(req->ctx, req->response_port, - &msg, sizeof(msg), NULL); - if (nxt_slow_path(res != sizeof(msg))) { - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_process_websocket(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg) -{ - size_t hsize; - nxt_unit_impl_t *lib; - nxt_unit_mmap_buf_t *b; - nxt_unit_callbacks_t *cb; - nxt_unit_request_info_t *req; - nxt_unit_request_info_impl_t *req_impl; - nxt_unit_websocket_frame_impl_t *ws_impl; - - req = nxt_unit_request_hash_find(ctx, recv_msg->stream, recv_msg->last); - if (nxt_slow_path(req == NULL)) { - return NXT_UNIT_OK; - } - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - cb = &lib->callbacks; - - if (cb->websocket_handler && recv_msg->size >= 2) { - ws_impl = nxt_unit_websocket_frame_get(ctx); - if (nxt_slow_path(ws_impl == NULL)) { - nxt_unit_warn(ctx, "#%"PRIu32": websocket frame allocation failed", - req_impl->stream); - - return NXT_UNIT_ERROR; - } - - ws_impl->ws.req = req; - - ws_impl->buf = NULL; - - if (recv_msg->mmap) { - for (b = recv_msg->incoming_buf; b != NULL; b = b->next) { - b->req = req; - } - - /* "Move" incoming buffer list to ws_impl. */ - ws_impl->buf = recv_msg->incoming_buf; - ws_impl->buf->prev = &ws_impl->buf; - recv_msg->incoming_buf = NULL; - - b = ws_impl->buf; - - } else { - b = nxt_unit_mmap_buf_get(ctx); - if (nxt_slow_path(b == NULL)) { - nxt_unit_alert(ctx, "#%"PRIu32": failed to allocate buf", - req_impl->stream); - - nxt_unit_websocket_frame_release(&ws_impl->ws); - - return NXT_UNIT_ERROR; - } - - b->req = req; - b->buf.start = recv_msg->start; - b->buf.free = b->buf.start; - b->buf.end = b->buf.start + recv_msg->size; - - nxt_unit_mmap_buf_insert(&ws_impl->buf, b); - } - - ws_impl->ws.header = (void *) b->buf.start; - ws_impl->ws.payload_len = nxt_websocket_frame_payload_len( - ws_impl->ws.header); - - hsize = nxt_websocket_frame_header_size(ws_impl->ws.header); - - if (ws_impl->ws.header->mask) { - ws_impl->ws.mask = (uint8_t *) b->buf.start + hsize - 4; - - } else { - ws_impl->ws.mask = NULL; - } - - b->buf.free += hsize; - - ws_impl->ws.content_buf = &b->buf; - ws_impl->ws.content_length = ws_impl->ws.payload_len; - - nxt_unit_req_debug(req, "websocket_handler: opcode=%d, " - "payload_len=%"PRIu64, - ws_impl->ws.header->opcode, - ws_impl->ws.payload_len); - - cb->websocket_handler(&ws_impl->ws); - } - - if (recv_msg->last) { - if (cb->close_handler) { - nxt_unit_req_debug(req, "close_handler"); - - cb->close_handler(req); - - } else { - nxt_unit_request_done(req, NXT_UNIT_ERROR); - } - } - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_process_shm_ack(nxt_unit_ctx_t *ctx) -{ - nxt_unit_impl_t *lib; - nxt_unit_callbacks_t *cb; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - cb = &lib->callbacks; - - if (cb->shm_ack_handler != NULL) { - cb->shm_ack_handler(ctx); - } - - return NXT_UNIT_OK; -} - - -static nxt_unit_request_info_impl_t * -nxt_unit_request_info_get(nxt_unit_ctx_t *ctx) -{ - nxt_unit_impl_t *lib; - nxt_queue_link_t *lnk; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_request_info_impl_t *req_impl; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - pthread_mutex_lock(&ctx_impl->mutex); - - if (nxt_queue_is_empty(&ctx_impl->free_req)) { - pthread_mutex_unlock(&ctx_impl->mutex); - - req_impl = nxt_unit_malloc(ctx, sizeof(nxt_unit_request_info_impl_t) - + lib->request_data_size); - if (nxt_slow_path(req_impl == NULL)) { - return NULL; - } - - req_impl->req.unit = ctx->unit; - req_impl->req.ctx = ctx; - - pthread_mutex_lock(&ctx_impl->mutex); - - } else { - lnk = nxt_queue_first(&ctx_impl->free_req); - nxt_queue_remove(lnk); - - req_impl = nxt_container_of(lnk, nxt_unit_request_info_impl_t, link); - } - - nxt_queue_insert_tail(&ctx_impl->active_req, &req_impl->link); - - pthread_mutex_unlock(&ctx_impl->mutex); - - req_impl->req.data = lib->request_data_size ? req_impl->extra_data : NULL; - - return req_impl; -} - - -static void -nxt_unit_request_info_release(nxt_unit_request_info_t *req) -{ - nxt_unit_ctx_t *ctx; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_request_info_impl_t *req_impl; - - ctx = req->ctx; - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - req->response = NULL; - req->response_buf = NULL; - - if (req_impl->in_hash) { - nxt_unit_request_hash_find(req->ctx, req_impl->stream, 1); - } - - while (req_impl->outgoing_buf != NULL) { - nxt_unit_mmap_buf_free(req_impl->outgoing_buf); - } - - while (req_impl->incoming_buf != NULL) { - nxt_unit_mmap_buf_free(req_impl->incoming_buf); - } - - if (req->content_fd != -1) { - nxt_unit_close(req->content_fd); - - req->content_fd = -1; - } - - if (req->response_port != NULL) { - nxt_unit_port_release(req->response_port); - - req->response_port = NULL; - } - - req_impl->state = NXT_UNIT_RS_RELEASED; - - pthread_mutex_lock(&ctx_impl->mutex); - - nxt_queue_remove(&req_impl->link); - - nxt_queue_insert_tail(&ctx_impl->free_req, &req_impl->link); - - pthread_mutex_unlock(&ctx_impl->mutex); - - if (nxt_slow_path(!nxt_unit_chk_ready(ctx))) { - nxt_unit_quit(ctx, NXT_QUIT_GRACEFUL); - } -} - - -static void -nxt_unit_request_info_free(nxt_unit_request_info_impl_t *req_impl) -{ - nxt_unit_ctx_impl_t *ctx_impl; - - ctx_impl = nxt_container_of(req_impl->req.ctx, nxt_unit_ctx_impl_t, ctx); - - nxt_queue_remove(&req_impl->link); - - if (req_impl != &ctx_impl->req) { - nxt_unit_free(&ctx_impl->ctx, req_impl); - } -} - - -static nxt_unit_websocket_frame_impl_t * -nxt_unit_websocket_frame_get(nxt_unit_ctx_t *ctx) -{ - nxt_queue_link_t *lnk; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_websocket_frame_impl_t *ws_impl; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - pthread_mutex_lock(&ctx_impl->mutex); - - if (nxt_queue_is_empty(&ctx_impl->free_ws)) { - pthread_mutex_unlock(&ctx_impl->mutex); - - ws_impl = nxt_unit_malloc(ctx, sizeof(nxt_unit_websocket_frame_impl_t)); - if (nxt_slow_path(ws_impl == NULL)) { - return NULL; - } - - } else { - lnk = nxt_queue_first(&ctx_impl->free_ws); - nxt_queue_remove(lnk); - - pthread_mutex_unlock(&ctx_impl->mutex); - - ws_impl = nxt_container_of(lnk, nxt_unit_websocket_frame_impl_t, link); - } - - ws_impl->ctx_impl = ctx_impl; - - return ws_impl; -} - - -static void -nxt_unit_websocket_frame_release(nxt_unit_websocket_frame_t *ws) -{ - nxt_unit_websocket_frame_impl_t *ws_impl; - - ws_impl = nxt_container_of(ws, nxt_unit_websocket_frame_impl_t, ws); - - while (ws_impl->buf != NULL) { - nxt_unit_mmap_buf_free(ws_impl->buf); - } - - ws->req = NULL; - - pthread_mutex_lock(&ws_impl->ctx_impl->mutex); - - nxt_queue_insert_tail(&ws_impl->ctx_impl->free_ws, &ws_impl->link); - - pthread_mutex_unlock(&ws_impl->ctx_impl->mutex); -} - - -static void -nxt_unit_websocket_frame_free(nxt_unit_ctx_t *ctx, - nxt_unit_websocket_frame_impl_t *ws_impl) -{ - nxt_queue_remove(&ws_impl->link); - - nxt_unit_free(ctx, ws_impl); -} - - -uint16_t -nxt_unit_field_hash(const char *name, size_t name_length) -{ - u_char ch; - uint32_t hash; - const char *p, *end; - - hash = 159406; /* Magic value copied from nxt_http_parse.c */ - end = name + name_length; - - for (p = name; p < end; p++) { - ch = *p; - hash = (hash << 4) + hash + nxt_lowcase(ch); - } - - hash = (hash >> 16) ^ hash; - - return hash; -} - - -void -nxt_unit_request_group_dup_fields(nxt_unit_request_info_t *req) -{ - char *name; - uint32_t i, j; - nxt_unit_field_t *fields, f; - nxt_unit_request_t *r; - - static nxt_str_t content_length = nxt_string("content-length"); - static nxt_str_t content_type = nxt_string("content-type"); - static nxt_str_t cookie = nxt_string("cookie"); - - nxt_unit_req_debug(req, "group_dup_fields"); - - r = req->request; - fields = r->fields; - - for (i = 0; i < r->fields_count; i++) { - name = nxt_unit_sptr_get(&fields[i].name); - - switch (fields[i].hash) { - case NXT_UNIT_HASH_CONTENT_LENGTH: - if (fields[i].name_length == content_length.length - && nxt_unit_memcasecmp(name, content_length.start, - content_length.length) == 0) - { - r->content_length_field = i; - } - - break; - - case NXT_UNIT_HASH_CONTENT_TYPE: - if (fields[i].name_length == content_type.length - && nxt_unit_memcasecmp(name, content_type.start, - content_type.length) == 0) - { - r->content_type_field = i; - } - - break; - - case NXT_UNIT_HASH_COOKIE: - if (fields[i].name_length == cookie.length - && nxt_unit_memcasecmp(name, cookie.start, - cookie.length) == 0) - { - r->cookie_field = i; - } - - break; - } - - for (j = i + 1; j < r->fields_count; j++) { - if (fields[i].hash != fields[j].hash - || fields[i].name_length != fields[j].name_length - || nxt_unit_memcasecmp(name, - nxt_unit_sptr_get(&fields[j].name), - fields[j].name_length) != 0) - { - continue; - } - - f = fields[j]; - f.value.offset += (j - (i + 1)) * sizeof(f); - - while (j > i + 1) { - fields[j] = fields[j - 1]; - fields[j].name.offset -= sizeof(f); - fields[j].value.offset -= sizeof(f); - j--; - } - - fields[j] = f; - - /* Assign the same name pointer for further grouping simplicity. */ - nxt_unit_sptr_set(&fields[j].name, name); - - i++; - } - } -} - - -int -nxt_unit_response_init(nxt_unit_request_info_t *req, - uint16_t status, uint32_t max_fields_count, uint32_t max_fields_size) -{ - uint32_t buf_size; - nxt_unit_buf_t *buf; - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT)) { - nxt_unit_req_warn(req, "init: response already sent"); - - return NXT_UNIT_ERROR; - } - - nxt_unit_req_debug(req, "init: %d, max fields %d/%d", (int) status, - (int) max_fields_count, (int) max_fields_size); - - if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_INIT)) { - nxt_unit_req_debug(req, "duplicate response init"); - } - - /* - * Each field name and value 0-terminated by libunit, - * this is the reason of '+ 2' below. - */ - buf_size = sizeof(nxt_unit_response_t) - + max_fields_count * (sizeof(nxt_unit_field_t) + 2) - + max_fields_size; - - if (nxt_slow_path(req->response_buf != NULL)) { - buf = req->response_buf; - - if (nxt_fast_path(buf_size <= (uint32_t) (buf->end - buf->start))) { - goto init_response; - } - - nxt_unit_buf_free(buf); - - req->response_buf = NULL; - req->response = NULL; - req->response_max_fields = 0; - - req_impl->state = NXT_UNIT_RS_START; - } - - buf = nxt_unit_response_buf_alloc(req, buf_size); - if (nxt_slow_path(buf == NULL)) { - return NXT_UNIT_ERROR; - } - -init_response: - - memset(buf->start, 0, sizeof(nxt_unit_response_t)); - - req->response_buf = buf; - - req->response = (nxt_unit_response_t *) buf->start; - req->response->status = status; - - buf->free = buf->start + sizeof(nxt_unit_response_t) - + max_fields_count * sizeof(nxt_unit_field_t); - - req->response_max_fields = max_fields_count; - req_impl->state = NXT_UNIT_RS_RESPONSE_INIT; - - return NXT_UNIT_OK; -} - - -int -nxt_unit_response_realloc(nxt_unit_request_info_t *req, - uint32_t max_fields_count, uint32_t max_fields_size) -{ - char *p; - uint32_t i, buf_size; - nxt_unit_buf_t *buf; - nxt_unit_field_t *f, *src; - nxt_unit_response_t *resp; - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) { - nxt_unit_req_warn(req, "realloc: response not init"); - - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT)) { - nxt_unit_req_warn(req, "realloc: response already sent"); - - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(max_fields_count < req->response->fields_count)) { - nxt_unit_req_warn(req, "realloc: new max_fields_count is too small"); - - return NXT_UNIT_ERROR; - } - - /* - * Each field name and value 0-terminated by libunit, - * this is the reason of '+ 2' below. - */ - buf_size = sizeof(nxt_unit_response_t) - + max_fields_count * (sizeof(nxt_unit_field_t) + 2) - + max_fields_size; - - nxt_unit_req_debug(req, "realloc %"PRIu32"", buf_size); - - buf = nxt_unit_response_buf_alloc(req, buf_size); - if (nxt_slow_path(buf == NULL)) { - nxt_unit_req_warn(req, "realloc: new buf allocation failed"); - return NXT_UNIT_ERROR; - } - - resp = (nxt_unit_response_t *) buf->start; - - memset(resp, 0, sizeof(nxt_unit_response_t)); - - resp->status = req->response->status; - resp->content_length = req->response->content_length; - - p = buf->start + sizeof(nxt_unit_response_t) - + max_fields_count * sizeof(nxt_unit_field_t); - f = resp->fields; - - for (i = 0; i < req->response->fields_count; i++) { - src = req->response->fields + i; - - if (nxt_slow_path(src->skip != 0)) { - continue; - } - - if (nxt_slow_path(src->name_length + src->value_length + 2 - > (uint32_t) (buf->end - p))) - { - nxt_unit_req_warn(req, "realloc: not enough space for field" - " #%"PRIu32" (%p), (%"PRIu32" + %"PRIu32") required", - i, src, src->name_length, src->value_length); - - goto fail; - } - - nxt_unit_sptr_set(&f->name, p); - p = nxt_cpymem(p, nxt_unit_sptr_get(&src->name), src->name_length); - *p++ = '\0'; - - nxt_unit_sptr_set(&f->value, p); - p = nxt_cpymem(p, nxt_unit_sptr_get(&src->value), src->value_length); - *p++ = '\0'; - - f->hash = src->hash; - f->skip = 0; - f->name_length = src->name_length; - f->value_length = src->value_length; - - resp->fields_count++; - f++; - } - - if (req->response->piggyback_content_length > 0) { - if (nxt_slow_path(req->response->piggyback_content_length - > (uint32_t) (buf->end - p))) - { - nxt_unit_req_warn(req, "realloc: not enought space for content" - " #%"PRIu32", %"PRIu32" required", - i, req->response->piggyback_content_length); - - goto fail; - } - - resp->piggyback_content_length = - req->response->piggyback_content_length; - - nxt_unit_sptr_set(&resp->piggyback_content, p); - p = nxt_cpymem(p, nxt_unit_sptr_get(&req->response->piggyback_content), - req->response->piggyback_content_length); - } - - buf->free = p; - - nxt_unit_buf_free(req->response_buf); - - req->response = resp; - req->response_buf = buf; - req->response_max_fields = max_fields_count; - - return NXT_UNIT_OK; - -fail: - - nxt_unit_buf_free(buf); - - return NXT_UNIT_ERROR; -} - - -int -nxt_unit_response_is_init(nxt_unit_request_info_t *req) -{ - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - return req_impl->state >= NXT_UNIT_RS_RESPONSE_INIT; -} - - -int -nxt_unit_response_add_field(nxt_unit_request_info_t *req, - const char *name, uint8_t name_length, - const char *value, uint32_t value_length) -{ - nxt_unit_buf_t *buf; - nxt_unit_field_t *f; - nxt_unit_response_t *resp; - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - if (nxt_slow_path(req_impl->state != NXT_UNIT_RS_RESPONSE_INIT)) { - nxt_unit_req_warn(req, "add_field: response not initialized or " - "already sent"); - - return NXT_UNIT_ERROR; - } - - resp = req->response; - - if (nxt_slow_path(resp->fields_count >= req->response_max_fields)) { - nxt_unit_req_warn(req, "add_field: too many response fields (%d)", - (int) resp->fields_count); - - return NXT_UNIT_ERROR; - } - - buf = req->response_buf; - - if (nxt_slow_path(name_length + value_length + 2 - > (uint32_t) (buf->end - buf->free))) - { - nxt_unit_req_warn(req, "add_field: response buffer overflow"); - - return NXT_UNIT_ERROR; - } - - nxt_unit_req_debug(req, "add_field #%"PRIu32": %.*s: %.*s", - resp->fields_count, - (int) name_length, name, - (int) value_length, value); - - f = resp->fields + resp->fields_count; - - nxt_unit_sptr_set(&f->name, buf->free); - buf->free = nxt_cpymem(buf->free, name, name_length); - *buf->free++ = '\0'; - - nxt_unit_sptr_set(&f->value, buf->free); - buf->free = nxt_cpymem(buf->free, value, value_length); - *buf->free++ = '\0'; - - f->hash = nxt_unit_field_hash(name, name_length); - f->skip = 0; - f->name_length = name_length; - f->value_length = value_length; - - resp->fields_count++; - - return NXT_UNIT_OK; -} - - -int -nxt_unit_response_add_content(nxt_unit_request_info_t *req, - const void* src, uint32_t size) -{ - nxt_unit_buf_t *buf; - nxt_unit_response_t *resp; - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) { - nxt_unit_req_warn(req, "add_content: response not initialized yet"); - - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT)) { - nxt_unit_req_warn(req, "add_content: response already sent"); - - return NXT_UNIT_ERROR; - } - - buf = req->response_buf; - - if (nxt_slow_path(size > (uint32_t) (buf->end - buf->free))) { - nxt_unit_req_warn(req, "add_content: buffer overflow"); - - return NXT_UNIT_ERROR; - } - - resp = req->response; - - if (resp->piggyback_content_length == 0) { - nxt_unit_sptr_set(&resp->piggyback_content, buf->free); - req_impl->state = NXT_UNIT_RS_RESPONSE_HAS_CONTENT; - } - - resp->piggyback_content_length += size; - - buf->free = nxt_cpymem(buf->free, src, size); - - return NXT_UNIT_OK; -} - - -int -nxt_unit_response_send(nxt_unit_request_info_t *req) -{ - int rc; - nxt_unit_mmap_buf_t *mmap_buf; - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) { - nxt_unit_req_warn(req, "send: response is not initialized yet"); - - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT)) { - nxt_unit_req_warn(req, "send: response already sent"); - - return NXT_UNIT_ERROR; - } - - if (req->request->websocket_handshake && req->response->status == 101) { - nxt_unit_response_upgrade(req); - } - - nxt_unit_req_debug(req, "send: %"PRIu32" fields, %d bytes", - req->response->fields_count, - (int) (req->response_buf->free - - req->response_buf->start)); - - mmap_buf = nxt_container_of(req->response_buf, nxt_unit_mmap_buf_t, buf); - - rc = nxt_unit_mmap_buf_send(req, mmap_buf, 0); - if (nxt_fast_path(rc == NXT_UNIT_OK)) { - req->response = NULL; - req->response_buf = NULL; - req_impl->state = NXT_UNIT_RS_RESPONSE_SENT; - - nxt_unit_mmap_buf_free(mmap_buf); - } - - return rc; -} - - -int -nxt_unit_response_is_sent(nxt_unit_request_info_t *req) -{ - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - return req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT; -} - - -nxt_unit_buf_t * -nxt_unit_response_buf_alloc(nxt_unit_request_info_t *req, uint32_t size) -{ - int rc; - nxt_unit_mmap_buf_t *mmap_buf; - nxt_unit_request_info_impl_t *req_impl; - - if (nxt_slow_path(size > PORT_MMAP_DATA_SIZE)) { - nxt_unit_req_warn(req, "response_buf_alloc: " - "requested buffer (%"PRIu32") too big", size); - - return NULL; - } - - nxt_unit_req_debug(req, "response_buf_alloc: %"PRIu32, size); - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - mmap_buf = nxt_unit_mmap_buf_get(req->ctx); - if (nxt_slow_path(mmap_buf == NULL)) { - nxt_unit_req_alert(req, "response_buf_alloc: failed to allocate buf"); - - return NULL; - } - - mmap_buf->req = req; - - nxt_unit_mmap_buf_insert_tail(&req_impl->outgoing_buf, mmap_buf); - - rc = nxt_unit_get_outgoing_buf(req->ctx, req->response_port, - size, size, mmap_buf, - NULL); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_mmap_buf_release(mmap_buf); - - nxt_unit_req_alert(req, "response_buf_alloc: failed to get out buf"); - - return NULL; - } - - return &mmap_buf->buf; -} - - -static nxt_unit_mmap_buf_t * -nxt_unit_mmap_buf_get(nxt_unit_ctx_t *ctx) -{ - nxt_unit_mmap_buf_t *mmap_buf; - nxt_unit_ctx_impl_t *ctx_impl; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - pthread_mutex_lock(&ctx_impl->mutex); - - if (ctx_impl->free_buf == NULL) { - pthread_mutex_unlock(&ctx_impl->mutex); - - mmap_buf = nxt_unit_malloc(ctx, sizeof(nxt_unit_mmap_buf_t)); - if (nxt_slow_path(mmap_buf == NULL)) { - return NULL; - } - - } else { - mmap_buf = ctx_impl->free_buf; - - nxt_unit_mmap_buf_unlink(mmap_buf); - - pthread_mutex_unlock(&ctx_impl->mutex); - } - - mmap_buf->ctx_impl = ctx_impl; - - mmap_buf->hdr = NULL; - mmap_buf->free_ptr = NULL; - - return mmap_buf; -} - - -static void -nxt_unit_mmap_buf_release(nxt_unit_mmap_buf_t *mmap_buf) -{ - nxt_unit_mmap_buf_unlink(mmap_buf); - - pthread_mutex_lock(&mmap_buf->ctx_impl->mutex); - - nxt_unit_mmap_buf_insert(&mmap_buf->ctx_impl->free_buf, mmap_buf); - - pthread_mutex_unlock(&mmap_buf->ctx_impl->mutex); -} - - -int -nxt_unit_request_is_websocket_handshake(nxt_unit_request_info_t *req) -{ - return req->request->websocket_handshake; -} - - -int -nxt_unit_response_upgrade(nxt_unit_request_info_t *req) -{ - int rc; - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - if (nxt_slow_path(req_impl->websocket != 0)) { - nxt_unit_req_debug(req, "upgrade: already upgraded"); - - return NXT_UNIT_OK; - } - - if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) { - nxt_unit_req_warn(req, "upgrade: response is not initialized yet"); - - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT)) { - nxt_unit_req_warn(req, "upgrade: response already sent"); - - return NXT_UNIT_ERROR; - } - - rc = nxt_unit_request_hash_add(req->ctx, req); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_req_warn(req, "upgrade: failed to add request to hash"); - - return NXT_UNIT_ERROR; - } - - req_impl->websocket = 1; - - req->response->status = 101; - - return NXT_UNIT_OK; -} - - -int -nxt_unit_response_is_websocket(nxt_unit_request_info_t *req) -{ - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - return req_impl->websocket; -} - - -nxt_unit_request_info_t * -nxt_unit_get_request_info_from_data(void *data) -{ - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(data, nxt_unit_request_info_impl_t, extra_data); - - return &req_impl->req; -} - - -int -nxt_unit_buf_send(nxt_unit_buf_t *buf) -{ - int rc; - nxt_unit_mmap_buf_t *mmap_buf; - nxt_unit_request_info_t *req; - nxt_unit_request_info_impl_t *req_impl; - - mmap_buf = nxt_container_of(buf, nxt_unit_mmap_buf_t, buf); - - req = mmap_buf->req; - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - nxt_unit_req_debug(req, "buf_send: %d bytes", - (int) (buf->free - buf->start)); - - if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) { - nxt_unit_req_warn(req, "buf_send: response not initialized yet"); - - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_SENT)) { - nxt_unit_req_warn(req, "buf_send: headers not sent yet"); - - return NXT_UNIT_ERROR; - } - - if (nxt_fast_path(buf->free > buf->start)) { - rc = nxt_unit_mmap_buf_send(req, mmap_buf, 0); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - } - - nxt_unit_mmap_buf_free(mmap_buf); - - return NXT_UNIT_OK; -} - - -static void -nxt_unit_buf_send_done(nxt_unit_buf_t *buf) -{ - int rc; - nxt_unit_mmap_buf_t *mmap_buf; - nxt_unit_request_info_t *req; - - mmap_buf = nxt_container_of(buf, nxt_unit_mmap_buf_t, buf); - - req = mmap_buf->req; - - rc = nxt_unit_mmap_buf_send(req, mmap_buf, 1); - if (nxt_slow_path(rc == NXT_UNIT_OK)) { - nxt_unit_mmap_buf_free(mmap_buf); - - nxt_unit_request_info_release(req); - - } else { - nxt_unit_request_done(req, rc); - } -} - - -static int -nxt_unit_mmap_buf_send(nxt_unit_request_info_t *req, - nxt_unit_mmap_buf_t *mmap_buf, int last) -{ - struct { - nxt_port_msg_t msg; - nxt_port_mmap_msg_t mmap_msg; - } m; - - int rc; - u_char *last_used, *first_free; - ssize_t res; - nxt_chunk_id_t first_free_chunk; - nxt_unit_buf_t *buf; - nxt_unit_impl_t *lib; - nxt_port_mmap_header_t *hdr; - nxt_unit_request_info_impl_t *req_impl; - - lib = nxt_container_of(req->ctx->unit, nxt_unit_impl_t, unit); - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - buf = &mmap_buf->buf; - hdr = mmap_buf->hdr; - - m.mmap_msg.size = buf->free - buf->start; - - m.msg.stream = req_impl->stream; - m.msg.pid = lib->pid; - m.msg.reply_port = 0; - m.msg.type = _NXT_PORT_MSG_DATA; - m.msg.last = last != 0; - m.msg.mmap = hdr != NULL && m.mmap_msg.size > 0; - m.msg.nf = 0; - m.msg.mf = 0; - - rc = NXT_UNIT_ERROR; - - if (m.msg.mmap) { - m.mmap_msg.mmap_id = hdr->id; - m.mmap_msg.chunk_id = nxt_port_mmap_chunk_id(hdr, - (u_char *) buf->start); - - nxt_unit_debug(req->ctx, "#%"PRIu32": send mmap: (%d,%d,%d)", - req_impl->stream, - (int) m.mmap_msg.mmap_id, - (int) m.mmap_msg.chunk_id, - (int) m.mmap_msg.size); - - res = nxt_unit_port_send(req->ctx, req->response_port, &m, sizeof(m), - NULL); - if (nxt_slow_path(res != sizeof(m))) { - goto free_buf; - } - - last_used = (u_char *) buf->free - 1; - first_free_chunk = nxt_port_mmap_chunk_id(hdr, last_used) + 1; - - if (buf->end - buf->free >= PORT_MMAP_CHUNK_SIZE) { - first_free = nxt_port_mmap_chunk_start(hdr, first_free_chunk); - - buf->start = (char *) first_free; - buf->free = buf->start; - - if (buf->end < buf->start) { - buf->end = buf->start; - } - - } else { - buf->start = NULL; - buf->free = NULL; - buf->end = NULL; - - mmap_buf->hdr = NULL; - } - - nxt_atomic_fetch_add(&lib->outgoing.allocated_chunks, - (int) m.mmap_msg.chunk_id - (int) first_free_chunk); - - nxt_unit_debug(req->ctx, "allocated_chunks %d", - (int) lib->outgoing.allocated_chunks); - - } else { - if (nxt_slow_path(mmap_buf->plain_ptr == NULL - || mmap_buf->plain_ptr > buf->start - sizeof(m.msg))) - { - nxt_unit_alert(req->ctx, - "#%"PRIu32": failed to send plain memory buffer" - ": no space reserved for message header", - req_impl->stream); - - goto free_buf; - } - - memcpy(buf->start - sizeof(m.msg), &m.msg, sizeof(m.msg)); - - nxt_unit_debug(req->ctx, "#%"PRIu32": send plain: %d", - req_impl->stream, - (int) (sizeof(m.msg) + m.mmap_msg.size)); - - res = nxt_unit_port_send(req->ctx, req->response_port, - buf->start - sizeof(m.msg), - m.mmap_msg.size + sizeof(m.msg), NULL); - - if (nxt_slow_path(res != (ssize_t) (m.mmap_msg.size + sizeof(m.msg)))) { - goto free_buf; - } - } - - rc = NXT_UNIT_OK; - -free_buf: - - nxt_unit_free_outgoing_buf(mmap_buf); - - return rc; -} - - -void -nxt_unit_buf_free(nxt_unit_buf_t *buf) -{ - nxt_unit_mmap_buf_free(nxt_container_of(buf, nxt_unit_mmap_buf_t, buf)); -} - - -static void -nxt_unit_mmap_buf_free(nxt_unit_mmap_buf_t *mmap_buf) -{ - nxt_unit_free_outgoing_buf(mmap_buf); - - nxt_unit_mmap_buf_release(mmap_buf); -} - - -static void -nxt_unit_free_outgoing_buf(nxt_unit_mmap_buf_t *mmap_buf) -{ - if (mmap_buf->hdr != NULL) { - nxt_unit_mmap_release(&mmap_buf->ctx_impl->ctx, - mmap_buf->hdr, mmap_buf->buf.start, - mmap_buf->buf.end - mmap_buf->buf.start); - - mmap_buf->hdr = NULL; - - return; - } - - if (mmap_buf->free_ptr != NULL) { - nxt_unit_free(&mmap_buf->ctx_impl->ctx, mmap_buf->free_ptr); - - mmap_buf->free_ptr = NULL; - } -} - - -static nxt_unit_read_buf_t * -nxt_unit_read_buf_get(nxt_unit_ctx_t *ctx) -{ - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_read_buf_t *rbuf; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - pthread_mutex_lock(&ctx_impl->mutex); - - rbuf = nxt_unit_read_buf_get_impl(ctx_impl); - - pthread_mutex_unlock(&ctx_impl->mutex); - - rbuf->oob.size = 0; - - return rbuf; -} - - -static nxt_unit_read_buf_t * -nxt_unit_read_buf_get_impl(nxt_unit_ctx_impl_t *ctx_impl) -{ - nxt_queue_link_t *link; - nxt_unit_read_buf_t *rbuf; - - if (!nxt_queue_is_empty(&ctx_impl->free_rbuf)) { - link = nxt_queue_first(&ctx_impl->free_rbuf); - nxt_queue_remove(link); - - rbuf = nxt_container_of(link, nxt_unit_read_buf_t, link); - - return rbuf; - } - - rbuf = nxt_unit_malloc(&ctx_impl->ctx, sizeof(nxt_unit_read_buf_t)); - - if (nxt_fast_path(rbuf != NULL)) { - rbuf->ctx_impl = ctx_impl; - } - - return rbuf; -} - - -static void -nxt_unit_read_buf_release(nxt_unit_ctx_t *ctx, - nxt_unit_read_buf_t *rbuf) -{ - nxt_unit_ctx_impl_t *ctx_impl; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - pthread_mutex_lock(&ctx_impl->mutex); - - nxt_queue_insert_head(&ctx_impl->free_rbuf, &rbuf->link); - - pthread_mutex_unlock(&ctx_impl->mutex); -} - - -nxt_unit_buf_t * -nxt_unit_buf_next(nxt_unit_buf_t *buf) -{ - nxt_unit_mmap_buf_t *mmap_buf; - - mmap_buf = nxt_container_of(buf, nxt_unit_mmap_buf_t, buf); - - if (mmap_buf->next == NULL) { - return NULL; - } - - return &mmap_buf->next->buf; -} - - -uint32_t -nxt_unit_buf_max(void) -{ - return PORT_MMAP_DATA_SIZE; -} - - -uint32_t -nxt_unit_buf_min(void) -{ - return PORT_MMAP_CHUNK_SIZE; -} - - -int -nxt_unit_response_write(nxt_unit_request_info_t *req, const void *start, - size_t size) -{ - ssize_t res; - - res = nxt_unit_response_write_nb(req, start, size, size); - - return res < 0 ? -res : NXT_UNIT_OK; -} - - -ssize_t -nxt_unit_response_write_nb(nxt_unit_request_info_t *req, const void *start, - size_t size, size_t min_size) -{ - int rc; - ssize_t sent; - uint32_t part_size, min_part_size, buf_size; - const char *part_start; - nxt_unit_mmap_buf_t mmap_buf; - nxt_unit_request_info_impl_t *req_impl; - char local_buf[NXT_UNIT_LOCAL_BUF_SIZE]; - - nxt_unit_req_debug(req, "write: %d", (int) size); - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - part_start = start; - sent = 0; - - if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) { - nxt_unit_req_alert(req, "write: response not initialized yet"); - - return -NXT_UNIT_ERROR; - } - - /* Check if response is not send yet. */ - if (nxt_slow_path(req->response_buf != NULL)) { - part_size = req->response_buf->end - req->response_buf->free; - part_size = nxt_min(size, part_size); - - rc = nxt_unit_response_add_content(req, part_start, part_size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return -rc; - } - - rc = nxt_unit_response_send(req); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return -rc; - } - - size -= part_size; - part_start += part_size; - sent += part_size; - - min_size -= nxt_min(min_size, part_size); - } - - while (size > 0) { - part_size = nxt_min(size, PORT_MMAP_DATA_SIZE); - min_part_size = nxt_min(min_size, part_size); - min_part_size = nxt_min(min_part_size, PORT_MMAP_CHUNK_SIZE); - - rc = nxt_unit_get_outgoing_buf(req->ctx, req->response_port, part_size, - min_part_size, &mmap_buf, local_buf); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return -rc; - } - - buf_size = mmap_buf.buf.end - mmap_buf.buf.free; - if (nxt_slow_path(buf_size == 0)) { - return sent; - } - part_size = nxt_min(buf_size, part_size); - - mmap_buf.buf.free = nxt_cpymem(mmap_buf.buf.free, - part_start, part_size); - - rc = nxt_unit_mmap_buf_send(req, &mmap_buf, 0); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return -rc; - } - - size -= part_size; - part_start += part_size; - sent += part_size; - - min_size -= nxt_min(min_size, part_size); - } - - return sent; -} - - -int -nxt_unit_response_write_cb(nxt_unit_request_info_t *req, - nxt_unit_read_info_t *read_info) -{ - int rc; - ssize_t n; - uint32_t buf_size; - nxt_unit_buf_t *buf; - nxt_unit_mmap_buf_t mmap_buf; - nxt_unit_request_info_impl_t *req_impl; - char local_buf[NXT_UNIT_LOCAL_BUF_SIZE]; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) { - nxt_unit_req_alert(req, "write: response not initialized yet"); - - return NXT_UNIT_ERROR; - } - - /* Check if response is not send yet. */ - if (nxt_slow_path(req->response_buf != NULL)) { - - /* Enable content in headers buf. */ - rc = nxt_unit_response_add_content(req, "", 0); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_req_error(req, "Failed to add piggyback content"); - - return rc; - } - - buf = req->response_buf; - - while (buf->end - buf->free > 0) { - n = read_info->read(read_info, buf->free, buf->end - buf->free); - if (nxt_slow_path(n < 0)) { - nxt_unit_req_error(req, "Read error"); - - return NXT_UNIT_ERROR; - } - - /* Manually increase sizes. */ - buf->free += n; - req->response->piggyback_content_length += n; - - if (read_info->eof) { - break; - } - } - - rc = nxt_unit_response_send(req); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_req_error(req, "Failed to send headers with content"); - - return rc; - } - - if (read_info->eof) { - return NXT_UNIT_OK; - } - } - - while (!read_info->eof) { - nxt_unit_req_debug(req, "write_cb, alloc %"PRIu32"", - read_info->buf_size); - - buf_size = nxt_min(read_info->buf_size, PORT_MMAP_DATA_SIZE); - - rc = nxt_unit_get_outgoing_buf(req->ctx, req->response_port, - buf_size, buf_size, - &mmap_buf, local_buf); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - buf = &mmap_buf.buf; - - while (!read_info->eof && buf->end > buf->free) { - n = read_info->read(read_info, buf->free, buf->end - buf->free); - if (nxt_slow_path(n < 0)) { - nxt_unit_req_error(req, "Read error"); - - nxt_unit_free_outgoing_buf(&mmap_buf); - - return NXT_UNIT_ERROR; - } - - buf->free += n; - } - - rc = nxt_unit_mmap_buf_send(req, &mmap_buf, 0); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_req_error(req, "Failed to send content"); - - return rc; - } - } - - return NXT_UNIT_OK; -} - - -ssize_t -nxt_unit_request_read(nxt_unit_request_info_t *req, void *dst, size_t size) -{ - ssize_t buf_res, res; - - buf_res = nxt_unit_buf_read(&req->content_buf, &req->content_length, - dst, size); - - if (buf_res < (ssize_t) size && req->content_fd != -1) { - res = read(req->content_fd, dst, size); - if (nxt_slow_path(res < 0)) { - nxt_unit_req_alert(req, "failed to read content: %s (%d)", - strerror(errno), errno); - - return res; - } - - if (res < (ssize_t) size) { - nxt_unit_close(req->content_fd); - - req->content_fd = -1; - } - - req->content_length -= res; - - dst = nxt_pointer_to(dst, res); - - } else { - res = 0; - } - - return buf_res + res; -} - - -ssize_t -nxt_unit_request_readline_size(nxt_unit_request_info_t *req, size_t max_size) -{ - char *p; - size_t l_size, b_size; - nxt_unit_buf_t *b; - nxt_unit_mmap_buf_t *mmap_buf, *preread_buf; - - if (req->content_length == 0) { - return 0; - } - - l_size = 0; - - b = req->content_buf; - - while (b != NULL) { - b_size = b->end - b->free; - p = memchr(b->free, '\n', b_size); - - if (p != NULL) { - p++; - l_size += p - b->free; - break; - } - - l_size += b_size; - - if (max_size <= l_size) { - break; - } - - mmap_buf = nxt_container_of(b, nxt_unit_mmap_buf_t, buf); - if (mmap_buf->next == NULL - && req->content_fd != -1 - && l_size < req->content_length) - { - preread_buf = nxt_unit_request_preread(req, 16384); - if (nxt_slow_path(preread_buf == NULL)) { - return -1; - } - - nxt_unit_mmap_buf_insert(&mmap_buf->next, preread_buf); - } - - b = nxt_unit_buf_next(b); - } - - return nxt_min(max_size, l_size); -} - - -static nxt_unit_mmap_buf_t * -nxt_unit_request_preread(nxt_unit_request_info_t *req, size_t size) -{ - ssize_t res; - nxt_unit_mmap_buf_t *mmap_buf; - - if (req->content_fd == -1) { - nxt_unit_req_alert(req, "preread: content_fd == -1"); - return NULL; - } - - mmap_buf = nxt_unit_mmap_buf_get(req->ctx); - if (nxt_slow_path(mmap_buf == NULL)) { - nxt_unit_req_alert(req, "preread: failed to allocate buf"); - return NULL; - } - - mmap_buf->free_ptr = nxt_unit_malloc(req->ctx, size); - if (nxt_slow_path(mmap_buf->free_ptr == NULL)) { - nxt_unit_req_alert(req, "preread: failed to allocate buf memory"); - nxt_unit_mmap_buf_release(mmap_buf); - return NULL; - } - - mmap_buf->plain_ptr = mmap_buf->free_ptr; - - mmap_buf->hdr = NULL; - mmap_buf->buf.start = mmap_buf->free_ptr; - mmap_buf->buf.free = mmap_buf->buf.start; - mmap_buf->buf.end = mmap_buf->buf.start + size; - - res = read(req->content_fd, mmap_buf->free_ptr, size); - if (res < 0) { - nxt_unit_req_alert(req, "failed to read content: %s (%d)", - strerror(errno), errno); - - nxt_unit_mmap_buf_free(mmap_buf); - - return NULL; - } - - if (res < (ssize_t) size) { - nxt_unit_close(req->content_fd); - - req->content_fd = -1; - } - - nxt_unit_req_debug(req, "preread: read %d", (int) res); - - mmap_buf->buf.end = mmap_buf->buf.free + res; - - return mmap_buf; -} - - -static ssize_t -nxt_unit_buf_read(nxt_unit_buf_t **b, uint64_t *len, void *dst, size_t size) -{ - u_char *p; - size_t rest, copy, read; - nxt_unit_buf_t *buf, *last_buf; - - p = dst; - rest = size; - - buf = *b; - last_buf = buf; - - while (buf != NULL) { - last_buf = buf; - - copy = buf->end - buf->free; - copy = nxt_min(rest, copy); - - p = nxt_cpymem(p, buf->free, copy); - - buf->free += copy; - rest -= copy; - - if (rest == 0) { - if (buf->end == buf->free) { - buf = nxt_unit_buf_next(buf); - } - - break; - } - - buf = nxt_unit_buf_next(buf); - } - - *b = last_buf; - - read = size - rest; - - *len -= read; - - return read; -} - - -void -nxt_unit_request_done(nxt_unit_request_info_t *req, int rc) -{ - uint32_t size; - nxt_port_msg_t msg; - nxt_unit_impl_t *lib; - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - nxt_unit_req_debug(req, "done: %d", rc); - - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto skip_response_send; - } - - if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) { - - size = nxt_length("Content-Type") + nxt_length("text/plain"); - - rc = nxt_unit_response_init(req, 200, 1, size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto skip_response_send; - } - - rc = nxt_unit_response_add_field(req, "Content-Type", - nxt_length("Content-Type"), - "text/plain", nxt_length("text/plain")); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto skip_response_send; - } - } - - if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_SENT)) { - - req_impl->state = NXT_UNIT_RS_RESPONSE_SENT; - - nxt_unit_buf_send_done(req->response_buf); - - return; - } - -skip_response_send: - - lib = nxt_container_of(req->unit, nxt_unit_impl_t, unit); - - msg.stream = req_impl->stream; - msg.pid = lib->pid; - msg.reply_port = 0; - msg.type = (rc == NXT_UNIT_OK) ? _NXT_PORT_MSG_DATA - : _NXT_PORT_MSG_RPC_ERROR; - msg.last = 1; - msg.mmap = 0; - msg.nf = 0; - msg.mf = 0; - - (void) nxt_unit_port_send(req->ctx, req->response_port, - &msg, sizeof(msg), NULL); - - nxt_unit_request_info_release(req); -} - - -int -nxt_unit_websocket_send(nxt_unit_request_info_t *req, uint8_t opcode, - uint8_t last, const void *start, size_t size) -{ - const struct iovec iov = { (void *) start, size }; - - return nxt_unit_websocket_sendv(req, opcode, last, &iov, 1); -} - - -int -nxt_unit_websocket_sendv(nxt_unit_request_info_t *req, uint8_t opcode, - uint8_t last, const struct iovec *iov, int iovcnt) -{ - int i, rc; - size_t l, copy; - uint32_t payload_len, buf_size, alloc_size; - const uint8_t *b; - nxt_unit_buf_t *buf; - nxt_unit_mmap_buf_t mmap_buf; - nxt_websocket_header_t *wh; - char local_buf[NXT_UNIT_LOCAL_BUF_SIZE]; - - payload_len = 0; - - for (i = 0; i < iovcnt; i++) { - payload_len += iov[i].iov_len; - } - - buf_size = 10 + payload_len; - alloc_size = nxt_min(buf_size, PORT_MMAP_DATA_SIZE); - - rc = nxt_unit_get_outgoing_buf(req->ctx, req->response_port, - alloc_size, alloc_size, - &mmap_buf, local_buf); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - buf = &mmap_buf.buf; - - buf->start[0] = 0; - buf->start[1] = 0; - - buf_size -= buf->end - buf->start; - - wh = (void *) buf->free; - - buf->free = nxt_websocket_frame_init(wh, payload_len); - wh->fin = last; - wh->opcode = opcode; - - for (i = 0; i < iovcnt; i++) { - b = iov[i].iov_base; - l = iov[i].iov_len; - - while (l > 0) { - copy = buf->end - buf->free; - copy = nxt_min(l, copy); - - buf->free = nxt_cpymem(buf->free, b, copy); - b += copy; - l -= copy; - - if (l > 0) { - if (nxt_fast_path(buf->free > buf->start)) { - rc = nxt_unit_mmap_buf_send(req, &mmap_buf, 0); - - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - } - - alloc_size = nxt_min(buf_size, PORT_MMAP_DATA_SIZE); - - rc = nxt_unit_get_outgoing_buf(req->ctx, req->response_port, - alloc_size, alloc_size, - &mmap_buf, local_buf); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - buf_size -= buf->end - buf->start; - } - } - } - - if (buf->free > buf->start) { - rc = nxt_unit_mmap_buf_send(req, &mmap_buf, 0); - } - - return rc; -} - - -ssize_t -nxt_unit_websocket_read(nxt_unit_websocket_frame_t *ws, void *dst, - size_t size) -{ - ssize_t res; - uint8_t *b; - uint64_t i, d; - - res = nxt_unit_buf_read(&ws->content_buf, &ws->content_length, - dst, size); - - if (ws->mask == NULL) { - return res; - } - - b = dst; - d = (ws->payload_len - ws->content_length - res) % 4; - - for (i = 0; i < (uint64_t) res; i++) { - b[i] ^= ws->mask[ (i + d) % 4 ]; - } - - return res; -} - - -int -nxt_unit_websocket_retain(nxt_unit_websocket_frame_t *ws) -{ - char *b; - size_t size, hsize; - nxt_unit_websocket_frame_impl_t *ws_impl; - - ws_impl = nxt_container_of(ws, nxt_unit_websocket_frame_impl_t, ws); - - if (ws_impl->buf->free_ptr != NULL || ws_impl->buf->hdr != NULL) { - return NXT_UNIT_OK; - } - - size = ws_impl->buf->buf.end - ws_impl->buf->buf.start; - - b = nxt_unit_malloc(ws->req->ctx, size); - if (nxt_slow_path(b == NULL)) { - return NXT_UNIT_ERROR; - } - - memcpy(b, ws_impl->buf->buf.start, size); - - hsize = nxt_websocket_frame_header_size(b); - - ws_impl->buf->buf.start = b; - ws_impl->buf->buf.free = b + hsize; - ws_impl->buf->buf.end = b + size; - - ws_impl->buf->free_ptr = b; - - ws_impl->ws.header = (nxt_websocket_header_t *) b; - - if (ws_impl->ws.header->mask) { - ws_impl->ws.mask = (uint8_t *) b + hsize - 4; - - } else { - ws_impl->ws.mask = NULL; - } - - return NXT_UNIT_OK; -} - - -void -nxt_unit_websocket_done(nxt_unit_websocket_frame_t *ws) -{ - nxt_unit_websocket_frame_release(ws); -} - - -static nxt_port_mmap_header_t * -nxt_unit_mmap_get(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - nxt_chunk_id_t *c, int *n, int min_n) -{ - int res, nchunks, i; - uint32_t outgoing_size; - nxt_unit_mmap_t *mm, *mm_end; - nxt_unit_impl_t *lib; - nxt_port_mmap_header_t *hdr; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - pthread_mutex_lock(&lib->outgoing.mutex); - -retry: - - outgoing_size = lib->outgoing.size; - - mm_end = lib->outgoing.elts + outgoing_size; - - for (mm = lib->outgoing.elts; mm < mm_end; mm++) { - hdr = mm->hdr; - - if (hdr->sent_over != 0xFFFFu - && (hdr->sent_over != port->id.id - || mm->src_thread != pthread_self())) - { - continue; - } - - *c = 0; - - while (nxt_port_mmap_get_free_chunk(hdr->free_map, c)) { - nchunks = 1; - - while (nchunks < *n) { - res = nxt_port_mmap_chk_set_chunk_busy(hdr->free_map, - *c + nchunks); - - if (res == 0) { - if (nchunks >= min_n) { - *n = nchunks; - - goto unlock; - } - - for (i = 0; i < nchunks; i++) { - nxt_port_mmap_set_chunk_free(hdr->free_map, *c + i); - } - - *c += nchunks + 1; - nchunks = 0; - break; - } - - nchunks++; - } - - if (nchunks >= min_n) { - *n = nchunks; - - goto unlock; - } - } - - hdr->oosm = 1; - } - - if (outgoing_size >= lib->shm_mmap_limit) { - /* Cannot allocate more shared memory. */ - pthread_mutex_unlock(&lib->outgoing.mutex); - - if (min_n == 0) { - *n = 0; - } - - if (nxt_slow_path(lib->outgoing.allocated_chunks + min_n - >= lib->shm_mmap_limit * PORT_MMAP_CHUNK_COUNT)) - { - /* Memory allocated by application, but not send to router. */ - return NULL; - } - - /* Notify router about OOSM condition. */ - - res = nxt_unit_send_oosm(ctx, port); - if (nxt_slow_path(res != NXT_UNIT_OK)) { - return NULL; - } - - /* Return if caller can handle OOSM condition. Non-blocking mode. */ - - if (min_n == 0) { - return NULL; - } - - nxt_unit_debug(ctx, "oosm: waiting for ACK"); - - res = nxt_unit_wait_shm_ack(ctx); - if (nxt_slow_path(res != NXT_UNIT_OK)) { - return NULL; - } - - nxt_unit_debug(ctx, "oosm: retry"); - - pthread_mutex_lock(&lib->outgoing.mutex); - - goto retry; - } - - *c = 0; - hdr = nxt_unit_new_mmap(ctx, port, *n); - -unlock: - - nxt_atomic_fetch_add(&lib->outgoing.allocated_chunks, *n); - - nxt_unit_debug(ctx, "allocated_chunks %d", - (int) lib->outgoing.allocated_chunks); - - pthread_mutex_unlock(&lib->outgoing.mutex); - - return hdr; -} - - -static int -nxt_unit_send_oosm(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) -{ - ssize_t res; - nxt_port_msg_t msg; - nxt_unit_impl_t *lib; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - msg.stream = 0; - msg.pid = lib->pid; - msg.reply_port = 0; - msg.type = _NXT_PORT_MSG_OOSM; - msg.last = 0; - msg.mmap = 0; - msg.nf = 0; - msg.mf = 0; - - res = nxt_unit_port_send(ctx, lib->router_port, &msg, sizeof(msg), NULL); - if (nxt_slow_path(res != sizeof(msg))) { - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_wait_shm_ack(nxt_unit_ctx_t *ctx) -{ - int res; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_read_buf_t *rbuf; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - while (1) { - rbuf = nxt_unit_read_buf_get(ctx); - if (nxt_slow_path(rbuf == NULL)) { - return NXT_UNIT_ERROR; - } - - do { - res = nxt_unit_ctx_port_recv(ctx, ctx_impl->read_port, rbuf); - } while (res == NXT_UNIT_AGAIN); - - if (res == NXT_UNIT_ERROR) { - nxt_unit_read_buf_release(ctx, rbuf); - - return NXT_UNIT_ERROR; - } - - if (nxt_unit_is_shm_ack(rbuf)) { - nxt_unit_read_buf_release(ctx, rbuf); - break; - } - - pthread_mutex_lock(&ctx_impl->mutex); - - nxt_queue_insert_tail(&ctx_impl->pending_rbuf, &rbuf->link); - - pthread_mutex_unlock(&ctx_impl->mutex); - - if (nxt_unit_is_quit(rbuf)) { - nxt_unit_debug(ctx, "oosm: quit received"); - - return NXT_UNIT_ERROR; - } - } - - return NXT_UNIT_OK; -} - - -static nxt_unit_mmap_t * -nxt_unit_mmap_at(nxt_unit_mmaps_t *mmaps, uint32_t i) -{ - uint32_t cap, n; - nxt_unit_mmap_t *e; - - if (nxt_fast_path(mmaps->size > i)) { - return mmaps->elts + i; - } - - cap = mmaps->cap; - - if (cap == 0) { - cap = i + 1; - } - - while (i + 1 > cap) { - - if (cap < 16) { - cap = cap * 2; - - } else { - cap = cap + cap / 2; - } - } - - if (cap != mmaps->cap) { - - e = realloc(mmaps->elts, cap * sizeof(nxt_unit_mmap_t)); - if (nxt_slow_path(e == NULL)) { - return NULL; - } - - mmaps->elts = e; - - for (n = mmaps->cap; n < cap; n++) { - e = mmaps->elts + n; - - e->hdr = NULL; - nxt_queue_init(&e->awaiting_rbuf); - } - - mmaps->cap = cap; - } - - if (i + 1 > mmaps->size) { - mmaps->size = i + 1; - } - - return mmaps->elts + i; -} - - -static nxt_port_mmap_header_t * -nxt_unit_new_mmap(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, int n) -{ - int i, fd, rc; - void *mem; - nxt_unit_mmap_t *mm; - nxt_unit_impl_t *lib; - nxt_port_mmap_header_t *hdr; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - mm = nxt_unit_mmap_at(&lib->outgoing, lib->outgoing.size); - if (nxt_slow_path(mm == NULL)) { - nxt_unit_alert(ctx, "failed to add mmap to outgoing array"); - - return NULL; - } - - fd = nxt_unit_shm_open(ctx, PORT_MMAP_SIZE); - if (nxt_slow_path(fd == -1)) { - goto remove_fail; - } - - mem = mmap(NULL, PORT_MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (nxt_slow_path(mem == MAP_FAILED)) { - nxt_unit_alert(ctx, "mmap(%d) failed: %s (%d)", fd, - strerror(errno), errno); - - nxt_unit_close(fd); - - goto remove_fail; - } - - mm->hdr = mem; - hdr = mem; - - memset(hdr->free_map, 0xFFU, sizeof(hdr->free_map)); - memset(hdr->free_tracking_map, 0xFFU, sizeof(hdr->free_tracking_map)); - - hdr->id = lib->outgoing.size - 1; - hdr->src_pid = lib->pid; - hdr->dst_pid = port->id.pid; - hdr->sent_over = port->id.id; - mm->src_thread = pthread_self(); - - /* Mark first n chunk(s) as busy */ - for (i = 0; i < n; i++) { - nxt_port_mmap_set_chunk_busy(hdr->free_map, i); - } - - /* Mark as busy chunk followed the last available chunk. */ - nxt_port_mmap_set_chunk_busy(hdr->free_map, PORT_MMAP_CHUNK_COUNT); - nxt_port_mmap_set_chunk_busy(hdr->free_tracking_map, PORT_MMAP_CHUNK_COUNT); - - pthread_mutex_unlock(&lib->outgoing.mutex); - - rc = nxt_unit_send_mmap(ctx, port, fd); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - munmap(mem, PORT_MMAP_SIZE); - hdr = NULL; - - } else { - nxt_unit_debug(ctx, "new mmap #%"PRIu32" created for %d -> %d", - hdr->id, (int) lib->pid, (int) port->id.pid); - } - - nxt_unit_close(fd); - - pthread_mutex_lock(&lib->outgoing.mutex); - - if (nxt_fast_path(hdr != NULL)) { - return hdr; - } - -remove_fail: - - lib->outgoing.size--; - - return NULL; -} - - -static int -nxt_unit_shm_open(nxt_unit_ctx_t *ctx, size_t size) -{ - int fd; - -#if (NXT_HAVE_MEMFD_CREATE || NXT_HAVE_SHM_OPEN) - char name[64]; - nxt_unit_impl_t *lib; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - snprintf(name, sizeof(name), NXT_SHM_PREFIX "unit.%d.%p", - lib->pid, (void *) (uintptr_t) pthread_self()); -#endif - -#if (NXT_HAVE_MEMFD_CREATE) - - fd = syscall(SYS_memfd_create, name, MFD_CLOEXEC); - if (nxt_slow_path(fd == -1)) { - nxt_unit_alert(ctx, "memfd_create(%s) failed: %s (%d)", name, - strerror(errno), errno); - - return -1; - } - - nxt_unit_debug(ctx, "memfd_create(%s): %d", name, fd); - -#elif (NXT_HAVE_SHM_OPEN_ANON) - - fd = shm_open(SHM_ANON, O_RDWR, S_IRUSR | S_IWUSR); - if (nxt_slow_path(fd == -1)) { - nxt_unit_alert(ctx, "shm_open(SHM_ANON) failed: %s (%d)", - strerror(errno), errno); - - return -1; - } - -#elif (NXT_HAVE_SHM_OPEN) - - /* Just in case. */ - shm_unlink(name); - - fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); - if (nxt_slow_path(fd == -1)) { - nxt_unit_alert(ctx, "shm_open(%s) failed: %s (%d)", name, - strerror(errno), errno); - - return -1; - } - - if (nxt_slow_path(shm_unlink(name) == -1)) { - nxt_unit_alert(ctx, "shm_unlink(%s) failed: %s (%d)", name, - strerror(errno), errno); - } - -#else - -#error No working shared memory implementation. - -#endif - - if (nxt_slow_path(ftruncate(fd, size) == -1)) { - nxt_unit_alert(ctx, "ftruncate(%d) failed: %s (%d)", fd, - strerror(errno), errno); - - nxt_unit_close(fd); - - return -1; - } - - return fd; -} - - -static int -nxt_unit_send_mmap(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, int fd) -{ - ssize_t res; - nxt_send_oob_t oob; - nxt_port_msg_t msg; - nxt_unit_impl_t *lib; - int fds[2] = {fd, -1}; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - msg.stream = 0; - msg.pid = lib->pid; - msg.reply_port = 0; - msg.type = _NXT_PORT_MSG_MMAP; - msg.last = 0; - msg.mmap = 0; - msg.nf = 0; - msg.mf = 0; - - nxt_socket_msg_oob_init(&oob, fds); - - res = nxt_unit_port_send(ctx, port, &msg, sizeof(msg), &oob); - if (nxt_slow_path(res != sizeof(msg))) { - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_get_outgoing_buf(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - uint32_t size, uint32_t min_size, - nxt_unit_mmap_buf_t *mmap_buf, char *local_buf) -{ - int nchunks, min_nchunks; - nxt_chunk_id_t c; - nxt_port_mmap_header_t *hdr; - - if (size <= NXT_UNIT_MAX_PLAIN_SIZE) { - if (local_buf != NULL) { - mmap_buf->free_ptr = NULL; - mmap_buf->plain_ptr = local_buf; - - } else { - mmap_buf->free_ptr = nxt_unit_malloc(ctx, - size + sizeof(nxt_port_msg_t)); - if (nxt_slow_path(mmap_buf->free_ptr == NULL)) { - return NXT_UNIT_ERROR; - } - - mmap_buf->plain_ptr = mmap_buf->free_ptr; - } - - mmap_buf->hdr = NULL; - mmap_buf->buf.start = mmap_buf->plain_ptr + sizeof(nxt_port_msg_t); - mmap_buf->buf.free = mmap_buf->buf.start; - mmap_buf->buf.end = mmap_buf->buf.start + size; - - nxt_unit_debug(ctx, "outgoing plain buffer allocation: (%p, %d)", - mmap_buf->buf.start, (int) size); - - return NXT_UNIT_OK; - } - - nchunks = (size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE; - min_nchunks = (min_size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE; - - hdr = nxt_unit_mmap_get(ctx, port, &c, &nchunks, min_nchunks); - if (nxt_slow_path(hdr == NULL)) { - if (nxt_fast_path(min_nchunks == 0 && nchunks == 0)) { - mmap_buf->hdr = NULL; - mmap_buf->buf.start = NULL; - mmap_buf->buf.free = NULL; - mmap_buf->buf.end = NULL; - mmap_buf->free_ptr = NULL; - - return NXT_UNIT_OK; - } - - return NXT_UNIT_ERROR; - } - - mmap_buf->hdr = hdr; - mmap_buf->buf.start = (char *) nxt_port_mmap_chunk_start(hdr, c); - mmap_buf->buf.free = mmap_buf->buf.start; - mmap_buf->buf.end = mmap_buf->buf.start + nchunks * PORT_MMAP_CHUNK_SIZE; - mmap_buf->free_ptr = NULL; - mmap_buf->ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - nxt_unit_debug(ctx, "outgoing mmap allocation: (%d,%d,%d)", - (int) hdr->id, (int) c, - (int) (nchunks * PORT_MMAP_CHUNK_SIZE)); - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_incoming_mmap(nxt_unit_ctx_t *ctx, pid_t pid, int fd) -{ - int rc; - void *mem; - nxt_queue_t awaiting_rbuf; - struct stat mmap_stat; - nxt_unit_mmap_t *mm; - nxt_unit_impl_t *lib; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_read_buf_t *rbuf; - nxt_port_mmap_header_t *hdr; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - nxt_unit_debug(ctx, "incoming_mmap: fd %d from process %d", fd, (int) pid); - - if (fstat(fd, &mmap_stat) == -1) { - nxt_unit_alert(ctx, "incoming_mmap: fstat(%d) failed: %s (%d)", fd, - strerror(errno), errno); - - return NXT_UNIT_ERROR; - } - - mem = mmap(NULL, mmap_stat.st_size, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - if (nxt_slow_path(mem == MAP_FAILED)) { - nxt_unit_alert(ctx, "incoming_mmap: mmap() failed: %s (%d)", - strerror(errno), errno); - - return NXT_UNIT_ERROR; - } - - hdr = mem; - - if (nxt_slow_path(hdr->src_pid != pid)) { - - nxt_unit_alert(ctx, "incoming_mmap: unexpected pid in mmap header " - "detected: %d != %d or %d != %d", (int) hdr->src_pid, - (int) pid, (int) hdr->dst_pid, (int) lib->pid); - - munmap(mem, PORT_MMAP_SIZE); - - return NXT_UNIT_ERROR; - } - - nxt_queue_init(&awaiting_rbuf); - - pthread_mutex_lock(&lib->incoming.mutex); - - mm = nxt_unit_mmap_at(&lib->incoming, hdr->id); - if (nxt_slow_path(mm == NULL)) { - nxt_unit_alert(ctx, "incoming_mmap: failed to add to incoming array"); - - munmap(mem, PORT_MMAP_SIZE); - - rc = NXT_UNIT_ERROR; - - } else { - mm->hdr = hdr; - - hdr->sent_over = 0xFFFFu; - - nxt_queue_add(&awaiting_rbuf, &mm->awaiting_rbuf); - nxt_queue_init(&mm->awaiting_rbuf); - - rc = NXT_UNIT_OK; - } - - pthread_mutex_unlock(&lib->incoming.mutex); - - nxt_queue_each(rbuf, &awaiting_rbuf, nxt_unit_read_buf_t, link) { - - ctx_impl = rbuf->ctx_impl; - - pthread_mutex_lock(&ctx_impl->mutex); - - nxt_queue_insert_head(&ctx_impl->pending_rbuf, &rbuf->link); - - pthread_mutex_unlock(&ctx_impl->mutex); - - nxt_atomic_fetch_add(&ctx_impl->wait_items, -1); - - nxt_unit_awake_ctx(ctx, ctx_impl); - - } nxt_queue_loop; - - return rc; -} - - -static void -nxt_unit_awake_ctx(nxt_unit_ctx_t *ctx, nxt_unit_ctx_impl_t *ctx_impl) -{ - nxt_port_msg_t msg; - - if (nxt_fast_path(ctx == &ctx_impl->ctx)) { - return; - } - - if (nxt_slow_path(ctx_impl->read_port == NULL - || ctx_impl->read_port->out_fd == -1)) - { - nxt_unit_alert(ctx, "target context read_port is NULL or not writable"); - - return; - } - - memset(&msg, 0, sizeof(nxt_port_msg_t)); - - msg.type = _NXT_PORT_MSG_RPC_READY; - - (void) nxt_unit_port_send(ctx, ctx_impl->read_port, - &msg, sizeof(msg), NULL); -} - - -static int -nxt_unit_mmaps_init(nxt_unit_mmaps_t *mmaps) -{ - mmaps->size = 0; - mmaps->cap = 0; - mmaps->elts = NULL; - mmaps->allocated_chunks = 0; - - return pthread_mutex_init(&mmaps->mutex, NULL); -} - - -nxt_inline void -nxt_unit_process_use(nxt_unit_process_t *process) -{ - nxt_atomic_fetch_add(&process->use_count, 1); -} - - -nxt_inline void -nxt_unit_process_release(nxt_unit_process_t *process) -{ - long c; - - c = nxt_atomic_fetch_add(&process->use_count, -1); - - if (c == 1) { - nxt_unit_debug(NULL, "destroy process #%d", (int) process->pid); - - nxt_unit_free(NULL, process); - } -} - - -static void -nxt_unit_mmaps_destroy(nxt_unit_mmaps_t *mmaps) -{ - nxt_unit_mmap_t *mm, *end; - - if (mmaps->elts != NULL) { - end = mmaps->elts + mmaps->size; - - for (mm = mmaps->elts; mm < end; mm++) { - munmap(mm->hdr, PORT_MMAP_SIZE); - } - - nxt_unit_free(NULL, mmaps->elts); - } - - pthread_mutex_destroy(&mmaps->mutex); -} - - -static int -nxt_unit_check_rbuf_mmap(nxt_unit_ctx_t *ctx, nxt_unit_mmaps_t *mmaps, - pid_t pid, uint32_t id, nxt_port_mmap_header_t **hdr, - nxt_unit_read_buf_t *rbuf) -{ - int res, need_rbuf; - nxt_unit_mmap_t *mm; - nxt_unit_ctx_impl_t *ctx_impl; - - mm = nxt_unit_mmap_at(mmaps, id); - if (nxt_slow_path(mm == NULL)) { - nxt_unit_alert(ctx, "failed to allocate mmap"); - - pthread_mutex_unlock(&mmaps->mutex); - - *hdr = NULL; - - return NXT_UNIT_ERROR; - } - - *hdr = mm->hdr; - - if (nxt_fast_path(*hdr != NULL)) { - return NXT_UNIT_OK; - } - - need_rbuf = nxt_queue_is_empty(&mm->awaiting_rbuf); - - nxt_queue_insert_tail(&mm->awaiting_rbuf, &rbuf->link); - - pthread_mutex_unlock(&mmaps->mutex); - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - nxt_atomic_fetch_add(&ctx_impl->wait_items, 1); - - if (need_rbuf) { - res = nxt_unit_get_mmap(ctx, pid, id); - if (nxt_slow_path(res == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - } - - return NXT_UNIT_AGAIN; -} - - -static int -nxt_unit_mmap_read(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg, - nxt_unit_read_buf_t *rbuf) -{ - int res; - void *start; - uint32_t size; - nxt_unit_impl_t *lib; - nxt_unit_mmaps_t *mmaps; - nxt_unit_mmap_buf_t *b, **incoming_tail; - nxt_port_mmap_msg_t *mmap_msg, *end; - nxt_port_mmap_header_t *hdr; - - if (nxt_slow_path(recv_msg->size < sizeof(nxt_port_mmap_msg_t))) { - nxt_unit_warn(ctx, "#%"PRIu32": mmap_read: too small message (%d)", - recv_msg->stream, (int) recv_msg->size); - - return NXT_UNIT_ERROR; - } - - mmap_msg = recv_msg->start; - end = nxt_pointer_to(recv_msg->start, recv_msg->size); - - incoming_tail = &recv_msg->incoming_buf; - - /* Allocating buffer structures. */ - for (; mmap_msg < end; mmap_msg++) { - b = nxt_unit_mmap_buf_get(ctx); - if (nxt_slow_path(b == NULL)) { - nxt_unit_warn(ctx, "#%"PRIu32": mmap_read: failed to allocate buf", - recv_msg->stream); - - while (recv_msg->incoming_buf != NULL) { - nxt_unit_mmap_buf_release(recv_msg->incoming_buf); - } - - return NXT_UNIT_ERROR; - } - - nxt_unit_mmap_buf_insert(incoming_tail, b); - incoming_tail = &b->next; - } - - b = recv_msg->incoming_buf; - mmap_msg = recv_msg->start; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - mmaps = &lib->incoming; - - pthread_mutex_lock(&mmaps->mutex); - - for (; mmap_msg < end; mmap_msg++) { - res = nxt_unit_check_rbuf_mmap(ctx, mmaps, - recv_msg->pid, mmap_msg->mmap_id, - &hdr, rbuf); - - if (nxt_slow_path(res != NXT_UNIT_OK)) { - while (recv_msg->incoming_buf != NULL) { - nxt_unit_mmap_buf_release(recv_msg->incoming_buf); - } - - return res; - } - - start = nxt_port_mmap_chunk_start(hdr, mmap_msg->chunk_id); - size = mmap_msg->size; - - if (recv_msg->start == mmap_msg) { - recv_msg->start = start; - recv_msg->size = size; - } - - b->buf.start = start; - b->buf.free = start; - b->buf.end = b->buf.start + size; - b->hdr = hdr; - - b = b->next; - - nxt_unit_debug(ctx, "#%"PRIu32": mmap_read: [%p,%d] %d->%d,(%d,%d,%d)", - recv_msg->stream, - start, (int) size, - (int) hdr->src_pid, (int) hdr->dst_pid, - (int) hdr->id, (int) mmap_msg->chunk_id, - (int) mmap_msg->size); - } - - pthread_mutex_unlock(&mmaps->mutex); - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_get_mmap(nxt_unit_ctx_t *ctx, pid_t pid, uint32_t id) -{ - ssize_t res; - nxt_unit_impl_t *lib; - nxt_unit_ctx_impl_t *ctx_impl; - - struct { - nxt_port_msg_t msg; - nxt_port_msg_get_mmap_t get_mmap; - } m; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - memset(&m.msg, 0, sizeof(nxt_port_msg_t)); - - m.msg.pid = lib->pid; - m.msg.reply_port = ctx_impl->read_port->id.id; - m.msg.type = _NXT_PORT_MSG_GET_MMAP; - - m.get_mmap.id = id; - - nxt_unit_debug(ctx, "get_mmap: %d %d", (int) pid, (int) id); - - res = nxt_unit_port_send(ctx, lib->router_port, &m, sizeof(m), NULL); - if (nxt_slow_path(res != sizeof(m))) { - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static void -nxt_unit_mmap_release(nxt_unit_ctx_t *ctx, nxt_port_mmap_header_t *hdr, - void *start, uint32_t size) -{ - int freed_chunks; - u_char *p, *end; - nxt_chunk_id_t c; - nxt_unit_impl_t *lib; - - memset(start, 0xA5, size); - - p = start; - end = p + size; - c = nxt_port_mmap_chunk_id(hdr, p); - freed_chunks = 0; - - while (p < end) { - nxt_port_mmap_set_chunk_free(hdr->free_map, c); - - p += PORT_MMAP_CHUNK_SIZE; - c++; - freed_chunks++; - } - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - if (hdr->src_pid == lib->pid && freed_chunks != 0) { - nxt_atomic_fetch_add(&lib->outgoing.allocated_chunks, -freed_chunks); - - nxt_unit_debug(ctx, "allocated_chunks %d", - (int) lib->outgoing.allocated_chunks); - } - - if (hdr->dst_pid == lib->pid - && freed_chunks != 0 - && nxt_atomic_cmp_set(&hdr->oosm, 1, 0)) - { - nxt_unit_send_shm_ack(ctx, hdr->src_pid); - } -} - - -static int -nxt_unit_send_shm_ack(nxt_unit_ctx_t *ctx, pid_t pid) -{ - ssize_t res; - nxt_port_msg_t msg; - nxt_unit_impl_t *lib; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - msg.stream = 0; - msg.pid = lib->pid; - msg.reply_port = 0; - msg.type = _NXT_PORT_MSG_SHM_ACK; - msg.last = 0; - msg.mmap = 0; - msg.nf = 0; - msg.mf = 0; - - res = nxt_unit_port_send(ctx, lib->router_port, &msg, sizeof(msg), NULL); - if (nxt_slow_path(res != sizeof(msg))) { - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static nxt_int_t -nxt_unit_lvlhsh_pid_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_process_t *process; - - process = data; - - if (lhq->key.length == sizeof(pid_t) - && *(pid_t *) lhq->key.start == process->pid) - { - return NXT_OK; - } - - return NXT_DECLINED; -} - - -static const nxt_lvlhsh_proto_t lvlhsh_processes_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_unit_lvlhsh_pid_test, - nxt_unit_lvlhsh_alloc, - nxt_unit_lvlhsh_free, -}; - - -static inline void -nxt_unit_process_lhq_pid(nxt_lvlhsh_query_t *lhq, pid_t *pid) -{ - lhq->key_hash = nxt_murmur_hash2(pid, sizeof(*pid)); - lhq->key.length = sizeof(*pid); - lhq->key.start = (u_char *) pid; - lhq->proto = &lvlhsh_processes_proto; -} - - -static nxt_unit_process_t * -nxt_unit_process_get(nxt_unit_ctx_t *ctx, pid_t pid) -{ - nxt_unit_impl_t *lib; - nxt_unit_process_t *process; - nxt_lvlhsh_query_t lhq; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - nxt_unit_process_lhq_pid(&lhq, &pid); - - if (nxt_lvlhsh_find(&lib->processes, &lhq) == NXT_OK) { - process = lhq.value; - nxt_unit_process_use(process); - - return process; - } - - process = nxt_unit_malloc(ctx, sizeof(nxt_unit_process_t)); - if (nxt_slow_path(process == NULL)) { - nxt_unit_alert(ctx, "failed to allocate process for #%d", (int) pid); - - return NULL; - } - - process->pid = pid; - process->use_count = 2; - process->next_port_id = 0; - process->lib = lib; - - nxt_queue_init(&process->ports); - - lhq.replace = 0; - lhq.value = process; - - switch (nxt_lvlhsh_insert(&lib->processes, &lhq)) { - - case NXT_OK: - break; - - default: - nxt_unit_alert(ctx, "process %d insert failed", (int) pid); - - nxt_unit_free(ctx, process); - process = NULL; - break; - } - - return process; -} - - -static nxt_unit_process_t * -nxt_unit_process_find(nxt_unit_impl_t *lib, pid_t pid, int remove) -{ - int rc; - nxt_lvlhsh_query_t lhq; - - nxt_unit_process_lhq_pid(&lhq, &pid); - - if (remove) { - rc = nxt_lvlhsh_delete(&lib->processes, &lhq); - - } else { - rc = nxt_lvlhsh_find(&lib->processes, &lhq); - } - - if (rc == NXT_OK) { - if (!remove) { - nxt_unit_process_use(lhq.value); - } - - return lhq.value; - } - - return NULL; -} - - -static nxt_unit_process_t * -nxt_unit_process_pop_first(nxt_unit_impl_t *lib) -{ - return nxt_lvlhsh_retrieve(&lib->processes, &lvlhsh_processes_proto, NULL); -} - - -int -nxt_unit_run(nxt_unit_ctx_t *ctx) -{ - int rc; - nxt_unit_ctx_impl_t *ctx_impl; - - nxt_unit_ctx_use(ctx); - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - rc = NXT_UNIT_OK; - - while (nxt_fast_path(ctx_impl->online)) { - rc = nxt_unit_run_once_impl(ctx); - - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - nxt_unit_quit(ctx, NXT_QUIT_NORMAL); - break; - } - } - - nxt_unit_ctx_release(ctx); - - return rc; -} - - -int -nxt_unit_run_once(nxt_unit_ctx_t *ctx) -{ - int rc; - - nxt_unit_ctx_use(ctx); - - rc = nxt_unit_run_once_impl(ctx); - - nxt_unit_ctx_release(ctx); - - return rc; -} - - -static int -nxt_unit_run_once_impl(nxt_unit_ctx_t *ctx) -{ - int rc; - nxt_unit_read_buf_t *rbuf; - - rbuf = nxt_unit_read_buf_get(ctx); - if (nxt_slow_path(rbuf == NULL)) { - return NXT_UNIT_ERROR; - } - - rc = nxt_unit_read_buf(ctx, rbuf); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_read_buf_release(ctx, rbuf); - - return rc; - } - - rc = nxt_unit_process_msg(ctx, rbuf, NULL); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - - rc = nxt_unit_process_pending_rbuf(ctx); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - - nxt_unit_process_ready_req(ctx); - - return rc; -} - - -static int -nxt_unit_read_buf(nxt_unit_ctx_t *ctx, nxt_unit_read_buf_t *rbuf) -{ - int nevents, res, err; - nxt_uint_t nfds; - nxt_unit_impl_t *lib; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_port_impl_t *port_impl; - struct pollfd fds[2]; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - if (ctx_impl->wait_items > 0 || !nxt_unit_chk_ready(ctx)) { - return nxt_unit_ctx_port_recv(ctx, ctx_impl->read_port, rbuf); - } - - port_impl = nxt_container_of(ctx_impl->read_port, nxt_unit_port_impl_t, - port); - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - -retry: - - if (port_impl->from_socket == 0) { - res = nxt_unit_port_queue_recv(ctx_impl->read_port, rbuf); - if (res == NXT_UNIT_OK) { - if (nxt_unit_is_read_socket(rbuf)) { - port_impl->from_socket++; - - nxt_unit_debug(ctx, "port{%d,%d} dequeue 1 read_socket %d", - (int) ctx_impl->read_port->id.pid, - (int) ctx_impl->read_port->id.id, - port_impl->from_socket); - - } else { - nxt_unit_debug(ctx, "port{%d,%d} dequeue %d", - (int) ctx_impl->read_port->id.pid, - (int) ctx_impl->read_port->id.id, - (int) rbuf->size); - - return NXT_UNIT_OK; - } - } - } - - if (nxt_fast_path(nxt_unit_chk_ready(ctx))) { - res = nxt_unit_app_queue_recv(ctx, lib->shared_port, rbuf); - if (res == NXT_UNIT_OK) { - return NXT_UNIT_OK; - } - - fds[1].fd = lib->shared_port->in_fd; - fds[1].events = POLLIN; - - nfds = 2; - - } else { - nfds = 1; - } - - fds[0].fd = ctx_impl->read_port->in_fd; - fds[0].events = POLLIN; - fds[0].revents = 0; - - fds[1].revents = 0; - - nevents = poll(fds, nfds, -1); - if (nxt_slow_path(nevents == -1)) { - err = errno; - - if (err == EINTR) { - goto retry; - } - - nxt_unit_alert(ctx, "poll(%d,%d) failed: %s (%d)", - fds[0].fd, fds[1].fd, strerror(err), err); - - rbuf->size = -1; - - return (err == EAGAIN) ? NXT_UNIT_AGAIN : NXT_UNIT_ERROR; - } - - nxt_unit_debug(ctx, "poll(%d,%d): %d, revents [%04X, %04X]", - fds[0].fd, fds[1].fd, nevents, fds[0].revents, - fds[1].revents); - - if ((fds[0].revents & POLLIN) != 0) { - res = nxt_unit_ctx_port_recv(ctx, ctx_impl->read_port, rbuf); - if (res == NXT_UNIT_AGAIN) { - goto retry; - } - - return res; - } - - if ((fds[1].revents & POLLIN) != 0) { - res = nxt_unit_shared_port_recv(ctx, lib->shared_port, rbuf); - if (res == NXT_UNIT_AGAIN) { - goto retry; - } - - return res; - } - - nxt_unit_alert(ctx, "poll(%d,%d): %d unexpected revents [%04uXi, %04uXi]", - fds[0].fd, fds[1].fd, nevents, fds[0].revents, - fds[1].revents); - - return NXT_UNIT_ERROR; -} - - -static int -nxt_unit_chk_ready(nxt_unit_ctx_t *ctx) -{ - nxt_unit_impl_t *lib; - nxt_unit_ctx_impl_t *ctx_impl; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - return (ctx_impl->ready - && (lib->request_limit == 0 - || lib->request_count < lib->request_limit)); -} - - -static int -nxt_unit_process_pending_rbuf(nxt_unit_ctx_t *ctx) -{ - int rc; - nxt_queue_t pending_rbuf; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_read_buf_t *rbuf; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - pthread_mutex_lock(&ctx_impl->mutex); - - if (nxt_queue_is_empty(&ctx_impl->pending_rbuf)) { - pthread_mutex_unlock(&ctx_impl->mutex); - - return NXT_UNIT_OK; - } - - nxt_queue_init(&pending_rbuf); - - nxt_queue_add(&pending_rbuf, &ctx_impl->pending_rbuf); - nxt_queue_init(&ctx_impl->pending_rbuf); - - pthread_mutex_unlock(&ctx_impl->mutex); - - rc = NXT_UNIT_OK; - - nxt_queue_each(rbuf, &pending_rbuf, nxt_unit_read_buf_t, link) { - - if (nxt_fast_path(rc != NXT_UNIT_ERROR)) { - rc = nxt_unit_process_msg(&ctx_impl->ctx, rbuf, NULL); - - } else { - nxt_unit_read_buf_release(ctx, rbuf); - } - - } nxt_queue_loop; - - if (!ctx_impl->ready) { - nxt_unit_quit(ctx, NXT_QUIT_GRACEFUL); - } - - return rc; -} - - -static void -nxt_unit_process_ready_req(nxt_unit_ctx_t *ctx) -{ - int res; - nxt_queue_t ready_req; - nxt_unit_impl_t *lib; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_request_info_t *req; - nxt_unit_request_info_impl_t *req_impl; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - pthread_mutex_lock(&ctx_impl->mutex); - - if (nxt_queue_is_empty(&ctx_impl->ready_req)) { - pthread_mutex_unlock(&ctx_impl->mutex); - - return; - } - - nxt_queue_init(&ready_req); - - nxt_queue_add(&ready_req, &ctx_impl->ready_req); - nxt_queue_init(&ctx_impl->ready_req); - - pthread_mutex_unlock(&ctx_impl->mutex); - - nxt_queue_each(req_impl, &ready_req, - nxt_unit_request_info_impl_t, port_wait_link) - { - lib = nxt_container_of(ctx_impl->ctx.unit, nxt_unit_impl_t, unit); - - req = &req_impl->req; - - res = nxt_unit_send_req_headers_ack(req); - if (nxt_slow_path(res != NXT_UNIT_OK)) { - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - continue; - } - - if (req->content_length - > (uint64_t) (req->content_buf->end - req->content_buf->free)) - { - res = nxt_unit_request_hash_add(ctx, req); - if (nxt_slow_path(res != NXT_UNIT_OK)) { - nxt_unit_req_warn(req, "failed to add request to hash"); - - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - continue; - } - - /* - * If application have separate data handler, we may start - * request processing and process data when it is arrived. - */ - if (lib->callbacks.data_handler == NULL) { - continue; - } - } - - lib->callbacks.request_handler(&req_impl->req); - - } nxt_queue_loop; -} - - -int -nxt_unit_run_ctx(nxt_unit_ctx_t *ctx) -{ - int rc; - nxt_unit_read_buf_t *rbuf; - nxt_unit_ctx_impl_t *ctx_impl; - - nxt_unit_ctx_use(ctx); - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - rc = NXT_UNIT_OK; - - while (nxt_fast_path(ctx_impl->online)) { - rbuf = nxt_unit_read_buf_get(ctx); - if (nxt_slow_path(rbuf == NULL)) { - rc = NXT_UNIT_ERROR; - break; - } - - retry: - - rc = nxt_unit_ctx_port_recv(ctx, ctx_impl->read_port, rbuf); - if (rc == NXT_UNIT_AGAIN) { - goto retry; - } - - rc = nxt_unit_process_msg(ctx, rbuf, NULL); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - break; - } - - rc = nxt_unit_process_pending_rbuf(ctx); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - break; - } - - nxt_unit_process_ready_req(ctx); - } - - nxt_unit_ctx_release(ctx); - - return rc; -} - - -nxt_inline int -nxt_unit_is_read_queue(nxt_unit_read_buf_t *rbuf) -{ - nxt_port_msg_t *port_msg; - - if (nxt_fast_path(rbuf->size == (ssize_t) sizeof(nxt_port_msg_t))) { - port_msg = (nxt_port_msg_t *) rbuf->buf; - - return port_msg->type == _NXT_PORT_MSG_READ_QUEUE; - } - - return 0; -} - - -nxt_inline int -nxt_unit_is_read_socket(nxt_unit_read_buf_t *rbuf) -{ - if (nxt_fast_path(rbuf->size == 1)) { - return rbuf->buf[0] == _NXT_PORT_MSG_READ_SOCKET; - } - - return 0; -} - - -nxt_inline int -nxt_unit_is_shm_ack(nxt_unit_read_buf_t *rbuf) -{ - nxt_port_msg_t *port_msg; - - if (nxt_fast_path(rbuf->size == (ssize_t) sizeof(nxt_port_msg_t))) { - port_msg = (nxt_port_msg_t *) rbuf->buf; - - return port_msg->type == _NXT_PORT_MSG_SHM_ACK; - } - - return 0; -} - - -nxt_inline int -nxt_unit_is_quit(nxt_unit_read_buf_t *rbuf) -{ - nxt_port_msg_t *port_msg; - - if (nxt_fast_path(rbuf->size == (ssize_t) sizeof(nxt_port_msg_t))) { - port_msg = (nxt_port_msg_t *) rbuf->buf; - - return port_msg->type == _NXT_PORT_MSG_QUIT; - } - - return 0; -} - - -int -nxt_unit_run_shared(nxt_unit_ctx_t *ctx) -{ - int rc; - nxt_unit_impl_t *lib; - nxt_unit_read_buf_t *rbuf; - - nxt_unit_ctx_use(ctx); - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - rc = NXT_UNIT_OK; - - while (nxt_fast_path(nxt_unit_chk_ready(ctx))) { - rbuf = nxt_unit_read_buf_get(ctx); - if (nxt_slow_path(rbuf == NULL)) { - rc = NXT_UNIT_ERROR; - break; - } - - retry: - - rc = nxt_unit_shared_port_recv(ctx, lib->shared_port, rbuf); - if (rc == NXT_UNIT_AGAIN) { - goto retry; - } - - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - nxt_unit_read_buf_release(ctx, rbuf); - break; - } - - rc = nxt_unit_process_msg(ctx, rbuf, NULL); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - break; - } - } - - nxt_unit_ctx_release(ctx); - - return rc; -} - - -nxt_unit_request_info_t * -nxt_unit_dequeue_request(nxt_unit_ctx_t *ctx) -{ - int rc; - nxt_unit_impl_t *lib; - nxt_unit_read_buf_t *rbuf; - nxt_unit_request_info_t *req; - - nxt_unit_ctx_use(ctx); - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - req = NULL; - - if (nxt_slow_path(!nxt_unit_chk_ready(ctx))) { - goto done; - } - - rbuf = nxt_unit_read_buf_get(ctx); - if (nxt_slow_path(rbuf == NULL)) { - goto done; - } - - rc = nxt_unit_app_queue_recv(ctx, lib->shared_port, rbuf); - if (rc != NXT_UNIT_OK) { - nxt_unit_read_buf_release(ctx, rbuf); - goto done; - } - - (void) nxt_unit_process_msg(ctx, rbuf, &req); - -done: - - nxt_unit_ctx_release(ctx); - - return req; -} - - -int -nxt_unit_process_port_msg(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) -{ - int rc; - - nxt_unit_ctx_use(ctx); - - rc = nxt_unit_process_port_msg_impl(ctx, port); - - nxt_unit_ctx_release(ctx); - - return rc; -} - - -static int -nxt_unit_process_port_msg_impl(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) -{ - int rc; - nxt_unit_impl_t *lib; - nxt_unit_read_buf_t *rbuf; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - if (port == lib->shared_port && !nxt_unit_chk_ready(ctx)) { - return NXT_UNIT_AGAIN; - } - - rbuf = nxt_unit_read_buf_get(ctx); - if (nxt_slow_path(rbuf == NULL)) { - return NXT_UNIT_ERROR; - } - - if (port == lib->shared_port) { - rc = nxt_unit_shared_port_recv(ctx, port, rbuf); - - } else { - rc = nxt_unit_ctx_port_recv(ctx, port, rbuf); - } - - if (rc != NXT_UNIT_OK) { - nxt_unit_read_buf_release(ctx, rbuf); - return rc; - } - - rc = nxt_unit_process_msg(ctx, rbuf, NULL); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - - rc = nxt_unit_process_pending_rbuf(ctx); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - - nxt_unit_process_ready_req(ctx); - - return rc; -} - - -void -nxt_unit_done(nxt_unit_ctx_t *ctx) -{ - nxt_unit_ctx_release(ctx); -} - - -nxt_unit_ctx_t * -nxt_unit_ctx_alloc(nxt_unit_ctx_t *ctx, void *data) -{ - int rc, queue_fd; - void *mem; - nxt_unit_impl_t *lib; - nxt_unit_port_t *port; - nxt_unit_ctx_impl_t *new_ctx; - nxt_unit_port_impl_t *port_impl; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - new_ctx = nxt_unit_malloc(ctx, sizeof(nxt_unit_ctx_impl_t) - + lib->request_data_size); - if (nxt_slow_path(new_ctx == NULL)) { - nxt_unit_alert(ctx, "failed to allocate context"); - - return NULL; - } - - rc = nxt_unit_ctx_init(lib, new_ctx, data); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_free(ctx, new_ctx); - - return NULL; - } - - queue_fd = -1; - - port = nxt_unit_create_port(&new_ctx->ctx); - if (nxt_slow_path(port == NULL)) { - goto fail; - } - - new_ctx->read_port = port; - - queue_fd = nxt_unit_shm_open(&new_ctx->ctx, sizeof(nxt_port_queue_t)); - if (nxt_slow_path(queue_fd == -1)) { - goto fail; - } - - mem = mmap(NULL, sizeof(nxt_port_queue_t), - PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0); - if (nxt_slow_path(mem == MAP_FAILED)) { - nxt_unit_alert(ctx, "mmap(%d) failed: %s (%d)", queue_fd, - strerror(errno), errno); - - goto fail; - } - - nxt_port_queue_init(mem); - - port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - port_impl->queue = mem; - - rc = nxt_unit_send_port(&new_ctx->ctx, lib->router_port, port, queue_fd); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - nxt_unit_close(queue_fd); - - return &new_ctx->ctx; - -fail: - - if (queue_fd != -1) { - nxt_unit_close(queue_fd); - } - - nxt_unit_ctx_release(&new_ctx->ctx); - - return NULL; -} - - -static void -nxt_unit_ctx_free(nxt_unit_ctx_impl_t *ctx_impl) -{ - nxt_unit_impl_t *lib; - nxt_unit_mmap_buf_t *mmap_buf; - nxt_unit_read_buf_t *rbuf; - nxt_unit_request_info_impl_t *req_impl; - nxt_unit_websocket_frame_impl_t *ws_impl; - - lib = nxt_container_of(ctx_impl->ctx.unit, nxt_unit_impl_t, unit); - - nxt_queue_each(req_impl, &ctx_impl->active_req, - nxt_unit_request_info_impl_t, link) - { - nxt_unit_req_warn(&req_impl->req, "active request on ctx free"); - - nxt_unit_request_done(&req_impl->req, NXT_UNIT_ERROR); - - } nxt_queue_loop; - - nxt_unit_mmap_buf_unlink(&ctx_impl->ctx_buf[0]); - nxt_unit_mmap_buf_unlink(&ctx_impl->ctx_buf[1]); - - while (ctx_impl->free_buf != NULL) { - mmap_buf = ctx_impl->free_buf; - nxt_unit_mmap_buf_unlink(mmap_buf); - nxt_unit_free(&ctx_impl->ctx, mmap_buf); - } - - nxt_queue_each(req_impl, &ctx_impl->free_req, - nxt_unit_request_info_impl_t, link) - { - nxt_unit_request_info_free(req_impl); - - } nxt_queue_loop; - - nxt_queue_each(ws_impl, &ctx_impl->free_ws, - nxt_unit_websocket_frame_impl_t, link) - { - nxt_unit_websocket_frame_free(&ctx_impl->ctx, ws_impl); - - } nxt_queue_loop; - - nxt_queue_each(rbuf, &ctx_impl->free_rbuf, nxt_unit_read_buf_t, link) - { - if (rbuf != &ctx_impl->ctx_read_buf) { - nxt_unit_free(&ctx_impl->ctx, rbuf); - } - } nxt_queue_loop; - - pthread_mutex_destroy(&ctx_impl->mutex); - - pthread_mutex_lock(&lib->mutex); - - nxt_queue_remove(&ctx_impl->link); - - pthread_mutex_unlock(&lib->mutex); - - if (nxt_fast_path(ctx_impl->read_port != NULL)) { - nxt_unit_remove_port(lib, NULL, &ctx_impl->read_port->id); - nxt_unit_port_release(ctx_impl->read_port); - } - - if (ctx_impl != &lib->main_ctx) { - nxt_unit_free(&lib->main_ctx.ctx, ctx_impl); - } - - nxt_unit_lib_release(lib); -} - - -/* SOCK_SEQPACKET is disabled to test SOCK_DGRAM on all platforms. */ -#if (0 || NXT_HAVE_AF_UNIX_SOCK_SEQPACKET) -#define NXT_UNIX_SOCKET SOCK_SEQPACKET -#else -#define NXT_UNIX_SOCKET SOCK_DGRAM -#endif - - -void -nxt_unit_port_id_init(nxt_unit_port_id_t *port_id, pid_t pid, uint16_t id) -{ - nxt_unit_port_hash_id_t port_hash_id; - - port_hash_id.pid = pid; - port_hash_id.id = id; - - port_id->pid = pid; - port_id->hash = nxt_murmur_hash2(&port_hash_id, sizeof(port_hash_id)); - port_id->id = id; -} - - -static nxt_unit_port_t * -nxt_unit_create_port(nxt_unit_ctx_t *ctx) -{ - int rc, port_sockets[2]; - nxt_unit_impl_t *lib; - nxt_unit_port_t new_port, *port; - nxt_unit_process_t *process; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - rc = socketpair(AF_UNIX, NXT_UNIX_SOCKET, 0, port_sockets); - if (nxt_slow_path(rc != 0)) { - nxt_unit_warn(ctx, "create_port: socketpair() failed: %s (%d)", - strerror(errno), errno); - - return NULL; - } - -#if (NXT_HAVE_SOCKOPT_SO_PASSCRED) - int enable_creds = 1; - - if (nxt_slow_path(setsockopt(port_sockets[0], SOL_SOCKET, SO_PASSCRED, - &enable_creds, sizeof(enable_creds)) == -1)) - { - nxt_unit_warn(ctx, "failed to set SO_PASSCRED %s", strerror(errno)); - return NULL; - } - - if (nxt_slow_path(setsockopt(port_sockets[1], SOL_SOCKET, SO_PASSCRED, - &enable_creds, sizeof(enable_creds)) == -1)) - { - nxt_unit_warn(ctx, "failed to set SO_PASSCRED %s", strerror(errno)); - return NULL; - } -#endif - - nxt_unit_debug(ctx, "create_port: new socketpair: %d->%d", - port_sockets[0], port_sockets[1]); - - pthread_mutex_lock(&lib->mutex); - - process = nxt_unit_process_get(ctx, lib->pid); - if (nxt_slow_path(process == NULL)) { - pthread_mutex_unlock(&lib->mutex); - - nxt_unit_close(port_sockets[0]); - nxt_unit_close(port_sockets[1]); - - return NULL; - } - - nxt_unit_port_id_init(&new_port.id, lib->pid, process->next_port_id++); - - new_port.in_fd = port_sockets[0]; - new_port.out_fd = port_sockets[1]; - new_port.data = NULL; - - pthread_mutex_unlock(&lib->mutex); - - nxt_unit_process_release(process); - - port = nxt_unit_add_port(ctx, &new_port, NULL); - if (nxt_slow_path(port == NULL)) { - nxt_unit_close(port_sockets[0]); - nxt_unit_close(port_sockets[1]); - } - - return port; -} - - -static int -nxt_unit_send_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *dst, - nxt_unit_port_t *port, int queue_fd) -{ - ssize_t res; - nxt_send_oob_t oob; - nxt_unit_impl_t *lib; - int fds[2] = { port->out_fd, queue_fd }; - - struct { - nxt_port_msg_t msg; - nxt_port_msg_new_port_t new_port; - } m; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - m.msg.stream = 0; - m.msg.pid = lib->pid; - m.msg.reply_port = 0; - m.msg.type = _NXT_PORT_MSG_NEW_PORT; - m.msg.last = 0; - m.msg.mmap = 0; - m.msg.nf = 0; - m.msg.mf = 0; - - m.new_port.id = port->id.id; - m.new_port.pid = port->id.pid; - m.new_port.type = NXT_PROCESS_APP; - m.new_port.max_size = 16 * 1024; - m.new_port.max_share = 64 * 1024; - - nxt_socket_msg_oob_init(&oob, fds); - - res = nxt_unit_port_send(ctx, dst, &m, sizeof(m), &oob); - - return (res == sizeof(m)) ? NXT_UNIT_OK : NXT_UNIT_ERROR; -} - - -nxt_inline void nxt_unit_port_use(nxt_unit_port_t *port) -{ - nxt_unit_port_impl_t *port_impl; - - port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - - nxt_atomic_fetch_add(&port_impl->use_count, 1); -} - - -nxt_inline void nxt_unit_port_release(nxt_unit_port_t *port) -{ - long c; - nxt_unit_port_impl_t *port_impl; - - port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - - c = nxt_atomic_fetch_add(&port_impl->use_count, -1); - - if (c == 1) { - nxt_unit_debug(NULL, "destroy port{%d,%d} in_fd %d out_fd %d", - (int) port->id.pid, (int) port->id.id, - port->in_fd, port->out_fd); - - nxt_unit_process_release(port_impl->process); - - if (port->in_fd != -1) { - nxt_unit_close(port->in_fd); - - port->in_fd = -1; - } - - if (port->out_fd != -1) { - nxt_unit_close(port->out_fd); - - port->out_fd = -1; - } - - if (port_impl->queue != NULL) { - munmap(port_impl->queue, (port->id.id == NXT_UNIT_SHARED_PORT_ID) - ? sizeof(nxt_app_queue_t) - : sizeof(nxt_port_queue_t)); - } - - nxt_unit_free(NULL, port_impl); - } -} - - -static nxt_unit_port_t * -nxt_unit_add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, void *queue) -{ - int rc, ready; - nxt_queue_t awaiting_req; - nxt_unit_impl_t *lib; - nxt_unit_port_t *old_port; - nxt_unit_process_t *process; - nxt_unit_port_impl_t *new_port, *old_port_impl; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - pthread_mutex_lock(&lib->mutex); - - old_port = nxt_unit_port_hash_find(&lib->ports, &port->id, 0); - - if (nxt_slow_path(old_port != NULL)) { - nxt_unit_debug(ctx, "add_port: duplicate port{%d,%d} " - "in_fd %d out_fd %d queue %p", - port->id.pid, port->id.id, - port->in_fd, port->out_fd, queue); - - if (old_port->data == NULL) { - old_port->data = port->data; - port->data = NULL; - } - - if (old_port->in_fd == -1) { - old_port->in_fd = port->in_fd; - port->in_fd = -1; - } - - if (port->in_fd != -1) { - nxt_unit_close(port->in_fd); - port->in_fd = -1; - } - - if (old_port->out_fd == -1) { - old_port->out_fd = port->out_fd; - port->out_fd = -1; - } - - if (port->out_fd != -1) { - nxt_unit_close(port->out_fd); - port->out_fd = -1; - } - - *port = *old_port; - - nxt_queue_init(&awaiting_req); - - old_port_impl = nxt_container_of(old_port, nxt_unit_port_impl_t, port); - - if (old_port_impl->queue == NULL) { - old_port_impl->queue = queue; - } - - ready = (port->in_fd != -1 || port->out_fd != -1); - - /* - * Port can be market as 'ready' only after callbacks.add_port() call. - * Otherwise, request may try to use the port before callback. - */ - if (lib->callbacks.add_port == NULL && ready) { - old_port_impl->ready = ready; - - if (!nxt_queue_is_empty(&old_port_impl->awaiting_req)) { - nxt_queue_add(&awaiting_req, &old_port_impl->awaiting_req); - nxt_queue_init(&old_port_impl->awaiting_req); - } - } - - pthread_mutex_unlock(&lib->mutex); - - if (lib->callbacks.add_port != NULL && ready) { - lib->callbacks.add_port(ctx, old_port); - - pthread_mutex_lock(&lib->mutex); - - old_port_impl->ready = ready; - - if (!nxt_queue_is_empty(&old_port_impl->awaiting_req)) { - nxt_queue_add(&awaiting_req, &old_port_impl->awaiting_req); - nxt_queue_init(&old_port_impl->awaiting_req); - } - - pthread_mutex_unlock(&lib->mutex); - } - - nxt_unit_process_awaiting_req(ctx, &awaiting_req); - - return old_port; - } - - new_port = NULL; - ready = 0; - - nxt_unit_debug(ctx, "add_port: port{%d,%d} in_fd %d out_fd %d queue %p", - port->id.pid, port->id.id, - port->in_fd, port->out_fd, queue); - - process = nxt_unit_process_get(ctx, port->id.pid); - if (nxt_slow_path(process == NULL)) { - goto unlock; - } - - if (port->id.id != NXT_UNIT_SHARED_PORT_ID - && port->id.id >= process->next_port_id) - { - process->next_port_id = port->id.id + 1; - } - - new_port = nxt_unit_malloc(ctx, sizeof(nxt_unit_port_impl_t)); - if (nxt_slow_path(new_port == NULL)) { - nxt_unit_alert(ctx, "add_port: %d,%d malloc() failed", - port->id.pid, port->id.id); - - goto unlock; - } - - new_port->port = *port; - - rc = nxt_unit_port_hash_add(&lib->ports, &new_port->port); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_alert(ctx, "add_port: %d,%d hash_add failed", - port->id.pid, port->id.id); - - nxt_unit_free(ctx, new_port); - - new_port = NULL; - - goto unlock; - } - - nxt_queue_insert_tail(&process->ports, &new_port->link); - - new_port->use_count = 2; - new_port->process = process; - new_port->queue = queue; - new_port->from_socket = 0; - new_port->socket_rbuf = NULL; - - nxt_queue_init(&new_port->awaiting_req); - - ready = (port->in_fd != -1 || port->out_fd != -1); - - if (lib->callbacks.add_port == NULL) { - new_port->ready = ready; - - } else { - new_port->ready = 0; - } - - process = NULL; - -unlock: - - pthread_mutex_unlock(&lib->mutex); - - if (nxt_slow_path(process != NULL)) { - nxt_unit_process_release(process); - } - - if (lib->callbacks.add_port != NULL && new_port != NULL && ready) { - lib->callbacks.add_port(ctx, &new_port->port); - - nxt_queue_init(&awaiting_req); - - pthread_mutex_lock(&lib->mutex); - - new_port->ready = 1; - - if (!nxt_queue_is_empty(&new_port->awaiting_req)) { - nxt_queue_add(&awaiting_req, &new_port->awaiting_req); - nxt_queue_init(&new_port->awaiting_req); - } - - pthread_mutex_unlock(&lib->mutex); - - nxt_unit_process_awaiting_req(ctx, &awaiting_req); - } - - return (new_port == NULL) ? NULL : &new_port->port; -} - - -static void -nxt_unit_process_awaiting_req(nxt_unit_ctx_t *ctx, nxt_queue_t *awaiting_req) -{ - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_request_info_impl_t *req_impl; - - nxt_queue_each(req_impl, awaiting_req, - nxt_unit_request_info_impl_t, port_wait_link) - { - nxt_queue_remove(&req_impl->port_wait_link); - - ctx_impl = nxt_container_of(req_impl->req.ctx, nxt_unit_ctx_impl_t, - ctx); - - pthread_mutex_lock(&ctx_impl->mutex); - - nxt_queue_insert_tail(&ctx_impl->ready_req, - &req_impl->port_wait_link); - - pthread_mutex_unlock(&ctx_impl->mutex); - - nxt_atomic_fetch_add(&ctx_impl->wait_items, -1); - - nxt_unit_awake_ctx(ctx, ctx_impl); - - } nxt_queue_loop; -} - - -static void -nxt_unit_remove_port(nxt_unit_impl_t *lib, nxt_unit_ctx_t *ctx, - nxt_unit_port_id_t *port_id) -{ - nxt_unit_port_t *port; - nxt_unit_port_impl_t *port_impl; - - pthread_mutex_lock(&lib->mutex); - - port = nxt_unit_remove_port_unsafe(lib, port_id); - - if (nxt_fast_path(port != NULL)) { - port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - - nxt_queue_remove(&port_impl->link); - } - - pthread_mutex_unlock(&lib->mutex); - - if (lib->callbacks.remove_port != NULL && port != NULL) { - lib->callbacks.remove_port(&lib->unit, ctx, port); - } - - if (nxt_fast_path(port != NULL)) { - nxt_unit_port_release(port); - } -} - - -static nxt_unit_port_t * -nxt_unit_remove_port_unsafe(nxt_unit_impl_t *lib, nxt_unit_port_id_t *port_id) -{ - nxt_unit_port_t *port; - - port = nxt_unit_port_hash_find(&lib->ports, port_id, 1); - if (nxt_slow_path(port == NULL)) { - nxt_unit_debug(NULL, "remove_port: port{%d,%d} not found", - (int) port_id->pid, (int) port_id->id); - - return NULL; - } - - nxt_unit_debug(NULL, "remove_port: port{%d,%d}, fds %d,%d, data %p", - (int) port_id->pid, (int) port_id->id, - port->in_fd, port->out_fd, port->data); - - return port; -} - - -static void -nxt_unit_remove_pid(nxt_unit_impl_t *lib, pid_t pid) -{ - nxt_unit_process_t *process; - - pthread_mutex_lock(&lib->mutex); - - process = nxt_unit_process_find(lib, pid, 1); - if (nxt_slow_path(process == NULL)) { - nxt_unit_debug(NULL, "remove_pid: process %d not found", (int) pid); - - pthread_mutex_unlock(&lib->mutex); - - return; - } - - nxt_unit_remove_process(lib, process); - - if (lib->callbacks.remove_pid != NULL) { - lib->callbacks.remove_pid(&lib->unit, pid); - } -} - - -static void -nxt_unit_remove_process(nxt_unit_impl_t *lib, nxt_unit_process_t *process) -{ - nxt_queue_t ports; - nxt_unit_port_impl_t *port; - - nxt_queue_init(&ports); - - nxt_queue_add(&ports, &process->ports); - - nxt_queue_each(port, &ports, nxt_unit_port_impl_t, link) { - - nxt_unit_remove_port_unsafe(lib, &port->port.id); - - } nxt_queue_loop; - - pthread_mutex_unlock(&lib->mutex); - - nxt_queue_each(port, &ports, nxt_unit_port_impl_t, link) { - - nxt_queue_remove(&port->link); - - if (lib->callbacks.remove_port != NULL) { - lib->callbacks.remove_port(&lib->unit, NULL, &port->port); - } - - nxt_unit_port_release(&port->port); - - } nxt_queue_loop; - - nxt_unit_process_release(process); -} - - -static void -nxt_unit_quit(nxt_unit_ctx_t *ctx, uint8_t quit_param) -{ - nxt_bool_t skip_graceful_broadcast, quit; - nxt_unit_impl_t *lib; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_callbacks_t *cb; - nxt_unit_request_info_t *req; - nxt_unit_request_info_impl_t *req_impl; - - struct { - nxt_port_msg_t msg; - uint8_t quit_param; - } nxt_packed m; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - nxt_unit_debug(ctx, "quit: %d/%d/%d", (int) quit_param, ctx_impl->ready, - ctx_impl->online); - - if (nxt_slow_path(!ctx_impl->online)) { - return; - } - - skip_graceful_broadcast = quit_param == NXT_QUIT_GRACEFUL - && !ctx_impl->ready; - - cb = &lib->callbacks; - - if (nxt_fast_path(ctx_impl->ready)) { - ctx_impl->ready = 0; - - if (cb->remove_port != NULL) { - cb->remove_port(&lib->unit, ctx, lib->shared_port); - } - } - - if (quit_param == NXT_QUIT_GRACEFUL) { - pthread_mutex_lock(&ctx_impl->mutex); - - quit = nxt_queue_is_empty(&ctx_impl->active_req) - && nxt_queue_is_empty(&ctx_impl->pending_rbuf) - && ctx_impl->wait_items == 0; - - pthread_mutex_unlock(&ctx_impl->mutex); - - } else { - quit = 1; - ctx_impl->quit_param = NXT_QUIT_GRACEFUL; - } - - if (quit) { - ctx_impl->online = 0; - - if (cb->quit != NULL) { - cb->quit(ctx); - } - - nxt_queue_each(req_impl, &ctx_impl->active_req, - nxt_unit_request_info_impl_t, link) - { - req = &req_impl->req; - - nxt_unit_req_warn(req, "active request on ctx quit"); - - if (cb->close_handler) { - nxt_unit_req_debug(req, "close_handler"); - - cb->close_handler(req); - - } else { - nxt_unit_request_done(req, NXT_UNIT_ERROR); - } - - } nxt_queue_loop; - - if (nxt_fast_path(ctx_impl->read_port != NULL)) { - nxt_unit_remove_port(lib, ctx, &ctx_impl->read_port->id); - } - } - - if (ctx != &lib->main_ctx.ctx || skip_graceful_broadcast) { - return; - } - - memset(&m.msg, 0, sizeof(nxt_port_msg_t)); - - m.msg.pid = lib->pid; - m.msg.type = _NXT_PORT_MSG_QUIT; - m.quit_param = quit_param; - - pthread_mutex_lock(&lib->mutex); - - nxt_queue_each(ctx_impl, &lib->contexts, nxt_unit_ctx_impl_t, link) { - - if (ctx == &ctx_impl->ctx - || ctx_impl->read_port == NULL - || ctx_impl->read_port->out_fd == -1) - { - continue; - } - - (void) nxt_unit_port_send(ctx, ctx_impl->read_port, - &m, sizeof(m), NULL); - - } nxt_queue_loop; - - pthread_mutex_unlock(&lib->mutex); -} - - -static int -nxt_unit_get_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) -{ - ssize_t res; - nxt_unit_impl_t *lib; - nxt_unit_ctx_impl_t *ctx_impl; - - struct { - nxt_port_msg_t msg; - nxt_port_msg_get_port_t get_port; - } m; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - memset(&m.msg, 0, sizeof(nxt_port_msg_t)); - - m.msg.pid = lib->pid; - m.msg.reply_port = ctx_impl->read_port->id.id; - m.msg.type = _NXT_PORT_MSG_GET_PORT; - - m.get_port.id = port_id->id; - m.get_port.pid = port_id->pid; - - nxt_unit_debug(ctx, "get_port: %d %d", (int) port_id->pid, - (int) port_id->id); - - res = nxt_unit_port_send(ctx, lib->router_port, &m, sizeof(m), NULL); - if (nxt_slow_path(res != sizeof(m))) { - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static ssize_t -nxt_unit_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - const void *buf, size_t buf_size, const nxt_send_oob_t *oob) -{ - int notify; - ssize_t ret; - nxt_int_t rc; - nxt_port_msg_t msg; - nxt_unit_impl_t *lib; - nxt_unit_port_impl_t *port_impl; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - if (port_impl->queue != NULL && (oob == NULL || oob->size == 0) - && buf_size <= NXT_PORT_QUEUE_MSG_SIZE) - { - rc = nxt_port_queue_send(port_impl->queue, buf, buf_size, ¬ify); - if (nxt_slow_path(rc != NXT_OK)) { - nxt_unit_alert(ctx, "port_send: port %d,%d queue overflow", - (int) port->id.pid, (int) port->id.id); - - return -1; - } - - nxt_unit_debug(ctx, "port{%d,%d} enqueue %d notify %d", - (int) port->id.pid, (int) port->id.id, - (int) buf_size, notify); - - if (notify) { - memcpy(&msg, buf, sizeof(nxt_port_msg_t)); - - msg.type = _NXT_PORT_MSG_READ_QUEUE; - - if (lib->callbacks.port_send == NULL) { - ret = nxt_unit_sendmsg(ctx, port->out_fd, &msg, - sizeof(nxt_port_msg_t), NULL); - - nxt_unit_debug(ctx, "port{%d,%d} send %d read_queue", - (int) port->id.pid, (int) port->id.id, - (int) ret); - - } else { - ret = lib->callbacks.port_send(ctx, port, &msg, - sizeof(nxt_port_msg_t), NULL, 0); - - nxt_unit_debug(ctx, "port{%d,%d} sendcb %d read_queue", - (int) port->id.pid, (int) port->id.id, - (int) ret); - } - - } - - return buf_size; - } - - if (port_impl->queue != NULL) { - msg.type = _NXT_PORT_MSG_READ_SOCKET; - - rc = nxt_port_queue_send(port_impl->queue, &msg.type, 1, ¬ify); - if (nxt_slow_path(rc != NXT_OK)) { - nxt_unit_alert(ctx, "port_send: port %d,%d queue overflow", - (int) port->id.pid, (int) port->id.id); - - return -1; - } - - nxt_unit_debug(ctx, "port{%d,%d} enqueue 1 read_socket notify %d", - (int) port->id.pid, (int) port->id.id, notify); - } - - if (lib->callbacks.port_send != NULL) { - ret = lib->callbacks.port_send(ctx, port, buf, buf_size, - oob != NULL ? oob->buf : NULL, - oob != NULL ? oob->size : 0); - - nxt_unit_debug(ctx, "port{%d,%d} sendcb %d", - (int) port->id.pid, (int) port->id.id, - (int) ret); - - } else { - ret = nxt_unit_sendmsg(ctx, port->out_fd, buf, buf_size, oob); - - nxt_unit_debug(ctx, "port{%d,%d} sendmsg %d", - (int) port->id.pid, (int) port->id.id, - (int) ret); - } - - return ret; -} - - -static ssize_t -nxt_unit_sendmsg(nxt_unit_ctx_t *ctx, int fd, - const void *buf, size_t buf_size, const nxt_send_oob_t *oob) -{ - int err; - ssize_t n; - struct iovec iov[1]; - - iov[0].iov_base = (void *) buf; - iov[0].iov_len = buf_size; - -retry: - - n = nxt_sendmsg(fd, iov, 1, oob); - - if (nxt_slow_path(n == -1)) { - err = errno; - - if (err == EINTR) { - goto retry; - } - - /* - * FIXME: This should be "alert" after router graceful shutdown - * implementation. - */ - nxt_unit_warn(ctx, "sendmsg(%d, %d) failed: %s (%d)", - fd, (int) buf_size, strerror(err), err); - - } else { - nxt_unit_debug(ctx, "sendmsg(%d, %d, %d): %d", fd, (int) buf_size, - (oob != NULL ? (int) oob->size : 0), (int) n); - } - - return n; -} - - -static int -nxt_unit_ctx_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - nxt_unit_read_buf_t *rbuf) -{ - int res, read; - nxt_unit_port_impl_t *port_impl; - - port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - - read = 0; - -retry: - - if (port_impl->from_socket > 0) { - if (port_impl->socket_rbuf != NULL - && port_impl->socket_rbuf->size > 0) - { - port_impl->from_socket--; - - nxt_unit_rbuf_cpy(rbuf, port_impl->socket_rbuf); - port_impl->socket_rbuf->size = 0; - - nxt_unit_debug(ctx, "port{%d,%d} use suspended message %d", - (int) port->id.pid, (int) port->id.id, - (int) rbuf->size); - - return NXT_UNIT_OK; - } - - } else { - res = nxt_unit_port_queue_recv(port, rbuf); - - if (res == NXT_UNIT_OK) { - if (nxt_unit_is_read_socket(rbuf)) { - port_impl->from_socket++; - - nxt_unit_debug(ctx, "port{%d,%d} dequeue 1 read_socket %d", - (int) port->id.pid, (int) port->id.id, - port_impl->from_socket); - - goto retry; - } - - nxt_unit_debug(ctx, "port{%d,%d} dequeue %d", - (int) port->id.pid, (int) port->id.id, - (int) rbuf->size); - - return NXT_UNIT_OK; - } - } - - if (read) { - return NXT_UNIT_AGAIN; - } - - res = nxt_unit_port_recv(ctx, port, rbuf); - if (nxt_slow_path(res == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - - read = 1; - - if (nxt_unit_is_read_queue(rbuf)) { - nxt_unit_debug(ctx, "port{%d,%d} recv %d read_queue", - (int) port->id.pid, (int) port->id.id, (int) rbuf->size); - - goto retry; - } - - nxt_unit_debug(ctx, "port{%d,%d} recvmsg %d", - (int) port->id.pid, (int) port->id.id, - (int) rbuf->size); - - if (res == NXT_UNIT_AGAIN) { - return NXT_UNIT_AGAIN; - } - - if (port_impl->from_socket > 0) { - port_impl->from_socket--; - - return NXT_UNIT_OK; - } - - nxt_unit_debug(ctx, "port{%d,%d} suspend message %d", - (int) port->id.pid, (int) port->id.id, - (int) rbuf->size); - - if (port_impl->socket_rbuf == NULL) { - port_impl->socket_rbuf = nxt_unit_read_buf_get(ctx); - - if (nxt_slow_path(port_impl->socket_rbuf == NULL)) { - return NXT_UNIT_ERROR; - } - - port_impl->socket_rbuf->size = 0; - } - - if (port_impl->socket_rbuf->size > 0) { - nxt_unit_alert(ctx, "too many port socket messages"); - - return NXT_UNIT_ERROR; - } - - nxt_unit_rbuf_cpy(port_impl->socket_rbuf, rbuf); - - rbuf->oob.size = 0; - - goto retry; -} - - -nxt_inline void -nxt_unit_rbuf_cpy(nxt_unit_read_buf_t *dst, nxt_unit_read_buf_t *src) -{ - memcpy(dst->buf, src->buf, src->size); - dst->size = src->size; - dst->oob.size = src->oob.size; - memcpy(dst->oob.buf, src->oob.buf, src->oob.size); -} - - -static int -nxt_unit_shared_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - nxt_unit_read_buf_t *rbuf) -{ - int res; - nxt_unit_port_impl_t *port_impl; - - port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - -retry: - - res = nxt_unit_app_queue_recv(ctx, port, rbuf); - - if (res == NXT_UNIT_OK) { - return NXT_UNIT_OK; - } - - if (res == NXT_UNIT_AGAIN) { - res = nxt_unit_port_recv(ctx, port, rbuf); - if (nxt_slow_path(res == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - - if (nxt_unit_is_read_queue(rbuf)) { - nxt_app_queue_notification_received(port_impl->queue); - - nxt_unit_debug(ctx, "port{%d,%d} recv %d read_queue", - (int) port->id.pid, (int) port->id.id, (int) rbuf->size); - - goto retry; - } - } - - return res; -} - - -static int -nxt_unit_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - nxt_unit_read_buf_t *rbuf) -{ - int fd, err; - size_t oob_size; - struct iovec iov[1]; - nxt_unit_impl_t *lib; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - if (lib->callbacks.port_recv != NULL) { - oob_size = sizeof(rbuf->oob.buf); - - rbuf->size = lib->callbacks.port_recv(ctx, port, - rbuf->buf, sizeof(rbuf->buf), - rbuf->oob.buf, &oob_size); - - nxt_unit_debug(ctx, "port{%d,%d} recvcb %d", - (int) port->id.pid, (int) port->id.id, (int) rbuf->size); - - if (nxt_slow_path(rbuf->size < 0)) { - return NXT_UNIT_ERROR; - } - - rbuf->oob.size = oob_size; - return NXT_UNIT_OK; - } - - iov[0].iov_base = rbuf->buf; - iov[0].iov_len = sizeof(rbuf->buf); - - fd = port->in_fd; - -retry: - - rbuf->size = nxt_recvmsg(fd, iov, 1, &rbuf->oob); - - if (nxt_slow_path(rbuf->size == -1)) { - err = errno; - - if (err == EINTR) { - goto retry; - } - - if (err == EAGAIN) { - nxt_unit_debug(ctx, "recvmsg(%d) failed: %s (%d)", - fd, strerror(err), err); - - return NXT_UNIT_AGAIN; - } - - nxt_unit_alert(ctx, "recvmsg(%d) failed: %s (%d)", - fd, strerror(err), err); - - return NXT_UNIT_ERROR; - } - - nxt_unit_debug(ctx, "recvmsg(%d): %d", fd, (int) rbuf->size); - - return NXT_UNIT_OK; -} - - -static int -nxt_unit_port_queue_recv(nxt_unit_port_t *port, nxt_unit_read_buf_t *rbuf) -{ - nxt_unit_port_impl_t *port_impl; - - port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - - rbuf->size = nxt_port_queue_recv(port_impl->queue, rbuf->buf); - - return (rbuf->size == -1) ? NXT_UNIT_AGAIN : NXT_UNIT_OK; -} - - -static int -nxt_unit_app_queue_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - nxt_unit_read_buf_t *rbuf) -{ - uint32_t cookie; - nxt_port_msg_t *port_msg; - nxt_app_queue_t *queue; - nxt_unit_impl_t *lib; - nxt_unit_port_impl_t *port_impl; - - struct { - nxt_port_msg_t msg; - uint8_t quit_param; - } nxt_packed m; - - port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - queue = port_impl->queue; - -retry: - - rbuf->size = nxt_app_queue_recv(queue, rbuf->buf, &cookie); - - nxt_unit_debug(NULL, "app_queue_recv: %d", (int) rbuf->size); - - if (rbuf->size >= (ssize_t) sizeof(nxt_port_msg_t)) { - port_msg = (nxt_port_msg_t *) rbuf->buf; - - if (nxt_app_queue_cancel(queue, cookie, port_msg->stream)) { - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - if (lib->request_limit != 0) { - nxt_atomic_fetch_add(&lib->request_count, 1); - - if (nxt_slow_path(lib->request_count >= lib->request_limit)) { - nxt_unit_debug(ctx, "request limit reached"); - - memset(&m.msg, 0, sizeof(nxt_port_msg_t)); - - m.msg.pid = lib->pid; - m.msg.type = _NXT_PORT_MSG_QUIT; - m.quit_param = NXT_QUIT_GRACEFUL; - - (void) nxt_unit_port_send(ctx, lib->main_ctx.read_port, - &m, sizeof(m), NULL); - } - } - - return NXT_UNIT_OK; - } - - nxt_unit_debug(NULL, "app_queue_recv: message cancelled"); - - goto retry; - } - - return (rbuf->size == -1) ? NXT_UNIT_AGAIN : NXT_UNIT_OK; -} - - -nxt_inline int -nxt_unit_close(int fd) -{ - int res; - - res = close(fd); - - if (nxt_slow_path(res == -1)) { - nxt_unit_alert(NULL, "close(%d) failed: %s (%d)", - fd, strerror(errno), errno); - - } else { - nxt_unit_debug(NULL, "close(%d): %d", fd, res); - } - - return res; -} - - -static int -nxt_unit_fd_blocking(int fd) -{ - int nb; - - nb = 0; - - if (nxt_slow_path(ioctl(fd, FIONBIO, &nb) == -1)) { - nxt_unit_alert(NULL, "ioctl(%d, FIONBIO, 0) failed: %s (%d)", - fd, strerror(errno), errno); - - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static nxt_int_t -nxt_unit_port_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_unit_port_t *port; - nxt_unit_port_hash_id_t *port_id; - - port = data; - port_id = (nxt_unit_port_hash_id_t *) lhq->key.start; - - if (lhq->key.length == sizeof(nxt_unit_port_hash_id_t) - && port_id->pid == port->id.pid - && port_id->id == port->id.id) - { - return NXT_OK; - } - - return NXT_DECLINED; -} - - -static const nxt_lvlhsh_proto_t lvlhsh_ports_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_unit_port_hash_test, - nxt_unit_lvlhsh_alloc, - nxt_unit_lvlhsh_free, -}; - - -static inline void -nxt_unit_port_hash_lhq(nxt_lvlhsh_query_t *lhq, - nxt_unit_port_hash_id_t *port_hash_id, - nxt_unit_port_id_t *port_id) -{ - port_hash_id->pid = port_id->pid; - port_hash_id->id = port_id->id; - - if (nxt_fast_path(port_id->hash != 0)) { - lhq->key_hash = port_id->hash; - - } else { - lhq->key_hash = nxt_murmur_hash2(port_hash_id, sizeof(*port_hash_id)); - - port_id->hash = lhq->key_hash; - - nxt_unit_debug(NULL, "calculate hash for port_id (%d, %d): %04X", - (int) port_id->pid, (int) port_id->id, - (int) port_id->hash); - } - - lhq->key.length = sizeof(nxt_unit_port_hash_id_t); - lhq->key.start = (u_char *) port_hash_id; - lhq->proto = &lvlhsh_ports_proto; - lhq->pool = NULL; -} - - -static int -nxt_unit_port_hash_add(nxt_lvlhsh_t *port_hash, nxt_unit_port_t *port) -{ - nxt_int_t res; - nxt_lvlhsh_query_t lhq; - nxt_unit_port_hash_id_t port_hash_id; - - nxt_unit_port_hash_lhq(&lhq, &port_hash_id, &port->id); - lhq.replace = 0; - lhq.value = port; - - res = nxt_lvlhsh_insert(port_hash, &lhq); - - switch (res) { - - case NXT_OK: - return NXT_UNIT_OK; - - default: - return NXT_UNIT_ERROR; - } -} - - -static nxt_unit_port_t * -nxt_unit_port_hash_find(nxt_lvlhsh_t *port_hash, nxt_unit_port_id_t *port_id, - int remove) -{ - nxt_int_t res; - nxt_lvlhsh_query_t lhq; - nxt_unit_port_hash_id_t port_hash_id; - - nxt_unit_port_hash_lhq(&lhq, &port_hash_id, port_id); - - if (remove) { - res = nxt_lvlhsh_delete(port_hash, &lhq); - - } else { - res = nxt_lvlhsh_find(port_hash, &lhq); - } - - switch (res) { - - case NXT_OK: - if (!remove) { - nxt_unit_port_use(lhq.value); - } - - return lhq.value; - - default: - return NULL; - } -} - - -static nxt_int_t -nxt_unit_request_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - return NXT_OK; -} - - -static const nxt_lvlhsh_proto_t lvlhsh_requests_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_unit_request_hash_test, - nxt_unit_lvlhsh_alloc, - nxt_unit_lvlhsh_free, -}; - - -static int -nxt_unit_request_hash_add(nxt_unit_ctx_t *ctx, - nxt_unit_request_info_t *req) -{ - uint32_t *stream; - nxt_int_t res; - nxt_lvlhsh_query_t lhq; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_request_info_impl_t *req_impl; - - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - if (req_impl->in_hash) { - return NXT_UNIT_OK; - } - - stream = &req_impl->stream; - - lhq.key_hash = nxt_murmur_hash2(stream, sizeof(*stream)); - lhq.key.length = sizeof(*stream); - lhq.key.start = (u_char *) stream; - lhq.proto = &lvlhsh_requests_proto; - lhq.pool = NULL; - lhq.replace = 0; - lhq.value = req_impl; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - pthread_mutex_lock(&ctx_impl->mutex); - - res = nxt_lvlhsh_insert(&ctx_impl->requests, &lhq); - - pthread_mutex_unlock(&ctx_impl->mutex); - - switch (res) { - - case NXT_OK: - req_impl->in_hash = 1; - return NXT_UNIT_OK; - - default: - return NXT_UNIT_ERROR; - } -} - - -static nxt_unit_request_info_t * -nxt_unit_request_hash_find(nxt_unit_ctx_t *ctx, uint32_t stream, int remove) -{ - nxt_int_t res; - nxt_lvlhsh_query_t lhq; - nxt_unit_ctx_impl_t *ctx_impl; - nxt_unit_request_info_impl_t *req_impl; - - lhq.key_hash = nxt_murmur_hash2(&stream, sizeof(stream)); - lhq.key.length = sizeof(stream); - lhq.key.start = (u_char *) &stream; - lhq.proto = &lvlhsh_requests_proto; - lhq.pool = NULL; - - ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx); - - pthread_mutex_lock(&ctx_impl->mutex); - - if (remove) { - res = nxt_lvlhsh_delete(&ctx_impl->requests, &lhq); - - } else { - res = nxt_lvlhsh_find(&ctx_impl->requests, &lhq); - } - - pthread_mutex_unlock(&ctx_impl->mutex); - - switch (res) { - - case NXT_OK: - req_impl = nxt_container_of(lhq.value, nxt_unit_request_info_impl_t, - req); - if (remove) { - req_impl->in_hash = 0; - } - - return lhq.value; - - default: - return NULL; - } -} - - -void -nxt_unit_log(nxt_unit_ctx_t *ctx, int level, const char *fmt, ...) -{ - int log_fd, n; - char msg[NXT_MAX_ERROR_STR], *p, *end; - pid_t pid; - va_list ap; - nxt_unit_impl_t *lib; - - if (nxt_fast_path(ctx != NULL)) { - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); - - pid = lib->pid; - log_fd = lib->log_fd; - - } else { - pid = nxt_unit_pid; - log_fd = STDERR_FILENO; - } - - p = msg; - end = p + sizeof(msg) - 1; - - p = nxt_unit_snprint_prefix(p, end, pid, level); - - va_start(ap, fmt); - p += vsnprintf(p, end - p, fmt, ap); - va_end(ap); - - if (nxt_slow_path(p > end)) { - memcpy(end - 5, "[...]", 5); - p = end; - } - - *p++ = '\n'; - - n = write(log_fd, msg, p - msg); - if (nxt_slow_path(n < 0)) { - fprintf(stderr, "Failed to write log: %.*s", (int) (p - msg), msg); - } -} - - -void -nxt_unit_req_log(nxt_unit_request_info_t *req, int level, const char *fmt, ...) -{ - int log_fd, n; - char msg[NXT_MAX_ERROR_STR], *p, *end; - pid_t pid; - va_list ap; - nxt_unit_impl_t *lib; - nxt_unit_request_info_impl_t *req_impl; - - if (nxt_fast_path(req != NULL)) { - lib = nxt_container_of(req->ctx->unit, nxt_unit_impl_t, unit); - - pid = lib->pid; - log_fd = lib->log_fd; - - } else { - pid = nxt_unit_pid; - log_fd = STDERR_FILENO; - } - - p = msg; - end = p + sizeof(msg) - 1; - - p = nxt_unit_snprint_prefix(p, end, pid, level); - - if (nxt_fast_path(req != NULL)) { - req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req); - - p += snprintf(p, end - p, "#%"PRIu32": ", req_impl->stream); - } - - va_start(ap, fmt); - p += vsnprintf(p, end - p, fmt, ap); - va_end(ap); - - if (nxt_slow_path(p > end)) { - memcpy(end - 5, "[...]", 5); - p = end; - } - - *p++ = '\n'; - - n = write(log_fd, msg, p - msg); - if (nxt_slow_path(n < 0)) { - fprintf(stderr, "Failed to write log: %.*s", (int) (p - msg), msg); - } -} - - -static const char * nxt_unit_log_levels[] = { - "alert", - "error", - "warn", - "notice", - "info", - "debug", -}; - - -static char * -nxt_unit_snprint_prefix(char *p, char *end, pid_t pid, int level) -{ - struct tm tm; - struct timespec ts; - - (void) clock_gettime(CLOCK_REALTIME, &ts); - -#if (NXT_HAVE_LOCALTIME_R) - (void) localtime_r(&ts.tv_sec, &tm); -#else - tm = *localtime(&ts.tv_sec); -#endif - -#if (NXT_DEBUG) - p += snprintf(p, end - p, - "%4d/%02d/%02d %02d:%02d:%02d.%03d ", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - (int) ts.tv_nsec / 1000000); -#else - p += snprintf(p, end - p, - "%4d/%02d/%02d %02d:%02d:%02d ", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); -#endif - - p += snprintf(p, end - p, - "[%s] %d#%"PRIu64" [unit] ", nxt_unit_log_levels[level], - (int) pid, - (uint64_t) (uintptr_t) nxt_thread_get_tid()); - - return p; -} - - -static void * -nxt_unit_lvlhsh_alloc(void *data, size_t size) -{ - int err; - void *p; - - err = posix_memalign(&p, size, size); - - if (nxt_fast_path(err == 0)) { - nxt_unit_debug(NULL, "posix_memalign(%d, %d): %p", - (int) size, (int) size, p); - return p; - } - - nxt_unit_alert(NULL, "posix_memalign(%d, %d) failed: %s (%d)", - (int) size, (int) size, strerror(err), err); - return NULL; -} - - -static void -nxt_unit_lvlhsh_free(void *data, void *p) -{ - nxt_unit_free(NULL, p); -} - - -void * -nxt_unit_malloc(nxt_unit_ctx_t *ctx, size_t size) -{ - void *p; - - p = malloc(size); - - if (nxt_fast_path(p != NULL)) { -#if (NXT_DEBUG_ALLOC) - nxt_unit_debug(ctx, "malloc(%d): %p", (int) size, p); -#endif - - } else { - nxt_unit_alert(ctx, "malloc(%d) failed: %s (%d)", - (int) size, strerror(errno), errno); - } - - return p; -} - - -void -nxt_unit_free(nxt_unit_ctx_t *ctx, void *p) -{ -#if (NXT_DEBUG_ALLOC) - nxt_unit_debug(ctx, "free(%p)", p); -#endif - - free(p); -} - - -static int -nxt_unit_memcasecmp(const void *p1, const void *p2, size_t length) -{ - u_char c1, c2; - nxt_int_t n; - const u_char *s1, *s2; - - s1 = p1; - s2 = p2; - - while (length-- != 0) { - c1 = *s1++; - c2 = *s2++; - - c1 = nxt_lowcase(c1); - c2 = nxt_lowcase(c2); - - n = c1 - c2; - - if (n != 0) { - return n; - } - } - - return 0; -} diff --git a/src/nxt_unit.h b/src/nxt_unit.h deleted file mode 100644 index a50046a5..00000000 --- a/src/nxt_unit.h +++ /dev/null @@ -1,400 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIT_H_INCLUDED_ -#define _NXT_UNIT_H_INCLUDED_ - - -#include -#include -#include -#include - -#include "nxt_auto_config.h" -#include "nxt_version.h" -#include "nxt_unit_typedefs.h" - - -enum { - NXT_UNIT_OK = 0, - NXT_UNIT_ERROR = 1, - NXT_UNIT_AGAIN = 2, - NXT_UNIT_CANCELLED = 3, -}; - -enum { - NXT_UNIT_LOG_ALERT = 0, - NXT_UNIT_LOG_ERR = 1, - NXT_UNIT_LOG_WARN = 2, - NXT_UNIT_LOG_NOTICE = 3, - NXT_UNIT_LOG_INFO = 4, - NXT_UNIT_LOG_DEBUG = 5, -}; - -#define NXT_UNIT_INIT_ENV "NXT_UNIT_INIT" - -#define NXT_UNIT_SHARED_PORT_ID ((uint16_t) 0xFFFFu) - -/* - * Mostly opaque structure with library state. - * - * Only the user defined 'data' pointer is exposed here. The rest is unit - * implementation specific and hidden. - */ -struct nxt_unit_s { - void *data; /* User defined data. */ -}; - -/* - * Thread context. - * - * First (main) context is provided 'for free'. To receive and process - * requests in other threads, one needs to allocate a new context and use it - * further in that thread. - */ -struct nxt_unit_ctx_s { - void *data; /* User context-specific data. */ - nxt_unit_t *unit; -}; - -/* - * Unit port identification structure. - * - * Each port can be uniquely identified by listen process id (pid) and port id. - * This identification is required to refer the port from different process. - */ -struct nxt_unit_port_id_s { - pid_t pid; - uint32_t hash; - uint16_t id; -}; - -/* - * Unit provides port storage which is able to store and find the following - * data structures. - */ -struct nxt_unit_port_s { - nxt_unit_port_id_t id; - - int in_fd; - int out_fd; - - void *data; -}; - - -struct nxt_unit_buf_s { - char *start; - char *free; - char *end; -}; - - -struct nxt_unit_request_info_s { - nxt_unit_t *unit; - nxt_unit_ctx_t *ctx; - - nxt_unit_port_t *response_port; - - nxt_unit_request_t *request; - nxt_unit_buf_t *request_buf; - - nxt_unit_response_t *response; - nxt_unit_buf_t *response_buf; - uint32_t response_max_fields; - - nxt_unit_buf_t *content_buf; - uint64_t content_length; - int content_fd; - - void *data; -}; - - -/* - * Set of application-specific callbacks. The application may leave all - * optional callbacks as NULL. - */ -struct nxt_unit_callbacks_s { - /* - * Process request. Unlike all other callbacks, this callback is required - * and needs to be defined by the application. - */ - void (*request_handler)(nxt_unit_request_info_t *req); - - void (*data_handler)(nxt_unit_request_info_t *req); - - /* Process websocket frame. */ - void (*websocket_handler)(nxt_unit_websocket_frame_t *ws); - - /* Connection closed. */ - void (*close_handler)(nxt_unit_request_info_t *req); - - /* Add new Unit port to communicate with process pid. Optional. */ - int (*add_port)(nxt_unit_ctx_t *, nxt_unit_port_t *port); - - /* Remove previously added port. Optional. */ - void (*remove_port)(nxt_unit_t *, nxt_unit_ctx_t *, - nxt_unit_port_t *port); - - /* Remove all data associated with process pid including ports. Optional. */ - void (*remove_pid)(nxt_unit_t *, pid_t pid); - - /* Gracefully quit the application. Optional. */ - void (*quit)(nxt_unit_ctx_t *); - - /* Shared memory release acknowledgement. Optional. */ - void (*shm_ack_handler)(nxt_unit_ctx_t *); - - /* Send data and control to process pid using port id. Optional. */ - ssize_t (*port_send)(nxt_unit_ctx_t *, nxt_unit_port_t *port, - const void *buf, size_t buf_size, - const void *oob, size_t oob_size); - - /* Receive data on port id. Optional. */ - ssize_t (*port_recv)(nxt_unit_ctx_t *, nxt_unit_port_t *port, - void *buf, size_t buf_size, void *oob, size_t *oob_size); - - int (*ready_handler)(nxt_unit_ctx_t *); -}; - - -struct nxt_unit_init_s { - void *data; /* Opaque pointer to user-defined data. */ - void *ctx_data; /* Opaque pointer to user-defined data. */ - int max_pending_requests; - - uint32_t request_data_size; - uint32_t shm_limit; - uint32_t request_limit; - - nxt_unit_callbacks_t callbacks; - - nxt_unit_port_t ready_port; - uint32_t ready_stream; - nxt_unit_port_t router_port; - nxt_unit_port_t read_port; - int shared_port_fd; - int shared_queue_fd; - int log_fd; -}; - - -typedef ssize_t (*nxt_unit_read_func_t)(nxt_unit_read_info_t *read_info, - void *dst, size_t size); - - -struct nxt_unit_read_info_s { - nxt_unit_read_func_t read; - int eof; - uint32_t buf_size; - void *data; -}; - - -/* - * Initialize Unit application library with necessary callbacks and - * ready/reply port parameters, send 'READY' response to main. - */ -nxt_unit_ctx_t *nxt_unit_init(nxt_unit_init_t *); - -/* - * Main function, useful in case the application does not have its own event - * loop. nxt_unit_run() starts an infinite message wait and process loop. - * - * for (;;) { - * app_lib->port_recv(...); - * nxt_unit_process_msg(...); - * } - * - * The function returns normally when a QUIT message is received from Unit. - */ -int nxt_unit_run(nxt_unit_ctx_t *); - -int nxt_unit_run_ctx(nxt_unit_ctx_t *ctx); - -int nxt_unit_run_shared(nxt_unit_ctx_t *ctx); - -nxt_unit_request_info_t *nxt_unit_dequeue_request(nxt_unit_ctx_t *ctx); - -/* - * Receive and process one message, and invoke configured callbacks. - * - * If the application implements its own event loop, each datagram received - * from the port socket should be initially processed by unit. This function - * may invoke other application-defined callback for message processing. - */ -int nxt_unit_run_once(nxt_unit_ctx_t *ctx); - -int nxt_unit_process_port_msg(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port); - -/* Destroy application library object. */ -void nxt_unit_done(nxt_unit_ctx_t *); - -/* - * Allocate and initialize a new execution context with a new listen port to - * process requests in another thread. - */ -nxt_unit_ctx_t *nxt_unit_ctx_alloc(nxt_unit_ctx_t *, void *); - -/* Initialize port_id, calculate hash. */ -void nxt_unit_port_id_init(nxt_unit_port_id_t *port_id, pid_t pid, uint16_t id); - -/* Calculates hash for given field name. */ -uint16_t nxt_unit_field_hash(const char* name, size_t name_length); - -/* Split host for server name and port. */ -void nxt_unit_split_host(char *host_start, uint32_t host_length, - char **name, uint32_t *name_length, char **port, uint32_t *port_length); - -/* Group duplicate fields for easy enumeration. */ -void nxt_unit_request_group_dup_fields(nxt_unit_request_info_t *req); - -/* - * Allocate response structure capable of storing a limited number of fields. - * The structure may be accessed directly via req->response pointer or - * filled step-by-step using functions add_field and add_content. - */ -int nxt_unit_response_init(nxt_unit_request_info_t *req, - uint16_t status, uint32_t max_fields_count, uint32_t max_fields_size); - -int nxt_unit_response_realloc(nxt_unit_request_info_t *req, - uint32_t max_fields_count, uint32_t max_fields_size); - -int nxt_unit_response_is_init(nxt_unit_request_info_t *req); - -int nxt_unit_response_add_field(nxt_unit_request_info_t *req, - const char* name, uint8_t name_length, - const char* value, uint32_t value_length); - -int nxt_unit_response_add_content(nxt_unit_request_info_t *req, - const void* src, uint32_t size); - -/* - * Send the prepared response to the Unit server. The Response structure is - * destroyed during this call. - */ -int nxt_unit_response_send(nxt_unit_request_info_t *req); - -int nxt_unit_response_is_sent(nxt_unit_request_info_t *req); - -nxt_unit_buf_t *nxt_unit_response_buf_alloc(nxt_unit_request_info_t *req, - uint32_t size); - -int nxt_unit_request_is_websocket_handshake(nxt_unit_request_info_t *req); - -int nxt_unit_response_upgrade(nxt_unit_request_info_t *req); - -int nxt_unit_response_is_websocket(nxt_unit_request_info_t *req); - -nxt_unit_request_info_t *nxt_unit_get_request_info_from_data(void *data); - -int nxt_unit_buf_send(nxt_unit_buf_t *buf); - -void nxt_unit_buf_free(nxt_unit_buf_t *buf); - -nxt_unit_buf_t *nxt_unit_buf_next(nxt_unit_buf_t *buf); - -uint32_t nxt_unit_buf_max(void); - -uint32_t nxt_unit_buf_min(void); - -int nxt_unit_response_write(nxt_unit_request_info_t *req, const void *start, - size_t size); - -ssize_t nxt_unit_response_write_nb(nxt_unit_request_info_t *req, - const void *start, size_t size, size_t min_size); - -int nxt_unit_response_write_cb(nxt_unit_request_info_t *req, - nxt_unit_read_info_t *read_info); - -ssize_t nxt_unit_request_read(nxt_unit_request_info_t *req, void *dst, - size_t size); - -ssize_t nxt_unit_request_readline_size(nxt_unit_request_info_t *req, - size_t max_size); - -void nxt_unit_request_done(nxt_unit_request_info_t *req, int rc); - - -int nxt_unit_websocket_send(nxt_unit_request_info_t *req, uint8_t opcode, - uint8_t last, const void *start, size_t size); - -int nxt_unit_websocket_sendv(nxt_unit_request_info_t *req, uint8_t opcode, - uint8_t last, const struct iovec *iov, int iovcnt); - -ssize_t nxt_unit_websocket_read(nxt_unit_websocket_frame_t *ws, void *dst, - size_t size); - -int nxt_unit_websocket_retain(nxt_unit_websocket_frame_t *ws); - -void nxt_unit_websocket_done(nxt_unit_websocket_frame_t *ws); - - -void *nxt_unit_malloc(nxt_unit_ctx_t *ctx, size_t size); - -void nxt_unit_free(nxt_unit_ctx_t *ctx, void *p); - -#if defined __has_attribute - -#if __has_attribute(format) - -#define NXT_ATTR_FORMAT __attribute__((format(printf, 3, 4))) - -#endif - -#endif - - -#if !defined(NXT_ATTR_FORMAT) - -#define NXT_ATTR_FORMAT - -#endif - - -void nxt_unit_log(nxt_unit_ctx_t *ctx, int level, const char* fmt, ...) - NXT_ATTR_FORMAT; - -void nxt_unit_req_log(nxt_unit_request_info_t *req, int level, - const char* fmt, ...) NXT_ATTR_FORMAT; - -#if (NXT_DEBUG) - -#define nxt_unit_debug(ctx, fmt, ARGS...) \ - nxt_unit_log(ctx, NXT_UNIT_LOG_DEBUG, fmt, ##ARGS) - -#define nxt_unit_req_debug(req, fmt, ARGS...) \ - nxt_unit_req_log(req, NXT_UNIT_LOG_DEBUG, fmt, ##ARGS) - -#else - -#define nxt_unit_debug(ctx, fmt, ARGS...) - -#define nxt_unit_req_debug(req, fmt, ARGS...) - -#endif - - -#define nxt_unit_warn(ctx, fmt, ARGS...) \ - nxt_unit_log(ctx, NXT_UNIT_LOG_WARN, fmt, ##ARGS) - -#define nxt_unit_req_warn(req, fmt, ARGS...) \ - nxt_unit_req_log(req, NXT_UNIT_LOG_WARN, fmt, ##ARGS) - -#define nxt_unit_error(ctx, fmt, ARGS...) \ - nxt_unit_log(ctx, NXT_UNIT_LOG_ERR, fmt, ##ARGS) - -#define nxt_unit_req_error(req, fmt, ARGS...) \ - nxt_unit_req_log(req, NXT_UNIT_LOG_ERR, fmt, ##ARGS) - -#define nxt_unit_alert(ctx, fmt, ARGS...) \ - nxt_unit_log(ctx, NXT_UNIT_LOG_ALERT, fmt, ##ARGS) - -#define nxt_unit_req_alert(req, fmt, ARGS...) \ - nxt_unit_req_log(req, NXT_UNIT_LOG_ALERT, fmt, ##ARGS) - - -#endif /* _NXT_UNIT_H_INCLUDED_ */ diff --git a/src/nxt_unit_field.h b/src/nxt_unit_field.h deleted file mode 100644 index b07d3046..00000000 --- a/src/nxt_unit_field.h +++ /dev/null @@ -1,34 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIT_FIELD_H_INCLUDED_ -#define _NXT_UNIT_FIELD_H_INCLUDED_ - - -#include - -#include "nxt_unit_sptr.h" - -enum { - NXT_UNIT_HASH_CONTENT_LENGTH = 0x1EA0, - NXT_UNIT_HASH_CONTENT_TYPE = 0x5F7D, - NXT_UNIT_HASH_COOKIE = 0x23F2, -}; - - -/* Name and Value field aka HTTP header. */ -struct nxt_unit_field_s { - uint16_t hash; - uint8_t skip:1; - uint8_t hopbyhop:1; - uint8_t name_length; - uint32_t value_length; - - nxt_unit_sptr_t name; - nxt_unit_sptr_t value; -}; - - -#endif /* _NXT_UNIT_FIELD_H_INCLUDED_ */ diff --git a/src/nxt_unit_request.h b/src/nxt_unit_request.h deleted file mode 100644 index a6ebf0b6..00000000 --- a/src/nxt_unit_request.h +++ /dev/null @@ -1,55 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIT_REQUEST_H_INCLUDED_ -#define _NXT_UNIT_REQUEST_H_INCLUDED_ - - -#include - -#include "nxt_unit_sptr.h" -#include "nxt_unit_field.h" - -#define NXT_UNIT_NONE_FIELD 0xFFFFFFFFU - -struct nxt_unit_request_s { - uint8_t method_length; - uint8_t version_length; - uint8_t remote_length; - uint8_t local_addr_length; - uint8_t local_port_length; - uint8_t tls; - uint8_t websocket_handshake; - uint8_t app_target; - uint32_t server_name_length; - uint32_t target_length; - uint32_t path_length; - uint32_t query_length; - uint32_t fields_count; - - uint32_t content_length_field; - uint32_t content_type_field; - uint32_t cookie_field; - uint32_t authorization_field; - - uint64_t content_length; - - nxt_unit_sptr_t method; - nxt_unit_sptr_t version; - nxt_unit_sptr_t remote; - nxt_unit_sptr_t local_addr; - nxt_unit_sptr_t local_port; - nxt_unit_sptr_t server_name; - nxt_unit_sptr_t target; - nxt_unit_sptr_t path; - nxt_unit_sptr_t query; - nxt_unit_sptr_t preread_content; - - nxt_unit_field_t fields[]; -}; - - -#endif /* _NXT_UNIT_REQUEST_H_INCLUDED_ */ - diff --git a/src/nxt_unit_response.h b/src/nxt_unit_response.h deleted file mode 100644 index 481ed701..00000000 --- a/src/nxt_unit_response.h +++ /dev/null @@ -1,27 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIT_RESPONSE_H_INCLUDED_ -#define _NXT_UNIT_RESPONSE_H_INCLUDED_ - - -#include - -#include "nxt_unit_sptr.h" -#include "nxt_unit_field.h" - -struct nxt_unit_response_s { - uint64_t content_length; - uint32_t fields_count; - uint32_t piggyback_content_length; - uint16_t status; - - nxt_unit_sptr_t piggyback_content; - - nxt_unit_field_t fields[]; -}; - - -#endif /* _NXT_UNIT_RESPONSE_H_INCLUDED_ */ diff --git a/src/nxt_unit_sptr.h b/src/nxt_unit_sptr.h deleted file mode 100644 index 314416e4..00000000 --- a/src/nxt_unit_sptr.h +++ /dev/null @@ -1,38 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIT_SPTR_H_INCLUDED_ -#define _NXT_UNIT_SPTR_H_INCLUDED_ - - -#include -#include -#include - -#include "nxt_unit_typedefs.h" - - -/* Serialized pointer. */ -union nxt_unit_sptr_u { - uint8_t base[1]; - uint32_t offset; -}; - - -static inline void -nxt_unit_sptr_set(nxt_unit_sptr_t *sptr, void *ptr) -{ - sptr->offset = (uint8_t *) ptr - sptr->base; -} - - -static inline void * -nxt_unit_sptr_get(nxt_unit_sptr_t *sptr) -{ - return sptr->base + sptr->offset; -} - - -#endif /* _NXT_UNIT_SPTR_H_INCLUDED_ */ diff --git a/src/nxt_unit_typedefs.h b/src/nxt_unit_typedefs.h deleted file mode 100644 index 26e54f91..00000000 --- a/src/nxt_unit_typedefs.h +++ /dev/null @@ -1,26 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIT_TYPEDEFS_H_INCLUDED_ -#define _NXT_UNIT_TYPEDEFS_H_INCLUDED_ - - -typedef struct nxt_unit_s nxt_unit_t; -typedef struct nxt_unit_ctx_s nxt_unit_ctx_t; -typedef struct nxt_unit_port_id_s nxt_unit_port_id_t; -typedef struct nxt_unit_port_s nxt_unit_port_t; -typedef struct nxt_unit_buf_s nxt_unit_buf_t; -typedef struct nxt_unit_request_info_s nxt_unit_request_info_t; -typedef struct nxt_unit_callbacks_s nxt_unit_callbacks_t; -typedef struct nxt_unit_init_s nxt_unit_init_t; -typedef union nxt_unit_sptr_u nxt_unit_sptr_t; -typedef struct nxt_unit_field_s nxt_unit_field_t; -typedef struct nxt_unit_request_s nxt_unit_request_t; -typedef struct nxt_unit_response_s nxt_unit_response_t; -typedef struct nxt_unit_read_info_s nxt_unit_read_info_t; -typedef struct nxt_unit_websocket_frame_s nxt_unit_websocket_frame_t; - - -#endif /* _NXT_UNIT_TYPEDEFS_H_INCLUDED_ */ diff --git a/src/nxt_unit_websocket.h b/src/nxt_unit_websocket.h deleted file mode 100644 index beb2536e..00000000 --- a/src/nxt_unit_websocket.h +++ /dev/null @@ -1,27 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UNIT_WEBSOCKET_H_INCLUDED_ -#define _NXT_UNIT_WEBSOCKET_H_INCLUDED_ - -#include - -#include "nxt_unit_typedefs.h" -#include "nxt_websocket_header.h" - - -struct nxt_unit_websocket_frame_s { - nxt_unit_request_info_t *req; - - uint64_t payload_len; - nxt_websocket_header_t *header; - uint8_t *mask; - - nxt_unit_buf_t *content_buf; - uint64_t content_length; -}; - - -#endif /* _NXT_UNIT_WEBSOCKET_H_INCLUDED_ */ diff --git a/src/nxt_unix.h b/src/nxt_unix.h deleted file mode 100644 index 6bc6be5e..00000000 --- a/src/nxt_unix.h +++ /dev/null @@ -1,292 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - - -#ifndef _NXT_UNIX_H_INCLUDED_ -#define _NXT_UNIX_H_INCLUDED_ - - -#if (NXT_LINUX) - -#ifdef _FORTIFY_SOURCE -/* - * _FORTIFY_SOURCE - * may call sigaltstack() while _longjmp() checking; - * may cause _longjmp() to fail with message: - * "longjmp() causes uninitialized stack frame"; - * does not allow to use "(void) write()"; - * does surplus checks. - */ -#undef _FORTIFY_SOURCE -#endif - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE /* pread(), pwrite(), gethostname(). */ -#endif - -#define _FILE_OFFSET_BITS 64 - -#include /* malloc_usable_size(). */ -#include /* syscall(SYS_gettid). */ - -#if (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 4) -/* - * POSIX semaphores using NPTL atomic/futex operations - * were introduced during glibc 2.3 development time. - */ -#define NXT_HAVE_SEM_TRYWAIT_FAST 1 -#endif - -#endif /* NXT_LINUX */ - - -#if (NXT_FREEBSD) - -#if (NXT_HAVE_MALLOC_USABLE_SIZE) -#include /* malloc_usable_size(). */ -#endif - -#if (__FreeBSD_version >= 900007) -/* POSIX semaphores using atomic/umtx. */ -#define NXT_HAVE_SEM_TRYWAIT_FAST 1 -#endif - -#endif /* NXT_FREEBSD */ - - -#if (NXT_SOLARIS) - -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 /* Must be before . */ -#endif - -#ifndef _REENTRANT /* May be set by "-mt" options. */ -#define _REENTRANT /* Thread safe errno. */ -#endif - -#ifndef _POSIX_PTHREAD_SEMANTICS -#define _POSIX_PTHREAD_SEMANTICS /* 2 arguments in sigwait(). */ -#endif - -/* - * Solaris provides two sockets API: - * - * 1) 4.3BSD sockets (int instead of socklen_t in accept(), etc.; - * struct msghdr.msg_accrights) in libsocket; - * 2) X/Open sockets (socklen_t, struct msghdr.msg_control) with __xnet_ - * function name prefix in libxnet and libsocket. - */ - -/* Enable X/Open sockets API. */ -#define _XOPEN_SOURCE -#define _XOPEN_SOURCE_EXTENDED 1 -/* Enable Solaris extensions disabled by _XOPEN_SOURCE. */ -#ifndef __EXTENSIONS__ -#define __EXTENSIONS__ -#endif - -#endif /* NXT_SOLARIS */ - - -#if (NXT_MACOSX) - -#ifndef _DARWIN_C_SOURCE -#define _DARWIN_C_SOURCE /* pthread_threadid_np(), mach_port_t. */ -#endif - -#include /* mach_absolute_time(). */ -#include /* malloc_size(). */ - -#endif /* NXT_MACOSX */ - - -#if (NXT_AIX) - -#define _THREAD_SAFE /* Must before any include. */ - -#endif /* NXT_AIX */ - - -#if (NXT_HPUX) - -#define _FILE_OFFSET_BITS 64 - -/* - * HP-UX provides three sockets API: - * - * 1) 4.3BSD sockets (int instead of socklen_t in accept(), etc.; - * struct msghdr.msg_accrights) in libc; - * 2) X/Open sockets (socklen_t, struct msghdr.msg_control) with _xpg_ - * function name prefix in libc; - * 3) and X/Open sockets (socklen_t, struct msghdr.msg_control) in libxnet. - */ - -/* Enable X/Open sockets API. */ -#define _XOPEN_SOURCE -#define _XOPEN_SOURCE_EXTENDED -/* Enable static function wrappers for _xpg_ X/Open sockets API in libc. */ -#define _HPUX_ALT_XOPEN_SOCKET_API - -#include - -#if (NXT_HAVE_HG_GETHRTIME) -#include -#endif - -#endif /* NXT_HPUX */ - - -#if (NXT_HAVE_ALLOCA_H) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* offsetof() */ -#include -#include -#include -#include -#include -#if (NXT_HAVE_SYS_FILIO_H) -#include /* FIONBIO */ -#endif -#include -#include -#include /* MAXPATHLEN */ -#include -#include -#include -#include -#include -#include -#if (NXT_HAVE_UNIX_DOMAIN) -#include -#endif -#include -#include -#include -#include - -#if (NXT_HAVE_EPOLL) -#include - -#ifdef EPOLLRDHUP -/* - * Epoll edge-tiggered mode is pretty much useless without EPOLLRDHUP support. - */ -#define NXT_HAVE_EPOLL_EDGE 1 -#endif - -#endif - -#if (NXT_HAVE_SIGNALFD) -#include -#endif - -#if (NXT_HAVE_EVENTFD) -#include -#endif - -#if (NXT_HAVE_KQUEUE) -#include -#endif - -#if (NXT_HAVE_EVENTPORT) -#include -#endif - -#if (NXT_HAVE_DEVPOLL) -#include -#endif - -#if (NXT_HAVE_POLLSET) -#include -#endif - -#if (NXT_HAVE_LINUX_SENDFILE) -#include -#endif - -#if (NXT_HAVE_SOLARIS_SENDFILEV) -#include -#endif - -#if (NXT_HAVE_GETRANDOM) -#include /* getrandom(). */ -#elif (NXT_HAVE_LINUX_SYS_GETRANDOM) -#include /* SYS_getrandom. */ -#elif (NXT_HAVE_GETENTROPY_SYS_RANDOM) -#include /* getentropy(). */ -#endif - -#if (NXT_HAVE_ISOLATION_ROOTFS) -#include -#endif - -#if (NXT_HAVE_OPENAT2) -#include -#endif - -#if (NXT_TEST_BUILD) -#include -#endif - - -/* - * On Linux IOV_MAX is 1024. Linux uses kernel stack for 8 iovec's - * to avoid kernel allocation/deallocation. - * - * On FreeBSD IOV_MAX is 1024. FreeBSD used kernel stack for 8 iovec's - * to avoid kernel allocation/deallocation until FreeBSD 5.2. - * FreeBSD 5.2 and later do not use stack at all. - * - * On Solaris IOV_MAX is 16 and Solaris uses only kernel stack. - * - * On MacOSX IOV_MAX is 1024. MacOSX used kernel stack for 8 iovec's - * to avoid kernel allocation/deallocation until MacOSX 10.4 (Tiger). - * MacOSX 10.4 and later do not use stack at all. - * - * On NetBSD, OpenBSD, and DragonFlyBSD IOV_MAX is 1024. All these OSes - * uses kernel stack for 8 iovec's to avoid kernel allocation/deallocation. - * - * On AIX and HP-UX IOV_MAX is 16. - */ -#define NXT_IOBUF_MAX 8 - - -typedef struct iovec nxt_iobuf_t; - -#define nxt_iobuf_data(iob) \ - (iob)->iov_base - -#define nxt_iobuf_size(iob) \ - (iob)->iov_len - -#define nxt_iobuf_set(iob, p, size) \ - do { \ - (iob)->iov_base = (void *) p; \ - (iob)->iov_len = size; \ - } while (0) - -#define nxt_iobuf_add(iob, size) \ - (iob)->iov_len += size - - -#endif /* _NXT_UNIX_H_INCLUDED_ */ diff --git a/src/nxt_upstream.c b/src/nxt_upstream.c deleted file mode 100644 index 17593173..00000000 --- a/src/nxt_upstream.c +++ /dev/null @@ -1,151 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -static nxt_http_action_t *nxt_upstream_handler(nxt_task_t *task, - nxt_http_request_t *r, nxt_http_action_t *action); - - -nxt_int_t -nxt_upstreams_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *conf) -{ - size_t size; - uint32_t i, n, next; - nxt_mp_t *mp; - nxt_int_t ret; - nxt_str_t name, *string; - nxt_upstreams_t *upstreams; - nxt_conf_value_t *upstreams_conf, *upcf; - - static nxt_str_t upstreams_name = nxt_string("upstreams"); - - upstreams_conf = nxt_conf_get_object_member(conf, &upstreams_name, NULL); - - if (upstreams_conf == NULL) { - return NXT_OK; - } - - n = nxt_conf_object_members_count(upstreams_conf); - - if (n == 0) { - return NXT_OK; - } - - mp = tmcf->router_conf->mem_pool; - size = sizeof(nxt_upstreams_t) + n * sizeof(nxt_upstream_t); - - upstreams = nxt_mp_zalloc(mp, size); - if (nxt_slow_path(upstreams == NULL)) { - return NXT_ERROR; - } - - upstreams->items = n; - next = 0; - - for (i = 0; i < n; i++) { - upcf = nxt_conf_next_object_member(upstreams_conf, &name, &next); - - string = nxt_str_dup(mp, &upstreams->upstream[i].name, &name); - if (nxt_slow_path(string == NULL)) { - return NXT_ERROR; - } - - ret = nxt_upstream_round_robin_create(task, tmcf, upcf, - &upstreams->upstream[i]); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - - tmcf->router_conf->upstreams = upstreams; - - return NXT_OK; -} - - -nxt_int_t -nxt_upstream_find(nxt_upstreams_t *upstreams, nxt_str_t *name, - nxt_http_action_t *action) -{ - uint32_t i, n; - nxt_upstream_t *upstream; - - if (upstreams == NULL) { - return NXT_DECLINED; - } - - upstream = &upstreams->upstream[0]; - n = upstreams->items; - - for (i = 0; i < n; i++) { - if (nxt_strstr_eq(&upstream[i].name, name)) { - action->u.upstream_number = i; - action->handler = nxt_upstream_handler; - - return NXT_OK; - } - } - - return NXT_DECLINED; -} - - -nxt_int_t -nxt_upstreams_joint_create(nxt_router_temp_conf_t *tmcf, - nxt_upstream_t ***upstream_joint) -{ - uint32_t i, n; - nxt_upstream_t *u, **up; - nxt_upstreams_t *upstreams; - nxt_router_conf_t *router_conf; - - router_conf = tmcf->router_conf; - upstreams = router_conf->upstreams; - - if (upstreams == NULL) { - *upstream_joint = NULL; - return NXT_OK; - } - - n = upstreams->items; - - up = nxt_mp_zalloc(router_conf->mem_pool, n * sizeof(nxt_upstream_t *)); - if (nxt_slow_path(up == NULL)) { - return NXT_ERROR; - } - - u = &upstreams->upstream[0]; - - for (i = 0; i < n; i++) { - up[i] = u[i].proto->joint_create(tmcf, &u[i]); - if (nxt_slow_path(up[i] == NULL)) { - return NXT_ERROR; - } - } - - *upstream_joint = up; - - return NXT_OK; -} - - -static nxt_http_action_t * -nxt_upstream_handler(nxt_task_t *task, nxt_http_request_t *r, - nxt_http_action_t *action) -{ - nxt_upstream_t *u; - - u = r->conf->upstreams[action->u.upstream_number]; - - nxt_debug(task, "upstream handler: \"%V\"", &u->name); - - return nxt_upstream_proxy_handler(task, r, u); -} diff --git a/src/nxt_upstream.h b/src/nxt_upstream.h deleted file mode 100644 index afc53774..00000000 --- a/src/nxt_upstream.h +++ /dev/null @@ -1,81 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UPSTREAM_H_INCLUDED_ -#define _NXT_UPSTREAM_H_INCLUDED_ - - -typedef struct nxt_upstream_proxy_s nxt_upstream_proxy_t; -typedef struct nxt_upstream_round_robin_s nxt_upstream_round_robin_t; -typedef struct nxt_upstream_round_robin_server_s - nxt_upstream_round_robin_server_t; - - -typedef void (*nxt_upstream_peer_ready_t)(nxt_task_t *task, - nxt_upstream_server_t *us); -typedef void (*nxt_upstream_peer_error_t)(nxt_task_t *task, - nxt_upstream_server_t *us); - - -typedef struct { - nxt_upstream_peer_ready_t ready; - nxt_upstream_peer_error_t error; -} nxt_upstream_peer_state_t; - - -typedef nxt_upstream_t *(*nxt_upstream_joint_create_t)( - nxt_router_temp_conf_t *tmcf, nxt_upstream_t *upstream); -typedef void (*nxt_upstream_server_get_t)(nxt_task_t *task, - nxt_upstream_server_t *us); - - -typedef struct { - nxt_upstream_joint_create_t joint_create; - nxt_upstream_server_get_t get; -} nxt_upstream_server_proto_t; - - -struct nxt_upstream_s { - const nxt_upstream_server_proto_t *proto; - - union { - nxt_upstream_proxy_t *proxy; - nxt_upstream_round_robin_t *round_robin; - } type; - - nxt_str_t name; -}; - - -struct nxt_upstreams_s { - uint32_t items; - nxt_upstream_t upstream[0]; -}; - - -struct nxt_upstream_server_s { - nxt_sockaddr_t *sockaddr; - const nxt_upstream_peer_state_t *state; - nxt_upstream_t *upstream; - - uint8_t protocol; - - union { - nxt_upstream_round_robin_server_t *round_robin; - } server; - - union { - nxt_http_peer_t *http; - } peer; -}; - - -nxt_int_t nxt_upstream_round_robin_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *upstream_conf, - nxt_upstream_t *upstream); - - -#endif /* _NXT_UPSTREAM_H_INCLUDED_ */ diff --git a/src/nxt_upstream_round_robin.c b/src/nxt_upstream_round_robin.c deleted file mode 100644 index 31e2f48a..00000000 --- a/src/nxt_upstream_round_robin.c +++ /dev/null @@ -1,205 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include - - -struct nxt_upstream_round_robin_server_s { - nxt_sockaddr_t *sockaddr; - - int32_t current_weight; - int32_t effective_weight; - int32_t weight; - - uint8_t protocol; -}; - - -struct nxt_upstream_round_robin_s { - uint32_t items; - nxt_upstream_round_robin_server_t server[0]; -}; - - -static nxt_upstream_t *nxt_upstream_round_robin_joint_create( - nxt_router_temp_conf_t *tmcf, nxt_upstream_t *upstream); -static void nxt_upstream_round_robin_server_get(nxt_task_t *task, - nxt_upstream_server_t *us); - - -static const nxt_upstream_server_proto_t nxt_upstream_round_robin_proto = { - .joint_create = nxt_upstream_round_robin_joint_create, - .get = nxt_upstream_round_robin_server_get, -}; - - -nxt_int_t -nxt_upstream_round_robin_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_conf_value_t *upstream_conf, nxt_upstream_t *upstream) -{ - double total, k, w; - size_t size; - uint32_t i, n, next, wt; - nxt_mp_t *mp; - nxt_str_t name; - nxt_sockaddr_t *sa; - nxt_conf_value_t *servers_conf, *srvcf, *wtcf; - nxt_upstream_round_robin_t *urr; - - static nxt_str_t servers = nxt_string("servers"); - static nxt_str_t weight = nxt_string("weight"); - - mp = tmcf->router_conf->mem_pool; - - servers_conf = nxt_conf_get_object_member(upstream_conf, &servers, NULL); - n = nxt_conf_object_members_count(servers_conf); - - total = 0.0; - next = 0; - - for (i = 0; i < n; i++) { - srvcf = nxt_conf_next_object_member(servers_conf, &name, &next); - wtcf = nxt_conf_get_object_member(srvcf, &weight, NULL); - w = (wtcf != NULL) ? nxt_conf_get_number(wtcf) : 1; - total += w; - } - - /* - * This prevents overflow of int32_t - * in nxt_upstream_round_robin_server_get(). - */ - k = (total == 0) ? 0 : (NXT_INT32_T_MAX / 2) / total; - - if (isinf(k)) { - k = 1; - } - - size = sizeof(nxt_upstream_round_robin_t) - + n * sizeof(nxt_upstream_round_robin_server_t); - - urr = nxt_mp_zalloc(mp, size); - if (nxt_slow_path(urr == NULL)) { - return NXT_ERROR; - } - - urr->items = n; - next = 0; - - for (i = 0; i < n; i++) { - srvcf = nxt_conf_next_object_member(servers_conf, &name, &next); - - sa = nxt_sockaddr_parse(mp, &name); - if (nxt_slow_path(sa == NULL)) { - return NXT_ERROR; - } - - sa->type = SOCK_STREAM; - - urr->server[i].sockaddr = sa; - urr->server[i].protocol = NXT_HTTP_PROTO_H1; - - wtcf = nxt_conf_get_object_member(srvcf, &weight, NULL); - w = (wtcf != NULL) ? k * nxt_conf_get_number(wtcf) : k; - wt = (w > 1 || w == 0) ? round(w) : 1; - - urr->server[i].weight = wt; - urr->server[i].effective_weight = wt; - } - - upstream->proto = &nxt_upstream_round_robin_proto; - upstream->type.round_robin = urr; - - return NXT_OK; -} - - -static nxt_upstream_t * -nxt_upstream_round_robin_joint_create(nxt_router_temp_conf_t *tmcf, - nxt_upstream_t *upstream) -{ - size_t size; - uint32_t i, n; - nxt_mp_t *mp; - nxt_upstream_t *u; - nxt_upstream_round_robin_t *urr, *urrcf; - - mp = tmcf->router_conf->mem_pool; - - u = nxt_mp_alloc(mp, sizeof(nxt_upstream_t)); - if (nxt_slow_path(u == NULL)) { - return NULL; - } - - *u = *upstream; - - urrcf = upstream->type.round_robin; - - size = sizeof(nxt_upstream_round_robin_t) - + urrcf->items * sizeof(nxt_upstream_round_robin_server_t); - - urr = nxt_mp_alloc(mp, size); - if (nxt_slow_path(urr == NULL)) { - return NULL; - } - - u->type.round_robin = urr; - - n = urrcf->items; - urr->items = n; - - for (i = 0; i < n; i++) { - urr->server[i] = urrcf->server[i]; - } - - return u; -} - - -static void -nxt_upstream_round_robin_server_get(nxt_task_t *task, nxt_upstream_server_t *us) -{ - int32_t total; - uint32_t i, n; - nxt_upstream_round_robin_t *round_robin; - nxt_upstream_round_robin_server_t *s, *best; - - best = NULL; - total = 0; - - round_robin = us->upstream->type.round_robin; - - s = round_robin->server; - n = round_robin->items; - - for (i = 0; i < n; i++) { - - s[i].current_weight += s[i].effective_weight; - total += s[i].effective_weight; - - if (s[i].effective_weight < s[i].weight) { - s[i].effective_weight++; - } - - if (best == NULL || s[i].current_weight > best->current_weight) { - best = &s[i]; - } - } - - if (best == NULL || total == 0) { - us->state->error(task, us); - return; - } - - best->current_weight -= total; - us->sockaddr = best->sockaddr; - us->protocol = best->protocol; - us->server.round_robin = best; - - us->state->ready(task, us); -} diff --git a/src/nxt_utf8.c b/src/nxt_utf8.c deleted file mode 100644 index d983be84..00000000 --- a/src/nxt_utf8.c +++ /dev/null @@ -1,273 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - -/* - * The nxt_unicode_lowcase.h file is the auto-generated file from - * the CaseFolding-6.3.0.txt file provided by Unicode, Inc.: - * - * ./lib/src/nxt_unicode_lowcase.pl CaseFolding-6.3.0.txt - * - * This file should be copied to system specific nxt_unicode_SYSTEM_lowcase.h - * file and utf8_file_name_test should be built with this file. - * Then a correct system specific file should be generated: - * - * ./build/utf8_file_name_test | ./lib/src/nxt_unicode_lowcase.pl - * - * Only common and simple case foldings are supported. Full case foldings - * is not supported. Combined characters are also not supported. - */ - -#if (NXT_MACOSX) -#include - -#else -#include -#endif - - -u_char * -nxt_utf8_encode(u_char *p, uint32_t u) -{ - if (u < 0x80) { - *p++ = (u_char) (u & 0xFF); - return p; - } - - if (u < 0x0800) { - *p++ = (u_char) (( u >> 6) | 0xC0); - *p++ = (u_char) (( u & 0x3F) | 0x80); - return p; - } - - if (u < 0x10000) { - *p++ = (u_char) ( (u >> 12) | 0xE0); - *p++ = (u_char) (((u >> 6) & 0x3F) | 0x80); - *p++ = (u_char) (( u & 0x3F) | 0x80); - return p; - } - - if (u < 0x110000) { - *p++ = (u_char) ( (u >> 18) | 0xF0); - *p++ = (u_char) (((u >> 12) & 0x3F) | 0x80); - *p++ = (u_char) (((u >> 6) & 0x3F) | 0x80); - *p++ = (u_char) (( u & 0x3F) | 0x80); - return p; - } - - return NULL; -} - - -/* - * nxt_utf8_decode() decodes UTF-8 sequences and returns a valid - * character 0x00 - 0x10FFFF, or 0xFFFFFFFF for invalid or overlong - * UTF-8 sequence. - */ - -uint32_t -nxt_utf8_decode(const u_char **start, const u_char *end) -{ - uint32_t u; - - u = (uint32_t) **start; - - if (u < 0x80) { - (*start)++; - return u; - } - - return nxt_utf8_decode2(start, end); -} - - -/* - * nxt_utf8_decode2() decodes two and more bytes UTF-8 sequences only - * and returns a valid character 0x80 - 0x10FFFF, or 0xFFFFFFFF for - * invalid or overlong UTF-8 sequence. - */ - -uint32_t -nxt_utf8_decode2(const u_char **start, const u_char *end) -{ - u_char c; - size_t n; - uint32_t u, overlong; - const u_char *p; - - p = *start; - u = (uint32_t) *p; - - if (u >= 0xE0) { - - if (u >= 0xF0) { - - if (nxt_slow_path(u > 0xF4)) { - /* - * The maximum valid Unicode character is 0x10FFFF - * which is encoded as 0xF4 0x8F 0xBF 0xBF. - */ - return 0xFFFFFFFF; - } - - u &= 0x07; - overlong = 0x00FFFF; - n = 3; - - } else { - u &= 0x0F; - overlong = 0x07FF; - n = 2; - } - - } else if (u >= 0xC2) { - - /* 0x80 is encoded as 0xC2 0x80. */ - - u &= 0x1F; - overlong = 0x007F; - n = 1; - - } else { - /* u <= 0xC2 */ - return 0xFFFFFFFF; - } - - p++; - - if (nxt_fast_path(p + n <= end)) { - - do { - c = *p++; - /* - * The byte must in the 0x80 - 0xBF range. - * Values below 0x80 become >= 0x80. - */ - c = c - 0x80; - - if (nxt_slow_path(c > 0x3F)) { - return 0xFFFFFFFF; - } - - u = (u << 6) | c; - n--; - - } while (n != 0); - - if (overlong < u && u < 0x110000) { - *start = p; - return u; - } - } - - return 0xFFFFFFFF; -} - - -/* - * nxt_utf8_casecmp() tests only up to the minimum of given lengths, but - * requires lengths of both strings because otherwise nxt_utf8_decode2() - * may fail due to incomplete sequence. - */ - -nxt_int_t -nxt_utf8_casecmp(const u_char *start1, const u_char *start2, size_t len1, - size_t len2) -{ - int32_t n; - uint32_t u1, u2; - const u_char *end1, *end2; - - end1 = start1 + len1; - end2 = start2 + len2; - - while (start1 < end1 && start2 < end2) { - - u1 = nxt_utf8_lowcase(&start1, end1); - - u2 = nxt_utf8_lowcase(&start2, end2); - - if (nxt_slow_path((u1 | u2) == 0xFFFFFFFF)) { - return NXT_UTF8_SORT_INVALID; - } - - n = u1 - u2; - - if (n != 0) { - return (nxt_int_t) n; - } - } - - return 0; -} - - -uint32_t -nxt_utf8_lowcase(const u_char **start, const u_char *end) -{ - uint32_t u; - const uint32_t *block; - - u = (uint32_t) **start; - - if (nxt_fast_path(u < 0x80)) { - (*start)++; - - return nxt_unicode_block_000[u]; - } - - u = nxt_utf8_decode2(start, end); - - if (u <= NXT_UNICODE_MAX_LOWCASE) { - block = nxt_unicode_blocks[u / NXT_UNICODE_BLOCK_SIZE]; - - if (block != NULL) { - return block[u % NXT_UNICODE_BLOCK_SIZE]; - } - } - - return u; -} - - -ssize_t -nxt_utf8_length(const u_char *p, size_t len) -{ - ssize_t length; - const u_char *end; - - length = 0; - - end = p + len; - - while (p < end) { - if (nxt_slow_path(nxt_utf8_decode(&p, end) == 0xFFFFFFFF)) { - return -1; - } - - length++; - } - - return length; -} - - -nxt_bool_t -nxt_utf8_is_valid(const u_char *p, size_t len) -{ - const u_char *end; - - end = p + len; - - while (p < end) { - if (nxt_slow_path(nxt_utf8_decode(&p, end) == 0xFFFFFFFF)) { - return 0; - } - } - - return 1; -} diff --git a/src/nxt_utf8.h b/src/nxt_utf8.h deleted file mode 100644 index 13f42e16..00000000 --- a/src/nxt_utf8.h +++ /dev/null @@ -1,60 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_UTF8_H_INCLUDED_ -#define _NXT_UTF8_H_INCLUDED_ - - -/* - * Since the maximum valid Unicode character is 0x0010FFFF, the maximum - * difference between Unicode characters is lesser 0x0010FFFF and - * 0x0EEE0EEE can be used as value to indicate UTF-8 encoding error. - */ -#define NXT_UTF8_SORT_INVALID 0x0EEE0EEE - - -NXT_EXPORT u_char *nxt_utf8_encode(u_char *p, uint32_t u); -NXT_EXPORT uint32_t nxt_utf8_decode(const u_char **start, const u_char *end); -NXT_EXPORT uint32_t nxt_utf8_decode2(const u_char **start, const u_char *end); -NXT_EXPORT nxt_int_t nxt_utf8_casecmp(const u_char *start1, - const u_char *start2, size_t len1, size_t len2); -NXT_EXPORT uint32_t nxt_utf8_lowcase(const u_char **start, const u_char *end); -NXT_EXPORT ssize_t nxt_utf8_length(const u_char *p, size_t len); -NXT_EXPORT nxt_bool_t nxt_utf8_is_valid(const u_char *p, size_t len); - - -/* nxt_utf8_next() expects a valid UTF-8 string. */ - -nxt_inline const u_char * -nxt_utf8_next(const u_char *p, const u_char *end) -{ - u_char c; - - c = *p++; - - if ((c & 0x80) != 0) { - - do { - /* - * The first UTF-8 byte is either 0xxxxxxx or 11xxxxxx. - * The next UTF-8 bytes are 10xxxxxx. - */ - c = *p; - - if ((c & 0xC0) != 0x80) { - return p; - } - - p++; - - } while (p < end); - } - - return p; -} - - -#endif /* _NXT_UTF8_H_INCLUDED_ */ diff --git a/src/nxt_var.c b/src/nxt_var.c deleted file mode 100644 index 57110f66..00000000 --- a/src/nxt_var.c +++ /dev/null @@ -1,588 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include - - -struct nxt_var_s { - size_t length; - nxt_uint_t vars; - u_char data[]; - -/* - nxt_var_sub_t subs[vars]; - u_char raw[length]; -*/ -}; - - -typedef struct { - uint32_t index; - uint32_t length; - uint32_t position; -} nxt_var_sub_t; - - -struct nxt_var_query_s { - nxt_mp_t *pool; - - nxt_var_cache_t cache; - - nxt_uint_t waiting; - nxt_uint_t failed; /* 1 bit */ - - void *ctx; - void *data; - - nxt_work_handler_t ready; - nxt_work_handler_t error; -}; - - -#define nxt_var_subs(var) ((nxt_var_sub_t *) (var)->data) - -#define nxt_var_raw_start(var) \ - ((var)->data + (var)->vars * sizeof(nxt_var_sub_t)) - - -static nxt_int_t nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data); -static nxt_var_decl_t *nxt_var_hash_find(nxt_str_t *name); - -static nxt_var_ref_t *nxt_var_ref_get(nxt_tstr_state_t *state, nxt_str_t *name, - nxt_mp_t *mp); - -static nxt_int_t nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data); -static nxt_str_t *nxt_var_cache_value(nxt_task_t *task, nxt_tstr_state_t *state, - nxt_var_cache_t *cache, nxt_var_ref_t *ref, void *ctx); - -static u_char *nxt_var_next_part(u_char *start, u_char *end, nxt_str_t *part); - - -static const nxt_lvlhsh_proto_t nxt_var_hash_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_var_hash_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - -static const nxt_lvlhsh_proto_t nxt_var_cache_proto nxt_aligned(64) = { - NXT_LVLHSH_DEFAULT, - nxt_var_cache_test, - nxt_mp_lvlhsh_alloc, - nxt_mp_lvlhsh_free, -}; - - -static nxt_lvlhsh_t nxt_var_hash; -static uint32_t nxt_var_count; - -static nxt_var_decl_t **nxt_vars; - - -static nxt_int_t -nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - nxt_var_decl_t *decl; - - decl = data; - - return nxt_strstr_eq(&lhq->key, &decl->name) ? NXT_OK : NXT_DECLINED; -} - - -static nxt_var_decl_t * -nxt_var_hash_find(nxt_str_t *name) -{ - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_djb_hash(name->start, name->length); - lhq.key = *name; - lhq.proto = &nxt_var_hash_proto; - - if (nxt_lvlhsh_find(&nxt_var_hash, &lhq) != NXT_OK) { - return NULL; - } - - return lhq.value; -} - - -static nxt_var_ref_t * -nxt_var_ref_get(nxt_tstr_state_t *state, nxt_str_t *name, nxt_mp_t *mp) -{ - nxt_int_t ret; - nxt_uint_t i; - nxt_var_ref_t *ref; - nxt_var_decl_t *decl; - - ref = state->var_refs->elts; - - for (i = 0; i < state->var_refs->nelts; i++) { - - if (nxt_strstr_eq(ref[i].name, name)) { - return &ref[i]; - } - } - - if (mp != NULL) { - ref = nxt_mp_alloc(mp, sizeof(nxt_var_ref_t)); - if (nxt_slow_path(ref == NULL)) { - return NULL; - } - - } else { - ref = nxt_array_add(state->var_refs); - if (nxt_slow_path(ref == NULL)) { - return NULL; - } - - ref->index = state->var_refs->nelts - 1; - - mp = state->pool; - } - - decl = nxt_var_hash_find(name); - - if (decl != NULL) { - ref->handler = decl->handler; - ref->cacheable = (mp == state->pool) ? decl->cacheable : 0; - - goto done; - } - - ret = nxt_http_unknown_var_ref(mp, ref, name); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - -done: - - ref->name = nxt_str_dup(mp, NULL, name); - if (nxt_slow_path(ref->name == NULL)) { - return NULL; - } - - return ref; -} - - -nxt_var_field_t * -nxt_var_field_new(nxt_mp_t *mp, nxt_str_t *name, uint32_t hash) -{ - nxt_str_t *str; - nxt_var_field_t *field; - - field = nxt_mp_alloc(mp, sizeof(nxt_var_field_t)); - if (nxt_slow_path(field == NULL)) { - return NULL; - } - - str = nxt_str_dup(mp, &field->name, name); - if (nxt_slow_path(str == NULL)) { - return NULL; - } - - field->hash = hash; - - return field; -} - - -nxt_var_field_t * -nxt_var_field_get(nxt_array_t *fields, uint16_t index) -{ - nxt_uint_t nfields; - nxt_var_field_t *field; - - field = fields->elts; - nfields = fields->nelts; - - if (nfields > 0 && index <= nfields) { - return &field[index]; - } - - return NULL; -} - - -static nxt_int_t -nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - return NXT_OK; -} - - -static nxt_str_t * -nxt_var_cache_value(nxt_task_t *task, nxt_tstr_state_t *state, - nxt_var_cache_t *cache, nxt_var_ref_t *ref, void *ctx) -{ - nxt_int_t ret; - nxt_str_t *value; - nxt_lvlhsh_query_t lhq; - - value = cache->spare; - - if (value == NULL) { - value = nxt_mp_zget(cache->pool, sizeof(nxt_str_t)); - if (nxt_slow_path(value == NULL)) { - return NULL; - } - - cache->spare = value; - } - - if (!ref->cacheable) { - goto not_cached; - } - - lhq.key_hash = nxt_murmur_hash2_uint32(&ref->index); - lhq.replace = 0; - lhq.key.length = sizeof(uint32_t); - lhq.key.start = (u_char *) &ref->index; - lhq.value = value; - lhq.proto = &nxt_var_cache_proto; - lhq.pool = cache->pool; - - ret = nxt_lvlhsh_insert(&cache->hash, &lhq); - if (nxt_slow_path(ret == NXT_ERROR)) { - return NULL; - } - - if (ret == NXT_DECLINED) { - return lhq.value; - } - -not_cached: - - ret = ref->handler(task, value, ctx, ref->data); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - cache->spare = NULL; - - return value; -} - - -nxt_int_t -nxt_var_register(nxt_var_decl_t *decl, size_t n) -{ - nxt_uint_t i; - nxt_lvlhsh_query_t lhq; - - lhq.replace = 0; - lhq.proto = &nxt_var_hash_proto; - - for (i = 0; i < n; i++) { - lhq.key = decl[i].name; - lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); - lhq.value = &decl[i]; - - if (nxt_slow_path(nxt_lvlhsh_insert(&nxt_var_hash, &lhq) != NXT_OK)) { - return NXT_ERROR; - } - } - - nxt_var_count += n; - - return NXT_OK; -} - - -nxt_int_t -nxt_var_index_init(void) -{ - nxt_uint_t i; - nxt_var_decl_t *decl, **vars; - nxt_lvlhsh_each_t lhe; - - vars = nxt_memalign(64, nxt_var_count * sizeof(nxt_var_decl_t *)); - if (vars == NULL) { - return NXT_ERROR; - } - - nxt_lvlhsh_each_init(&lhe, &nxt_var_hash_proto); - - for (i = 0; i < nxt_var_count; i++) { - decl = nxt_lvlhsh_each(&nxt_var_hash, &lhe); - vars[i] = decl; - } - - nxt_vars = vars; - - return NXT_OK; -} - - -nxt_var_t * -nxt_var_compile(nxt_tstr_state_t *state, nxt_str_t *str) -{ - u_char *p, *end, *next, *src; - size_t size; - nxt_var_t *var; - nxt_str_t part; - nxt_uint_t n; - nxt_var_sub_t *subs; - nxt_var_ref_t *ref; - - n = 0; - - p = str->start; - end = p + str->length; - - while (p < end) { - p = nxt_var_next_part(p, end, &part); - if (nxt_slow_path(p == NULL)) { - return NULL; - } - - if (part.start != NULL) { - n++; - } - } - - size = sizeof(nxt_var_t) + n * sizeof(nxt_var_sub_t) + str->length; - - var = nxt_mp_get(state->pool, size); - if (nxt_slow_path(var == NULL)) { - return NULL; - } - - var->length = str->length; - var->vars = n; - - subs = nxt_var_subs(var); - src = nxt_var_raw_start(var); - - nxt_memcpy(src, str->start, str->length); - - n = 0; - p = str->start; - - while (p < end) { - next = nxt_var_next_part(p, end, &part); - - if (part.start != NULL) { - ref = nxt_var_ref_get(state, &part, NULL); - if (nxt_slow_path(ref == NULL)) { - return NULL; - } - - subs[n].index = ref->index; - subs[n].length = next - p; - subs[n].position = p - str->start; - - n++; - } - - p = next; - } - - return var; -} - - -nxt_int_t -nxt_var_test(nxt_tstr_state_t *state, nxt_str_t *str, u_char *error) -{ - u_char *p, *end, *next; - nxt_str_t part; - nxt_var_ref_t *ref; - - p = str->start; - end = p + str->length; - - while (p < end) { - next = nxt_var_next_part(p, end, &part); - - if (next == NULL) { - nxt_sprintf(error, error + NXT_MAX_ERROR_STR, - "Invalid variable at position %uz%Z", p - str->start); - - return NXT_ERROR; - } - - if (part.start != NULL) { - ref = nxt_var_ref_get(state, &part, NULL); - - if (ref == NULL) { - nxt_sprintf(error, error + NXT_MAX_ERROR_STR, - "Unknown variable \"%V\"%Z", &part); - - return NXT_ERROR; - } - } - - p = next; - } - - return NXT_OK; -} - - -static u_char * -nxt_var_next_part(u_char *start, u_char *end, nxt_str_t *part) -{ - size_t length; - u_char *p, ch, c; - nxt_bool_t bracket; - - p = memchr(start, '$', end - start); - - if (p == start) { - p++; - - if (p == end) { - return NULL; - } - - if (*p == '{') { - bracket = 1; - - if (end - p < 2) { - return NULL; - } - - p++; - - } else { - bracket = 0; - } - - length = 0; - start = p; - - while (p < end) { - ch = *p; - - c = (u_char) (ch | 0x20); - - if ((c >= 'a' && c <= 'z') || ch == '_') { - p++; - length++; - continue; - } - - if (bracket && ch == '}') { - p++; - bracket = 0; - } - - break; - } - - if (bracket || length == 0) { - return NULL; - } - - part->length = length; - part->start = start; - - } else { - if (p == NULL) { - p = end; - } - - nxt_str_null(part); - } - - return p; -} - - -nxt_int_t -nxt_var_interpreter(nxt_task_t *task, nxt_tstr_state_t *state, - nxt_var_cache_t *cache, nxt_var_t *var, nxt_str_t *str, void *ctx, - nxt_bool_t logging) -{ - u_char *p, *src; - size_t length, last, next; - uint32_t index; - nxt_str_t *value, **part; - nxt_uint_t i; - nxt_array_t parts; - nxt_var_ref_t *ref; - nxt_var_sub_t *subs; - - nxt_memzero(&parts, sizeof(nxt_array_t)); - nxt_array_init(&parts, cache->pool, sizeof(nxt_str_t *)); - - ref = state->var_refs->elts; - subs = nxt_var_subs(var); - - length = var->length; - - for (i = 0; i < var->vars; i++) { - index = subs[i].index; - value = nxt_var_cache_value(task, state, cache, &ref[index], ctx); - if (nxt_slow_path(value == NULL)) { - return NXT_ERROR; - } - - part = nxt_array_add(&parts); - if (nxt_slow_path(part == NULL)) { - return NXT_ERROR; - } - - *part = value; - - length += value->length - subs[i].length; - - if (logging && value->start == NULL) { - length += 1; - } - } - - p = nxt_mp_nget(cache->pool, length); - if (nxt_slow_path(p == NULL)) { - return NXT_ERROR; - } - - str->length = length; - str->start = p; - - part = parts.elts; - src = nxt_var_raw_start(var); - - last = 0; - - for (i = 0; i < var->vars; i++) { - next = subs[i].position; - - if (next != last) { - p = nxt_cpymem(p, &src[last], next - last); - } - - p = nxt_cpymem(p, part[i]->start, part[i]->length); - - if (logging && part[i]->start == NULL) { - *p++ = '-'; - } - - last = next + subs[i].length; - } - - if (last != var->length) { - p = nxt_cpymem(p, &src[last], var->length - last); - } - - return NXT_OK; -} - - -nxt_str_t * -nxt_var_get(nxt_task_t *task, nxt_tstr_state_t *state, nxt_var_cache_t *cache, - nxt_str_t *name, void *ctx) -{ - nxt_var_ref_t *ref; - - ref = nxt_var_ref_get(state, name, cache->pool); - if (nxt_slow_path(ref == NULL)) { - return NULL; - } - - return nxt_var_cache_value(task, state, cache, ref, ctx); -} diff --git a/src/nxt_var.h b/src/nxt_var.h deleted file mode 100644 index 08a92c08..00000000 --- a/src/nxt_var.h +++ /dev/null @@ -1,69 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_VAR_H_INCLUDED_ -#define _NXT_VAR_H_INCLUDED_ - - -typedef struct nxt_var_s nxt_var_t; -typedef struct nxt_var_query_s nxt_var_query_t; - - -typedef nxt_int_t (*nxt_var_handler_t)(nxt_task_t *task, - nxt_str_t *str, - void *ctx, void *data); - -typedef int64_t (*nxt_var_field_hash_t)(nxt_mp_t *mp, nxt_str_t *str); - -typedef struct { - nxt_str_t name; - nxt_var_handler_t handler; - uint8_t cacheable; /* 1 bit */ -} nxt_var_decl_t; - - -typedef struct { - nxt_str_t *name; - nxt_var_handler_t handler; - void *data; - uint32_t index; - uint8_t cacheable; /* 1 bit */ -} nxt_var_ref_t; - - -typedef struct { - nxt_str_t name; - uint16_t hash; -} nxt_var_field_t; - - -typedef struct { - nxt_mp_t *pool; - nxt_lvlhsh_t hash; - nxt_str_t *spare; -} nxt_var_cache_t; - - -nxt_int_t nxt_var_register(nxt_var_decl_t *decl, size_t n); -nxt_int_t nxt_var_index_init(void); - -nxt_var_field_t *nxt_var_field_get(nxt_array_t *fields, uint16_t index); -nxt_var_field_t *nxt_var_field_new(nxt_mp_t *mp, nxt_str_t *name, - uint32_t hash); - -nxt_var_t *nxt_var_compile(nxt_tstr_state_t *state, nxt_str_t *str); -nxt_int_t nxt_var_test(nxt_tstr_state_t *state, nxt_str_t *str, u_char *error); - -nxt_int_t nxt_var_interpreter(nxt_task_t *task, nxt_tstr_state_t *state, - nxt_var_cache_t *cache, nxt_var_t *var, nxt_str_t *str, void *ctx, - nxt_bool_t logging); -nxt_str_t *nxt_var_get(nxt_task_t *task, nxt_tstr_state_t *state, - nxt_var_cache_t *cache, nxt_str_t *name, void *ctx); - -nxt_int_t nxt_http_unknown_var_ref(nxt_mp_t *mp, nxt_var_ref_t *ref, - nxt_str_t *name); - - -#endif /* _NXT_VAR_H_INCLUDED_ */ diff --git a/src/nxt_vector.c b/src/nxt_vector.c deleted file mode 100644 index 4737248c..00000000 --- a/src/nxt_vector.c +++ /dev/null @@ -1,156 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -nxt_vector_t * -nxt_vector_create(nxt_uint_t items, size_t item_size, - const nxt_mem_proto_t *proto, void *pool) -{ - nxt_vector_t *vector; - - vector = proto->alloc(pool, sizeof(nxt_vector_t) + items * item_size); - - if (nxt_fast_path(vector != NULL)) { - vector->start = nxt_pointer_to(vector, sizeof(nxt_vector_t)); - vector->items = 0; - vector->item_size = item_size; - vector->avalaible = items; - vector->type = NXT_VECTOR_EMBEDDED; - } - - return vector; -} - - -void * -nxt_vector_init(nxt_vector_t *vector, nxt_uint_t items, size_t item_size, - const nxt_mem_proto_t *proto, void *pool) -{ - vector->start = proto->alloc(pool, items * item_size); - - if (nxt_fast_path(vector->start != NULL)) { - vector->items = 0; - vector->item_size = item_size; - vector->avalaible = items; - vector->type = NXT_VECTOR_INITED; - } - - return vector->start; -} - - -void -nxt_vector_destroy(nxt_vector_t *vector, const nxt_mem_proto_t *proto, - void *pool) -{ - switch (vector->type) { - - case NXT_VECTOR_INITED: - proto->free(pool, vector->start); -#if (NXT_DEBUG) - vector->start = NULL; - vector->items = 0; - vector->avalaible = 0; -#endif - break; - - case NXT_VECTOR_DESCRETE: - proto->free(pool, vector->start); - - /* Fall through. */ - - case NXT_VECTOR_EMBEDDED: - proto->free(pool, vector); - break; - } -} - - -void * -nxt_vector_add(nxt_vector_t *vector, const nxt_mem_proto_t *proto, void *pool) -{ - void *item, *start, *old; - size_t size; - uint32_t n; - - n = vector->avalaible; - - if (n == vector->items) { - - if (n < 16) { - /* Allocate new vector twice as much as current. */ - n *= 2; - - } else { - /* Allocate new vector half as much as current. */ - n += n / 2; - } - - size = n * vector->item_size; - - start = proto->alloc(pool, size); - if (nxt_slow_path(start == NULL)) { - return NULL; - } - - vector->avalaible = n; - old = vector->start; - vector->start = start; - - nxt_memcpy(start, old, size); - - if (vector->type == NXT_VECTOR_EMBEDDED) { - vector->type = NXT_VECTOR_DESCRETE; - - } else { - proto->free(pool, old); - } - } - - item = nxt_pointer_to(vector->start, vector->item_size * vector->items); - - vector->items++; - - return item; -} - - -void * -nxt_vector_zero_add(nxt_vector_t *vector, const nxt_mem_proto_t *proto, - void *pool) -{ - void *item; - - item = nxt_vector_add(vector, proto, pool); - - if (nxt_fast_path(item != NULL)) { - nxt_memzero(item, vector->item_size); - } - - return item; -} - - -void -nxt_vector_remove(nxt_vector_t *vector, void *item) -{ - u_char *next, *last, *end; - uint32_t item_size; - - item_size = vector->item_size; - end = nxt_pointer_to(vector->start, item_size * vector->items); - last = end - item_size; - - if (item != last) { - next = nxt_pointer_to(item, item_size); - - nxt_memmove(item, next, end - next); - } - - vector->items--; -} diff --git a/src/nxt_vector.h b/src/nxt_vector.h deleted file mode 100644 index dcac53d4..00000000 --- a/src/nxt_vector.h +++ /dev/null @@ -1,65 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_VECTOR_H_INCLUDED_ -#define _NXT_VECTOR_H_INCLUDED_ - - -typedef enum { - NXT_VECTOR_INITED = 0, - NXT_VECTOR_DESCRETE, - NXT_VECTOR_EMBEDDED, -} nxt_vector_type_t; - - -typedef struct { - void *start; - /* - * A vector can hold no more than 65536 items. - * The item size is no more than 64K. - */ - uint16_t items; - uint16_t avalaible; - uint16_t item_size; - nxt_vector_type_t type:8; -} nxt_vector_t; - - -NXT_EXPORT nxt_vector_t *nxt_vector_create(nxt_uint_t items, size_t item_size, - const nxt_mem_proto_t *proto, void *pool); -NXT_EXPORT void *nxt_vector_init(nxt_vector_t *vector, nxt_uint_t items, - size_t item_size, const nxt_mem_proto_t *proto, void *pool); -NXT_EXPORT void nxt_vector_destroy(nxt_vector_t *vector, - const nxt_mem_proto_t *proto, void *pool); -NXT_EXPORT void *nxt_vector_add(nxt_vector_t *vector, - const nxt_mem_proto_t *proto, void *pool); -NXT_EXPORT void *nxt_vector_zero_add(nxt_vector_t *vector, - const nxt_mem_proto_t *proto, void *pool); -NXT_EXPORT void nxt_vector_remove(nxt_vector_t *vector, void *item); - - -#define nxt_vector_last(vector) \ - nxt_pointer_to((vector)->start, \ - (vector)->item_size * ((vector)->items - 1)) - - -#define nxt_vector_reset(vector) \ - (vector)->items = 0; - - -#define nxt_vector_is_empty(vector) \ - ((vector)->items == 0) - - -nxt_inline void * -nxt_vector_remove_last(nxt_vector_t *vector) -{ - vector->items--; - return nxt_pointer_to(vector->start, vector->item_size * vector->items); -} - - -#endif /* _NXT_VECTOR_H_INCLUDED_ */ diff --git a/src/nxt_websocket.c b/src/nxt_websocket.c deleted file mode 100644 index 91002237..00000000 --- a/src/nxt_websocket.c +++ /dev/null @@ -1,122 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -nxt_inline uint16_t -nxt_ntoh16(const uint8_t *b) -{ - return ((uint16_t) b[0]) << 8 | ((uint16_t) b[1]); -} - - -nxt_inline void -nxt_hton16(uint8_t *b, uint16_t v) -{ - b[0] = (v >> 8); - b[1] = (v & 0xFFu); -} - - -nxt_inline uint64_t -nxt_ntoh64(const uint8_t *b) -{ - return ((uint64_t) b[0]) << 56 - | ((uint64_t) b[1]) << 48 - | ((uint64_t) b[2]) << 40 - | ((uint64_t) b[3]) << 32 - | ((uint64_t) b[4]) << 24 - | ((uint64_t) b[5]) << 16 - | ((uint64_t) b[6]) << 8 - | ((uint64_t) b[7]); -} - - -nxt_inline void -nxt_hton64(uint8_t *b, uint64_t v) -{ - b[0] = (v >> 56); - b[1] = (v >> 48) & 0xFFu; - b[2] = (v >> 40) & 0xFFu; - b[3] = (v >> 32) & 0xFFu; - b[4] = (v >> 24) & 0xFFu; - b[5] = (v >> 16) & 0xFFu; - b[6] = (v >> 8) & 0xFFu; - b[7] = v & 0xFFu; -} - - -size_t -nxt_websocket_frame_header_size(const void *data) -{ - size_t res; - uint64_t p; - const nxt_websocket_header_t *h; - - h = data; - p = h->payload_len; - - res = 2; - - if (p == 126) { - res += 2; - } else if (p == 127) { - res += 8; - } - - if (h->mask) { - res += 4; - } - - return res; -} - - -uint64_t -nxt_websocket_frame_payload_len(const void *data) -{ - uint64_t p; - const nxt_websocket_header_t *h; - - h = data; - p = h->payload_len; - - if (p == 126) { - p = nxt_ntoh16(h->payload_len_); - } else if (p == 127) { - p = nxt_ntoh64(h->payload_len_); - } - - return p; -} - - -void * -nxt_websocket_frame_init(void *data, uint64_t payload_len) -{ - uint8_t *p; - nxt_websocket_header_t *h; - - h = data; - p = data; - - if (payload_len < 126) { - h->payload_len = payload_len; - return p + 2; - } - - if (payload_len < 65536) { - h->payload_len = 126; - nxt_hton16(h->payload_len_, payload_len); - return p + 4; - } - - h->payload_len = 127; - nxt_hton64(h->payload_len_, payload_len); - return p + 10; -} diff --git a/src/nxt_websocket.h b/src/nxt_websocket.h deleted file mode 100644 index 499a3268..00000000 --- a/src/nxt_websocket.h +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_WEBSOCKET_H_INCLUDED_ -#define _NXT_WEBSOCKET_H_INCLUDED_ - - -enum { - NXT_WEBSOCKET_ACCEPT_SIZE = 28, -}; - - -NXT_EXPORT size_t nxt_websocket_frame_header_size(const void *data); -NXT_EXPORT uint64_t nxt_websocket_frame_payload_len(const void *data); -NXT_EXPORT void *nxt_websocket_frame_init(void *data, uint64_t payload_len); -NXT_EXPORT void nxt_websocket_accept(u_char *accept, const void *key); - - -#endif /* _NXT_WEBSOCKET_H_INCLUDED_ */ diff --git a/src/nxt_websocket_accept.c b/src/nxt_websocket_accept.c deleted file mode 100644 index 0e2cef58..00000000 --- a/src/nxt_websocket_accept.c +++ /dev/null @@ -1,68 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -static void -nxt_websocket_base64_encode(u_char *d, const uint8_t *s, size_t len) -{ - u_char c0, c1, c2; - static const u_char basis[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - while (len > 2) { - c0 = s[0]; - c1 = s[1]; - c2 = s[2]; - - *d++ = basis[c0 >> 2]; - *d++ = basis[((c0 & 0x03) << 4) | (c1 >> 4)]; - *d++ = basis[((c1 & 0x0f) << 2) | (c2 >> 6)]; - *d++ = basis[c2 & 0x3f]; - - s += 3; - len -= 3; - } - - if (len > 0) { - c0 = s[0]; - *d++ = basis[c0 >> 2]; - - if (len == 1) { - *d++ = basis[(c0 & 0x03) << 4]; - *d++ = '='; - *d++ = '='; - - } else { - c1 = s[1]; - - *d++ = basis[((c0 & 0x03) << 4) | (c1 >> 4)]; - *d++ = basis[(c1 & 0x0f) << 2]; - - *d++ = '='; - } - } -} - - -void -nxt_websocket_accept(u_char *accept, const void *key) -{ - u_char bin_accept[20]; - nxt_sha1_t ctx; - static const char accept_guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - - nxt_sha1_init(&ctx); - nxt_sha1_update(&ctx, key, 24); - nxt_sha1_update(&ctx, accept_guid, nxt_length(accept_guid)); - nxt_sha1_final(bin_accept, &ctx); - - nxt_websocket_base64_encode(accept, bin_accept, sizeof(bin_accept)); -} - - diff --git a/src/nxt_websocket_header.h b/src/nxt_websocket_header.h deleted file mode 100644 index cb7431dd..00000000 --- a/src/nxt_websocket_header.h +++ /dev/null @@ -1,68 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_WEBSOCKET_HEADER_H_INCLUDED_ -#define _NXT_WEBSOCKET_HEADER_H_INCLUDED_ - -#include - - -typedef struct { -#if (NXT_HAVE_BIG_ENDIAN) - uint8_t fin:1; - uint8_t rsv1:1; - uint8_t rsv2:1; - uint8_t rsv3:1; - uint8_t opcode:4; - - uint8_t mask:1; - uint8_t payload_len:7; -#endif - -#if (NXT_HAVE_LITTLE_ENDIAN) - uint8_t opcode:4; - uint8_t rsv3:1; - uint8_t rsv2:1; - uint8_t rsv1:1; - uint8_t fin:1; - - uint8_t payload_len:7; - uint8_t mask:1; -#endif - - uint8_t payload_len_[8]; -} nxt_websocket_header_t; - - -enum { - NXT_WEBSOCKET_OP_CONT = 0x00, - NXT_WEBSOCKET_OP_TEXT = 0x01, - NXT_WEBSOCKET_OP_BINARY = 0x02, - NXT_WEBSOCKET_OP_CLOSE = 0x08, - NXT_WEBSOCKET_OP_PING = 0x09, - NXT_WEBSOCKET_OP_PONG = 0x0A, - - NXT_WEBSOCKET_OP_CTRL = 0x08, -}; - - -enum { - NXT_WEBSOCKET_CR_NORMAL = 1000, - NXT_WEBSOCKET_CR_GOING_AWAY = 1001, - NXT_WEBSOCKET_CR_PROTOCOL_ERROR = 1002, - NXT_WEBSOCKET_CR_UNPROCESSABLE_INPUT = 1003, - NXT_WEBSOCKET_CR_RESERVED = 1004, - NXT_WEBSOCKET_CR_NOT_PROVIDED = 1005, - NXT_WEBSOCKET_CR_ABNORMAL = 1006, - NXT_WEBSOCKET_CR_INVALID_DATA = 1007, - NXT_WEBSOCKET_CR_POLICY_VIOLATION = 1008, - NXT_WEBSOCKET_CR_MESSAGE_TOO_BIG = 1009, - NXT_WEBSOCKET_CR_EXTENSION_REQUIRED = 1010, - NXT_WEBSOCKET_CR_INTERNAL_SERVER_ERROR = 1011, - NXT_WEBSOCKET_CR_TLS_HANDSHAKE_FAILED = 1015, -}; - - -#endif /* _NXT_WEBSOCKET_HEADER_H_INCLUDED_ */ diff --git a/src/nxt_work_queue.c b/src/nxt_work_queue.c deleted file mode 100644 index f38f700b..00000000 --- a/src/nxt_work_queue.c +++ /dev/null @@ -1,311 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -/* - * Available work items are crucial for overall engine operation, so - * the items are preallocated in two chunks: cache and spare chunks. - * By default each chunk preallocates 409 work items on two or four - * CPU pages depending on platform. If all items in a cache chunk are - * exhausted then a spare chunk becomes a cache chunk, and a new spare - * chunk is allocated. This two-step allocation mitigates low memory - * condition impact on work queue operation. However, if both chunks - * are exhausted then a thread will sleep in reliance on another thread - * frees some memory. However, this may lead to deadlock and probably - * a process should be aborted. This behaviour should be considered as - * abort on program stack exhaustion. - * - * The cache and spare chunks initially are also allocated in two steps: - * a spare chunk is allocated first, then it becomes the cache chunk and - * a new spare chunk is allocated again. - */ - -static void nxt_work_queue_allocate(nxt_work_queue_cache_t *cache); - - -/* It should be adjusted with the "work_queue_bucket_items" directive. */ -static nxt_uint_t nxt_work_queue_bucket_items = 409; - - -#if (NXT_DEBUG) - -nxt_inline void -nxt_work_queue_thread_assert(nxt_work_queue_t *wq) -{ - nxt_tid_t tid; - nxt_thread_t *thread; - - thread = nxt_thread(); - tid = nxt_thread_tid(thread); - - if (nxt_fast_path(wq->tid == tid)) { - return; - } - - if (nxt_slow_path(nxt_pid != wq->pid)) { - wq->pid = nxt_pid; - wq->tid = tid; - - return; - } - - nxt_log_alert(thread->log, "work queue locked by thread %PT", wq->tid); - nxt_abort(); -} - - -void nxt_work_queue_thread_adopt(nxt_work_queue_t *wq) -{ - nxt_thread_t *thread; - - thread = nxt_thread(); - - wq->pid = nxt_pid; - wq->tid = nxt_thread_tid(thread); -} - - -void -nxt_work_queue_name(nxt_work_queue_t *wq, const char *name) -{ - nxt_work_queue_thread_assert(wq); - - wq->name = name; -} - -#else - -#define nxt_work_queue_thread_assert(wq) - -#endif - - -void -nxt_work_queue_cache_create(nxt_work_queue_cache_t *cache, size_t chunk_size) -{ - nxt_memzero(cache, sizeof(nxt_work_queue_cache_t)); - - if (chunk_size == 0) { - chunk_size = nxt_work_queue_bucket_items; - } - - /* nxt_work_queue_chunk_t already has one work item. */ - cache->chunk_size = chunk_size - 1; - - while (cache->next == NULL) { - nxt_work_queue_allocate(cache); - } -} - - -void -nxt_work_queue_cache_destroy(nxt_work_queue_cache_t *cache) -{ - nxt_work_queue_chunk_t *chunk, *next; - - for (chunk = cache->chunk; chunk; chunk = next) { - next = chunk->next; - nxt_free(chunk); - } -} - - -static void -nxt_work_queue_allocate(nxt_work_queue_cache_t *cache) -{ - size_t size; - nxt_uint_t i, n; - nxt_work_t *work; - nxt_work_queue_chunk_t *chunk; - - n = cache->chunk_size; - size = sizeof(nxt_work_queue_chunk_t) + n * sizeof(nxt_work_t); - - chunk = nxt_malloc(size); - - if (nxt_fast_path(chunk != NULL)) { - - chunk->next = cache->chunk; - cache->chunk = chunk; - work = &chunk->work; - - for (i = 0; i < n; i++) { - work[i].next = &work[i + 1]; - } - - work[i].next = NULL; - work++; - - } else if (cache->spare != NULL) { - - work = NULL; - - } else { - return; - } - - cache->next = cache->spare; - cache->spare = work; -} - - -/* Add a work to a work queue tail. */ - -void -nxt_work_queue_add(nxt_work_queue_t *wq, nxt_work_handler_t handler, - nxt_task_t *task, void *obj, void *data) -{ - nxt_work_t *work; - - nxt_work_queue_thread_assert(wq); - - for ( ;; ) { - work = wq->cache->next; - - if (nxt_fast_path(work != NULL)) { - wq->cache->next = work->next; - work->next = NULL; - - work->handler = handler; - work->task = task; - work->obj = obj; - work->data = data; - - if (wq->tail != NULL) { - wq->tail->next = work; - - } else { - wq->head = work; - } - - wq->tail = work; - - return; - } - - nxt_work_queue_allocate(wq->cache); - } -} - - -nxt_work_handler_t -nxt_work_queue_pop(nxt_work_queue_t *wq, nxt_task_t **task, void **obj, - void **data) -{ - nxt_work_t *work; - - nxt_work_queue_thread_assert(wq); - - work = wq->head; - - wq->head = work->next; - - if (work->next == NULL) { - wq->tail = NULL; - } - - *task = work->task; - - *obj = work->obj; - nxt_prefetch(*obj); - - *data = work->data; - nxt_prefetch(*data); - - work->next = wq->cache->next; - wq->cache->next = work; - - return work->handler; -} - - -/* Add a work to a locked work queue tail. */ - -void -nxt_locked_work_queue_add(nxt_locked_work_queue_t *lwq, nxt_work_t *work) -{ - nxt_thread_spin_lock(&lwq->lock); - - if (lwq->tail != NULL) { - lwq->tail->next = work; - - } else { - lwq->head = work; - } - - lwq->tail = work; - - nxt_thread_spin_unlock(&lwq->lock); -} - - -/* Pop a work from a locked work queue head. */ - -nxt_work_handler_t -nxt_locked_work_queue_pop(nxt_locked_work_queue_t *lwq, nxt_task_t **task, - void **obj, void **data) -{ - nxt_work_t *work; - nxt_work_handler_t handler; - - handler = NULL; - - nxt_thread_spin_lock(&lwq->lock); - - work = lwq->head; - - if (work != NULL) { - *task = work->task; - - *obj = work->obj; - nxt_prefetch(*obj); - - *data = work->data; - nxt_prefetch(*data); - - lwq->head = work->next; - - if (work->next == NULL) { - lwq->tail = NULL; - } - - handler = work->handler; - } - - nxt_thread_spin_unlock(&lwq->lock); - - return handler; -} - - -/* Move all works from a locked work queue to a usual work queue. */ - -void -nxt_locked_work_queue_move(nxt_thread_t *thr, nxt_locked_work_queue_t *lwq, - nxt_work_queue_t *wq) -{ - nxt_work_t *work; - - nxt_thread_spin_lock(&lwq->lock); - - work = lwq->head; - - lwq->head = NULL; - lwq->tail = NULL; - - nxt_thread_spin_unlock(&lwq->lock); - - while (work != NULL) { - work->task->thread = thr; - - nxt_work_queue_add(wq, work->handler, work->task, - work->obj, work->data); - - work = work->next; - } -} diff --git a/src/nxt_work_queue.h b/src/nxt_work_queue.h deleted file mode 100644 index b6aa4d4c..00000000 --- a/src/nxt_work_queue.h +++ /dev/null @@ -1,127 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_WORK_QUEUE_H_INCLUDED_ -#define _NXT_WORK_QUEUE_H_INCLUDED_ - - -typedef struct nxt_work_s nxt_work_t; - -struct nxt_task_s { - nxt_thread_t *thread; - nxt_log_t *log; - uint32_t ident; - nxt_work_t *next_work; - - /* TODO: exception_handler, prev/next task, subtasks. */ -}; - - -#define nxt_task_next_ident() \ - ((uint32_t) nxt_atomic_fetch_add(&nxt_task_ident, 1) & 0x3FFFFFFF) - - -/* - * A work handler with just the obj and data arguments instead - * of pointer to a possibly large a work struct allows to call - * the handler not only via a work queue but also directly. - * The only obj argument is enough for the most cases except the - * source filters, so the data argument has been introduced and - * is used where appropriate. - */ -//typedef void (*nxt_work_handler_t)(nxt_task_t *task, void *obj, void *data); - - -struct nxt_work_s { - nxt_work_t *next; - nxt_work_handler_t handler; - nxt_task_t *task; - void *obj; - void *data; -}; - - -typedef struct nxt_work_queue_chunk_s nxt_work_queue_chunk_t; - -struct nxt_work_queue_chunk_s { - nxt_work_queue_chunk_t *next; - nxt_work_t work; -}; - - -typedef struct { - nxt_work_t *next; - nxt_work_t *spare; - nxt_work_queue_chunk_t *chunk; - size_t chunk_size; -} nxt_work_queue_cache_t; - - -typedef struct nxt_work_queue_s nxt_work_queue_t; - -struct nxt_work_queue_s { - nxt_work_t *head; - nxt_work_t *tail; - nxt_work_queue_cache_t *cache; -#if (NXT_DEBUG) - const char *name; - int32_t pid; - nxt_tid_t tid; -#endif -}; - - -typedef struct { - nxt_thread_spinlock_t lock; - nxt_work_t *head; - nxt_work_t *tail; - nxt_work_queue_cache_t cache; -} nxt_locked_work_queue_t; - - -NXT_EXPORT void nxt_work_queue_cache_create(nxt_work_queue_cache_t *cache, - size_t chunk_size); -NXT_EXPORT void nxt_work_queue_cache_destroy(nxt_work_queue_cache_t *cache); - -NXT_EXPORT void nxt_work_queue_add(nxt_work_queue_t *wq, - nxt_work_handler_t handler, nxt_task_t *task, void *obj, void *data); -NXT_EXPORT nxt_work_handler_t nxt_work_queue_pop(nxt_work_queue_t *wq, - nxt_task_t **task, void **obj, void **data); - - -#define nxt_work_set(_work, _handler, _task, _obj, _data) \ - do { \ - nxt_work_t *work = _work; \ - \ - work->handler = _handler; \ - work->task = _task; \ - work->obj = _obj; \ - work->data = _data; \ - } while (0) - -#if (NXT_DEBUG) - -NXT_EXPORT void nxt_work_queue_name(nxt_work_queue_t *wq, const char *name); -NXT_EXPORT void nxt_work_queue_thread_adopt(nxt_work_queue_t *wq); - -#else - -#define nxt_work_queue_name(_wq, _name) - -#define nxt_work_queue_thread_adopt(_wq) - -#endif - - -NXT_EXPORT void nxt_locked_work_queue_add(nxt_locked_work_queue_t *lwq, - nxt_work_t *work); -NXT_EXPORT nxt_work_handler_t nxt_locked_work_queue_pop( - nxt_locked_work_queue_t *lwq, nxt_task_t **task, void **obj, void **data); -NXT_EXPORT void nxt_locked_work_queue_move(nxt_thread_t *thr, - nxt_locked_work_queue_t *lwq, nxt_work_queue_t *wq); - - -#endif /* _NXT_WORK_QUEUE_H_INCLUDED_ */ diff --git a/src/perl/nxt_perl_psgi.c b/src/perl/nxt_perl_psgi.c deleted file mode 100644 index 807d1741..00000000 --- a/src/perl/nxt_perl_psgi.c +++ /dev/null @@ -1,1435 +0,0 @@ - -/* - * Copyright (C) Alexander Borisov - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -typedef struct { - PerlInterpreter *my_perl; - nxt_perl_psgi_io_arg_t arg_input; - nxt_perl_psgi_io_arg_t arg_error; - SV *app; - CV *cb; - nxt_unit_request_info_t *req; - pthread_t thread; - nxt_unit_ctx_t *ctx; -} nxt_perl_psgi_ctx_t; - - -static SSize_t nxt_perl_psgi_io_input_read(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length); -static SSize_t nxt_perl_psgi_io_input_write(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length); - -static SSize_t nxt_perl_psgi_io_error_read(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length); -static SSize_t nxt_perl_psgi_io_error_write(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length); - -/* -static void nxt_perl_psgi_xs_core_global_changes(PerlInterpreter *my_perl, - const char *core, const char *sub, XSUBADDR_t sub_addr); -*/ - -static void nxt_perl_psgi_xs_init(pTHX); - -static SV *nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl, - SV *env, SV *app, nxt_unit_request_info_t *req); -static SV *nxt_perl_psgi_call_method(PerlInterpreter *my_perl, SV *obj, - const char *method, nxt_unit_request_info_t *req); - -/* For currect load XS modules */ -EXTERN_C void boot_DynaLoader(pTHX_ CV *cv); - -static int nxt_perl_psgi_io_init(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, const char *mode, void *req); - -static int nxt_perl_psgi_ctx_init(const char *script, - nxt_perl_psgi_ctx_t *pctx); - -static SV *nxt_perl_psgi_env_create(PerlInterpreter *my_perl, - nxt_unit_request_info_t *req); -nxt_inline int nxt_perl_psgi_add_sptr(PerlInterpreter *my_perl, HV *hash_env, - const char *name, uint32_t name_len, nxt_unit_sptr_t *sptr, uint32_t len); -nxt_inline int nxt_perl_psgi_add_str(PerlInterpreter *my_perl, HV *hash_env, - const char *name, uint32_t name_len, const char *str, uint32_t len); -nxt_inline int nxt_perl_psgi_add_value(PerlInterpreter *my_perl, HV *hash_env, - const char *name, uint32_t name_len, void *value); - - -static char *nxt_perl_psgi_module_create(const char *script); - -static nxt_int_t nxt_perl_psgi_result_status(PerlInterpreter *my_perl, - SV *result); -static int nxt_perl_psgi_result_head(PerlInterpreter *my_perl, - SV *sv_head, nxt_unit_request_info_t *req, uint16_t status); -static int nxt_perl_psgi_result_body(PerlInterpreter *my_perl, - SV *result, nxt_unit_request_info_t *req); -static int nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl, - SV *sv_body, nxt_unit_request_info_t *req); -static int nxt_perl_psgi_result_body_fh(PerlInterpreter *my_perl, SV *sv_body, - nxt_unit_request_info_t *req); -static ssize_t nxt_perl_psgi_io_read(nxt_unit_read_info_t *read_info, void *dst, - size_t size); -static int nxt_perl_psgi_result_array(PerlInterpreter *my_perl, - SV *result, nxt_unit_request_info_t *req); -static void nxt_perl_psgi_result_cb(PerlInterpreter *my_perl, SV *result, - nxt_unit_request_info_t *req); - -static nxt_int_t nxt_perl_psgi_start(nxt_task_t *task, - nxt_process_data_t *data); -static void nxt_perl_psgi_request_handler(nxt_unit_request_info_t *req); -static int nxt_perl_psgi_ready_handler(nxt_unit_ctx_t *ctx); -static void *nxt_perl_psgi_thread_func(void *main_ctx); -static int nxt_perl_psgi_init_threads(nxt_perl_app_conf_t *c); -static void nxt_perl_psgi_join_threads(nxt_unit_ctx_t *ctx, - nxt_perl_app_conf_t *c); -static void nxt_perl_psgi_ctx_free(nxt_perl_psgi_ctx_t *pctx); - -static CV *nxt_perl_psgi_write; -static CV *nxt_perl_psgi_close; -static CV *nxt_perl_psgi_cb; -static pthread_attr_t *nxt_perl_psgi_thread_attr; -static nxt_perl_psgi_ctx_t *nxt_perl_psgi_ctxs; - -static uint32_t nxt_perl_psgi_compat[] = { - NXT_VERNUM, NXT_DEBUG, -}; - -NXT_EXPORT nxt_app_module_t nxt_app_module = { - sizeof(nxt_perl_psgi_compat), - nxt_perl_psgi_compat, - nxt_string("perl"), - PERL_VERSION_STRING, - NULL, - 0, - NULL, - nxt_perl_psgi_start, -}; - -const nxt_perl_psgi_io_tab_t nxt_perl_psgi_io_tab_input = { - .read = nxt_perl_psgi_io_input_read, - .write = nxt_perl_psgi_io_input_write, -}; - -const nxt_perl_psgi_io_tab_t nxt_perl_psgi_io_tab_error = { - .read = nxt_perl_psgi_io_error_read, - .write = nxt_perl_psgi_io_error_write, -}; - - -static SSize_t -nxt_perl_psgi_io_input_read(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length) -{ - return nxt_unit_request_read(arg->req, vbuf, length); -} - - -static SSize_t -nxt_perl_psgi_io_input_write(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length) -{ - return 0; -} - - -static SSize_t -nxt_perl_psgi_io_error_read(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length) -{ - return 0; -} - - -static SSize_t -nxt_perl_psgi_io_error_write(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length) -{ - nxt_unit_req_error(arg->req, "Perl: %s", (const char*) vbuf); - - return (SSize_t) length; -} - - -/* In the future it will be necessary to change some Perl functions. */ -/* -static void -nxt_perl_psgi_xs_core_global_changes(PerlInterpreter *my_perl, - const char *core, const char *sub, XSUBADDR_t sub_addr) -{ - GV *gv; - - gv = gv_fetchpv(core, TRUE, SVt_PVCV); - -#ifdef MUTABLE_CV - GvCV_set(gv, MUTABLE_CV(SvREFCNT_inc(get_cv(sub, TRUE)))); -#else - GvCV_set(gv, (CV *) (SvREFCNT_inc(get_cv(sub, TRUE)))); -#endif - GvIMPORTED_CV_on(gv); - - newXS(sub, sub_addr, __FILE__); -} -*/ - - -XS(XS_NGINX__Unit__PSGI_exit); -XS(XS_NGINX__Unit__PSGI_exit) -{ - I32 ax = POPMARK; - Perl_croak(aTHX_ (char *) NULL); - XSRETURN_EMPTY; -} - - -XS(XS_NGINX__Unit__Sandbox_write); -XS(XS_NGINX__Unit__Sandbox_write) -{ - int rc; - char *body; - size_t len; - nxt_perl_psgi_ctx_t *pctx; - - dXSARGS; - - if (nxt_slow_path(items != 2)) { - Perl_croak(aTHX_ "Wrong number of arguments. Need one string"); - - XSRETURN_EMPTY; - } - - body = SvPV(ST(1), len); - - pctx = CvXSUBANY(cv).any_ptr; - - rc = nxt_unit_response_write(pctx->req, body, len); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - Perl_croak(aTHX_ "Failed to write response body"); - - XSRETURN_EMPTY; - } - - XSRETURN_IV(len); -} - - -nxt_inline void -nxt_perl_psgi_cb_request_done(nxt_perl_psgi_ctx_t *pctx, int status) -{ - if (pctx->req != NULL) { - nxt_unit_request_done(pctx->req, status); - pctx->req = NULL; - } -} - - -XS(XS_NGINX__Unit__Sandbox_close); -XS(XS_NGINX__Unit__Sandbox_close) -{ - I32 ax; - - ax = POPMARK; - - nxt_perl_psgi_cb_request_done(CvXSUBANY(cv).any_ptr, NXT_UNIT_OK); - - XSRETURN_NO; -} - - -XS(XS_NGINX__Unit__Sandbox_cb); -XS(XS_NGINX__Unit__Sandbox_cb) -{ - SV *obj; - int rc; - long array_len; - nxt_perl_psgi_ctx_t *pctx; - - dXSARGS; - - if (nxt_slow_path(items != 1)) { - nxt_perl_psgi_cb_request_done(CvXSUBANY(cv).any_ptr, NXT_UNIT_ERROR); - - Perl_croak(aTHX_ "Wrong number of arguments"); - - XSRETURN_EMPTY; - } - - pctx = CvXSUBANY(cv).any_ptr; - - if (nxt_slow_path(SvOK(ST(0)) == 0 || SvROK(ST(0)) == 0 - || SvTYPE(SvRV(ST(0))) != SVt_PVAV - || pctx->req == NULL)) - { - nxt_perl_psgi_cb_request_done(CvXSUBANY(cv).any_ptr, NXT_UNIT_ERROR); - - Perl_croak(aTHX_ "PSGI: An unexpected response was received " - "from Perl Application"); - - XSRETURN_EMPTY; - } - - rc = nxt_perl_psgi_result_array(PERL_GET_CONTEXT, ST(0), pctx->req); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_perl_psgi_cb_request_done(CvXSUBANY(cv).any_ptr, NXT_UNIT_ERROR); - - Perl_croak(aTHX_ (char *) NULL); - - XSRETURN_EMPTY; - } - - array_len = av_len((AV *) SvRV(ST(0))); - - if (array_len < 2) { - obj = sv_bless(newRV_noinc((SV *) newHV()), - gv_stashpv("NGINX::Unit::Sandbox", GV_ADD)); - ST(0) = obj; - - XSRETURN(1); - } - - nxt_perl_psgi_cb_request_done(CvXSUBANY(cv).any_ptr, NXT_UNIT_OK); - - XSRETURN_EMPTY; -} - - -static void -nxt_perl_psgi_xs_init(pTHX) -{ -/* - nxt_perl_psgi_xs_core_global_changes(my_perl, "CORE::GLOBAL::exit", - "NGINX::Unit::PSGI::exit", - XS_NGINX__Unit__PSGI_exit); -*/ - nxt_perl_psgi_layer_stream_init(aTHX); - - /* DynaLoader for Perl modules who use XS */ - newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__); - - nxt_perl_psgi_write = newXS("NGINX::Unit::Sandbox::write", - XS_NGINX__Unit__Sandbox_write, __FILE__); - - nxt_perl_psgi_close = newXS("NGINX::Unit::Sandbox::close", - XS_NGINX__Unit__Sandbox_close, __FILE__); - - nxt_perl_psgi_cb = newXS("NGINX::Unit::Sandbox::cb", - XS_NGINX__Unit__Sandbox_cb, __FILE__); -} - - -static SV * -nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl, - SV *env, SV *app, nxt_unit_request_info_t *req) -{ - SV *result; - - dSP; - - ENTER; - SAVETMPS; - - PUSHMARK(sp); - XPUSHs(env); - PUTBACK; - - call_sv(app, G_EVAL|G_SCALAR); - - SPAGAIN; - - if (SvTRUE(ERRSV)) { - nxt_unit_req_error(req, "PSGI: Failed to run Perl Application: \n%s", - SvPV_nolen(ERRSV)); - } - - result = POPs; - SvREFCNT_inc(result); - - PUTBACK; - FREETMPS; - LEAVE; - - return result; -} - - -static SV * -nxt_perl_psgi_call_method(PerlInterpreter *my_perl, SV *obj, const char *method, - nxt_unit_request_info_t *req) -{ - SV *result; - - dSP; - - ENTER; - SAVETMPS; - - PUSHMARK(sp); - XPUSHs(obj); - PUTBACK; - - call_method(method, G_EVAL|G_SCALAR); - - SPAGAIN; - - if (SvTRUE(ERRSV)) { - nxt_unit_req_error(req, "PSGI: Failed to call method '%s':\n%s", - method, SvPV_nolen(ERRSV)); - result = NULL; - - } else { - result = SvREFCNT_inc(POPs); - } - - PUTBACK; - FREETMPS; - LEAVE; - - return result; -} - - -static char * -nxt_perl_psgi_module_create(const char *script) -{ - char *buf, *p; - size_t length; - - static nxt_str_t prefix = nxt_string( - "package NGINX::Unit::Sandbox;" - "sub new {" - " return bless {}, $_[0];" - "}" - "{my $app = do \"" - ); - - static nxt_str_t suffix = nxt_string_zero( - "\";" - "unless ($app) {" - " if($@ || $1) {die $@ || $1}" - " else {die \"File not found or compilation error.\"}" - "} " - "return $app}" - ); - - length = strlen(script); - - buf = nxt_unit_malloc(NULL, prefix.length + length + suffix.length); - if (nxt_slow_path(buf == NULL)) { - nxt_unit_alert(NULL, "PSGI: Failed to allocate memory " - "for Perl script file %s", script); - - return NULL; - } - - p = nxt_cpymem(buf, prefix.start, prefix.length); - p = nxt_cpymem(p, script, length); - nxt_memcpy(p, suffix.start, suffix.length); - - return buf; -} - - -static int -nxt_perl_psgi_io_init(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, const char *mode, void *req) -{ - SV *io; - PerlIO *fp; - - if (arg->io == NULL) { - fp = nxt_perl_psgi_layer_stream_fp_create(aTHX_ arg->rv, mode); - if (nxt_slow_path(fp == NULL)) { - return NXT_UNIT_ERROR; - } - - io = nxt_perl_psgi_layer_stream_io_create(aTHX_ fp); - if (nxt_slow_path(io == NULL)) { - nxt_perl_psgi_layer_stream_fp_destroy(aTHX_ fp); - return NXT_UNIT_ERROR; - } - - arg->io = io; - arg->fp = fp; - } - - arg->req = req; - - return NXT_UNIT_OK; -} - - -static void -nxt_perl_psgi_io_release(PerlInterpreter *my_perl, nxt_perl_psgi_io_arg_t *arg) -{ - if (arg->io != NULL) { - SvREFCNT_dec(arg->io); - arg->io = NULL; - } -} - - -static int -nxt_perl_psgi_ctx_init(const char *script, nxt_perl_psgi_ctx_t *pctx) -{ - int status, res; - char *run_module; - PerlInterpreter *my_perl; - - static char argv[] = "\0""-e\0""0"; - static char *embedding[] = { &argv[0], &argv[1], &argv[4] }; - - my_perl = perl_alloc(); - - if (nxt_slow_path(my_perl == NULL)) { - nxt_unit_alert(NULL, - "PSGI: Failed to allocate memory for Perl interpreter"); - - return NXT_UNIT_ERROR; - } - - pctx->my_perl = my_perl; - - run_module = NULL; - - perl_construct(my_perl); - PERL_SET_CONTEXT(my_perl); - - status = perl_parse(my_perl, nxt_perl_psgi_xs_init, 3, embedding, NULL); - - if (nxt_slow_path(status != 0)) { - nxt_unit_alert(NULL, "PSGI: Failed to parse Perl Script"); - goto fail; - } - - CvXSUBANY(nxt_perl_psgi_write).any_ptr = pctx; - CvXSUBANY(nxt_perl_psgi_close).any_ptr = pctx; - CvXSUBANY(nxt_perl_psgi_cb).any_ptr = pctx; - - pctx->cb = nxt_perl_psgi_cb; - - PL_exit_flags |= PERL_EXIT_DESTRUCT_END; - PL_origalen = 1; - - status = perl_run(my_perl); - - if (nxt_slow_path(status != 0)) { - nxt_unit_alert(NULL, "PSGI: Failed to run Perl"); - goto fail; - } - - sv_setsv(get_sv("0", 0), newSVpv(script, 0)); - - run_module = nxt_perl_psgi_module_create(script); - if (nxt_slow_path(run_module == NULL)) { - goto fail; - } - - pctx->arg_input.rv = newSV_type(SVt_RV); - sv_setptrref(pctx->arg_input.rv, &pctx->arg_input); - SvSETMAGIC(pctx->arg_input.rv); - - pctx->arg_input.io_tab = &nxt_perl_psgi_io_tab_input; - - res = nxt_perl_psgi_io_init(my_perl, &pctx->arg_input, "r", NULL); - if (nxt_slow_path(res != NXT_UNIT_OK)) { - nxt_unit_alert(NULL, "PSGI: Failed to init io.psgi.input"); - goto fail; - } - - pctx->arg_error.rv = newSV_type(SVt_RV); - sv_setptrref(pctx->arg_error.rv, &pctx->arg_error); - SvSETMAGIC(pctx->arg_error.rv); - - pctx->arg_error.io_tab = &nxt_perl_psgi_io_tab_error; - - res = nxt_perl_psgi_io_init(my_perl, &pctx->arg_error, "w", NULL); - if (nxt_slow_path(res != NXT_UNIT_OK)) { - nxt_unit_alert(NULL, "PSGI: Failed to init io.psgi.error"); - goto fail; - } - - pctx->app = eval_pv(run_module, FALSE); - - if (SvTRUE(ERRSV)) { - nxt_unit_alert(NULL, "PSGI: Failed to parse script: %s\n%s", - script, SvPV_nolen(ERRSV)); - goto fail; - } - - nxt_unit_free(NULL, run_module); - - return NXT_UNIT_OK; - -fail: - - nxt_perl_psgi_io_release(my_perl, &pctx->arg_input); - nxt_perl_psgi_io_release(my_perl, &pctx->arg_error); - - if (run_module != NULL) { - nxt_unit_free(NULL, run_module); - } - - perl_destruct(my_perl); - perl_free(my_perl); - - pctx->my_perl = NULL; - - return NXT_UNIT_ERROR; -} - - -static SV * -nxt_perl_psgi_env_create(PerlInterpreter *my_perl, - nxt_unit_request_info_t *req) -{ - HV *hash_env; - AV *array_version; - uint32_t i; - nxt_unit_field_t *f; - nxt_unit_request_t *r; - nxt_perl_psgi_ctx_t *pctx; - - pctx = req->ctx->data; - - hash_env = newHV(); - if (nxt_slow_path(hash_env == NULL)) { - return NULL; - } - -#define RC(FNS) \ - do { \ - if (nxt_slow_path((FNS) != NXT_UNIT_OK)) \ - goto fail; \ - } while (0) - -#define NL(S) (S), sizeof(S)-1 - - r = req->request; - - RC(nxt_perl_psgi_add_str(my_perl, hash_env, NL("SERVER_SOFTWARE"), - (char *) nxt_server.start, nxt_server.length)); - - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REQUEST_METHOD"), - &r->method, r->method_length)); - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REQUEST_URI"), - &r->target, r->target_length)); - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("PATH_INFO"), - &r->path, r->path_length)); - - array_version = newAV(); - - if (nxt_slow_path(array_version == NULL)) { - goto fail; - } - - av_push(array_version, newSViv(1)); - av_push(array_version, newSViv(1)); - - RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.version"), - newRV_noinc((SV *) array_version))); - - RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.url_scheme"), - r->tls ? newSVpv("https", 5) - : newSVpv("http", 4))); - - RC(nxt_perl_psgi_io_init(my_perl, &pctx->arg_input, "r", req)); - RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.input"), - SvREFCNT_inc(pctx->arg_input.io))); - - RC(nxt_perl_psgi_io_init(my_perl, &pctx->arg_error, "w", req)); - RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.errors"), - SvREFCNT_inc(pctx->arg_error.io))); - - RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.multithread"), - nxt_perl_psgi_ctxs != NULL - ? &PL_sv_yes : &PL_sv_no)); - RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.multiprocess"), - &PL_sv_yes)); - RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.run_once"), - &PL_sv_no)); - RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.nonblocking"), - &PL_sv_no)); - RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.streaming"), - &PL_sv_yes)); - - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("QUERY_STRING"), - &r->query, r->query_length)); - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_PROTOCOL"), - &r->version, r->version_length)); - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REMOTE_ADDR"), - &r->remote, r->remote_length)); - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_ADDR"), - &r->local_addr, r->local_addr_length)); - - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_NAME"), - &r->server_name, r->server_name_length)); - RC(nxt_perl_psgi_add_str(my_perl, hash_env, NL("SERVER_PORT"), "80", 2)); - - for (i = 0; i < r->fields_count; i++) { - f = r->fields + i; - - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, - nxt_unit_sptr_get(&f->name), f->name_length, - &f->value, f->value_length)); - } - - if (r->content_length_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->content_length_field; - - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("CONTENT_LENGTH"), - &f->value, f->value_length)); - } - - if (r->content_type_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->content_type_field; - - RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("CONTENT_TYPE"), - &f->value, f->value_length)); - } - -#undef NL -#undef RC - - return newRV_noinc((SV *) hash_env); - -fail: - - SvREFCNT_dec(hash_env); - - return NULL; -} - - -nxt_inline int -nxt_perl_psgi_add_sptr(PerlInterpreter *my_perl, HV *hash_env, - const char *name, uint32_t name_len, nxt_unit_sptr_t *sptr, uint32_t len) -{ - return nxt_perl_psgi_add_str(my_perl, hash_env, name, name_len, - nxt_unit_sptr_get(sptr), len); -} - - -nxt_inline int -nxt_perl_psgi_add_str(PerlInterpreter *my_perl, HV *hash_env, - const char *name, uint32_t name_len, const char *str, uint32_t len) -{ - SV **ha; - - ha = hv_store(hash_env, name, (I32) name_len, - newSVpv(str, (STRLEN) len), 0); - if (nxt_slow_path(ha == NULL)) { - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -nxt_inline int -nxt_perl_psgi_add_value(PerlInterpreter *my_perl, HV *hash_env, - const char *name, uint32_t name_len, void *value) -{ - SV **ha; - - ha = hv_store(hash_env, name, (I32) name_len, value, 0); - if (nxt_slow_path(ha == NULL)) { - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static nxt_int_t -nxt_perl_psgi_result_status(PerlInterpreter *my_perl, SV *result) -{ - SV **sv_status; - AV *array; - u_char *space; - nxt_str_t status; - - array = (AV *) SvRV(result); - sv_status = av_fetch(array, 0, 0); - - status.start = (u_char *) SvPV(*sv_status, status.length); - - space = memchr(status.start, ' ', status.length); - if (space != NULL) { - status.length = space - status.start; - } - - return nxt_int_parse(status.start, status.length); -} - - -static int -nxt_perl_psgi_result_head(PerlInterpreter *my_perl, SV *sv_head, - nxt_unit_request_info_t *req, uint16_t status) -{ - AV *array_head; - SV **entry; - int rc; - long i, array_len; - char *name, *value; - STRLEN name_len, value_len; - uint32_t fields, size; - - if (nxt_slow_path(SvROK(sv_head) == 0 - || SvTYPE(SvRV(sv_head)) != SVt_PVAV)) - { - nxt_unit_req_error(req, - "PSGI: An unsupported format was received from " - "Perl Application for head part"); - - return NXT_UNIT_ERROR; - } - - array_head = (AV *) SvRV(sv_head); - array_len = av_len(array_head); - - if (array_len < 1) { - return nxt_unit_response_init(req, status, 0, 0); - } - - if (nxt_slow_path((array_len % 2) == 0)) { - nxt_unit_req_error(req, "PSGI: Bad format for head from " - "Perl Application"); - - return NXT_UNIT_ERROR; - } - - fields = 0; - size = 0; - - for (i = 0; i <= array_len; i++) { - entry = av_fetch(array_head, i, 0); - - if (nxt_fast_path(entry == NULL)) { - nxt_unit_req_error(req, "PSGI: Failed to get head entry from " - "Perl Application"); - - return NXT_UNIT_ERROR; - } - - value = SvPV(*entry, value_len); - size += value_len; - - if ((i % 2) == 0) { - fields++; - } - } - - rc = nxt_unit_response_init(req, status, fields, size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - for (i = 0; i <= array_len; i += 2) { - entry = av_fetch(array_head, i, 0); - name = SvPV(*entry, name_len); - - entry = av_fetch(array_head, i + 1, 0); - value = SvPV(*entry, value_len); - - rc = nxt_unit_response_add_field(req, name, name_len, value, value_len); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - } - - return NXT_UNIT_OK; -} - - -static int -nxt_perl_psgi_result_body(PerlInterpreter *my_perl, SV *sv_body, - nxt_unit_request_info_t *req) -{ - SV **entry; - AV *body_array; - int rc; - long i; - nxt_str_t body; - - if (nxt_slow_path(SvROK(sv_body) == 0 - || SvTYPE(SvRV(sv_body)) != SVt_PVAV)) - { - nxt_unit_req_error(req, "PSGI: An unsupported format was received from " - "Perl Application for a body part"); - - return NXT_UNIT_ERROR; - } - - body_array = (AV *) SvRV(sv_body); - - for (i = 0; i <= av_len(body_array); i++) { - - entry = av_fetch(body_array, i, 0); - - if (nxt_fast_path(entry == NULL)) { - nxt_unit_req_error(req, "PSGI: Failed to get body entry from " - "Perl Application"); - - return NXT_UNIT_ERROR; - } - - body.start = (u_char *) SvPV(*entry, body.length); - - if (body.length == 0) { - continue; - } - - rc = nxt_unit_response_write(req, body.start, body.length); - - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_req_error(req, "PSGI: Failed to write content from " - "Perl Application"); - return rc; - } - } - - return NXT_UNIT_OK; -} - - -static int -nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl, SV *sv_body, - nxt_unit_request_info_t *req) -{ - SV *data, *old_rs, *old_perl_rs; - int rc; - size_t len; - const char *body; - - /* - * Servers should set the $/ special variable to the buffer size - * when reading content from $body using the getline method. - * This is done by setting $/ with a reference to an integer ($/ = \8192). - */ - - old_rs = PL_rs; - old_perl_rs = get_sv("/", GV_ADD); - - PL_rs = sv_2mortal(newRV_noinc(newSViv(nxt_unit_buf_min()))); - - sv_setsv(old_perl_rs, PL_rs); - - rc = NXT_UNIT_OK; - - for ( ;; ) { - data = nxt_perl_psgi_call_method(my_perl, sv_body, "getline", req); - if (nxt_slow_path(data == NULL)) { - rc = NXT_UNIT_ERROR; - break; - } - - body = SvPV(data, len); - - if (len == 0) { - SvREFCNT_dec(data); - - data = nxt_perl_psgi_call_method(my_perl, sv_body, "close", req); - if (nxt_fast_path(data != NULL)) { - SvREFCNT_dec(data); - } - - break; - } - - rc = nxt_unit_response_write(req, body, len); - - SvREFCNT_dec(data); - - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_req_error(req, "PSGI: Failed to write content from " - "Perl Application"); - break; - } - }; - - PL_rs = old_rs; - sv_setsv(get_sv("/", GV_ADD), old_perl_rs); - - return rc; -} - - -typedef struct { - PerlInterpreter *my_perl; - PerlIO *fp; -} nxt_perl_psgi_io_ctx_t; - - -static int -nxt_perl_psgi_result_body_fh(PerlInterpreter *my_perl, SV *sv_body, - nxt_unit_request_info_t *req) -{ - IO *io; - nxt_unit_read_info_t read_info; - nxt_perl_psgi_io_ctx_t io_ctx; - - io = GvIO(SvRV(sv_body)); - - if (io == NULL) { - return NXT_UNIT_OK; - } - - io_ctx.my_perl = my_perl; - io_ctx.fp = IoIFP(io); - - read_info.read = nxt_perl_psgi_io_read; - read_info.eof = PerlIO_eof(io_ctx.fp); - read_info.buf_size = 8192; - read_info.data = &io_ctx; - - return nxt_unit_response_write_cb(req, &read_info); -} - - -static ssize_t -nxt_perl_psgi_io_read(nxt_unit_read_info_t *read_info, void *dst, size_t size) -{ - ssize_t res; - nxt_perl_psgi_io_ctx_t *ctx; - - ctx = read_info->data; - - dTHXa(ctx->my_perl); - - res = PerlIO_read(ctx->fp, dst, size); - - read_info->eof = PerlIO_eof(ctx->fp); - - return res; -} - - -static int -nxt_perl_psgi_result_array(PerlInterpreter *my_perl, SV *result, - nxt_unit_request_info_t *req) -{ - AV *array; - SV **sv_temp; - int rc; - long array_len; - nxt_int_t status; - - array = (AV *) SvRV(result); - array_len = av_len(array); - - if (nxt_slow_path(array_len < 0)) { - nxt_unit_req_error(req, - "PSGI: Invalid result format from Perl Application"); - - return NXT_UNIT_ERROR; - } - - status = nxt_perl_psgi_result_status(my_perl, result); - - if (nxt_slow_path(status < 0)) { - nxt_unit_req_error(req, - "PSGI: An unexpected status was received " - "from Perl Application"); - - return NXT_UNIT_ERROR; - } - - if (array_len >= 1) { - sv_temp = av_fetch(array, 1, 0); - - if (nxt_slow_path(sv_temp == NULL)) { - nxt_unit_req_error(req, "PSGI: Failed to get head from " - "Perl ARRAY variable"); - - return NXT_UNIT_ERROR; - } - - rc = nxt_perl_psgi_result_head(my_perl, *sv_temp, req, status); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - } else { - return nxt_unit_response_init(req, status, 0, 0); - } - - if (nxt_fast_path(array_len < 2)) { - return NXT_UNIT_OK; - } - - sv_temp = av_fetch(array, 2, 0); - - if (nxt_slow_path(sv_temp == NULL || SvROK(*sv_temp) == FALSE)) { - nxt_unit_req_error(req, - "PSGI: Failed to get body from " - "Perl ARRAY variable"); - - return NXT_UNIT_ERROR; - } - - if (SvTYPE(SvRV(*sv_temp)) == SVt_PVAV) { - return nxt_perl_psgi_result_body(my_perl, *sv_temp, req); - } - - if (SvTYPE(SvRV(*sv_temp)) == SVt_PVGV) { - return nxt_perl_psgi_result_body_fh(my_perl, *sv_temp, req); - } - - return nxt_perl_psgi_result_body_ref(my_perl, *sv_temp, req); -} - - -static void -nxt_perl_psgi_result_cb(PerlInterpreter *my_perl, SV *result, - nxt_unit_request_info_t *req) -{ - nxt_perl_psgi_ctx_t *pctx; - - dSP; - - pctx = req->ctx->data; - - ENTER; - SAVETMPS; - - PUSHMARK(sp); - XPUSHs(newRV_noinc((SV*) pctx->cb)); - PUTBACK; - - call_sv(result, G_EVAL|G_SCALAR); - - SPAGAIN; - - if (SvTRUE(ERRSV)) { - nxt_unit_error(NULL, "PSGI: Failed to execute result callback: \n%s", - SvPV_nolen(ERRSV)); - - nxt_perl_psgi_cb_request_done(pctx, NXT_UNIT_ERROR); - } - - PUTBACK; - FREETMPS; - LEAVE; -} - - -static nxt_int_t -nxt_perl_psgi_start(nxt_task_t *task, nxt_process_data_t *data) -{ - int rc, pargc; - char **pargv, **penv; - nxt_unit_ctx_t *unit_ctx; - nxt_unit_init_t perl_init; - nxt_perl_psgi_ctx_t pctx; - nxt_perl_app_conf_t *c; - nxt_common_app_conf_t *common_conf; - - common_conf = data->app; - c = &common_conf->u.perl; - - pargc = 0; - pargv = NULL; - penv = NULL; - - PERL_SYS_INIT3(&pargc, &pargv, &penv); - - memset(&pctx, 0, sizeof(nxt_perl_psgi_ctx_t)); - - rc = nxt_perl_psgi_ctx_init(c->script, &pctx); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - rc = nxt_perl_psgi_init_threads(c); - - PERL_SET_CONTEXT(pctx.my_perl); - - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - nxt_unit_default_init(task, &perl_init, common_conf); - - perl_init.callbacks.request_handler = nxt_perl_psgi_request_handler; - perl_init.callbacks.ready_handler = nxt_perl_psgi_ready_handler; - perl_init.data = c; - perl_init.ctx_data = &pctx; - - unit_ctx = nxt_unit_init(&perl_init); - if (nxt_slow_path(unit_ctx == NULL)) { - goto fail; - } - - rc = nxt_unit_run(unit_ctx); - - nxt_perl_psgi_join_threads(unit_ctx, c); - - nxt_unit_done(unit_ctx); - - nxt_perl_psgi_ctx_free(&pctx); - - PERL_SYS_TERM(); - - exit(rc); - - return NXT_OK; - -fail: - - nxt_perl_psgi_join_threads(NULL, c); - - nxt_perl_psgi_ctx_free(&pctx); - - PERL_SYS_TERM(); - - return NXT_ERROR; -} - - -static void -nxt_perl_psgi_request_handler(nxt_unit_request_info_t *req) -{ - SV *env, *result; - nxt_int_t rc; - PerlInterpreter *my_perl; - nxt_perl_psgi_ctx_t *pctx; - - pctx = req->ctx->data; - my_perl = pctx->my_perl; - - pctx->req = req; - - /* - * Create environ variable for perl sub "application". - * > sub application { - * > my ($environ) = @_; - */ - env = nxt_perl_psgi_env_create(my_perl, req); - if (nxt_slow_path(env == NULL)) { - nxt_unit_req_error(req, - "PSGI: Failed to create 'env' for Perl Application"); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - pctx->req = NULL; - - return; - } - - /* Call perl sub and get result as SV*. */ - result = nxt_perl_psgi_call_var_application(my_perl, env, pctx->app, - req); - - if (nxt_fast_path(SvOK(result) != 0 && SvROK(result) != 0)) { - - if (SvTYPE(SvRV(result)) == SVt_PVAV) { - rc = nxt_perl_psgi_result_array(my_perl, result, req); - nxt_unit_request_done(req, rc); - pctx->req = NULL; - - goto release; - } - - if (SvTYPE(SvRV(result)) == SVt_PVCV) { - nxt_perl_psgi_result_cb(my_perl, result, req); - goto release; - } - } - - nxt_unit_req_error(req, "PSGI: An unexpected response was received " - "from Perl Application"); - - nxt_unit_request_done(req, NXT_UNIT_ERROR); - pctx->req = NULL; - -release: - - SvREFCNT_dec(result); - SvREFCNT_dec(env); -} - - -static int -nxt_perl_psgi_ready_handler(nxt_unit_ctx_t *ctx) -{ - int res; - uint32_t i; - nxt_perl_app_conf_t *c; - nxt_perl_psgi_ctx_t *pctx; - - c = ctx->unit->data; - - if (c->threads <= 1) { - return NXT_UNIT_OK; - } - - for (i = 0; i < c->threads - 1; i++) { - pctx = &nxt_perl_psgi_ctxs[i]; - - pctx->ctx = ctx; - - res = pthread_create(&pctx->thread, nxt_perl_psgi_thread_attr, - nxt_perl_psgi_thread_func, pctx); - - if (nxt_fast_path(res == 0)) { - nxt_unit_debug(ctx, "thread #%d created", (int) (i + 1)); - - } else { - nxt_unit_alert(ctx, "thread #%d create failed: %s (%d)", - (int) (i + 1), strerror(res), res); - - return NXT_UNIT_ERROR; - } - } - - return NXT_UNIT_OK; -} - - -static void * -nxt_perl_psgi_thread_func(void *data) -{ - nxt_unit_ctx_t *ctx; - nxt_perl_psgi_ctx_t *pctx; - - pctx = data; - - nxt_unit_debug(pctx->ctx, "worker thread start"); - - ctx = nxt_unit_ctx_alloc(pctx->ctx, pctx); - if (nxt_slow_path(ctx == NULL)) { - return NULL; - } - - pctx->ctx = ctx; - - PERL_SET_CONTEXT(pctx->my_perl); - - (void) nxt_unit_run(ctx); - - nxt_unit_done(ctx); - - nxt_unit_debug(NULL, "worker thread end"); - - return NULL; -} - - -static int -nxt_perl_psgi_init_threads(nxt_perl_app_conf_t *c) -{ - int rc; - uint32_t i; - static pthread_attr_t attr; - - if (c->threads <= 1) { - return NXT_UNIT_OK; - } - - if (c->thread_stack_size > 0) { - rc = pthread_attr_init(&attr); - if (nxt_slow_path(rc != 0)) { - nxt_unit_alert(NULL, "thread attr init failed: %s (%d)", - strerror(rc), rc); - - return NXT_UNIT_ERROR; - } - - rc = pthread_attr_setstacksize(&attr, c->thread_stack_size); - if (nxt_slow_path(rc != 0)) { - nxt_unit_alert(NULL, "thread attr set stack size failed: %s (%d)", - strerror(rc), rc); - - return NXT_UNIT_ERROR; - } - - nxt_perl_psgi_thread_attr = &attr; - } - - nxt_perl_psgi_ctxs = nxt_unit_malloc(NULL, sizeof(nxt_perl_psgi_ctx_t) - * (c->threads - 1)); - if (nxt_slow_path(nxt_perl_psgi_ctxs == NULL)) { - return NXT_UNIT_ERROR; - } - - memset(nxt_perl_psgi_ctxs, 0, sizeof(nxt_perl_psgi_ctx_t) - * (c->threads - 1)); - - for (i = 0; i < c->threads - 1; i++) { - rc = nxt_perl_psgi_ctx_init(c->script, &nxt_perl_psgi_ctxs[i]); - - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return NXT_UNIT_ERROR; - } - } - - return NXT_UNIT_OK; -} - - -static void -nxt_perl_psgi_join_threads(nxt_unit_ctx_t *ctx, nxt_perl_app_conf_t *c) -{ - int res; - uint32_t i; - nxt_perl_psgi_ctx_t *pctx; - - if (nxt_perl_psgi_ctxs == NULL) { - return; - } - - for (i = 0; i < c->threads - 1; i++) { - pctx = &nxt_perl_psgi_ctxs[i]; - - res = pthread_join(pctx->thread, NULL); - - if (nxt_fast_path(res == 0)) { - nxt_unit_debug(ctx, "thread #%d joined", (int) (i + 1)); - - } else { - nxt_unit_alert(ctx, "thread #%d join failed: %s (%d)", - (int) (i + 1), strerror(res), res); - } - } - - for (i = 0; i < c->threads - 1; i++) { - nxt_perl_psgi_ctx_free(&nxt_perl_psgi_ctxs[i]); - } - - nxt_unit_free(NULL, nxt_perl_psgi_ctxs); -} - - -static void -nxt_perl_psgi_ctx_free(nxt_perl_psgi_ctx_t *pctx) -{ - PerlInterpreter *my_perl; - - my_perl = pctx->my_perl; - - if (nxt_slow_path(my_perl == NULL)) { - return; - } - - PERL_SET_CONTEXT(my_perl); - - SvREFCNT_dec(pctx->arg_input.rv); - SvREFCNT_dec(pctx->arg_error.rv); - - nxt_perl_psgi_io_release(my_perl, &pctx->arg_input); - nxt_perl_psgi_io_release(my_perl, &pctx->arg_error); - - perl_destruct(my_perl); - perl_free(my_perl); -} diff --git a/src/perl/nxt_perl_psgi_layer.c b/src/perl/nxt_perl_psgi_layer.c deleted file mode 100644 index 303e5f27..00000000 --- a/src/perl/nxt_perl_psgi_layer.c +++ /dev/null @@ -1,382 +0,0 @@ - -/* - * Copyright (C) Alexander Borisov - * Copyright (C) NGINX, Inc. - */ - -#include - - -typedef struct { - struct _PerlIO base; - - SV *var; -} nxt_perl_psgi_layer_stream_t; - - -static IV nxt_perl_psgi_layer_stream_pushed(pTHX_ PerlIO *f, const char *mode, - SV *arg, PerlIO_funcs *tab); -static IV nxt_perl_psgi_layer_stream_popped(pTHX_ PerlIO *f); - -static PerlIO *nxt_perl_psgi_layer_stream_open(pTHX_ PerlIO_funcs *self, - PerlIO_list_t *layers, IV n, - const char *mode, int fd, int imode, int perm, - PerlIO *f, int narg, SV **args); - -static IV nxt_perl_psgi_layer_stream_close(pTHX_ PerlIO *f); - -static SSize_t nxt_perl_psgi_layer_stream_read(pTHX_ PerlIO *f, - void *vbuf, Size_t count); -static SSize_t nxt_perl_psgi_layer_stream_write(pTHX_ PerlIO *f, - const void *vbuf, Size_t count); - -static IV nxt_perl_psgi_layer_stream_fileno(pTHX_ PerlIO *f); -static IV nxt_perl_psgi_layer_stream_seek(pTHX_ PerlIO *f, - Off_t offset, int whence); -static Off_t nxt_perl_psgi_layer_stream_tell(pTHX_ PerlIO *f); -static IV nxt_perl_psgi_layer_stream_fill(pTHX_ PerlIO *f); -static IV nxt_perl_psgi_layer_stream_flush(pTHX_ PerlIO *f); - -static SV *nxt_perl_psgi_layer_stream_arg(pTHX_ PerlIO *f, - CLONE_PARAMS *param, int flags); - -static PerlIO *nxt_perl_psgi_layer_stream_dup(pTHX_ PerlIO *f, PerlIO *o, - CLONE_PARAMS *param, int flags); -static IV nxt_perl_psgi_layer_stream_eof(pTHX_ PerlIO *f); - -static STDCHAR *nxt_perl_psgi_layer_stream_get_base(pTHX_ PerlIO *f); -static STDCHAR *nxt_perl_psgi_layer_stream_get_ptr(pTHX_ PerlIO *f); -static SSize_t nxt_perl_psgi_layer_stream_get_cnt(pTHX_ PerlIO *f); -static Size_t nxt_perl_psgi_layer_stream_buffersize(pTHX_ PerlIO *f); -static void nxt_perl_psgi_layer_stream_set_ptrcnt(pTHX_ PerlIO *f, - STDCHAR *ptr, SSize_t cnt); - - -static PERLIO_FUNCS_DECL(PerlIO_NGINX_Unit) = { - sizeof(PerlIO_funcs), - "NGINX_Unit_PSGI_Layer_Stream", - sizeof(nxt_perl_psgi_layer_stream_t), - PERLIO_K_BUFFERED | PERLIO_K_RAW, - nxt_perl_psgi_layer_stream_pushed, - nxt_perl_psgi_layer_stream_popped, - nxt_perl_psgi_layer_stream_open, - PerlIOBase_binmode, - nxt_perl_psgi_layer_stream_arg, - nxt_perl_psgi_layer_stream_fileno, - nxt_perl_psgi_layer_stream_dup, - nxt_perl_psgi_layer_stream_read, - NULL, - nxt_perl_psgi_layer_stream_write, - nxt_perl_psgi_layer_stream_seek, - nxt_perl_psgi_layer_stream_tell, - nxt_perl_psgi_layer_stream_close, - nxt_perl_psgi_layer_stream_flush, - nxt_perl_psgi_layer_stream_fill, - nxt_perl_psgi_layer_stream_eof, - PerlIOBase_error, - PerlIOBase_clearerr, - PerlIOBase_setlinebuf, - nxt_perl_psgi_layer_stream_get_base, - nxt_perl_psgi_layer_stream_buffersize, - nxt_perl_psgi_layer_stream_get_ptr, - nxt_perl_psgi_layer_stream_get_cnt, - nxt_perl_psgi_layer_stream_set_ptrcnt, -}; - - -static IV -nxt_perl_psgi_layer_stream_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, - PerlIO_funcs *tab) -{ - nxt_perl_psgi_layer_stream_t *unit_stream; - - unit_stream = PerlIOSelf(f, nxt_perl_psgi_layer_stream_t); - - if (arg != NULL && SvOK(arg)) { - unit_stream->var = SvREFCNT_inc(arg); - } - - return PerlIOBase_pushed(aTHX_ f, mode, Nullsv, tab); -} - - -static IV -nxt_perl_psgi_layer_stream_popped(pTHX_ PerlIO *f) -{ - nxt_perl_psgi_io_arg_t *arg; - nxt_perl_psgi_layer_stream_t *unit_stream; - - unit_stream = PerlIOSelf(f, nxt_perl_psgi_layer_stream_t); - - if (unit_stream->var != NULL) { - arg = (void *) (intptr_t) SvIV(SvRV(unit_stream->var)); - - arg->io = NULL; - arg->fp = NULL; - - SvREFCNT_dec(unit_stream->var); - unit_stream->var = Nullsv; - } - - return 0; -} - - -static PerlIO * -nxt_perl_psgi_layer_stream_open(pTHX_ PerlIO_funcs *self, - PerlIO_list_t *layers, IV n, - const char *mode, int fd, int imode, int perm, - PerlIO *f, int narg, SV **args) -{ - SV *arg; - - arg = (narg > 0) ? *args : PerlIOArg; - - PERL_UNUSED_ARG(fd); - PERL_UNUSED_ARG(imode); - PERL_UNUSED_ARG(perm); - - if (SvROK(arg) || SvPOK(arg)) { - - if (f == NULL) { - f = PerlIO_allocate(aTHX); - } - - f = PerlIO_push(aTHX_ f, self, mode, arg); - - if (f != NULL) { - PerlIOBase(f)->flags |= PERLIO_F_OPEN; - } - - return f; - } - - return NULL; -} - - -static IV -nxt_perl_psgi_layer_stream_close(pTHX_ PerlIO *f) -{ - IV code; - - code = PerlIOBase_close(aTHX_ f); - PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF); - - return code; -} - - -static IV -nxt_perl_psgi_layer_stream_fileno(pTHX_ PerlIO *f) -{ - PERL_UNUSED_ARG(f); - return -1; -} - - -static SSize_t -nxt_perl_psgi_layer_stream_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) -{ - nxt_perl_psgi_io_arg_t *arg; - nxt_perl_psgi_layer_stream_t *unit_stream; - - if (f == NULL) { - return 0; - } - - if ((PerlIOBase(f)->flags & PERLIO_F_CANREAD) == 0) { - PerlIOBase(f)->flags |= PERLIO_F_ERROR; - - SETERRNO(EBADF, SS_IVCHAN); - - return 0; - } - - unit_stream = PerlIOSelf(f, nxt_perl_psgi_layer_stream_t); - arg = (void *) (intptr_t) SvIV(SvRV(unit_stream->var)); - - return arg->io_tab->read(PERL_GET_CONTEXT, arg, vbuf, count); -} - - -static SSize_t -nxt_perl_psgi_layer_stream_write(pTHX_ PerlIO *f, - const void *vbuf, Size_t count) -{ - nxt_perl_psgi_io_arg_t *arg; - nxt_perl_psgi_layer_stream_t *unit_stream; - - if (PerlIOBase(f)->flags & PERLIO_F_CANWRITE) { - unit_stream = PerlIOSelf(f, nxt_perl_psgi_layer_stream_t); - arg = (void *) (intptr_t) SvIV(SvRV(unit_stream->var)); - - return arg->io_tab->write(PERL_GET_CONTEXT, arg, vbuf, count); - } - - return 0; -} - - -static IV -nxt_perl_psgi_layer_stream_seek(pTHX_ PerlIO *f, Off_t offset, int whence) -{ - PERL_UNUSED_ARG(f); - return 0; -} - - -static Off_t -nxt_perl_psgi_layer_stream_tell(pTHX_ PerlIO *f) -{ - PERL_UNUSED_ARG(f); - return 0; -} - - -static IV -nxt_perl_psgi_layer_stream_fill(pTHX_ PerlIO *f) -{ - PERL_UNUSED_ARG(f); - return -1; -} - - -static IV -nxt_perl_psgi_layer_stream_flush(pTHX_ PerlIO *f) -{ - return 0; -} - - -static SV * -nxt_perl_psgi_layer_stream_arg(pTHX_ PerlIO * f, - CLONE_PARAMS *param, int flags) -{ - SV *var; - nxt_perl_psgi_layer_stream_t *unit_stream; - - unit_stream = PerlIOSelf(f, nxt_perl_psgi_layer_stream_t); - var = unit_stream->var; - - if (flags & PERLIO_DUP_CLONE) { - var = PerlIO_sv_dup(aTHX_ var, param); - - } else if (flags & PERLIO_DUP_FD) { - var = newSVsv(var); - - } else { - var = SvREFCNT_inc(var); - } - - return var; -} - - -static PerlIO * -nxt_perl_psgi_layer_stream_dup(pTHX_ PerlIO *f, PerlIO *o, - CLONE_PARAMS *param, int flags) -{ - nxt_perl_psgi_layer_stream_t *fs; - - f = PerlIOBase_dup(aTHX_ f, o, param, flags); - - if (f != NULL) { - fs = PerlIOSelf(f, nxt_perl_psgi_layer_stream_t); - fs->var = nxt_perl_psgi_layer_stream_arg(aTHX_ o, param, flags); - } - - return f; -} - - -static IV -nxt_perl_psgi_layer_stream_eof(pTHX_ PerlIO *f) -{ - return 1; -} - - -static STDCHAR * -nxt_perl_psgi_layer_stream_get_base(pTHX_ PerlIO *f) -{ - return (STDCHAR *) NULL; -} - - -static STDCHAR * -nxt_perl_psgi_layer_stream_get_ptr(pTHX_ PerlIO *f) -{ - return (STDCHAR *) NULL; -} - - -static SSize_t -nxt_perl_psgi_layer_stream_get_cnt(pTHX_ PerlIO *f) -{ - return 0; -} - - -static Size_t -nxt_perl_psgi_layer_stream_buffersize(pTHX_ PerlIO *f) -{ - return 0; -} - - -static void -nxt_perl_psgi_layer_stream_set_ptrcnt(pTHX_ PerlIO *f, - STDCHAR *ptr, SSize_t cnt) -{ - /* Need some code. */ -} - - -void -nxt_perl_psgi_layer_stream_init(pTHX) -{ - PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_NGINX_Unit)); -} - - -PerlIO * -nxt_perl_psgi_layer_stream_fp_create(pTHX_ SV *arg_rv, - const char *mode) -{ - return PerlIO_openn(aTHX_ "NGINX_Unit_PSGI_Layer_Stream", - mode, 0, 0, 0, NULL, 1, &arg_rv); -} - - -void -nxt_perl_psgi_layer_stream_fp_destroy(pTHX_ PerlIO *io) -{ - PerlIO_close(io); -} - - -SV * -nxt_perl_psgi_layer_stream_io_create(pTHX_ PerlIO *fp) -{ - SV *rvio; - IO *thatio; - - thatio = newIO(); - - if (thatio == NULL) { - return NULL; - } - - IoOFP(thatio) = fp; - IoIFP(thatio) = fp; - - rvio = newRV_noinc((SV *) thatio); - - if (rvio == NULL) { - SvREFCNT_dec(thatio); - return NULL; - } - - return rvio; -} diff --git a/src/perl/nxt_perl_psgi_layer.h b/src/perl/nxt_perl_psgi_layer.h deleted file mode 100644 index 0972d66f..00000000 --- a/src/perl/nxt_perl_psgi_layer.h +++ /dev/null @@ -1,48 +0,0 @@ - -/* - * Copyright (C) Alexander Borisov - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PERL_PSGI_LAYER_H_INCLUDED_ -#define _NXT_PERL_PSGI_LAYER_H_INCLUDED_ - - -#include -#include -#include -#include - - -typedef struct nxt_perl_psgi_io_tab_s nxt_perl_psgi_io_tab_t; -typedef struct nxt_perl_psgi_io_arg_s nxt_perl_psgi_io_arg_t; - - -struct nxt_perl_psgi_io_tab_s { - SSize_t (*read)(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length); - SSize_t (*write)(PerlInterpreter *my_perl, - nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length); -}; - - -struct nxt_perl_psgi_io_arg_s { - SV *rv; - SV *io; - PerlIO *fp; - - const nxt_perl_psgi_io_tab_t *io_tab; - - void *req; -}; - - -void nxt_perl_psgi_layer_stream_init(pTHX); - -PerlIO *nxt_perl_psgi_layer_stream_fp_create(pTHX_ SV *arg_rv, - const char *mode); -void nxt_perl_psgi_layer_stream_fp_destroy(pTHX_ PerlIO *io); - -SV *nxt_perl_psgi_layer_stream_io_create(pTHX_ PerlIO *fp); - -#endif /* _NXT_PERL_PSGI_LAYER_H_INCLUDED_ */ diff --git a/src/python/nxt_python.c b/src/python/nxt_python.c deleted file mode 100644 index 7c059649..00000000 --- a/src/python/nxt_python.c +++ /dev/null @@ -1,848 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - - -#include - -#include -#include -#include - -#include - -#include NXT_PYTHON_MOUNTS_H - - -typedef struct { - pthread_t thread; - nxt_unit_ctx_t *ctx; - void *ctx_data; -} nxt_py_thread_info_t; - - -#if PY_MAJOR_VERSION == 3 -static nxt_int_t nxt_python3_init_config(nxt_int_t pep405); -#endif - -static nxt_int_t nxt_python_start(nxt_task_t *task, - nxt_process_data_t *data); -static nxt_int_t nxt_python_set_target(nxt_task_t *task, - nxt_python_target_t *target, nxt_conf_value_t *conf); -nxt_inline nxt_int_t nxt_python_set_prefix(nxt_task_t *task, - nxt_python_target_t *target, nxt_conf_value_t *value); -static nxt_int_t nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value); -static int nxt_python_init_threads(nxt_python_app_conf_t *c); -static int nxt_python_ready_handler(nxt_unit_ctx_t *ctx); -static void *nxt_python_thread_func(void *main_ctx); -static void nxt_python_join_threads(nxt_unit_ctx_t *ctx, - nxt_python_app_conf_t *c); -static void nxt_python_atexit(void); - -static uint32_t compat[] = { - NXT_VERNUM, NXT_DEBUG, -}; - - -NXT_EXPORT nxt_app_module_t nxt_app_module = { - sizeof(compat), - compat, - nxt_string("python"), - PY_VERSION, - nxt_python_mounts, - nxt_nitems(nxt_python_mounts), - NULL, - nxt_python_start, -}; - -static PyObject *nxt_py_stderr_flush; -nxt_python_targets_t *nxt_py_targets; - -#if PY_MAJOR_VERSION == 3 -static wchar_t *nxt_py_home; -#else -static char *nxt_py_home; -#endif - -static pthread_attr_t *nxt_py_thread_attr; -static nxt_py_thread_info_t *nxt_py_threads; -static nxt_python_proto_t nxt_py_proto; - - -#if PY_VERSION_HEX >= NXT_PYTHON_VER(3, 8) - -static nxt_int_t -nxt_python3_init_config(nxt_int_t pep405) -{ - PyConfig config; - PyStatus status; - nxt_int_t ret; - PyPreConfig preconfig; - - ret = NXT_ERROR; - - PyPreConfig_InitIsolatedConfig(&preconfig); - /* - * Determine whether to use UTF-8 mode or not, UTF-8 - * will be enabled if LC_CTYPE is C, POSIX or some - * specific UTF-8 locale. - */ - preconfig.utf8_mode = -1; - - status = Py_PreInitialize(&preconfig); - if (PyStatus_Exception(status)) { - return ret; - } - - PyConfig_InitIsolatedConfig(&config); - - if (pep405) { - status = PyConfig_SetString(&config, &config.program_name, - nxt_py_home); - if (PyStatus_Exception(status)) { - goto out_config_clear; - } - - } else { - status = PyConfig_SetString(&config, &config.home, nxt_py_home); - if (PyStatus_Exception(status)) { - goto out_config_clear; - } - } - - status = Py_InitializeFromConfig(&config); - if (PyStatus_Exception(status)) { - goto out_config_clear; - } - - ret = NXT_OK; - -out_config_clear: - - PyConfig_Clear(&config); - - return ret; -} - -#elif PY_MAJOR_VERSION == 3 - -static nxt_int_t -nxt_python3_init_config(nxt_int_t pep405) -{ - if (pep405) { - Py_SetProgramName(nxt_py_home); - - } else { - Py_SetPythonHome(nxt_py_home); - } - - return NXT_OK; -} - -#endif - - -static nxt_int_t -nxt_python_start(nxt_task_t *task, nxt_process_data_t *data) -{ - int rc; - size_t len, size; - uint32_t next; - PyObject *obj; - nxt_str_t proto, probe_proto, name; - nxt_int_t ret, n, i; - nxt_unit_ctx_t *unit_ctx; - nxt_unit_init_t python_init; - nxt_conf_value_t *cv; - nxt_python_targets_t *targets; - nxt_common_app_conf_t *app_conf; - nxt_python_app_conf_t *c; -#if PY_MAJOR_VERSION == 3 - char *path; - nxt_int_t pep405; - - static const char pyvenv[] = "/pyvenv.cfg"; - static const char bin_python[] = "/bin/python"; -#endif - - static const nxt_str_t wsgi = nxt_string("wsgi"); - static const nxt_str_t asgi = nxt_string("asgi"); - - app_conf = data->app; - c = &app_conf->u.python; - - if (c->home != NULL) { - len = nxt_strlen(c->home); - -#if PY_MAJOR_VERSION == 3 - - path = nxt_malloc(len + sizeof(pyvenv)); - if (nxt_slow_path(path == NULL)) { - nxt_alert(task, "Failed to allocate memory"); - return NXT_ERROR; - } - - nxt_memcpy(path, c->home, len); - nxt_memcpy(path + len, pyvenv, sizeof(pyvenv)); - - pep405 = (access(path, R_OK) == 0); - - nxt_free(path); - - if (pep405) { - size = (len + sizeof(bin_python)) * sizeof(wchar_t); - - } else { - size = (len + 1) * sizeof(wchar_t); - } - - nxt_py_home = nxt_malloc(size); - if (nxt_slow_path(nxt_py_home == NULL)) { - nxt_alert(task, "Failed to allocate memory"); - return NXT_ERROR; - } - - if (pep405) { - mbstowcs(nxt_py_home, c->home, len); - mbstowcs(nxt_py_home + len, bin_python, sizeof(bin_python)); - - } else { - mbstowcs(nxt_py_home, c->home, len + 1); - } - - ret = nxt_python3_init_config(pep405); - if (nxt_slow_path(ret == NXT_ERROR)) { - nxt_alert(task, "Failed to initialise config"); - return NXT_ERROR; - } - -#else - nxt_py_home = nxt_malloc(len + 1); - if (nxt_slow_path(nxt_py_home == NULL)) { - nxt_alert(task, "Failed to allocate memory"); - return NXT_ERROR; - } - - nxt_memcpy(nxt_py_home, c->home, len + 1); - Py_SetPythonHome(nxt_py_home); -#endif - } - - Py_InitializeEx(0); - -#if PY_VERSION_HEX < NXT_PYTHON_VER(3, 7) - if (c->threads > 1) { - PyEval_InitThreads(); - } -#endif - - obj = NULL; - - python_init.ctx_data = NULL; - - obj = PySys_GetObject((char *) "stderr"); - if (nxt_slow_path(obj == NULL)) { - nxt_alert(task, "Python failed to get \"sys.stderr\" object"); - goto fail; - } - - nxt_py_stderr_flush = PyObject_GetAttrString(obj, "flush"); - - /* obj is a Borrowed reference. */ - obj = NULL; - - if (nxt_slow_path(nxt_py_stderr_flush == NULL)) { - nxt_alert(task, "Python failed to get \"flush\" attribute of " - "\"sys.stderr\" object"); - goto fail; - } - - if (nxt_slow_path(nxt_python_set_path(task, c->path) != NXT_OK)) { - goto fail; - } - - obj = Py_BuildValue("[s]", "unit"); - if (nxt_slow_path(obj == NULL)) { - nxt_alert(task, "Python failed to create the \"sys.argv\" list"); - goto fail; - } - - if (nxt_slow_path(PySys_SetObject((char *) "argv", obj) != 0)) { - nxt_alert(task, "Python failed to set the \"sys.argv\" list"); - goto fail; - } - - Py_CLEAR(obj); - - n = (c->targets != NULL ? nxt_conf_object_members_count(c->targets) : 1); - - size = sizeof(nxt_python_targets_t) + n * sizeof(nxt_python_target_t); - - targets = nxt_unit_malloc(NULL, size); - if (nxt_slow_path(targets == NULL)) { - nxt_alert(task, "Could not allocate targets"); - goto fail; - } - - memset(targets, 0, size); - - targets->count = n; - nxt_py_targets = targets; - - if (c->targets != NULL) { - next = 0; - - for (i = 0; /* void */; i++) { - cv = nxt_conf_next_object_member(c->targets, &name, &next); - if (cv == NULL) { - break; - } - - ret = nxt_python_set_target(task, &targets->target[i], cv); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - } - - } else { - ret = nxt_python_set_target(task, &targets->target[0], app_conf->self); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - } - - nxt_unit_default_init(task, &python_init, data->app); - - python_init.data = c; - python_init.callbacks.ready_handler = nxt_python_ready_handler; - - proto = c->protocol; - - if (proto.length == 0) { - proto = nxt_python_asgi_check(targets->target[0].application) - ? asgi : wsgi; - - for (i = 1; i < targets->count; i++) { - probe_proto = nxt_python_asgi_check(targets->target[i].application) - ? asgi : wsgi; - if (probe_proto.start != proto.start) { - nxt_alert(task, "A mix of ASGI & WSGI targets is forbidden, " - "specify protocol in config if incorrect"); - goto fail; - } - } - } - - if (nxt_strstr_eq(&proto, &asgi)) { - rc = nxt_python_asgi_init(&python_init, &nxt_py_proto); - - } else { - rc = nxt_python_wsgi_init(&python_init, &nxt_py_proto); - } - - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - goto fail; - } - - rc = nxt_py_proto.ctx_data_alloc(&python_init.ctx_data, 1); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - rc = nxt_python_init_threads(c); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - goto fail; - } - - if (nxt_py_proto.startup != NULL) { - if (nxt_py_proto.startup(python_init.ctx_data) != NXT_UNIT_OK) { - goto fail; - } - } - - unit_ctx = nxt_unit_init(&python_init); - if (nxt_slow_path(unit_ctx == NULL)) { - goto fail; - } - - rc = nxt_py_proto.run(unit_ctx); - - nxt_python_join_threads(unit_ctx, c); - - nxt_unit_done(unit_ctx); - - nxt_py_proto.ctx_data_free(python_init.ctx_data); - - nxt_python_atexit(); - - exit(rc); - - return NXT_OK; - -fail: - - nxt_python_join_threads(NULL, c); - - if (python_init.ctx_data != NULL) { - nxt_py_proto.ctx_data_free(python_init.ctx_data); - } - - Py_XDECREF(obj); - - nxt_python_atexit(); - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target, - nxt_conf_value_t *conf) -{ - char *callable, *module_name; - PyObject *module, *obj; - nxt_str_t str; - nxt_conf_value_t *value; - - static nxt_str_t module_str = nxt_string("module"); - static nxt_str_t callable_str = nxt_string("callable"); - static nxt_str_t prefix_str = nxt_string("prefix"); - - module = obj = NULL; - - value = nxt_conf_get_object_member(conf, &module_str, NULL); - if (nxt_slow_path(value == NULL)) { - goto fail; - } - - nxt_conf_get_string(value, &str); - - module_name = nxt_alloca(str.length + 1); - nxt_memcpy(module_name, str.start, str.length); - module_name[str.length] = '\0'; - - module = PyImport_ImportModule(module_name); - if (nxt_slow_path(module == NULL)) { - nxt_alert(task, "Python failed to import module \"%s\"", module_name); - nxt_python_print_exception(); - goto fail; - } - - value = nxt_conf_get_object_member(conf, &callable_str, NULL); - if (value == NULL) { - callable = nxt_alloca(12); - nxt_memcpy(callable, "application", 12); - - } else { - nxt_conf_get_string(value, &str); - - callable = nxt_alloca(str.length + 1); - nxt_memcpy(callable, str.start, str.length); - callable[str.length] = '\0'; - } - - obj = PyDict_GetItemString(PyModule_GetDict(module), callable); - if (nxt_slow_path(obj == NULL)) { - nxt_alert(task, "Python failed to get \"%s\" from module \"%s\"", - callable, module_name); - goto fail; - } - - if (nxt_slow_path(PyCallable_Check(obj) == 0)) { - nxt_alert(task, "\"%s\" in module \"%s\" is not a callable object", - callable, module_name); - goto fail; - } - - value = nxt_conf_get_object_member(conf, &prefix_str, NULL); - if (nxt_slow_path(nxt_python_set_prefix(task, target, value) != NXT_OK)) { - goto fail; - } - - target->application = obj; - obj = NULL; - - Py_INCREF(target->application); - Py_CLEAR(module); - - return NXT_OK; - -fail: - - Py_XDECREF(obj); - Py_XDECREF(module); - - return NXT_ERROR; -} - - -nxt_inline nxt_int_t -nxt_python_set_prefix(nxt_task_t *task, nxt_python_target_t *target, - nxt_conf_value_t *value) -{ - u_char *prefix; - nxt_str_t str; - - if (value == NULL) { - return NXT_OK; - } - - nxt_conf_get_string(value, &str); - - if (str.length == 0) { - return NXT_OK; - } - - if (str.start[str.length - 1] == '/') { - str.length--; - } - target->prefix.length = str.length; - prefix = nxt_malloc(str.length); - if (nxt_slow_path(prefix == NULL)) { - nxt_alert(task, "Failed to allocate target prefix string"); - return NXT_ERROR; - } - - target->py_prefix = PyString_FromStringAndSize((char *)str.start, - str.length); - if (nxt_slow_path(target->py_prefix == NULL)) { - nxt_free(prefix); - nxt_alert(task, "Python failed to allocate target prefix " - "string"); - return NXT_ERROR; - } - nxt_memcpy(prefix, str.start, str.length); - target->prefix.start = prefix; - - return NXT_OK; -} - - -static nxt_int_t -nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value) -{ - int ret; - PyObject *path, *sys; - nxt_str_t str; - nxt_uint_t n; - nxt_conf_value_t *array; - - if (value == NULL) { - return NXT_OK; - } - - sys = PySys_GetObject((char *) "path"); - if (nxt_slow_path(sys == NULL)) { - nxt_alert(task, "Python failed to get \"sys.path\" list"); - return NXT_ERROR; - } - - /* sys is a Borrowed reference. */ - - array = value; - n = nxt_conf_array_elements_count_or_1(array); - - while (n != 0) { - n--; - - /* - * Insertion in front of existing paths starting from the last element - * to preserve original order while giving priority to the values - * specified in the "path" option. - */ - - value = nxt_conf_get_array_element_or_itself(array, n); - - nxt_conf_get_string(value, &str); - - path = PyString_FromStringAndSize((char *) str.start, str.length); - if (nxt_slow_path(path == NULL)) { - nxt_alert(task, "Python failed to create string object \"%V\"", - &str); - return NXT_ERROR; - } - - ret = PyList_Insert(sys, 0, path); - - Py_DECREF(path); - - if (nxt_slow_path(ret != 0)) { - nxt_alert(task, "Python failed to insert \"%V\" into \"sys.path\"", - &str); - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -static int -nxt_python_init_threads(nxt_python_app_conf_t *c) -{ - int res; - uint32_t i; - nxt_py_thread_info_t *ti; - static pthread_attr_t attr; - - if (c->threads <= 1) { - return NXT_UNIT_OK; - } - - if (c->thread_stack_size > 0) { - res = pthread_attr_init(&attr); - if (nxt_slow_path(res != 0)) { - nxt_unit_alert(NULL, "thread attr init failed: %s (%d)", - strerror(res), res); - - return NXT_UNIT_ERROR; - } - - res = pthread_attr_setstacksize(&attr, c->thread_stack_size); - if (nxt_slow_path(res != 0)) { - nxt_unit_alert(NULL, "thread attr set stack size failed: %s (%d)", - strerror(res), res); - - return NXT_UNIT_ERROR; - } - - nxt_py_thread_attr = &attr; - } - - nxt_py_threads = nxt_unit_malloc(NULL, sizeof(nxt_py_thread_info_t) - * (c->threads - 1)); - if (nxt_slow_path(nxt_py_threads == NULL)) { - nxt_unit_alert(NULL, "Failed to allocate thread info array"); - - return NXT_UNIT_ERROR; - } - - memset(nxt_py_threads, 0, sizeof(nxt_py_thread_info_t) * (c->threads - 1)); - - for (i = 0; i < c->threads - 1; i++) { - ti = &nxt_py_threads[i]; - - res = nxt_py_proto.ctx_data_alloc(&ti->ctx_data, 0); - if (nxt_slow_path(res != NXT_UNIT_OK)) { - return NXT_UNIT_ERROR; - } - } - - return NXT_UNIT_OK; -} - - -static int -nxt_python_ready_handler(nxt_unit_ctx_t *ctx) -{ - int res; - uint32_t i; - nxt_py_thread_info_t *ti; - nxt_python_app_conf_t *c; - - c = ctx->unit->data; - - if (c->threads <= 1) { - return NXT_UNIT_OK; - } - - for (i = 0; i < c->threads - 1; i++) { - ti = &nxt_py_threads[i]; - - ti->ctx = ctx; - - res = pthread_create(&ti->thread, nxt_py_thread_attr, - nxt_python_thread_func, ti); - - if (nxt_fast_path(res == 0)) { - nxt_unit_debug(ctx, "thread #%d created", (int) (i + 1)); - - } else { - nxt_unit_alert(ctx, "thread #%d create failed: %s (%d)", - (int) (i + 1), strerror(res), res); - } - } - - return NXT_UNIT_OK; -} - - -static void * -nxt_python_thread_func(void *data) -{ - nxt_unit_ctx_t *ctx; - PyGILState_STATE gstate; - nxt_py_thread_info_t *ti; - - ti = data; - - nxt_unit_debug(ti->ctx, "worker thread #%d start", - (int) (ti - nxt_py_threads + 1)); - - gstate = PyGILState_Ensure(); - - if (nxt_py_proto.startup != NULL) { - if (nxt_py_proto.startup(ti->ctx_data) != NXT_UNIT_OK) { - goto fail; - } - } - - ctx = nxt_unit_ctx_alloc(ti->ctx, ti->ctx_data); - if (nxt_slow_path(ctx == NULL)) { - goto fail; - } - - (void) nxt_py_proto.run(ctx); - - nxt_unit_done(ctx); - -fail: - - PyGILState_Release(gstate); - - nxt_unit_debug(NULL, "worker thread #%d end", - (int) (ti - nxt_py_threads + 1)); - - return NULL; -} - - -static void -nxt_python_join_threads(nxt_unit_ctx_t *ctx, nxt_python_app_conf_t *c) -{ - int res; - uint32_t i; - PyThreadState *thread_state; - nxt_py_thread_info_t *ti; - - if (nxt_py_threads == NULL) { - return; - } - - thread_state = PyEval_SaveThread(); - - for (i = 0; i < c->threads - 1; i++) { - ti = &nxt_py_threads[i]; - - if ((uintptr_t) ti->thread == 0) { - continue; - } - - res = pthread_join(ti->thread, NULL); - - if (nxt_fast_path(res == 0)) { - nxt_unit_debug(ctx, "thread #%d joined", (int) (i + 1)); - - } else { - nxt_unit_alert(ctx, "thread #%d join failed: %s (%d)", - (int) (i + 1), strerror(res), res); - } - } - - PyEval_RestoreThread(thread_state); - - for (i = 0; i < c->threads - 1; i++) { - ti = &nxt_py_threads[i]; - - if (ti->ctx_data != NULL) { - nxt_py_proto.ctx_data_free(ti->ctx_data); - } - } - - nxt_unit_free(NULL, nxt_py_threads); -} - - -int -nxt_python_init_strings(nxt_python_string_t *pstr) -{ - PyObject *obj; - - while (pstr->string.start != NULL) { - obj = PyString_FromStringAndSize((char *) pstr->string.start, - pstr->string.length); - if (nxt_slow_path(obj == NULL)) { - return NXT_UNIT_ERROR; - } - - PyUnicode_InternInPlace(&obj); - - *pstr->object_p = obj; - - pstr++; - } - - return NXT_UNIT_OK; -} - - -void -nxt_python_done_strings(nxt_python_string_t *pstr) -{ - PyObject *obj; - - while (pstr->string.start != NULL) { - obj = *pstr->object_p; - - Py_XDECREF(obj); - *pstr->object_p = NULL; - - pstr++; - } -} - - -static void -nxt_python_atexit(void) -{ - nxt_int_t i; - nxt_python_target_t *target; - - if (nxt_py_proto.done != NULL) { - nxt_py_proto.done(); - } - - Py_XDECREF(nxt_py_stderr_flush); - - if (nxt_py_targets != NULL) { - for (i = 0; i < nxt_py_targets->count; i++) { - target = &nxt_py_targets->target[i]; - - Py_XDECREF(target->application); - Py_XDECREF(target->py_prefix); - - nxt_free(target->prefix.start); - } - - nxt_unit_free(NULL, nxt_py_targets); - } - - Py_Finalize(); - - if (nxt_py_home != NULL) { - nxt_free(nxt_py_home); - } -} - - -void -nxt_python_print_exception(void) -{ - PyErr_Print(); - -#if PY_MAJOR_VERSION == 3 - /* The backtrace may be buffered in sys.stderr file object. */ - { - PyObject *result; - - result = PyObject_CallFunction(nxt_py_stderr_flush, NULL); - if (nxt_slow_path(result == NULL)) { - PyErr_Clear(); - return; - } - - Py_DECREF(result); - } -#endif -} diff --git a/src/python/nxt_python.h b/src/python/nxt_python.h deleted file mode 100644 index 37e6265e..00000000 --- a/src/python/nxt_python.h +++ /dev/null @@ -1,84 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PYTHON_H_INCLUDED_ -#define _NXT_PYTHON_H_INCLUDED_ - - -#include -#include -#include - -#define NXT_PYTHON_VER(maj, min) ((maj << 24) | (min << 16)) - - -#if PY_MAJOR_VERSION == 3 -#define NXT_PYTHON_BYTES_TYPE "bytestring" - -#define PyString_FromStringAndSize(str, size) \ - PyUnicode_DecodeLatin1((str), (size), "strict") -#define PyString_AS_STRING PyUnicode_DATA - -#else -#define NXT_PYTHON_BYTES_TYPE "string" - -#define PyBytes_FromStringAndSize PyString_FromStringAndSize -#define PyBytes_Check PyString_Check -#define PyBytes_GET_SIZE PyString_GET_SIZE -#define PyBytes_AS_STRING PyString_AS_STRING -#define PyUnicode_InternInPlace PyString_InternInPlace -#define PyUnicode_AsUTF8 PyString_AS_STRING -#define PyUnicode_GET_LENGTH PyUnicode_GET_SIZE -#endif - -#if PY_VERSION_HEX >= NXT_PYTHON_VER(3, 5) -#define NXT_HAVE_ASGI 1 -#endif - - -typedef struct { - PyObject *application; - PyObject *py_prefix; - nxt_str_t prefix; - nxt_bool_t asgi_legacy; -} nxt_python_target_t; - - -typedef struct { - nxt_int_t count; - nxt_python_target_t target[0]; -} nxt_python_targets_t; - - -extern nxt_python_targets_t *nxt_py_targets; - - -typedef struct { - nxt_str_t string; - PyObject **object_p; -} nxt_python_string_t; - - -typedef struct { - int (*ctx_data_alloc)(void **pdata, int main); - void (*ctx_data_free)(void *data); - int (*startup)(void *data); - int (*run)(nxt_unit_ctx_t *ctx); - void (*done)(void); -} nxt_python_proto_t; - - -int nxt_python_init_strings(nxt_python_string_t *pstr); -void nxt_python_done_strings(nxt_python_string_t *pstr); - -void nxt_python_print_exception(void); - -int nxt_python_wsgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto); - -int nxt_python_asgi_check(PyObject *obj); -int nxt_python_asgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto); - - -#endif /* _NXT_PYTHON_H_INCLUDED_ */ diff --git a/src/python/nxt_python_asgi.c b/src/python/nxt_python_asgi.c deleted file mode 100644 index 8f300b53..00000000 --- a/src/python/nxt_python_asgi.c +++ /dev/null @@ -1,1570 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - - -#include - -#if (NXT_HAVE_ASGI) - -#include -#include -#include -#include -#include -#include - - -static PyObject *nxt_python_asgi_get_func(PyObject *obj); -static PyObject *nxt_python_asgi_get_event_loop(PyObject *asyncio, - const char *event_loop_func); -static int nxt_python_asgi_ctx_data_alloc(void **pdata, int main); -static void nxt_python_asgi_ctx_data_free(void *data); -static int nxt_python_asgi_startup(void *data); -static int nxt_python_asgi_run(nxt_unit_ctx_t *ctx); - -static void nxt_py_asgi_remove_reader(nxt_unit_ctx_t *ctx, - nxt_unit_port_t *port); -static void nxt_py_asgi_request_handler(nxt_unit_request_info_t *req); -static void nxt_py_asgi_close_handler(nxt_unit_request_info_t *req); - -static PyObject *nxt_py_asgi_create_http_scope(nxt_unit_request_info_t *req, - nxt_python_target_t *app_target); -static PyObject *nxt_py_asgi_create_address(nxt_unit_sptr_t *sptr, uint8_t len, - uint16_t port); -static PyObject *nxt_py_asgi_create_ip_address(nxt_unit_sptr_t *sptr, - uint8_t len, uint16_t port); -static PyObject *nxt_py_asgi_create_header(nxt_unit_field_t *f); -static PyObject *nxt_py_asgi_create_subprotocols(nxt_unit_field_t *f); - -static int nxt_py_asgi_add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port); -static int nxt_py_asgi_add_reader(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port); -static void nxt_py_asgi_remove_port(nxt_unit_t *lib, nxt_unit_ctx_t *ctx, - nxt_unit_port_t *port); -static void nxt_py_asgi_quit(nxt_unit_ctx_t *ctx); -static void nxt_py_asgi_shm_ack_handler(nxt_unit_ctx_t *ctx); - -static PyObject *nxt_py_asgi_port_read(PyObject *self, PyObject *args); -static void nxt_python_asgi_done(void); - -static PyObject *nxt_py_port_read; - -static PyMethodDef nxt_py_port_read_method = - {"unit_port_read", nxt_py_asgi_port_read, METH_VARARGS, ""}; - -static nxt_python_proto_t nxt_py_asgi_proto = { - .ctx_data_alloc = nxt_python_asgi_ctx_data_alloc, - .ctx_data_free = nxt_python_asgi_ctx_data_free, - .startup = nxt_python_asgi_startup, - .run = nxt_python_asgi_run, - .done = nxt_python_asgi_done, -}; - -#define NXT_UNIT_HASH_WS_PROTOCOL 0xED0A - - -int -nxt_python_asgi_check(PyObject *obj) -{ - int res; - PyObject *func; - PyCodeObject *code; - - func = nxt_python_asgi_get_func(obj); - - if (func == NULL) { - return 0; - } - - code = (PyCodeObject *) PyFunction_GET_CODE(func); - - nxt_unit_debug(NULL, "asgi_check: callable is %sa coroutine function with " - "%d argument(s)", - (code->co_flags & CO_COROUTINE) != 0 ? "" : "not ", - code->co_argcount); - - res = (code->co_flags & CO_COROUTINE) != 0 || code->co_argcount == 1; - - Py_DECREF(func); - - return res; -} - - -static PyObject * -nxt_python_asgi_get_func(PyObject *obj) -{ - PyObject *call; - - if (PyFunction_Check(obj)) { - Py_INCREF(obj); - return obj; - } - - if (PyMethod_Check(obj)) { - obj = PyMethod_GET_FUNCTION(obj); - - Py_INCREF(obj); - return obj; - } - - call = PyObject_GetAttrString(obj, "__call__"); - - if (call == NULL) { - return NULL; - } - - if (PyFunction_Check(call)) { - return call; - } - - if (PyMethod_Check(call)) { - obj = PyMethod_GET_FUNCTION(call); - - if (PyFunction_Check(obj)) { - Py_INCREF(obj); - - } else { - obj = NULL; - } - - } else { - obj = NULL; - } - - Py_DECREF(call); - - return obj; -} - - -int -nxt_python_asgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto) -{ - PyObject *func; - nxt_int_t i; - PyCodeObject *code; - - nxt_unit_debug(NULL, "asgi_init"); - - if (nxt_slow_path(nxt_py_asgi_str_init() != NXT_UNIT_OK)) { - nxt_unit_alert(NULL, "Python failed to init string objects"); - return NXT_UNIT_ERROR; - } - - nxt_py_port_read = PyCFunction_New(&nxt_py_port_read_method, NULL); - if (nxt_slow_path(nxt_py_port_read == NULL)) { - nxt_unit_alert(NULL, - "Python failed to initialize the 'port_read' function"); - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(nxt_py_asgi_http_init() == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - - if (nxt_slow_path(nxt_py_asgi_websocket_init() == NXT_UNIT_ERROR)) { - return NXT_UNIT_ERROR; - } - - for (i = 0; i < nxt_py_targets->count; i++) { - func = nxt_python_asgi_get_func(nxt_py_targets->target[i].application); - if (nxt_slow_path(func == NULL)) { - nxt_unit_debug(NULL, "asgi: cannot find function for callable, " - "unable to check for legacy mode (#%d)", - (int) i); - continue; - } - - code = (PyCodeObject *) PyFunction_GET_CODE(func); - - if ((code->co_flags & CO_COROUTINE) == 0) { - nxt_unit_debug(NULL, "asgi: callable is not a coroutine function " - "switching to legacy mode"); - nxt_py_targets->target[i].asgi_legacy = 1; - } - - Py_DECREF(func); - } - - init->callbacks.request_handler = nxt_py_asgi_request_handler; - init->callbacks.data_handler = nxt_py_asgi_http_data_handler; - init->callbacks.websocket_handler = nxt_py_asgi_websocket_handler; - init->callbacks.close_handler = nxt_py_asgi_close_handler; - init->callbacks.quit = nxt_py_asgi_quit; - init->callbacks.shm_ack_handler = nxt_py_asgi_shm_ack_handler; - init->callbacks.add_port = nxt_py_asgi_add_port; - init->callbacks.remove_port = nxt_py_asgi_remove_port; - - *proto = nxt_py_asgi_proto; - - return NXT_UNIT_OK; -} - - -static PyObject * -nxt_python_asgi_get_event_loop(PyObject *asyncio, const char *event_loop_func) -{ - PyObject *event_loop, *loop; - - event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio), - event_loop_func); - if (nxt_slow_path(event_loop == NULL)) { - nxt_unit_alert(NULL, "Python failed to get '%s' from module 'asyncio'", - event_loop_func); - return NULL; - } - - if (nxt_slow_path(PyCallable_Check(event_loop) == 0)) { - nxt_unit_alert(NULL, "'asyncio.%s' is not a callable object", - event_loop_func); - return NULL; - } - - loop = PyObject_CallObject(event_loop, NULL); - if (nxt_slow_path(loop == NULL)) { - if (strcmp(event_loop_func, "get_running_loop") != 0) { - nxt_unit_alert(NULL, "Python failed to call 'asyncio.%s'", - event_loop_func); - } - - return NULL; - } - - return loop; -} - - -static int -nxt_python_asgi_ctx_data_alloc(void **pdata, int main) -{ - uint32_t i; - PyObject *asyncio, *loop, *obj; - const char *event_loop_func; - nxt_py_asgi_ctx_data_t *ctx_data; - -#if PY_VERSION_HEX < NXT_PYTHON_VER(3, 7) - static const char *main_event_loop_func = "get_event_loop"; -#else - static const char *main_event_loop_func = "get_running_loop"; -#endif - - ctx_data = nxt_unit_malloc(NULL, sizeof(nxt_py_asgi_ctx_data_t)); - if (nxt_slow_path(ctx_data == NULL)) { - nxt_unit_alert(NULL, "Failed to allocate context data"); - return NXT_UNIT_ERROR; - } - - memset(ctx_data, 0, sizeof(nxt_py_asgi_ctx_data_t)); - - nxt_queue_init(&ctx_data->drain_queue); - - struct { - const char *key; - PyObject **handler; - - } handlers[] = { - { "create_task", &ctx_data->loop_create_task }, - { "add_reader", &ctx_data->loop_add_reader }, - { "remove_reader", &ctx_data->loop_remove_reader }, - { "call_soon", &ctx_data->loop_call_soon }, - { "run_until_complete", &ctx_data->loop_run_until_complete }, - { "create_future", &ctx_data->loop_create_future }, - }; - - loop = NULL; - - asyncio = PyImport_ImportModule("asyncio"); - if (nxt_slow_path(asyncio == NULL)) { - nxt_unit_alert(NULL, "Python failed to import module 'asyncio'"); - nxt_python_print_exception(); - goto fail; - } - - event_loop_func = main ? main_event_loop_func : "new_event_loop"; - - loop = nxt_python_asgi_get_event_loop(asyncio, event_loop_func); - if (loop == NULL) { -#if PY_VERSION_HEX < NXT_PYTHON_VER(3, 7) - goto fail; -#else - if (!main) { - goto fail; - } - - PyErr_Clear(); - - loop = nxt_python_asgi_get_event_loop(asyncio, "new_event_loop"); - if (nxt_slow_path(loop == NULL)) { - goto fail; - } -#endif - } - - for (i = 0; i < nxt_nitems(handlers); i++) { - obj = PyObject_GetAttrString(loop, handlers[i].key); - if (nxt_slow_path(obj == NULL)) { - nxt_unit_alert(NULL, "Python failed to get 'loop.%s'", - handlers[i].key); - goto fail; - } - - *handlers[i].handler = obj; - - if (nxt_slow_path(PyCallable_Check(obj) == 0)) { - nxt_unit_alert(NULL, "'loop.%s' is not a callable object", - handlers[i].key); - goto fail; - } - } - - obj = PyObject_CallObject(ctx_data->loop_create_future, NULL); - if (nxt_slow_path(obj == NULL)) { - nxt_unit_alert(NULL, "Python failed to create Future "); - nxt_python_print_exception(); - goto fail; - } - - ctx_data->quit_future = obj; - - obj = PyObject_GetAttrString(ctx_data->quit_future, "set_result"); - if (nxt_slow_path(obj == NULL)) { - nxt_unit_alert(NULL, "Python failed to get 'future.set_result'"); - goto fail; - } - - ctx_data->quit_future_set_result = obj; - - if (nxt_slow_path(PyCallable_Check(obj) == 0)) { - nxt_unit_alert(NULL, "'future.set_result' is not a callable object"); - goto fail; - } - - Py_DECREF(loop); - Py_DECREF(asyncio); - - *pdata = ctx_data; - - return NXT_UNIT_OK; - -fail: - - nxt_python_asgi_ctx_data_free(ctx_data); - - Py_XDECREF(loop); - Py_XDECREF(asyncio); - - return NXT_UNIT_ERROR; -} - - -static void -nxt_python_asgi_ctx_data_free(void *data) -{ - nxt_py_asgi_ctx_data_t *ctx_data; - - ctx_data = data; - - Py_XDECREF(ctx_data->loop_run_until_complete); - Py_XDECREF(ctx_data->loop_create_future); - Py_XDECREF(ctx_data->loop_create_task); - Py_XDECREF(ctx_data->loop_call_soon); - Py_XDECREF(ctx_data->loop_add_reader); - Py_XDECREF(ctx_data->loop_remove_reader); - Py_XDECREF(ctx_data->quit_future); - Py_XDECREF(ctx_data->quit_future_set_result); - - nxt_unit_free(NULL, ctx_data); -} - - -static int -nxt_python_asgi_startup(void *data) -{ - return nxt_py_asgi_lifespan_startup(data); -} - - -static int -nxt_python_asgi_run(nxt_unit_ctx_t *ctx) -{ - PyObject *res; - nxt_py_asgi_ctx_data_t *ctx_data; - - ctx_data = ctx->data; - - res = PyObject_CallFunctionObjArgs(ctx_data->loop_run_until_complete, - ctx_data->quit_future, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(ctx, "Python failed to call loop.run_until_complete"); - nxt_python_print_exception(); - - return NXT_UNIT_ERROR; - } - - Py_DECREF(res); - - nxt_py_asgi_lifespan_shutdown(ctx); - - return NXT_UNIT_OK; -} - - -static void -nxt_py_asgi_remove_reader(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) -{ - PyObject *res, *fd; - nxt_py_asgi_ctx_data_t *ctx_data; - - if (port == NULL || port->in_fd == -1) { - return; - } - - ctx_data = ctx->data; - - nxt_unit_debug(ctx, "asgi_remove_reader %d %p", port->in_fd, port); - - fd = PyLong_FromLong(port->in_fd); - if (nxt_slow_path(fd == NULL)) { - nxt_unit_alert(ctx, "Python failed to create Long object"); - nxt_python_print_exception(); - - return; - } - - res = PyObject_CallFunctionObjArgs(ctx_data->loop_remove_reader, fd, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(ctx, "Python failed to remove_reader"); - nxt_python_print_exception(); - - } else { - Py_DECREF(res); - } - - Py_DECREF(fd); -} - - -static void -nxt_py_asgi_request_handler(nxt_unit_request_info_t *req) -{ - PyObject *scope, *res, *task, *receive, *send, *done, *asgi; - PyObject *state, *newstate, *lifespan; - PyObject *stage2; - nxt_python_target_t *target; - nxt_py_asgi_ctx_data_t *ctx_data; - - if (req->request->websocket_handshake) { - asgi = nxt_py_asgi_websocket_create(req); - - } else { - asgi = nxt_py_asgi_http_create(req); - } - - if (nxt_slow_path(asgi == NULL)) { - nxt_unit_req_alert(req, "Python failed to create asgi object"); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - return; - } - - receive = PyObject_GetAttrString(asgi, "receive"); - if (nxt_slow_path(receive == NULL)) { - nxt_unit_req_alert(req, "Python failed to get 'receive' method"); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - goto release_asgi; - } - - send = PyObject_GetAttrString(asgi, "send"); - if (nxt_slow_path(send == NULL)) { - nxt_unit_req_alert(req, "Python failed to get 'send' method"); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - goto release_receive; - } - - done = PyObject_GetAttrString(asgi, "_done"); - if (nxt_slow_path(done == NULL)) { - nxt_unit_req_alert(req, "Python failed to get '_done' method"); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - goto release_send; - } - - req->data = asgi; - ctx_data = req->ctx->data; - target = &nxt_py_targets->target[req->request->app_target]; - lifespan = ctx_data->target_lifespans[req->request->app_target]; - state = PyObject_GetAttr(lifespan, nxt_py_state_str); - if (nxt_slow_path(state == NULL)) { - nxt_unit_req_alert(req, "Python failed to get 'state' attribute"); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - goto release_done; - } - - newstate = PyDict_Copy(state); - if (nxt_slow_path(newstate == NULL)) { - nxt_unit_req_alert(req, "Python failed to call state.copy()"); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - Py_DECREF(state); - goto release_done; - } - Py_DECREF(state); - - scope = nxt_py_asgi_create_http_scope(req, target); - if (nxt_slow_path(scope == NULL)) { - nxt_unit_request_done(req, NXT_UNIT_ERROR); - Py_DECREF(newstate); - goto release_done; - } - - if (nxt_slow_path(PyDict_SetItem(scope, nxt_py_state_str, newstate) - == -1)) - { - Py_DECREF(newstate); - goto release_scope; - } - Py_DECREF(newstate); - - if (!target->asgi_legacy) { - nxt_unit_req_debug(req, "Python call ASGI 3.0 application"); - - res = PyObject_CallFunctionObjArgs(target->application, - scope, receive, send, NULL); - - } else { - nxt_unit_req_debug(req, "Python call legacy application"); - - res = PyObject_CallFunctionObjArgs(target->application, scope, NULL); - - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_error(req, "Python failed to call legacy app stage1"); - nxt_python_print_exception(); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - goto release_scope; - } - - if (nxt_slow_path(PyCallable_Check(res) == 0)) { - nxt_unit_req_error(req, - "Legacy ASGI application returns not a callable"); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - Py_DECREF(res); - - goto release_scope; - } - - stage2 = res; - - res = PyObject_CallFunctionObjArgs(stage2, receive, send, NULL); - - Py_DECREF(stage2); - } - - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_error(req, "Python failed to call the application"); - nxt_python_print_exception(); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - goto release_scope; - } - - if (nxt_slow_path(!PyCoro_CheckExact(res))) { - nxt_unit_req_error(req, "Application result type is not a coroutine"); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - Py_DECREF(res); - - goto release_scope; - } - - - task = PyObject_CallFunctionObjArgs(ctx_data->loop_create_task, res, NULL); - if (nxt_slow_path(task == NULL)) { - nxt_unit_req_error(req, "Python failed to call the create_task"); - nxt_python_print_exception(); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - Py_DECREF(res); - - goto release_scope; - } - - Py_DECREF(res); - - res = PyObject_CallMethodObjArgs(task, nxt_py_add_done_callback_str, done, - NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_error(req, - "Python failed to call 'task.add_done_callback'"); - nxt_python_print_exception(); - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - goto release_task; - } - - Py_DECREF(res); -release_task: - Py_DECREF(task); -release_scope: - Py_DECREF(scope); -release_done: - Py_DECREF(done); -release_send: - Py_DECREF(send); -release_receive: - Py_DECREF(receive); -release_asgi: - Py_DECREF(asgi); -} - - -static void -nxt_py_asgi_close_handler(nxt_unit_request_info_t *req) -{ - if (req->request->websocket_handshake) { - nxt_py_asgi_websocket_close_handler(req); - - } else { - nxt_py_asgi_http_close_handler(req); - } -} - - -static PyObject * -nxt_py_asgi_create_http_scope(nxt_unit_request_info_t *req, - nxt_python_target_t *app_target) -{ - char *p, *target, *query; - uint32_t target_length, i, path_length; - PyObject *scope, *v, *type, *scheme; - PyObject *headers, *header; - nxt_str_t prefix; - nxt_unit_field_t *f; - nxt_unit_request_t *r; - - static const nxt_str_t ws_protocol = nxt_string("sec-websocket-protocol"); - -#define SET_ITEM(dict, key, value) \ - if (nxt_slow_path(PyDict_SetItem(dict, nxt_py_ ## key ## _str, value) \ - == -1)) \ - { \ - nxt_unit_req_alert(req, "Python failed to set '" \ - #dict "." #key "' item"); \ - goto fail; \ - } - - v = NULL; - headers = NULL; - - r = req->request; - - if (r->websocket_handshake) { - type = nxt_py_websocket_str; - scheme = r->tls ? nxt_py_wss_str : nxt_py_ws_str; - - } else { - type = nxt_py_http_str; - scheme = r->tls ? nxt_py_https_str : nxt_py_http_str; - } - - scope = nxt_py_asgi_new_scope(req, type, nxt_py_2_1_str); - if (nxt_slow_path(scope == NULL)) { - return NULL; - } - - prefix = app_target->prefix; - path_length = r->path_length; - p = nxt_unit_sptr_get(&r->path); - if (prefix.length > 0 - && ((path_length > prefix.length && p[prefix.length] == '/') - || path_length == prefix.length) - && memcmp(prefix.start, p, prefix.length) == 0) - { - SET_ITEM(scope, root_path, app_target->py_prefix); - } - - p = nxt_unit_sptr_get(&r->version); - SET_ITEM(scope, http_version, p[7] == '1' ? nxt_py_1_1_str - : nxt_py_1_0_str) - SET_ITEM(scope, scheme, scheme) - - v = PyString_FromStringAndSize(nxt_unit_sptr_get(&r->method), - r->method_length); - if (nxt_slow_path(v == NULL)) { - nxt_unit_req_alert(req, "Python failed to create 'method' string"); - goto fail; - } - - SET_ITEM(scope, method, v) - Py_DECREF(v); - - v = PyUnicode_DecodeUTF8(nxt_unit_sptr_get(&r->path), r->path_length, - "replace"); - if (nxt_slow_path(v == NULL)) { - nxt_unit_req_alert(req, "Python failed to create 'path' string"); - goto fail; - } - - SET_ITEM(scope, path, v) - Py_DECREF(v); - - target = nxt_unit_sptr_get(&r->target); - query = nxt_unit_sptr_get(&r->query); - - if (r->query.offset != 0) { - target_length = query - target - 1; - - } else { - target_length = r->target_length; - } - - v = PyBytes_FromStringAndSize(target, target_length); - if (nxt_slow_path(v == NULL)) { - nxt_unit_req_alert(req, "Python failed to create 'raw_path' string"); - goto fail; - } - - SET_ITEM(scope, raw_path, v) - Py_DECREF(v); - - v = PyBytes_FromStringAndSize(query, r->query_length); - if (nxt_slow_path(v == NULL)) { - nxt_unit_req_alert(req, "Python failed to create 'query' string"); - goto fail; - } - - SET_ITEM(scope, query_string, v) - Py_DECREF(v); - - v = nxt_py_asgi_create_address(&r->remote, r->remote_length, 0); - if (nxt_slow_path(v == NULL)) { - nxt_unit_req_alert(req, "Python failed to create 'client' pair"); - goto fail; - } - - SET_ITEM(scope, client, v) - Py_DECREF(v); - - v = nxt_py_asgi_create_address(&r->local_addr, r->local_addr_length, 80); - if (nxt_slow_path(v == NULL)) { - nxt_unit_req_alert(req, "Python failed to create 'server' pair"); - goto fail; - } - - SET_ITEM(scope, server, v) - Py_DECREF(v); - - v = NULL; - - headers = PyTuple_New(r->fields_count); - if (nxt_slow_path(headers == NULL)) { - nxt_unit_req_alert(req, "Python failed to create 'headers' object"); - goto fail; - } - - for (i = 0; i < r->fields_count; i++) { - f = r->fields + i; - - header = nxt_py_asgi_create_header(f); - if (nxt_slow_path(header == NULL)) { - nxt_unit_req_alert(req, "Python failed to create 'header' pair"); - goto fail; - } - - PyTuple_SET_ITEM(headers, i, header); - - if (f->hash == NXT_UNIT_HASH_WS_PROTOCOL - && f->name_length == ws_protocol.length - && f->value_length > 0 - && r->websocket_handshake) - { - v = nxt_py_asgi_create_subprotocols(f); - if (nxt_slow_path(v == NULL)) { - nxt_unit_req_alert(req, "Failed to create subprotocols"); - goto fail; - } - - SET_ITEM(scope, subprotocols, v); - Py_DECREF(v); - } - } - - SET_ITEM(scope, headers, headers) - Py_DECREF(headers); - - return scope; - -fail: - - Py_XDECREF(v); - Py_XDECREF(headers); - Py_DECREF(scope); - - return NULL; - -#undef SET_ITEM -} - - -static PyObject * -nxt_py_asgi_create_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port) -{ -#if (NXT_HAVE_UNIX_DOMAIN) - size_t prefix_len; - PyObject *pair, *v; - nxt_str_t addr; - - addr.length = len; - addr.start = nxt_unit_sptr_get(sptr); - - prefix_len = nxt_length("unix:"); - if (nxt_str_start(&addr, "unix:", prefix_len)) { - - pair = PyTuple_New(2); - if (nxt_slow_path(pair == NULL)) { - return NULL; - } - - addr.start += prefix_len; - addr.length -= prefix_len; - - v = PyString_FromStringAndSize((const char *) addr.start, addr.length); - if (nxt_slow_path(v == NULL)) { - Py_DECREF(pair); - - return NULL; - } - - PyTuple_SET_ITEM(pair, 0, v); - PyTuple_SET_ITEM(pair, 1, Py_None); - - return pair; - } - -#endif - return nxt_py_asgi_create_ip_address(sptr, len, port); -} - - -static PyObject * -nxt_py_asgi_create_ip_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port) -{ - char *p; - PyObject *pair, *v; - - pair = PyTuple_New(2); - if (nxt_slow_path(pair == NULL)) { - return NULL; - } - - p = nxt_unit_sptr_get(sptr); - - v = PyString_FromStringAndSize(p, len); - if (nxt_slow_path(v == NULL)) { - Py_DECREF(pair); - - return NULL; - } - - PyTuple_SET_ITEM(pair, 0, v); - - v = PyLong_FromLong(port); - if (nxt_slow_path(v == NULL)) { - Py_DECREF(pair); - - return NULL; - } - - PyTuple_SET_ITEM(pair, 1, v); - - return pair; -} - - -static PyObject * -nxt_py_asgi_create_header(nxt_unit_field_t *f) -{ - char c, *name; - uint8_t pos; - PyObject *header, *v; - - header = PyTuple_New(2); - if (nxt_slow_path(header == NULL)) { - return NULL; - } - - name = nxt_unit_sptr_get(&f->name); - - for (pos = 0; pos < f->name_length; pos++) { - c = name[pos]; - if (c >= 'A' && c <= 'Z') { - name[pos] = (c | 0x20); - } - } - - v = PyBytes_FromStringAndSize(name, f->name_length); - if (nxt_slow_path(v == NULL)) { - Py_DECREF(header); - - return NULL; - } - - PyTuple_SET_ITEM(header, 0, v); - - v = PyBytes_FromStringAndSize(nxt_unit_sptr_get(&f->value), - f->value_length); - if (nxt_slow_path(v == NULL)) { - Py_DECREF(header); - - return NULL; - } - - PyTuple_SET_ITEM(header, 1, v); - - return header; -} - - -static PyObject * -nxt_py_asgi_create_subprotocols(nxt_unit_field_t *f) -{ - char *v; - uint32_t i, n, start; - PyObject *res, *proto; - - v = nxt_unit_sptr_get(&f->value); - n = 1; - - for (i = 0; i < f->value_length; i++) { - if (v[i] == ',') { - n++; - } - } - - res = PyTuple_New(n); - if (nxt_slow_path(res == NULL)) { - return NULL; - } - - n = 0; - start = 0; - - for (i = 0; i < f->value_length; ) { - if (v[i] != ',') { - i++; - - continue; - } - - if (i - start > 0) { - proto = PyString_FromStringAndSize(v + start, i - start); - if (nxt_slow_path(proto == NULL)) { - goto fail; - } - - PyTuple_SET_ITEM(res, n, proto); - - n++; - } - - do { - i++; - } while (i < f->value_length && v[i] == ' '); - - start = i; - } - - if (i - start > 0) { - proto = PyString_FromStringAndSize(v + start, i - start); - if (nxt_slow_path(proto == NULL)) { - goto fail; - } - - PyTuple_SET_ITEM(res, n, proto); - } - - return res; - -fail: - - Py_DECREF(res); - - return NULL; -} - - -static int -nxt_py_asgi_add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) -{ - int nb; - - if (port->in_fd == -1) { - return NXT_UNIT_OK; - } - - nb = 1; - - if (nxt_slow_path(ioctl(port->in_fd, FIONBIO, &nb) == -1)) { - nxt_unit_alert(ctx, "ioctl(%d, FIONBIO, 0) failed: %s (%d)", - port->in_fd, strerror(errno), errno); - - return NXT_UNIT_ERROR; - } - - nxt_unit_debug(ctx, "asgi_add_port %d %p %p", port->in_fd, ctx, port); - - return nxt_py_asgi_add_reader(ctx, port); -} - - -static int -nxt_py_asgi_add_reader(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) -{ - int rc; - PyObject *res, *fd, *py_ctx, *py_port; - nxt_py_asgi_ctx_data_t *ctx_data; - - nxt_unit_debug(ctx, "asgi_add_reader %d %p %p", port->in_fd, ctx, port); - - ctx_data = ctx->data; - - fd = PyLong_FromLong(port->in_fd); - if (nxt_slow_path(fd == NULL)) { - nxt_unit_alert(ctx, "Python failed to create fd"); - nxt_python_print_exception(); - - return NXT_UNIT_ERROR; - } - - rc = NXT_UNIT_ERROR; - - py_ctx = PyLong_FromVoidPtr(ctx); - if (nxt_slow_path(py_ctx == NULL)) { - nxt_unit_alert(ctx, "Python failed to create py_ctx"); - nxt_python_print_exception(); - - goto clean_fd; - } - - py_port = PyLong_FromVoidPtr(port); - if (nxt_slow_path(py_port == NULL)) { - nxt_unit_alert(ctx, "Python failed to create py_port"); - nxt_python_print_exception(); - - goto clean_py_ctx; - } - - res = PyObject_CallFunctionObjArgs(ctx_data->loop_add_reader, - fd, nxt_py_port_read, - py_ctx, py_port, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(ctx, "Python failed to add_reader"); - nxt_python_print_exception(); - - } else { - Py_DECREF(res); - - rc = NXT_UNIT_OK; - } - - Py_DECREF(py_port); - -clean_py_ctx: - - Py_DECREF(py_ctx); - -clean_fd: - - Py_DECREF(fd); - - return rc; -} - - -static void -nxt_py_asgi_remove_port(nxt_unit_t *lib, nxt_unit_ctx_t *ctx, - nxt_unit_port_t *port) -{ - if (port->in_fd == -1 || ctx == NULL) { - return; - } - - nxt_unit_debug(NULL, "asgi_remove_port %d %p", port->in_fd, port); - - nxt_py_asgi_remove_reader(ctx, port); -} - - -static void -nxt_py_asgi_quit(nxt_unit_ctx_t *ctx) -{ - PyObject *res, *p; - nxt_py_asgi_ctx_data_t *ctx_data; - - nxt_unit_debug(ctx, "asgi_quit %p", ctx); - - ctx_data = ctx->data; - - p = PyLong_FromLong(0); - if (nxt_slow_path(p == NULL)) { - nxt_unit_alert(NULL, "Python failed to create Long"); - nxt_python_print_exception(); - - } else { - res = PyObject_CallFunctionObjArgs(ctx_data->quit_future_set_result, - p, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(ctx, "Python failed to set_result"); - nxt_python_print_exception(); - - } else { - Py_DECREF(res); - } - - Py_DECREF(p); - } -} - - -static void -nxt_py_asgi_shm_ack_handler(nxt_unit_ctx_t *ctx) -{ - int rc; - nxt_queue_link_t *lnk; - nxt_py_asgi_ctx_data_t *ctx_data; - - ctx_data = ctx->data; - - while (!nxt_queue_is_empty(&ctx_data->drain_queue)) { - lnk = nxt_queue_first(&ctx_data->drain_queue); - - rc = nxt_py_asgi_http_drain(lnk); - if (rc == NXT_UNIT_AGAIN) { - return; - } - - nxt_queue_remove(lnk); - } -} - - -static PyObject * -nxt_py_asgi_port_read(PyObject *self, PyObject *args) -{ - int rc; - PyObject *arg0, *arg1, *res; - Py_ssize_t n; - nxt_unit_ctx_t *ctx; - nxt_unit_port_t *port; - nxt_py_asgi_ctx_data_t *ctx_data; - - n = PyTuple_GET_SIZE(args); - - if (n != 2) { - nxt_unit_alert(NULL, - "nxt_py_asgi_port_read: invalid number of arguments %d", - (int) n); - - return PyErr_Format(PyExc_TypeError, "invalid number of arguments"); - } - - arg0 = PyTuple_GET_ITEM(args, 0); - if (nxt_slow_path(arg0 == NULL || PyLong_Check(arg0) == 0)) { - return PyErr_Format(PyExc_TypeError, - "the first argument is not a long"); - } - - ctx = PyLong_AsVoidPtr(arg0); - - arg1 = PyTuple_GET_ITEM(args, 1); - if (nxt_slow_path(arg1 == NULL || PyLong_Check(arg1) == 0)) { - return PyErr_Format(PyExc_TypeError, - "the second argument is not a long"); - } - - port = PyLong_AsVoidPtr(arg1); - - rc = nxt_unit_process_port_msg(ctx, port); - - nxt_unit_debug(ctx, "asgi_port_read(%p,%p): %d", ctx, port, rc); - - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - return PyErr_Format(PyExc_RuntimeError, - "error processing port %d message", port->id.id); - } - - if (rc == NXT_UNIT_OK) { - ctx_data = ctx->data; - - res = PyObject_CallFunctionObjArgs(ctx_data->loop_call_soon, - nxt_py_port_read, - arg0, arg1, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(ctx, "Python failed to call 'loop.call_soon'"); - nxt_python_print_exception(); - } - - Py_XDECREF(res); - } - - Py_RETURN_NONE; -} - - -PyObject * -nxt_py_asgi_enum_headers(PyObject *headers, nxt_py_asgi_enum_header_cb cb, - void *data) -{ - int i; - PyObject *iter, *header, *h_iter, *name, *val, *res; - - iter = PyObject_GetIter(headers); - if (nxt_slow_path(iter == NULL)) { - return PyErr_Format(PyExc_TypeError, "'headers' is not an iterable"); - } - - for (i = 0; /* void */; i++) { - header = PyIter_Next(iter); - if (header == NULL) { - break; - } - - h_iter = PyObject_GetIter(header); - if (nxt_slow_path(h_iter == NULL)) { - Py_DECREF(header); - Py_DECREF(iter); - - return PyErr_Format(PyExc_TypeError, - "'headers' item #%d is not an iterable", i); - } - - name = PyIter_Next(h_iter); - if (nxt_slow_path(name == NULL || !PyBytes_Check(name))) { - Py_XDECREF(name); - Py_DECREF(h_iter); - Py_DECREF(header); - Py_DECREF(iter); - - return PyErr_Format(PyExc_TypeError, - "'headers' item #%d 'name' is not a byte string", i); - } - - val = PyIter_Next(h_iter); - if (nxt_slow_path(val == NULL || !PyBytes_Check(val))) { - Py_XDECREF(val); - Py_DECREF(h_iter); - Py_DECREF(header); - Py_DECREF(iter); - - return PyErr_Format(PyExc_TypeError, - "'headers' item #%d 'value' is not a byte string", i); - } - - res = cb(data, i, name, val); - - Py_DECREF(name); - Py_DECREF(val); - Py_DECREF(h_iter); - Py_DECREF(header); - - if (nxt_slow_path(res == NULL)) { - Py_DECREF(iter); - - return NULL; - } - - Py_DECREF(res); - } - - Py_DECREF(iter); - - Py_RETURN_NONE; -} - - -PyObject * -nxt_py_asgi_calc_size(void *data, int i, PyObject *name, PyObject *val) -{ - nxt_py_asgi_calc_size_ctx_t *ctx; - - ctx = data; - - ctx->fields_count++; - ctx->fields_size += PyBytes_GET_SIZE(name) + PyBytes_GET_SIZE(val); - - Py_RETURN_NONE; -} - - -PyObject * -nxt_py_asgi_add_field(void *data, int i, PyObject *name, PyObject *val) -{ - int rc; - char *name_str, *val_str; - uint32_t name_len, val_len; - nxt_off_t content_length; - nxt_unit_request_info_t *req; - nxt_py_asgi_add_field_ctx_t *ctx; - - name_str = PyBytes_AS_STRING(name); - name_len = PyBytes_GET_SIZE(name); - - val_str = PyBytes_AS_STRING(val); - val_len = PyBytes_GET_SIZE(val); - - ctx = data; - req = ctx->req; - - rc = nxt_unit_response_add_field(req, name_str, name_len, - val_str, val_len); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to add header #%d", i); - } - - if (req->response->fields[i].hash == NXT_UNIT_HASH_CONTENT_LENGTH) { - content_length = nxt_off_t_parse((u_char *) val_str, val_len); - if (nxt_slow_path(content_length < 0)) { - nxt_unit_req_error(req, "failed to parse Content-Length " - "value %.*s", (int) val_len, val_str); - - return PyErr_Format(PyExc_ValueError, - "Failed to parse Content-Length: '%.*s'", - (int) val_len, val_str); - } - - ctx->content_length = content_length; - } - - Py_RETURN_NONE; -} - - -PyObject * -nxt_py_asgi_set_result_soon(nxt_unit_request_info_t *req, - nxt_py_asgi_ctx_data_t *ctx_data, PyObject *future, PyObject *result) -{ - PyObject *set_result, *res; - - if (nxt_slow_path(result == NULL)) { - Py_DECREF(future); - - return NULL; - } - - set_result = PyObject_GetAttrString(future, "set_result"); - if (nxt_slow_path(set_result == NULL)) { - nxt_unit_req_alert(req, "failed to get 'set_result' for future"); - - Py_CLEAR(future); - - goto cleanup_result; - } - - if (nxt_slow_path(PyCallable_Check(set_result) == 0)) { - nxt_unit_req_alert(req, "'future.set_result' is not a callable"); - - Py_CLEAR(future); - - goto cleanup; - } - - res = PyObject_CallFunctionObjArgs(ctx_data->loop_call_soon, set_result, - result, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_alert(req, "Python failed to call 'loop.call_soon'"); - nxt_python_print_exception(); - - Py_CLEAR(future); - } - - Py_XDECREF(res); - -cleanup: - - Py_DECREF(set_result); - -cleanup_result: - - Py_DECREF(result); - - return future; -} - - -PyObject * -nxt_py_asgi_new_msg(nxt_unit_request_info_t *req, PyObject *type) -{ - PyObject *msg; - - msg = PyDict_New(); - if (nxt_slow_path(msg == NULL)) { - nxt_unit_req_alert(req, "Python failed to create message dict"); - nxt_python_print_exception(); - - return PyErr_Format(PyExc_RuntimeError, - "failed to create message dict"); - } - - if (nxt_slow_path(PyDict_SetItem(msg, nxt_py_type_str, type) == -1)) { - nxt_unit_req_alert(req, "Python failed to set 'msg.type' item"); - - Py_DECREF(msg); - - return PyErr_Format(PyExc_RuntimeError, - "failed to set 'msg.type' item"); - } - - return msg; -} - - -PyObject * -nxt_py_asgi_new_scope(nxt_unit_request_info_t *req, PyObject *type, - PyObject *spec_version) -{ - PyObject *scope, *asgi; - - scope = PyDict_New(); - if (nxt_slow_path(scope == NULL)) { - nxt_unit_req_alert(req, "Python failed to create 'scope' dict"); - nxt_python_print_exception(); - - return PyErr_Format(PyExc_RuntimeError, - "failed to create 'scope' dict"); - } - - if (nxt_slow_path(PyDict_SetItem(scope, nxt_py_type_str, type) == -1)) { - nxt_unit_req_alert(req, "Python failed to set 'scope.type' item"); - - Py_DECREF(scope); - - return PyErr_Format(PyExc_RuntimeError, - "failed to set 'scope.type' item"); - } - - asgi = PyDict_New(); - if (nxt_slow_path(asgi == NULL)) { - nxt_unit_req_alert(req, "Python failed to create 'asgi' dict"); - nxt_python_print_exception(); - - Py_DECREF(scope); - - return PyErr_Format(PyExc_RuntimeError, - "failed to create 'asgi' dict"); - } - - if (nxt_slow_path(PyDict_SetItem(scope, nxt_py_asgi_str, asgi) == -1)) { - nxt_unit_req_alert(req, "Python failed to set 'scope.asgi' item"); - - Py_DECREF(asgi); - Py_DECREF(scope); - - return PyErr_Format(PyExc_RuntimeError, - "failed to set 'scope.asgi' item"); - } - - if (nxt_slow_path(PyDict_SetItem(asgi, nxt_py_version_str, - nxt_py_3_0_str) == -1)) - { - nxt_unit_req_alert(req, "Python failed to set 'asgi.version' item"); - - Py_DECREF(asgi); - Py_DECREF(scope); - - return PyErr_Format(PyExc_RuntimeError, - "failed to set 'asgi.version' item"); - } - - if (nxt_slow_path(PyDict_SetItem(asgi, nxt_py_spec_version_str, - spec_version) == -1)) - { - nxt_unit_req_alert(req, - "Python failed to set 'asgi.spec_version' item"); - - Py_DECREF(asgi); - Py_DECREF(scope); - - return PyErr_Format(PyExc_RuntimeError, - "failed to set 'asgi.spec_version' item"); - } - - Py_DECREF(asgi); - - return scope; -} - - -void -nxt_py_asgi_drain_wait(nxt_unit_request_info_t *req, nxt_queue_link_t *link) -{ - nxt_py_asgi_ctx_data_t *ctx_data; - - ctx_data = req->ctx->data; - - nxt_queue_insert_tail(&ctx_data->drain_queue, link); -} - - -void -nxt_py_asgi_dealloc(PyObject *self) -{ - PyObject_Del(self); -} - - -PyObject * -nxt_py_asgi_await(PyObject *self) -{ - Py_INCREF(self); - return self; -} - - -PyObject * -nxt_py_asgi_iter(PyObject *self) -{ - Py_INCREF(self); - return self; -} - - -PyObject * -nxt_py_asgi_next(PyObject *self) -{ - return NULL; -} - - -static void -nxt_python_asgi_done(void) -{ - nxt_py_asgi_str_done(); - - Py_XDECREF(nxt_py_port_read); -} - -#else /* !(NXT_HAVE_ASGI) */ - - -int -nxt_python_asgi_check(PyObject *obj) -{ - return 0; -} - - -int -nxt_python_asgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto) -{ - nxt_unit_alert(NULL, "ASGI not implemented"); - return NXT_UNIT_ERROR; -} - - -#endif /* NXT_HAVE_ASGI */ diff --git a/src/python/nxt_python_asgi.h b/src/python/nxt_python_asgi.h deleted file mode 100644 index 94478a36..00000000 --- a/src/python/nxt_python_asgi.h +++ /dev/null @@ -1,71 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PYTHON_ASGI_H_INCLUDED_ -#define _NXT_PYTHON_ASGI_H_INCLUDED_ - - -typedef PyObject * (*nxt_py_asgi_enum_header_cb)(void *ctx, int i, - PyObject *name, PyObject *val); - -void nxt_py_asgi_drain_wait(nxt_unit_request_info_t *req, - nxt_queue_link_t *link); - -typedef struct { - uint32_t fields_count; - uint32_t fields_size; -} nxt_py_asgi_calc_size_ctx_t; - -typedef struct { - nxt_unit_request_info_t *req; - uint64_t content_length; -} nxt_py_asgi_add_field_ctx_t; - -typedef struct { - nxt_queue_t drain_queue; - PyObject *loop_run_until_complete; - PyObject *loop_create_future; - PyObject *loop_create_task; - PyObject *loop_call_soon; - PyObject *loop_add_reader; - PyObject *loop_remove_reader; - PyObject *quit_future; - PyObject *quit_future_set_result; - PyObject **target_lifespans; -} nxt_py_asgi_ctx_data_t; - -PyObject *nxt_py_asgi_enum_headers(PyObject *headers, - nxt_py_asgi_enum_header_cb cb, void *data); - -PyObject *nxt_py_asgi_calc_size(void *data, int i, PyObject *n, PyObject *v); -PyObject *nxt_py_asgi_add_field(void *data, int i, PyObject *n, PyObject *v); - -PyObject *nxt_py_asgi_set_result_soon(nxt_unit_request_info_t *req, - nxt_py_asgi_ctx_data_t *ctx_data, PyObject *future, PyObject *result); -PyObject *nxt_py_asgi_new_msg(nxt_unit_request_info_t *req, PyObject *type); -PyObject *nxt_py_asgi_new_scope(nxt_unit_request_info_t *req, PyObject *type, - PyObject *spec_version); - -void nxt_py_asgi_dealloc(PyObject *self); -PyObject *nxt_py_asgi_await(PyObject *self); -PyObject *nxt_py_asgi_iter(PyObject *self); -PyObject *nxt_py_asgi_next(PyObject *self); - -int nxt_py_asgi_http_init(void); -PyObject *nxt_py_asgi_http_create(nxt_unit_request_info_t *req); -void nxt_py_asgi_http_data_handler(nxt_unit_request_info_t *req); -int nxt_py_asgi_http_drain(nxt_queue_link_t *lnk); -void nxt_py_asgi_http_close_handler(nxt_unit_request_info_t *req); - -int nxt_py_asgi_websocket_init(void); -PyObject *nxt_py_asgi_websocket_create(nxt_unit_request_info_t *req); -void nxt_py_asgi_websocket_handler(nxt_unit_websocket_frame_t *ws); -void nxt_py_asgi_websocket_close_handler(nxt_unit_request_info_t *req); - -int nxt_py_asgi_lifespan_startup(nxt_py_asgi_ctx_data_t *ctx_data); -int nxt_py_asgi_lifespan_shutdown(nxt_unit_ctx_t *ctx); - - -#endif /* _NXT_PYTHON_ASGI_H_INCLUDED_ */ diff --git a/src/python/nxt_python_asgi_http.c b/src/python/nxt_python_asgi_http.c deleted file mode 100644 index cdd6357e..00000000 --- a/src/python/nxt_python_asgi_http.c +++ /dev/null @@ -1,689 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - - -#include - -#if (NXT_HAVE_ASGI) - -#include -#include -#include -#include -#include - - -typedef struct { - PyObject_HEAD - nxt_unit_request_info_t *req; - nxt_queue_link_t link; - PyObject *receive_future; - PyObject *send_future; - uint64_t content_length; - uint64_t bytes_sent; - PyObject *send_body; - Py_ssize_t send_body_off; - uint8_t complete; - uint8_t closed; - uint8_t empty_body_received; -} nxt_py_asgi_http_t; - - -static PyObject *nxt_py_asgi_http_receive(PyObject *self, PyObject *none); -static PyObject *nxt_py_asgi_http_read_msg(nxt_py_asgi_http_t *http); -static PyObject *nxt_py_asgi_http_send(PyObject *self, PyObject *dict); -static PyObject *nxt_py_asgi_http_response_start(nxt_py_asgi_http_t *http, - PyObject *dict); -static PyObject *nxt_py_asgi_http_response_body(nxt_py_asgi_http_t *http, - PyObject *dict); -static void nxt_py_asgi_http_emit_disconnect(nxt_py_asgi_http_t *http); -static void nxt_py_asgi_http_set_result(nxt_py_asgi_http_t *http, - PyObject *future, PyObject *msg); -static PyObject *nxt_py_asgi_http_done(PyObject *self, PyObject *future); - - -static PyMethodDef nxt_py_asgi_http_methods[] = { - { "receive", nxt_py_asgi_http_receive, METH_NOARGS, 0 }, - { "send", nxt_py_asgi_http_send, METH_O, 0 }, - { "_done", nxt_py_asgi_http_done, METH_O, 0 }, - { NULL, NULL, 0, 0 } -}; - -static PyAsyncMethods nxt_py_asgi_async_methods = { - .am_await = nxt_py_asgi_await, -}; - -static PyTypeObject nxt_py_asgi_http_type = { - PyVarObject_HEAD_INIT(NULL, 0) - - .tp_name = "unit._asgi_http", - .tp_basicsize = sizeof(nxt_py_asgi_http_t), - .tp_dealloc = nxt_py_asgi_dealloc, - .tp_as_async = &nxt_py_asgi_async_methods, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "unit ASGI HTTP request object", - .tp_iter = nxt_py_asgi_iter, - .tp_iternext = nxt_py_asgi_next, - .tp_methods = nxt_py_asgi_http_methods, -}; - -static Py_ssize_t nxt_py_asgi_http_body_buf_size = 32 * 1024 * 1024; - - -int -nxt_py_asgi_http_init(void) -{ - if (nxt_slow_path(PyType_Ready(&nxt_py_asgi_http_type) != 0)) { - nxt_unit_alert(NULL, - "Python failed to initialize the 'http' type object"); - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -PyObject * -nxt_py_asgi_http_create(nxt_unit_request_info_t *req) -{ - nxt_py_asgi_http_t *http; - - http = PyObject_New(nxt_py_asgi_http_t, &nxt_py_asgi_http_type); - - if (nxt_fast_path(http != NULL)) { - http->req = req; - http->receive_future = NULL; - http->send_future = NULL; - http->content_length = -1; - http->bytes_sent = 0; - http->send_body = NULL; - http->send_body_off = 0; - http->complete = 0; - http->closed = 0; - http->empty_body_received = 0; - } - - return (PyObject *) http; -} - - -static PyObject * -nxt_py_asgi_http_receive(PyObject *self, PyObject *none) -{ - PyObject *msg, *future; - nxt_py_asgi_http_t *http; - nxt_py_asgi_ctx_data_t *ctx_data; - nxt_unit_request_info_t *req; - - http = (nxt_py_asgi_http_t *) self; - req = http->req; - - nxt_unit_req_debug(req, "asgi_http_receive"); - - if (nxt_slow_path(http->closed || http->complete )) { - msg = nxt_py_asgi_new_msg(req, nxt_py_http_disconnect_str); - - } else { - msg = nxt_py_asgi_http_read_msg(http); - } - - if (nxt_slow_path(msg == NULL)) { - return NULL; - } - - ctx_data = req->ctx->data; - - future = PyObject_CallObject(ctx_data->loop_create_future, NULL); - if (nxt_slow_path(future == NULL)) { - nxt_unit_req_alert(req, "Python failed to create Future object"); - nxt_python_print_exception(); - - Py_DECREF(msg); - - return PyErr_Format(PyExc_RuntimeError, - "failed to create Future object"); - } - - if (msg != Py_None) { - return nxt_py_asgi_set_result_soon(req, ctx_data, future, msg); - } - - http->receive_future = future; - Py_INCREF(http->receive_future); - - Py_DECREF(msg); - - return future; -} - - -static PyObject * -nxt_py_asgi_http_read_msg(nxt_py_asgi_http_t *http) -{ - char *body_buf; - ssize_t read_res; - PyObject *msg, *body; - Py_ssize_t size; - nxt_unit_request_info_t *req; - - req = http->req; - - size = req->content_length; - - if (size > nxt_py_asgi_http_body_buf_size) { - size = nxt_py_asgi_http_body_buf_size; - } - - if (size == 0) { - if (http->empty_body_received) { - Py_RETURN_NONE; - } - - http->empty_body_received = 1; - } - - if (size > 0) { - body = PyBytes_FromStringAndSize(NULL, size); - if (nxt_slow_path(body == NULL)) { - nxt_unit_req_alert(req, "Python failed to create body byte string"); - nxt_python_print_exception(); - - return PyErr_Format(PyExc_RuntimeError, - "failed to create Bytes object"); - } - - body_buf = PyBytes_AS_STRING(body); - - read_res = nxt_unit_request_read(req, body_buf, size); - - } else { - body = NULL; - read_res = 0; - } - - if (read_res > 0 || read_res == size) { - msg = nxt_py_asgi_new_msg(req, nxt_py_http_request_str); - if (nxt_slow_path(msg == NULL)) { - Py_XDECREF(body); - - return NULL; - } - -#define SET_ITEM(dict, key, value) \ - if (nxt_slow_path(PyDict_SetItem(dict, nxt_py_ ## key ## _str, value) \ - == -1)) \ - { \ - nxt_unit_req_alert(req, \ - "Python failed to set '" #dict "." #key "' item"); \ - PyErr_SetString(PyExc_RuntimeError, \ - "Python failed to set '" #dict "." #key "' item"); \ - goto fail; \ - } - - if (body != NULL) { - SET_ITEM(msg, body, body) - } - - if (req->content_length > 0) { - SET_ITEM(msg, more_body, Py_True) - } - -#undef SET_ITEM - - Py_XDECREF(body); - - return msg; - } - - Py_XDECREF(body); - - Py_RETURN_NONE; - -fail: - - Py_DECREF(msg); - Py_XDECREF(body); - - return NULL; -} - - -static PyObject * -nxt_py_asgi_http_send(PyObject *self, PyObject *dict) -{ - PyObject *type; - const char *type_str; - Py_ssize_t type_len; - nxt_py_asgi_http_t *http; - - static const nxt_str_t response_start = nxt_string("http.response.start"); - static const nxt_str_t response_body = nxt_string("http.response.body"); - - http = (nxt_py_asgi_http_t *) self; - - type = PyDict_GetItem(dict, nxt_py_type_str); - if (nxt_slow_path(type == NULL || !PyUnicode_Check(type))) { - nxt_unit_req_error(http->req, "asgi_http_send: " - "'type' is not a unicode string"); - return PyErr_Format(PyExc_TypeError, "'type' is not a unicode string"); - } - - type_str = PyUnicode_AsUTF8AndSize(type, &type_len); - - nxt_unit_req_debug(http->req, "asgi_http_send type is '%.*s'", - (int) type_len, type_str); - - if (nxt_unit_response_is_init(http->req)) { - if (nxt_str_eq(&response_body, type_str, (size_t) type_len)) { - return nxt_py_asgi_http_response_body(http, dict); - } - - return PyErr_Format(PyExc_RuntimeError, - "Expected ASGI message 'http.response.body', " - "but got '%U'", type); - } - - if (nxt_str_eq(&response_start, type_str, (size_t) type_len)) { - return nxt_py_asgi_http_response_start(http, dict); - } - - return PyErr_Format(PyExc_RuntimeError, - "Expected ASGI message 'http.response.start', " - "but got '%U'", type); -} - - -static PyObject * -nxt_py_asgi_http_response_start(nxt_py_asgi_http_t *http, PyObject *dict) -{ - int rc; - PyObject *status, *headers, *res; - nxt_py_asgi_calc_size_ctx_t calc_size_ctx; - nxt_py_asgi_add_field_ctx_t add_field_ctx; - - status = PyDict_GetItem(dict, nxt_py_status_str); - if (nxt_slow_path(status == NULL || !PyLong_Check(status))) { - nxt_unit_req_error(http->req, "asgi_http_response_start: " - "'status' is not an integer"); - return PyErr_Format(PyExc_TypeError, "'status' is not an integer"); - } - - calc_size_ctx.fields_size = 0; - calc_size_ctx.fields_count = 0; - - headers = PyDict_GetItem(dict, nxt_py_headers_str); - if (headers != NULL) { - res = nxt_py_asgi_enum_headers(headers, nxt_py_asgi_calc_size, - &calc_size_ctx); - if (nxt_slow_path(res == NULL)) { - return NULL; - } - - Py_DECREF(res); - } - - rc = nxt_unit_response_init(http->req, PyLong_AsLong(status), - calc_size_ctx.fields_count, - calc_size_ctx.fields_size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to allocate response object"); - } - - add_field_ctx.req = http->req; - add_field_ctx.content_length = -1; - - if (headers != NULL) { - res = nxt_py_asgi_enum_headers(headers, nxt_py_asgi_add_field, - &add_field_ctx); - if (nxt_slow_path(res == NULL)) { - return NULL; - } - - Py_DECREF(res); - } - - http->content_length = add_field_ctx.content_length; - - Py_INCREF(http); - return (PyObject *) http; -} - - -static PyObject * -nxt_py_asgi_http_response_body(nxt_py_asgi_http_t *http, PyObject *dict) -{ - int rc; - char *body_str; - ssize_t sent; - PyObject *body, *more_body, *future; - Py_ssize_t body_len, body_off; - nxt_py_asgi_ctx_data_t *ctx_data; - - if (nxt_slow_path(http->complete)) { - return PyErr_Format(PyExc_RuntimeError, - "Unexpected ASGI message 'http.response.body' " - "sent, after response already completed"); - } - - if (nxt_slow_path(http->send_future != NULL)) { - return PyErr_Format(PyExc_RuntimeError, "Concurrent send"); - } - - more_body = PyDict_GetItem(dict, nxt_py_more_body_str); - if (nxt_slow_path(more_body != NULL && !PyBool_Check(more_body))) { - return PyErr_Format(PyExc_TypeError, "'more_body' is not a bool"); - } - - body = PyDict_GetItem(dict, nxt_py_body_str); - - if (body != NULL) { - if (PyBytes_Check(body)) { - body_str = PyBytes_AS_STRING(body); - body_len = PyBytes_GET_SIZE(body); - - } else if (PyByteArray_Check(body)) { - body_str = PyByteArray_AS_STRING(body); - body_len = PyByteArray_GET_SIZE(body); - - } else { - return PyErr_Format(PyExc_TypeError, - "'body' is not a byte string or bytearray"); - } - - nxt_unit_req_debug(http->req, "asgi_http_response_body: %d, %d", - (int) body_len, (more_body == Py_True) ); - - if (nxt_slow_path(http->bytes_sent + body_len - > http->content_length)) - { - return PyErr_Format(PyExc_RuntimeError, - "Response content longer than Content-Length"); - } - - body_off = 0; - - ctx_data = http->req->ctx->data; - - while (body_len > 0) { - sent = nxt_unit_response_write_nb(http->req, body_str, body_len, 0); - if (nxt_slow_path(sent < 0)) { - return PyErr_Format(PyExc_RuntimeError, "failed to send body"); - } - - if (nxt_slow_path(sent == 0)) { - nxt_unit_req_debug(http->req, "asgi_http_response_body: " - "out of shared memory, %d", - (int) body_len); - - future = PyObject_CallObject(ctx_data->loop_create_future, - NULL); - if (nxt_slow_path(future == NULL)) { - nxt_unit_req_alert(http->req, - "Python failed to create Future object"); - nxt_python_print_exception(); - - return PyErr_Format(PyExc_RuntimeError, - "failed to create Future object"); - } - - http->send_body = body; - Py_INCREF(http->send_body); - http->send_body_off = body_off; - - nxt_py_asgi_drain_wait(http->req, &http->link); - - http->send_future = future; - Py_INCREF(http->send_future); - - return future; - } - - body_str += sent; - body_len -= sent; - body_off += sent; - http->bytes_sent += sent; - } - - } else { - nxt_unit_req_debug(http->req, "asgi_http_response_body: 0, %d", - (more_body == Py_True) ); - - if (!nxt_unit_response_is_sent(http->req)) { - rc = nxt_unit_response_send(http->req); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to send response"); - } - } - } - - if (more_body == NULL || more_body == Py_False) { - http->complete = 1; - - nxt_py_asgi_http_emit_disconnect(http); - } - - Py_INCREF(http); - return (PyObject *) http; -} - - -static void -nxt_py_asgi_http_emit_disconnect(nxt_py_asgi_http_t *http) -{ - PyObject *msg, *future; - - if (http->receive_future == NULL) { - return; - } - - msg = nxt_py_asgi_new_msg(http->req, nxt_py_http_disconnect_str); - if (nxt_slow_path(msg == NULL)) { - return; - } - - if (msg == Py_None) { - Py_DECREF(msg); - return; - } - - future = http->receive_future; - http->receive_future = NULL; - - nxt_py_asgi_http_set_result(http, future, msg); - - Py_DECREF(msg); -} - - -static void -nxt_py_asgi_http_set_result(nxt_py_asgi_http_t *http, PyObject *future, - PyObject *msg) -{ - PyObject *res; - - res = PyObject_CallMethodObjArgs(future, nxt_py_done_str, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_alert(http->req, "'done' call failed"); - nxt_python_print_exception(); - } - - if (nxt_fast_path(res == Py_False)) { - res = PyObject_CallMethodObjArgs(future, nxt_py_set_result_str, msg, - NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_alert(http->req, "'set_result' call failed"); - nxt_python_print_exception(); - } - - } else { - res = NULL; - } - - Py_XDECREF(res); - Py_DECREF(future); -} - - -void -nxt_py_asgi_http_data_handler(nxt_unit_request_info_t *req) -{ - PyObject *msg, *future; - nxt_py_asgi_http_t *http; - - http = req->data; - - nxt_unit_req_debug(req, "asgi_http_data_handler"); - - if (http->receive_future == NULL) { - return; - } - - msg = nxt_py_asgi_http_read_msg(http); - if (nxt_slow_path(msg == NULL)) { - return; - } - - if (msg == Py_None) { - Py_DECREF(msg); - return; - } - - future = http->receive_future; - http->receive_future = NULL; - - nxt_py_asgi_http_set_result(http, future, msg); - - Py_DECREF(msg); -} - - -int -nxt_py_asgi_http_drain(nxt_queue_link_t *lnk) -{ - char *body_str; - ssize_t sent; - PyObject *future, *exc, *res; - Py_ssize_t body_len; - nxt_py_asgi_http_t *http; - - http = nxt_container_of(lnk, nxt_py_asgi_http_t, link); - - body_str = PyBytes_AS_STRING(http->send_body) + http->send_body_off; - body_len = PyBytes_GET_SIZE(http->send_body) - http->send_body_off; - - nxt_unit_req_debug(http->req, "asgi_http_drain: %d", (int) body_len); - - while (body_len > 0) { - sent = nxt_unit_response_write_nb(http->req, body_str, body_len, 0); - if (nxt_slow_path(sent < 0)) { - goto fail; - } - - if (nxt_slow_path(sent == 0)) { - return NXT_UNIT_AGAIN; - } - - body_str += sent; - body_len -= sent; - - http->send_body_off += sent; - http->bytes_sent += sent; - } - - Py_CLEAR(http->send_body); - - future = http->send_future; - http->send_future = NULL; - - nxt_py_asgi_http_set_result(http, future, Py_None); - - return NXT_UNIT_OK; - -fail: - - exc = PyObject_CallFunctionObjArgs(PyExc_RuntimeError, - nxt_py_failed_to_send_body_str, - NULL); - if (nxt_slow_path(exc == NULL)) { - nxt_unit_req_alert(http->req, "RuntimeError create failed"); - nxt_python_print_exception(); - - exc = Py_None; - Py_INCREF(exc); - } - - future = http->send_future; - http->send_future = NULL; - - res = PyObject_CallMethodObjArgs(future, nxt_py_set_exception_str, exc, - NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_alert(http->req, "'set_exception' call failed"); - nxt_python_print_exception(); - } - - Py_XDECREF(res); - Py_DECREF(future); - Py_DECREF(exc); - - return NXT_UNIT_ERROR; -} - - -void -nxt_py_asgi_http_close_handler(nxt_unit_request_info_t *req) -{ - nxt_py_asgi_http_t *http; - - http = req->data; - - nxt_unit_req_debug(req, "asgi_http_close_handler"); - - if (nxt_fast_path(http != NULL)) { - http->closed = 1; - - nxt_py_asgi_http_emit_disconnect(http); - } -} - - -static PyObject * -nxt_py_asgi_http_done(PyObject *self, PyObject *future) -{ - int rc; - PyObject *res; - nxt_py_asgi_http_t *http; - - http = (nxt_py_asgi_http_t *) self; - - nxt_unit_req_debug(http->req, "asgi_http_done"); - - /* - * Get Future.result() and it raises an exception, if coroutine exited - * with exception. - */ - res = PyObject_CallMethodObjArgs(future, nxt_py_result_str, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_error(http->req, - "Python failed to call 'future.result()'"); - nxt_python_print_exception(); - - rc = NXT_UNIT_ERROR; - - } else { - Py_DECREF(res); - - rc = NXT_UNIT_OK; - } - - nxt_unit_request_done(http->req, rc); - - Py_RETURN_NONE; -} - - -#endif /* NXT_HAVE_ASGI */ diff --git a/src/python/nxt_python_asgi_lifespan.c b/src/python/nxt_python_asgi_lifespan.c deleted file mode 100644 index 041cca21..00000000 --- a/src/python/nxt_python_asgi_lifespan.c +++ /dev/null @@ -1,659 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - - -#include - -#if (NXT_HAVE_ASGI) - -#include -#include -#include - -#include - - -typedef struct { - PyObject_HEAD - nxt_py_asgi_ctx_data_t *ctx_data; - int disabled; - int startup_received; - int startup_sent; - int shutdown_received; - int shutdown_sent; - int shutdown_called; - PyObject *startup_future; - PyObject *shutdown_future; - PyObject *receive_future; - PyObject *state; -} nxt_py_asgi_lifespan_t; - -static PyObject *nxt_py_asgi_lifespan_target_startup( - nxt_py_asgi_ctx_data_t *ctx_data, nxt_python_target_t *target); -static int nxt_py_asgi_lifespan_target_shutdown( - nxt_py_asgi_lifespan_t *lifespan); -static PyObject *nxt_py_asgi_lifespan_receive(PyObject *self, PyObject *none); -static PyObject *nxt_py_asgi_lifespan_send(PyObject *self, PyObject *dict); -static PyObject *nxt_py_asgi_lifespan_send_startup( - nxt_py_asgi_lifespan_t *lifespan, int v, PyObject *dict); -static PyObject *nxt_py_asgi_lifespan_send_(nxt_py_asgi_lifespan_t *lifespan, - int v, int *sent, PyObject **future); -static PyObject *nxt_py_asgi_lifespan_send_shutdown( - nxt_py_asgi_lifespan_t *lifespan, int v, PyObject *dict); -static PyObject *nxt_py_asgi_lifespan_disable(nxt_py_asgi_lifespan_t *lifespan); -static PyObject *nxt_py_asgi_lifespan_done(PyObject *self, PyObject *future); -static void nxt_py_asgi_lifespan_dealloc(PyObject *self); - - -static PyMethodDef nxt_py_asgi_lifespan_methods[] = { - { "receive", nxt_py_asgi_lifespan_receive, METH_NOARGS, 0 }, - { "send", nxt_py_asgi_lifespan_send, METH_O, 0 }, - { "_done", nxt_py_asgi_lifespan_done, METH_O, 0 }, - { NULL, NULL, 0, 0 } -}; - -static PyMemberDef nxt_py_asgi_lifespan_members[] = { - { -#if PY_VERSION_HEX >= NXT_PYTHON_VER(3, 7) - .name = "state", -#else - .name = (char *)"state", -#endif - .type = T_OBJECT_EX, - .offset = offsetof(nxt_py_asgi_lifespan_t, state), - .flags = READONLY, -#if PY_VERSION_HEX >= NXT_PYTHON_VER(3, 7) - .doc = PyDoc_STR("lifespan.state") -#else - .doc = (char *)PyDoc_STR("lifespan.state") -#endif - }, - - { NULL, 0, 0, 0, NULL } -}; - -static PyAsyncMethods nxt_py_asgi_async_methods = { - .am_await = nxt_py_asgi_await, -}; - -static PyTypeObject nxt_py_asgi_lifespan_type = { - PyVarObject_HEAD_INIT(NULL, 0) - - .tp_name = "unit._asgi_lifespan", - .tp_basicsize = sizeof(nxt_py_asgi_lifespan_t), - .tp_dealloc = nxt_py_asgi_lifespan_dealloc, - .tp_as_async = &nxt_py_asgi_async_methods, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "unit ASGI Lifespan object", - .tp_iter = nxt_py_asgi_iter, - .tp_iternext = nxt_py_asgi_next, - .tp_methods = nxt_py_asgi_lifespan_methods, - .tp_members = nxt_py_asgi_lifespan_members, -}; - - -int -nxt_py_asgi_lifespan_startup(nxt_py_asgi_ctx_data_t *ctx_data) -{ - size_t size; - PyObject *lifespan; - PyObject **target_lifespans; - nxt_int_t i; - nxt_python_target_t *target; - - size = nxt_py_targets->count * sizeof(PyObject*); - - target_lifespans = nxt_unit_malloc(NULL, size); - if (nxt_slow_path(target_lifespans == NULL)) { - nxt_unit_alert(NULL, "Failed to allocate lifespan data"); - return NXT_UNIT_ERROR; - } - - memset(target_lifespans, 0, size); - - for (i = 0; i < nxt_py_targets->count; i++) { - target = &nxt_py_targets->target[i]; - - lifespan = nxt_py_asgi_lifespan_target_startup(ctx_data, target); - if (nxt_slow_path(lifespan == NULL)) { - return NXT_UNIT_ERROR; - } - - target_lifespans[i] = lifespan; - } - - ctx_data->target_lifespans = target_lifespans; - - return NXT_UNIT_OK; -} - - -static PyObject * -nxt_py_asgi_lifespan_target_startup(nxt_py_asgi_ctx_data_t *ctx_data, - nxt_python_target_t *target) -{ - PyObject *scope, *res, *py_task, *receive, *send, *done; - PyObject *stage2; - nxt_py_asgi_lifespan_t *lifespan, *ret; - - if (nxt_slow_path(PyType_Ready(&nxt_py_asgi_lifespan_type) != 0)) { - nxt_unit_alert(NULL, - "Python failed to initialize the 'asgi_lifespan' type object"); - return NULL; - } - - lifespan = PyObject_New(nxt_py_asgi_lifespan_t, &nxt_py_asgi_lifespan_type); - if (nxt_slow_path(lifespan == NULL)) { - nxt_unit_alert(NULL, "Python failed to create lifespan object"); - return NULL; - } - - ret = NULL; - - receive = PyObject_GetAttrString((PyObject *) lifespan, "receive"); - if (nxt_slow_path(receive == NULL)) { - nxt_unit_alert(NULL, "Python failed to get 'receive' method"); - goto release_lifespan; - } - - send = PyObject_GetAttrString((PyObject *) lifespan, "send"); - if (nxt_slow_path(receive == NULL)) { - nxt_unit_alert(NULL, "Python failed to get 'send' method"); - goto release_receive; - } - - done = PyObject_GetAttrString((PyObject *) lifespan, "_done"); - if (nxt_slow_path(receive == NULL)) { - nxt_unit_alert(NULL, "Python failed to get '_done' method"); - goto release_send; - } - - lifespan->startup_future = PyObject_CallObject(ctx_data->loop_create_future, - NULL); - if (nxt_slow_path(lifespan->startup_future == NULL)) { - nxt_unit_alert(NULL, "Python failed to create Future object"); - nxt_python_print_exception(); - - goto release_done; - } - - lifespan->ctx_data = ctx_data; - lifespan->disabled = 0; - lifespan->startup_received = 0; - lifespan->startup_sent = 0; - lifespan->shutdown_received = 0; - lifespan->shutdown_sent = 0; - lifespan->shutdown_called = 0; - lifespan->shutdown_future = NULL; - lifespan->receive_future = NULL; - lifespan->state = NULL; - - scope = nxt_py_asgi_new_scope(NULL, nxt_py_lifespan_str, nxt_py_2_0_str); - if (nxt_slow_path(scope == NULL)) { - goto release_future; - } - - lifespan->state = PyDict_New(); - if (nxt_slow_path(lifespan->state == NULL)) { - nxt_unit_req_error(NULL, - "Python failed to create 'state' dict"); - goto release_future; - } - - if (nxt_slow_path(PyDict_SetItem(scope, nxt_py_state_str, - lifespan->state) == -1)) - { - nxt_unit_req_error(NULL, - "Python failed to set 'scope.state' item"); - Py_CLEAR(lifespan->state); - goto release_future; - } - - if (!target->asgi_legacy) { - nxt_unit_req_debug(NULL, "Python call ASGI 3.0 application"); - - res = PyObject_CallFunctionObjArgs(target->application, - scope, receive, send, NULL); - - } else { - nxt_unit_req_debug(NULL, "Python call legacy application"); - - res = PyObject_CallFunctionObjArgs(target->application, scope, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_log(NULL, NXT_UNIT_LOG_INFO, - "ASGI Lifespan processing exception"); - nxt_python_print_exception(); - - lifespan->disabled = 1; - - Py_INCREF(lifespan); - ret = lifespan; - - goto release_scope; - } - - if (nxt_slow_path(PyCallable_Check(res) == 0)) { - nxt_unit_req_error(NULL, - "Legacy ASGI application returns not a callable"); - - Py_DECREF(res); - - goto release_scope; - } - - stage2 = res; - - res = PyObject_CallFunctionObjArgs(stage2, receive, send, NULL); - - Py_DECREF(stage2); - } - - if (nxt_slow_path(res == NULL)) { - nxt_unit_error(NULL, "Python failed to call the application"); - nxt_python_print_exception(); - goto release_scope; - } - - if (nxt_slow_path(!PyCoro_CheckExact(res))) { - nxt_unit_error(NULL, "Application result type is not a coroutine"); - Py_DECREF(res); - goto release_scope; - } - - py_task = PyObject_CallFunctionObjArgs(ctx_data->loop_create_task, res, - NULL); - if (nxt_slow_path(py_task == NULL)) { - nxt_unit_alert(NULL, "Python failed to call the create_task"); - nxt_python_print_exception(); - Py_DECREF(res); - goto release_scope; - } - - Py_DECREF(res); - - res = PyObject_CallMethodObjArgs(py_task, nxt_py_add_done_callback_str, - done, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(NULL, "Python failed to call 'task.add_done_callback'"); - nxt_python_print_exception(); - goto release_task; - } - - Py_DECREF(res); - - res = PyObject_CallFunctionObjArgs(ctx_data->loop_run_until_complete, - lifespan->startup_future, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(NULL, "Python failed to call loop.run_until_complete"); - nxt_python_print_exception(); - goto release_task; - } - - Py_DECREF(res); - - if (lifespan->startup_sent == 1 || lifespan->disabled) { - Py_INCREF(lifespan); - - ret = lifespan; - } - -release_task: - Py_DECREF(py_task); -release_scope: - Py_DECREF(scope); -release_future: - Py_CLEAR(lifespan->startup_future); -release_done: - Py_DECREF(done); -release_send: - Py_DECREF(send); -release_receive: - Py_DECREF(receive); -release_lifespan: - Py_DECREF(lifespan); - - return (PyObject *) ret; -} - - -int -nxt_py_asgi_lifespan_shutdown(nxt_unit_ctx_t *ctx) -{ - nxt_int_t i, ret; - nxt_py_asgi_lifespan_t *lifespan; - nxt_py_asgi_ctx_data_t *ctx_data; - - ctx_data = ctx->data; - - for (i = 0; i < nxt_py_targets->count; i++) { - lifespan = (nxt_py_asgi_lifespan_t *)ctx_data->target_lifespans[i]; - - ret = nxt_py_asgi_lifespan_target_shutdown(lifespan); - if (nxt_slow_path(ret != NXT_UNIT_OK)) { - return NXT_UNIT_ERROR; - } - } - - nxt_unit_free(NULL, ctx_data->target_lifespans); - - return NXT_UNIT_OK; -} - - -static int -nxt_py_asgi_lifespan_target_shutdown(nxt_py_asgi_lifespan_t *lifespan) -{ - PyObject *msg, *future, *res; - nxt_py_asgi_ctx_data_t *ctx_data; - - ctx_data = lifespan->ctx_data; - - if (nxt_slow_path(lifespan == NULL || lifespan->disabled)) { - return NXT_UNIT_OK; - } - - lifespan->shutdown_called = 1; - - if (lifespan->receive_future != NULL) { - future = lifespan->receive_future; - lifespan->receive_future = NULL; - - msg = nxt_py_asgi_new_msg(NULL, nxt_py_lifespan_shutdown_str); - - if (nxt_fast_path(msg != NULL)) { - res = PyObject_CallMethodObjArgs(future, nxt_py_set_result_str, - msg, NULL); - Py_XDECREF(res); - Py_DECREF(msg); - } - - Py_DECREF(future); - } - - if (lifespan->shutdown_sent) { - return NXT_UNIT_OK; - } - - lifespan->shutdown_future = PyObject_CallObject(ctx_data->loop_create_future, - NULL); - if (nxt_slow_path(lifespan->shutdown_future == NULL)) { - nxt_unit_alert(NULL, "Python failed to create Future object"); - nxt_python_print_exception(); - return NXT_UNIT_ERROR; - } - - res = PyObject_CallFunctionObjArgs(ctx_data->loop_run_until_complete, - lifespan->shutdown_future, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(NULL, "Python failed to call loop.run_until_complete"); - nxt_python_print_exception(); - return NXT_UNIT_ERROR; - } - - Py_DECREF(res); - Py_CLEAR(lifespan->shutdown_future); - - return NXT_UNIT_OK; -} - - -static PyObject * -nxt_py_asgi_lifespan_receive(PyObject *self, PyObject *none) -{ - PyObject *msg, *future; - nxt_py_asgi_lifespan_t *lifespan; - nxt_py_asgi_ctx_data_t *ctx_data; - - lifespan = (nxt_py_asgi_lifespan_t *) self; - ctx_data = lifespan->ctx_data; - - nxt_unit_debug(NULL, "asgi_lifespan_receive"); - - future = PyObject_CallObject(ctx_data->loop_create_future, NULL); - if (nxt_slow_path(future == NULL)) { - nxt_unit_alert(NULL, "Python failed to create Future object"); - nxt_python_print_exception(); - - return PyErr_Format(PyExc_RuntimeError, - "failed to create Future object"); - } - - if (!lifespan->startup_received) { - lifespan->startup_received = 1; - - msg = nxt_py_asgi_new_msg(NULL, nxt_py_lifespan_startup_str); - - return nxt_py_asgi_set_result_soon(NULL, ctx_data, future, msg); - } - - if (lifespan->shutdown_called && !lifespan->shutdown_received) { - lifespan->shutdown_received = 1; - - msg = nxt_py_asgi_new_msg(NULL, nxt_py_lifespan_shutdown_str); - - return nxt_py_asgi_set_result_soon(NULL, ctx_data, future, msg); - } - - Py_INCREF(future); - lifespan->receive_future = future; - - return future; -} - - -static PyObject * -nxt_py_asgi_lifespan_send(PyObject *self, PyObject *dict) -{ - PyObject *type, *msg; - const char *type_str; - Py_ssize_t type_len; - nxt_py_asgi_lifespan_t *lifespan; - - static const nxt_str_t startup_complete - = nxt_string("lifespan.startup.complete"); - static const nxt_str_t startup_failed - = nxt_string("lifespan.startup.failed"); - static const nxt_str_t shutdown_complete - = nxt_string("lifespan.shutdown.complete"); - static const nxt_str_t shutdown_failed - = nxt_string("lifespan.shutdown.failed"); - - lifespan = (nxt_py_asgi_lifespan_t *) self; - - type = PyDict_GetItem(dict, nxt_py_type_str); - if (nxt_slow_path(type == NULL || !PyUnicode_Check(type))) { - nxt_unit_error(NULL, - "asgi_lifespan_send: 'type' is not a unicode string"); - return PyErr_Format(PyExc_TypeError, - "'type' is not a unicode string"); - } - - type_str = PyUnicode_AsUTF8AndSize(type, &type_len); - - nxt_unit_debug(NULL, "asgi_lifespan_send type is '%.*s'", - (int) type_len, type_str); - - if (type_len == (Py_ssize_t) startup_complete.length - && memcmp(type_str, startup_complete.start, type_len) == 0) - { - return nxt_py_asgi_lifespan_send_startup(lifespan, 0, NULL); - } - - if (type_len == (Py_ssize_t) startup_failed.length - && memcmp(type_str, startup_failed.start, type_len) == 0) - { - msg = PyDict_GetItem(dict, nxt_py_message_str); - return nxt_py_asgi_lifespan_send_startup(lifespan, 1, msg); - } - - if (type_len == (Py_ssize_t) shutdown_complete.length - && memcmp(type_str, shutdown_complete.start, type_len) == 0) - { - return nxt_py_asgi_lifespan_send_shutdown(lifespan, 0, NULL); - } - - if (type_len == (Py_ssize_t) shutdown_failed.length - && memcmp(type_str, shutdown_failed.start, type_len) == 0) - { - msg = PyDict_GetItem(dict, nxt_py_message_str); - return nxt_py_asgi_lifespan_send_shutdown(lifespan, 1, msg); - } - - return nxt_py_asgi_lifespan_disable(lifespan); -} - - -static PyObject * -nxt_py_asgi_lifespan_send_startup(nxt_py_asgi_lifespan_t *lifespan, int v, - PyObject *message) -{ - const char *message_str; - Py_ssize_t message_len; - - if (nxt_slow_path(v != 0)) { - nxt_unit_error(NULL, "Application startup failed"); - - if (nxt_fast_path(message != NULL && PyUnicode_Check(message))) { - message_str = PyUnicode_AsUTF8AndSize(message, &message_len); - - nxt_unit_error(NULL, "%.*s", (int) message_len, message_str); - } - } - - return nxt_py_asgi_lifespan_send_(lifespan, v, - &lifespan->startup_sent, - &lifespan->startup_future); -} - - -static PyObject * -nxt_py_asgi_lifespan_send_(nxt_py_asgi_lifespan_t *lifespan, int v, int *sent, - PyObject **pfuture) -{ - PyObject *future, *res; - - if (*sent) { - return nxt_py_asgi_lifespan_disable(lifespan); - } - - *sent = 1 + v; - - if (*pfuture != NULL) { - future = *pfuture; - *pfuture = NULL; - - res = PyObject_CallMethodObjArgs(future, nxt_py_set_result_str, - Py_None, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(NULL, "Failed to call 'future.set_result'"); - nxt_python_print_exception(); - - return nxt_py_asgi_lifespan_disable(lifespan); - } - - Py_DECREF(res); - Py_DECREF(future); - } - - Py_INCREF(lifespan); - - return (PyObject *) lifespan; -} - - -static PyObject * -nxt_py_asgi_lifespan_disable(nxt_py_asgi_lifespan_t *lifespan) -{ - nxt_unit_warn(NULL, "Got invalid state transition on lifespan protocol"); - - lifespan->disabled = 1; - - return PyErr_Format(PyExc_AssertionError, - "Got invalid state transition on lifespan protocol"); -} - - -static PyObject * -nxt_py_asgi_lifespan_send_shutdown(nxt_py_asgi_lifespan_t *lifespan, int v, - PyObject *message) -{ - return nxt_py_asgi_lifespan_send_(lifespan, v, - &lifespan->shutdown_sent, - &lifespan->shutdown_future); -} - - -static PyObject * -nxt_py_asgi_lifespan_done(PyObject *self, PyObject *future) -{ - PyObject *res; - nxt_py_asgi_lifespan_t *lifespan; - - nxt_unit_debug(NULL, "asgi_lifespan_done"); - - lifespan = (nxt_py_asgi_lifespan_t *) self; - - if (lifespan->startup_sent == 0) { - lifespan->disabled = 1; - } - - /* - * Get Future.result() and it raises an exception, if coroutine exited - * with exception. - */ - res = PyObject_CallMethodObjArgs(future, nxt_py_result_str, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_log(NULL, NXT_UNIT_LOG_INFO, - "ASGI Lifespan processing exception"); - nxt_python_print_exception(); - } - - Py_XDECREF(res); - - if (lifespan->startup_future != NULL) { - future = lifespan->startup_future; - lifespan->startup_future = NULL; - - res = PyObject_CallMethodObjArgs(future, nxt_py_set_result_str, - Py_None, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(NULL, "Failed to call 'future.set_result'"); - nxt_python_print_exception(); - } - - Py_XDECREF(res); - Py_DECREF(future); - } - - if (lifespan->shutdown_future != NULL) { - future = lifespan->shutdown_future; - lifespan->shutdown_future = NULL; - - res = PyObject_CallMethodObjArgs(future, nxt_py_set_result_str, - Py_None, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_alert(NULL, "Failed to call 'future.set_result'"); - nxt_python_print_exception(); - } - - Py_XDECREF(res); - Py_DECREF(future); - } - - Py_RETURN_NONE; -} - - -static void -nxt_py_asgi_lifespan_dealloc(PyObject *self) -{ - nxt_py_asgi_lifespan_t *lifespan = (nxt_py_asgi_lifespan_t *)self; - - Py_CLEAR(lifespan->state); - PyObject_Del(self); -} - - -#endif /* NXT_HAVE_ASGI */ diff --git a/src/python/nxt_python_asgi_str.c b/src/python/nxt_python_asgi_str.c deleted file mode 100644 index 3bea87d5..00000000 --- a/src/python/nxt_python_asgi_str.c +++ /dev/null @@ -1,143 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - - -#include - -#if (NXT_HAVE_ASGI) - -#include -#include - - -PyObject *nxt_py_1_0_str; -PyObject *nxt_py_1_1_str; -PyObject *nxt_py_2_0_str; -PyObject *nxt_py_2_1_str; -PyObject *nxt_py_3_0_str; -PyObject *nxt_py_add_done_callback_str; -PyObject *nxt_py_asgi_str; -PyObject *nxt_py_bad_state_str; -PyObject *nxt_py_body_str; -PyObject *nxt_py_bytes_str; -PyObject *nxt_py_client_str; -PyObject *nxt_py_code_str; -PyObject *nxt_py_done_str; -PyObject *nxt_py_exception_str; -PyObject *nxt_py_failed_to_send_body_str; -PyObject *nxt_py_headers_str; -PyObject *nxt_py_http_str; -PyObject *nxt_py_http_disconnect_str; -PyObject *nxt_py_http_request_str; -PyObject *nxt_py_http_version_str; -PyObject *nxt_py_https_str; -PyObject *nxt_py_lifespan_str; -PyObject *nxt_py_lifespan_shutdown_str; -PyObject *nxt_py_lifespan_startup_str; -PyObject *nxt_py_method_str; -PyObject *nxt_py_message_str; -PyObject *nxt_py_message_too_big_str; -PyObject *nxt_py_more_body_str; -PyObject *nxt_py_path_str; -PyObject *nxt_py_query_string_str; -PyObject *nxt_py_raw_path_str; -PyObject *nxt_py_result_str; -PyObject *nxt_py_root_path_str; -PyObject *nxt_py_scheme_str; -PyObject *nxt_py_server_str; -PyObject *nxt_py_set_exception_str; -PyObject *nxt_py_set_result_str; -PyObject *nxt_py_spec_version_str; -PyObject *nxt_py_status_str; -PyObject *nxt_py_subprotocol_str; -PyObject *nxt_py_subprotocols_str; -PyObject *nxt_py_text_str; -PyObject *nxt_py_type_str; -PyObject *nxt_py_state_str; -PyObject *nxt_py_version_str; -PyObject *nxt_py_websocket_str; -PyObject *nxt_py_websocket_accept_str; -PyObject *nxt_py_websocket_close_str; -PyObject *nxt_py_websocket_connect_str; -PyObject *nxt_py_websocket_disconnect_str; -PyObject *nxt_py_websocket_receive_str; -PyObject *nxt_py_websocket_send_str; -PyObject *nxt_py_ws_str; -PyObject *nxt_py_wss_str; - -static nxt_python_string_t nxt_py_asgi_strings[] = { - { nxt_string("1.0"), &nxt_py_1_0_str }, - { nxt_string("1.1"), &nxt_py_1_1_str }, - { nxt_string("2.0"), &nxt_py_2_0_str }, - { nxt_string("2.1"), &nxt_py_2_1_str }, - { nxt_string("3.0"), &nxt_py_3_0_str }, - { nxt_string("add_done_callback"), &nxt_py_add_done_callback_str }, - { nxt_string("asgi"), &nxt_py_asgi_str }, - { nxt_string("bad state"), &nxt_py_bad_state_str }, - { nxt_string("body"), &nxt_py_body_str }, - { nxt_string("bytes"), &nxt_py_bytes_str }, - { nxt_string("client"), &nxt_py_client_str }, - { nxt_string("code"), &nxt_py_code_str }, - { nxt_string("done"), &nxt_py_done_str }, - { nxt_string("exception"), &nxt_py_exception_str }, - { nxt_string("failed to send body"), &nxt_py_failed_to_send_body_str }, - { nxt_string("headers"), &nxt_py_headers_str }, - { nxt_string("http"), &nxt_py_http_str }, - { nxt_string("http.disconnect"), &nxt_py_http_disconnect_str }, - { nxt_string("http.request"), &nxt_py_http_request_str }, - { nxt_string("http_version"), &nxt_py_http_version_str }, - { nxt_string("https"), &nxt_py_https_str }, - { nxt_string("lifespan"), &nxt_py_lifespan_str }, - { nxt_string("lifespan.shutdown"), &nxt_py_lifespan_shutdown_str }, - { nxt_string("lifespan.startup"), &nxt_py_lifespan_startup_str }, - { nxt_string("message"), &nxt_py_message_str }, - { nxt_string("message too big"), &nxt_py_message_too_big_str }, - { nxt_string("method"), &nxt_py_method_str }, - { nxt_string("more_body"), &nxt_py_more_body_str }, - { nxt_string("path"), &nxt_py_path_str }, - { nxt_string("query_string"), &nxt_py_query_string_str }, - { nxt_string("raw_path"), &nxt_py_raw_path_str }, - { nxt_string("result"), &nxt_py_result_str }, - { nxt_string("root_path"), &nxt_py_root_path_str }, - { nxt_string("scheme"), &nxt_py_scheme_str }, - { nxt_string("server"), &nxt_py_server_str }, - { nxt_string("set_exception"), &nxt_py_set_exception_str }, - { nxt_string("set_result"), &nxt_py_set_result_str }, - { nxt_string("spec_version"), &nxt_py_spec_version_str }, - { nxt_string("status"), &nxt_py_status_str }, - { nxt_string("subprotocol"), &nxt_py_subprotocol_str }, - { nxt_string("subprotocols"), &nxt_py_subprotocols_str }, - { nxt_string("text"), &nxt_py_text_str }, - { nxt_string("type"), &nxt_py_type_str }, - { nxt_string("state"), &nxt_py_state_str }, - { nxt_string("version"), &nxt_py_version_str }, - { nxt_string("websocket"), &nxt_py_websocket_str }, - { nxt_string("websocket.accept"), &nxt_py_websocket_accept_str }, - { nxt_string("websocket.close"), &nxt_py_websocket_close_str }, - { nxt_string("websocket.connect"), &nxt_py_websocket_connect_str }, - { nxt_string("websocket.disconnect"), &nxt_py_websocket_disconnect_str }, - { nxt_string("websocket.receive"), &nxt_py_websocket_receive_str }, - { nxt_string("websocket.send"), &nxt_py_websocket_send_str }, - { nxt_string("ws"), &nxt_py_ws_str }, - { nxt_string("wss"), &nxt_py_wss_str }, - { nxt_null_string, NULL }, -}; - - -int -nxt_py_asgi_str_init(void) -{ - return nxt_python_init_strings(nxt_py_asgi_strings); -} - - -void -nxt_py_asgi_str_done(void) -{ - nxt_python_done_strings(nxt_py_asgi_strings); -} - - -#endif /* NXT_HAVE_ASGI */ diff --git a/src/python/nxt_python_asgi_str.h b/src/python/nxt_python_asgi_str.h deleted file mode 100644 index 3c7a3ed9..00000000 --- a/src/python/nxt_python_asgi_str.h +++ /dev/null @@ -1,70 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_PYTHON_ASGI_STR_H_INCLUDED_ -#define _NXT_PYTHON_ASGI_STR_H_INCLUDED_ - - -extern PyObject *nxt_py_1_0_str; -extern PyObject *nxt_py_1_1_str; -extern PyObject *nxt_py_2_0_str; -extern PyObject *nxt_py_2_1_str; -extern PyObject *nxt_py_3_0_str; -extern PyObject *nxt_py_add_done_callback_str; -extern PyObject *nxt_py_asgi_str; -extern PyObject *nxt_py_bad_state_str; -extern PyObject *nxt_py_body_str; -extern PyObject *nxt_py_bytes_str; -extern PyObject *nxt_py_client_str; -extern PyObject *nxt_py_code_str; -extern PyObject *nxt_py_done_str; -extern PyObject *nxt_py_exception_str; -extern PyObject *nxt_py_failed_to_send_body_str; -extern PyObject *nxt_py_headers_str; -extern PyObject *nxt_py_http_str; -extern PyObject *nxt_py_http_disconnect_str; -extern PyObject *nxt_py_http_request_str; -extern PyObject *nxt_py_http_version_str; -extern PyObject *nxt_py_https_str; -extern PyObject *nxt_py_lifespan_str; -extern PyObject *nxt_py_lifespan_shutdown_str; -extern PyObject *nxt_py_lifespan_startup_str; -extern PyObject *nxt_py_method_str; -extern PyObject *nxt_py_message_str; -extern PyObject *nxt_py_message_too_big_str; -extern PyObject *nxt_py_more_body_str; -extern PyObject *nxt_py_path_str; -extern PyObject *nxt_py_query_string_str; -extern PyObject *nxt_py_result_str; -extern PyObject *nxt_py_raw_path_str; -extern PyObject *nxt_py_root_path_str; -extern PyObject *nxt_py_scheme_str; -extern PyObject *nxt_py_server_str; -extern PyObject *nxt_py_set_exception_str; -extern PyObject *nxt_py_set_result_str; -extern PyObject *nxt_py_spec_version_str; -extern PyObject *nxt_py_status_str; -extern PyObject *nxt_py_subprotocol_str; -extern PyObject *nxt_py_subprotocols_str; -extern PyObject *nxt_py_text_str; -extern PyObject *nxt_py_type_str; -extern PyObject *nxt_py_state_str; -extern PyObject *nxt_py_version_str; -extern PyObject *nxt_py_websocket_str; -extern PyObject *nxt_py_websocket_accept_str; -extern PyObject *nxt_py_websocket_close_str; -extern PyObject *nxt_py_websocket_connect_str; -extern PyObject *nxt_py_websocket_disconnect_str; -extern PyObject *nxt_py_websocket_receive_str; -extern PyObject *nxt_py_websocket_send_str; -extern PyObject *nxt_py_ws_str; -extern PyObject *nxt_py_wss_str; - - -int nxt_py_asgi_str_init(void); -void nxt_py_asgi_str_done(void); - - -#endif /* _NXT_PYTHON_ASGI_STR_H_INCLUDED_ */ diff --git a/src/python/nxt_python_asgi_websocket.c b/src/python/nxt_python_asgi_websocket.c deleted file mode 100644 index ab1d0324..00000000 --- a/src/python/nxt_python_asgi_websocket.c +++ /dev/null @@ -1,1091 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - - -#include - -#if (NXT_HAVE_ASGI) - -#include -#include -#include -#include -#include -#include -#include - - -enum { - NXT_WS_INIT, - NXT_WS_CONNECT, - NXT_WS_ACCEPTED, - NXT_WS_DISCONNECTED, - NXT_WS_CLOSED, -}; - - -typedef struct { - nxt_queue_link_t link; - nxt_unit_websocket_frame_t *frame; -} nxt_py_asgi_penging_frame_t; - - -typedef struct { - PyObject_HEAD - nxt_unit_request_info_t *req; - PyObject *receive_future; - PyObject *receive_exc_str; - int state; - nxt_queue_t pending_frames; - uint64_t pending_payload_len; - uint64_t pending_frame_len; - int pending_fins; -} nxt_py_asgi_websocket_t; - - -static PyObject *nxt_py_asgi_websocket_receive(PyObject *self, PyObject *none); -static PyObject *nxt_py_asgi_websocket_send(PyObject *self, PyObject *dict); -static PyObject *nxt_py_asgi_websocket_accept(nxt_py_asgi_websocket_t *ws, - PyObject *dict); -static PyObject *nxt_py_asgi_websocket_close(nxt_py_asgi_websocket_t *ws, - PyObject *dict); -static PyObject *nxt_py_asgi_websocket_send_frame(nxt_py_asgi_websocket_t *ws, - PyObject *dict); -static void nxt_py_asgi_websocket_receive_done(nxt_py_asgi_websocket_t *ws, - PyObject *msg); -static void nxt_py_asgi_websocket_receive_fail(nxt_py_asgi_websocket_t *ws, - PyObject *exc); -static void nxt_py_asgi_websocket_suspend_frame(nxt_unit_websocket_frame_t *f); -static PyObject *nxt_py_asgi_websocket_pop_msg(nxt_py_asgi_websocket_t *ws, - nxt_unit_websocket_frame_t *frame); -static uint64_t nxt_py_asgi_websocket_pending_len( - nxt_py_asgi_websocket_t *ws); -static nxt_unit_websocket_frame_t *nxt_py_asgi_websocket_pop_frame( - nxt_py_asgi_websocket_t *ws); -static PyObject *nxt_py_asgi_websocket_disconnect_msg( - nxt_py_asgi_websocket_t *ws); -static PyObject *nxt_py_asgi_websocket_done(PyObject *self, PyObject *future); - - -static PyMethodDef nxt_py_asgi_websocket_methods[] = { - { "receive", nxt_py_asgi_websocket_receive, METH_NOARGS, 0 }, - { "send", nxt_py_asgi_websocket_send, METH_O, 0 }, - { "_done", nxt_py_asgi_websocket_done, METH_O, 0 }, - { NULL, NULL, 0, 0 } -}; - -static PyAsyncMethods nxt_py_asgi_async_methods = { - .am_await = nxt_py_asgi_await, -}; - -static PyTypeObject nxt_py_asgi_websocket_type = { - PyVarObject_HEAD_INIT(NULL, 0) - - .tp_name = "unit._asgi_websocket", - .tp_basicsize = sizeof(nxt_py_asgi_websocket_t), - .tp_dealloc = nxt_py_asgi_dealloc, - .tp_as_async = &nxt_py_asgi_async_methods, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "unit ASGI WebSocket connection object", - .tp_iter = nxt_py_asgi_iter, - .tp_iternext = nxt_py_asgi_next, - .tp_methods = nxt_py_asgi_websocket_methods, -}; - -static uint64_t nxt_py_asgi_ws_max_frame_size = 1024 * 1024; -static uint64_t nxt_py_asgi_ws_max_buffer_size = 10 * 1024 * 1024; - - -int -nxt_py_asgi_websocket_init(void) -{ - if (nxt_slow_path(PyType_Ready(&nxt_py_asgi_websocket_type) != 0)) { - nxt_unit_alert(NULL, - "Python failed to initialize the \"asgi_websocket\" type object"); - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -PyObject * -nxt_py_asgi_websocket_create(nxt_unit_request_info_t *req) -{ - nxt_py_asgi_websocket_t *ws; - - ws = PyObject_New(nxt_py_asgi_websocket_t, &nxt_py_asgi_websocket_type); - - if (nxt_fast_path(ws != NULL)) { - ws->req = req; - ws->receive_future = NULL; - ws->receive_exc_str = NULL; - ws->state = NXT_WS_INIT; - nxt_queue_init(&ws->pending_frames); - ws->pending_payload_len = 0; - ws->pending_frame_len = 0; - ws->pending_fins = 0; - } - - return (PyObject *) ws; -} - - -static PyObject * -nxt_py_asgi_websocket_receive(PyObject *self, PyObject *none) -{ - PyObject *future, *msg; - nxt_py_asgi_ctx_data_t *ctx_data; - nxt_py_asgi_websocket_t *ws; - - ws = (nxt_py_asgi_websocket_t *) self; - - nxt_unit_req_debug(ws->req, "asgi_websocket_receive"); - - /* If exception happened out of receive() call, raise it now. */ - if (nxt_slow_path(ws->receive_exc_str != NULL)) { - PyErr_SetObject(PyExc_RuntimeError, ws->receive_exc_str); - - ws->receive_exc_str = NULL; - - return NULL; - } - - if (nxt_slow_path(ws->state == NXT_WS_CLOSED)) { - nxt_unit_req_error(ws->req, - "receive() called for closed WebSocket"); - - return PyErr_Format(PyExc_RuntimeError, - "WebSocket already closed"); - } - - ctx_data = ws->req->ctx->data; - - future = PyObject_CallObject(ctx_data->loop_create_future, NULL); - if (nxt_slow_path(future == NULL)) { - nxt_unit_req_alert(ws->req, "Python failed to create Future object"); - nxt_python_print_exception(); - - return PyErr_Format(PyExc_RuntimeError, - "failed to create Future object"); - } - - if (nxt_slow_path(ws->state == NXT_WS_INIT)) { - ws->state = NXT_WS_CONNECT; - - msg = nxt_py_asgi_new_msg(ws->req, nxt_py_websocket_connect_str); - - return nxt_py_asgi_set_result_soon(ws->req, ctx_data, future, msg); - } - - if (ws->pending_fins > 0) { - msg = nxt_py_asgi_websocket_pop_msg(ws, NULL); - - return nxt_py_asgi_set_result_soon(ws->req, ctx_data, future, msg); - } - - if (nxt_slow_path(ws->state == NXT_WS_DISCONNECTED)) { - msg = nxt_py_asgi_websocket_disconnect_msg(ws); - - return nxt_py_asgi_set_result_soon(ws->req, ctx_data, future, msg); - } - - ws->receive_future = future; - Py_INCREF(ws->receive_future); - - return future; -} - - -static PyObject * -nxt_py_asgi_websocket_send(PyObject *self, PyObject *dict) -{ - PyObject *type; - const char *type_str; - Py_ssize_t type_len; - nxt_py_asgi_websocket_t *ws; - - static const nxt_str_t websocket_accept = nxt_string("websocket.accept"); - static const nxt_str_t websocket_close = nxt_string("websocket.close"); - static const nxt_str_t websocket_send = nxt_string("websocket.send"); - - ws = (nxt_py_asgi_websocket_t *) self; - - type = PyDict_GetItem(dict, nxt_py_type_str); - if (nxt_slow_path(type == NULL || !PyUnicode_Check(type))) { - nxt_unit_req_error(ws->req, "asgi_websocket_send: " - "'type' is not a unicode string"); - return PyErr_Format(PyExc_TypeError, - "'type' is not a unicode string"); - } - - type_str = PyUnicode_AsUTF8AndSize(type, &type_len); - - nxt_unit_req_debug(ws->req, "asgi_websocket_send type is '%.*s'", - (int) type_len, type_str); - - if (type_len == (Py_ssize_t) websocket_accept.length - && memcmp(type_str, websocket_accept.start, type_len) == 0) - { - return nxt_py_asgi_websocket_accept(ws, dict); - } - - if (type_len == (Py_ssize_t) websocket_close.length - && memcmp(type_str, websocket_close.start, type_len) == 0) - { - return nxt_py_asgi_websocket_close(ws, dict); - } - - if (type_len == (Py_ssize_t) websocket_send.length - && memcmp(type_str, websocket_send.start, type_len) == 0) - { - return nxt_py_asgi_websocket_send_frame(ws, dict); - } - - nxt_unit_req_error(ws->req, "asgi_websocket_send: " - "unexpected 'type': '%.*s'", (int) type_len, type_str); - return PyErr_Format(PyExc_AssertionError, "unexpected 'type': '%U'", type); -} - - -static PyObject * -nxt_py_asgi_websocket_accept(nxt_py_asgi_websocket_t *ws, PyObject *dict) -{ - int rc; - char *subprotocol_str; - PyObject *res, *headers, *subprotocol; - Py_ssize_t subprotocol_len; - nxt_py_asgi_calc_size_ctx_t calc_size_ctx; - nxt_py_asgi_add_field_ctx_t add_field_ctx; - - static const nxt_str_t ws_protocol = nxt_string("sec-websocket-protocol"); - - switch(ws->state) { - case NXT_WS_INIT: - return PyErr_Format(PyExc_RuntimeError, - "WebSocket connect not received"); - case NXT_WS_CONNECT: - break; - - case NXT_WS_ACCEPTED: - return PyErr_Format(PyExc_RuntimeError, "WebSocket already accepted"); - - case NXT_WS_DISCONNECTED: - return PyErr_Format(PyExc_RuntimeError, "WebSocket disconnected"); - - case NXT_WS_CLOSED: - return PyErr_Format(PyExc_RuntimeError, "WebSocket already closed"); - } - - if (nxt_slow_path(nxt_unit_response_is_websocket(ws->req))) { - return PyErr_Format(PyExc_RuntimeError, "WebSocket already accepted"); - } - - if (nxt_slow_path(nxt_unit_response_is_sent(ws->req))) { - return PyErr_Format(PyExc_RuntimeError, "response already sent"); - } - - calc_size_ctx.fields_size = 0; - calc_size_ctx.fields_count = 0; - - headers = PyDict_GetItem(dict, nxt_py_headers_str); - if (headers != NULL) { - res = nxt_py_asgi_enum_headers(headers, nxt_py_asgi_calc_size, - &calc_size_ctx); - if (nxt_slow_path(res == NULL)) { - return NULL; - } - } - - subprotocol = PyDict_GetItem(dict, nxt_py_subprotocol_str); - if (subprotocol != NULL && PyUnicode_Check(subprotocol)) { - subprotocol_str = PyUnicode_DATA(subprotocol); - subprotocol_len = PyUnicode_GET_LENGTH(subprotocol); - - calc_size_ctx.fields_size += ws_protocol.length + subprotocol_len; - calc_size_ctx.fields_count++; - - } else { - subprotocol_str = NULL; - subprotocol_len = 0; - } - - rc = nxt_unit_response_init(ws->req, 101, - calc_size_ctx.fields_count, - calc_size_ctx.fields_size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to allocate response object"); - } - - add_field_ctx.req = ws->req; - add_field_ctx.content_length = -1; - - if (headers != NULL) { - res = nxt_py_asgi_enum_headers(headers, nxt_py_asgi_add_field, - &add_field_ctx); - if (nxt_slow_path(res == NULL)) { - return NULL; - } - } - - if (subprotocol_len > 0) { - rc = nxt_unit_response_add_field(ws->req, - (const char *) ws_protocol.start, - ws_protocol.length, - subprotocol_str, subprotocol_len); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to add header"); - } - } - - rc = nxt_unit_response_send(ws->req); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, "failed to send response"); - } - - ws->state = NXT_WS_ACCEPTED; - - Py_INCREF(ws); - - return (PyObject *) ws; -} - - -static PyObject * -nxt_py_asgi_websocket_close(nxt_py_asgi_websocket_t *ws, PyObject *dict) -{ - int rc; - uint16_t status_code; - PyObject *code; - - if (nxt_slow_path(ws->state == NXT_WS_INIT)) { - return PyErr_Format(PyExc_RuntimeError, - "WebSocket connect not received"); - } - - if (nxt_slow_path(ws->state == NXT_WS_DISCONNECTED)) { - return PyErr_Format(PyExc_RuntimeError, "WebSocket disconnected"); - } - - if (nxt_slow_path(ws->state == NXT_WS_CLOSED)) { - return PyErr_Format(PyExc_RuntimeError, "WebSocket already closed"); - } - - if (nxt_unit_response_is_websocket(ws->req)) { - code = PyDict_GetItem(dict, nxt_py_code_str); - if (nxt_slow_path(code != NULL && !PyLong_Check(code))) { - return PyErr_Format(PyExc_TypeError, "'code' is not integer"); - } - - status_code = (code != NULL) ? htons(PyLong_AsLong(code)) - : htons(NXT_WEBSOCKET_CR_NORMAL); - - rc = nxt_unit_websocket_send(ws->req, NXT_WEBSOCKET_OP_CLOSE, - 1, &status_code, 2); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to send close frame"); - } - - } else { - rc = nxt_unit_response_init(ws->req, 403, 0, 0); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to allocate response object"); - } - - rc = nxt_unit_response_send(ws->req); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to send response"); - } - } - - ws->state = NXT_WS_CLOSED; - - Py_INCREF(ws); - - return (PyObject *) ws; -} - - -static PyObject * -nxt_py_asgi_websocket_send_frame(nxt_py_asgi_websocket_t *ws, PyObject *dict) -{ - int rc; - uint8_t opcode; - PyObject *bytes, *text; - const void *buf; - Py_ssize_t buf_size; - - if (nxt_slow_path(ws->state == NXT_WS_INIT)) { - return PyErr_Format(PyExc_RuntimeError, - "WebSocket connect not received"); - } - - if (nxt_slow_path(ws->state == NXT_WS_CONNECT)) { - return PyErr_Format(PyExc_RuntimeError, - "WebSocket not accepted yet"); - } - - if (nxt_slow_path(ws->state == NXT_WS_DISCONNECTED)) { - return PyErr_Format(PyExc_RuntimeError, "WebSocket disconnected"); - } - - if (nxt_slow_path(ws->state == NXT_WS_CLOSED)) { - return PyErr_Format(PyExc_RuntimeError, "WebSocket already closed"); - } - - bytes = PyDict_GetItem(dict, nxt_py_bytes_str); - if (bytes == Py_None) { - bytes = NULL; - } - - if (nxt_slow_path(bytes != NULL && !PyBytes_Check(bytes))) { - return PyErr_Format(PyExc_TypeError, - "'bytes' is not a byte string"); - } - - text = PyDict_GetItem(dict, nxt_py_text_str); - if (text == Py_None) { - text = NULL; - } - - if (nxt_slow_path(text != NULL && !PyUnicode_Check(text))) { - return PyErr_Format(PyExc_TypeError, - "'text' is not a unicode string"); - } - - if (nxt_slow_path(((bytes != NULL) ^ (text != NULL)) == 0)) { - return PyErr_Format(PyExc_ValueError, - "Exactly one of 'bytes' or 'text' must be non-None"); - } - - if (bytes != NULL) { - buf = PyBytes_AS_STRING(bytes); - buf_size = PyBytes_GET_SIZE(bytes); - opcode = NXT_WEBSOCKET_OP_BINARY; - - } else { - buf = PyUnicode_AsUTF8AndSize(text, &buf_size); - opcode = NXT_WEBSOCKET_OP_TEXT; - } - - rc = nxt_unit_websocket_send(ws->req, opcode, 1, buf, buf_size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, "failed to send close frame"); - } - - Py_INCREF(ws); - return (PyObject *) ws; -} - - -void -nxt_py_asgi_websocket_handler(nxt_unit_websocket_frame_t *frame) -{ - uint8_t opcode; - uint16_t status_code; - uint64_t rest; - PyObject *msg, *exc; - nxt_py_asgi_websocket_t *ws; - - ws = frame->req->data; - - nxt_unit_req_debug(ws->req, "asgi_websocket_handler"); - - opcode = frame->header->opcode; - if (nxt_slow_path(opcode != NXT_WEBSOCKET_OP_CONT - && opcode != NXT_WEBSOCKET_OP_TEXT - && opcode != NXT_WEBSOCKET_OP_BINARY - && opcode != NXT_WEBSOCKET_OP_CLOSE)) - { - nxt_unit_websocket_done(frame); - - nxt_unit_req_debug(ws->req, - "asgi_websocket_handler: ignore frame with opcode %d", - opcode); - - return; - } - - if (nxt_slow_path(ws->state != NXT_WS_ACCEPTED)) { - nxt_unit_websocket_done(frame); - - goto bad_state; - } - - rest = nxt_py_asgi_ws_max_frame_size - ws->pending_frame_len; - - if (nxt_slow_path(frame->payload_len > rest)) { - nxt_unit_websocket_done(frame); - - goto too_big; - } - - rest = nxt_py_asgi_ws_max_buffer_size - ws->pending_payload_len; - - if (nxt_slow_path(frame->payload_len > rest)) { - nxt_unit_websocket_done(frame); - - goto too_big; - } - - if (ws->receive_future == NULL || frame->header->fin == 0) { - nxt_py_asgi_websocket_suspend_frame(frame); - - return; - } - - if (!nxt_queue_is_empty(&ws->pending_frames)) { - if (nxt_slow_path(opcode == NXT_WEBSOCKET_OP_TEXT - || opcode == NXT_WEBSOCKET_OP_BINARY)) - { - nxt_unit_req_alert(ws->req, - "Invalid state: pending frames with active receiver. " - "CONT frame expected. (%d)", opcode); - - PyErr_SetString(PyExc_AssertionError, - "Invalid state: pending frames with active receiver. " - "CONT frame expected."); - - nxt_unit_websocket_done(frame); - - return; - } - } - - msg = nxt_py_asgi_websocket_pop_msg(ws, frame); - if (nxt_slow_path(msg == NULL)) { - exc = PyErr_Occurred(); - Py_INCREF(exc); - - goto raise; - } - - nxt_py_asgi_websocket_receive_done(ws, msg); - - return; - -bad_state: - - if (ws->receive_future == NULL) { - ws->receive_exc_str = nxt_py_bad_state_str; - - return; - } - - exc = PyObject_CallFunctionObjArgs(PyExc_RuntimeError, - nxt_py_bad_state_str, - NULL); - if (nxt_slow_path(exc == NULL)) { - nxt_unit_req_alert(ws->req, "RuntimeError create failed"); - nxt_python_print_exception(); - - exc = Py_None; - Py_INCREF(exc); - } - - goto raise; - -too_big: - - status_code = htons(NXT_WEBSOCKET_CR_MESSAGE_TOO_BIG); - - (void) nxt_unit_websocket_send(ws->req, NXT_WEBSOCKET_OP_CLOSE, - 1, &status_code, 2); - - ws->state = NXT_WS_CLOSED; - - if (ws->receive_future == NULL) { - ws->receive_exc_str = nxt_py_message_too_big_str; - - return; - } - - exc = PyObject_CallFunctionObjArgs(PyExc_RuntimeError, - nxt_py_message_too_big_str, - NULL); - if (nxt_slow_path(exc == NULL)) { - nxt_unit_req_alert(ws->req, "RuntimeError create failed"); - nxt_python_print_exception(); - - exc = Py_None; - Py_INCREF(exc); - } - -raise: - - nxt_py_asgi_websocket_receive_fail(ws, exc); -} - - -static void -nxt_py_asgi_websocket_receive_done(nxt_py_asgi_websocket_t *ws, PyObject *msg) -{ - PyObject *future, *res; - - future = ws->receive_future; - ws->receive_future = NULL; - - res = PyObject_CallMethodObjArgs(future, nxt_py_set_result_str, msg, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_alert(ws->req, "'set_result' call failed"); - nxt_python_print_exception(); - } - - Py_XDECREF(res); - Py_DECREF(future); - - Py_DECREF(msg); -} - - -static void -nxt_py_asgi_websocket_receive_fail(nxt_py_asgi_websocket_t *ws, PyObject *exc) -{ - PyObject *future, *res; - - future = ws->receive_future; - ws->receive_future = NULL; - - res = PyObject_CallMethodObjArgs(future, nxt_py_set_exception_str, exc, - NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_alert(ws->req, "'set_exception' call failed"); - nxt_python_print_exception(); - } - - Py_XDECREF(res); - Py_DECREF(future); - - Py_DECREF(exc); -} - - -static void -nxt_py_asgi_websocket_suspend_frame(nxt_unit_websocket_frame_t *frame) -{ - int rc; - nxt_py_asgi_websocket_t *ws; - nxt_py_asgi_penging_frame_t *p; - - nxt_unit_req_debug(frame->req, "asgi_websocket_suspend_frame: " - "%d, %"PRIu64", %d", - frame->header->opcode, frame->payload_len, - frame->header->fin); - - ws = frame->req->data; - - rc = nxt_unit_websocket_retain(frame); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - nxt_unit_req_alert(ws->req, "Failed to retain frame for suspension."); - - nxt_unit_websocket_done(frame); - - PyErr_SetString(PyExc_RuntimeError, - "Failed to retain frame for suspension."); - - return; - } - - p = nxt_unit_malloc(frame->req->ctx, sizeof(nxt_py_asgi_penging_frame_t)); - if (nxt_slow_path(p == NULL)) { - nxt_unit_req_alert(ws->req, - "Failed to allocate buffer to suspend frame."); - - nxt_unit_websocket_done(frame); - - PyErr_SetString(PyExc_RuntimeError, - "Failed to allocate buffer to suspend frame."); - - return; - } - - p->frame = frame; - nxt_queue_insert_tail(&ws->pending_frames, &p->link); - - ws->pending_payload_len += frame->payload_len; - ws->pending_fins += frame->header->fin; - - if (frame->header->fin) { - ws->pending_frame_len = 0; - - } else { - if (frame->header->opcode == NXT_WEBSOCKET_OP_CONT) { - ws->pending_frame_len += frame->payload_len; - - } else { - ws->pending_frame_len = frame->payload_len; - } - } -} - - -static PyObject * -nxt_py_asgi_websocket_pop_msg(nxt_py_asgi_websocket_t *ws, - nxt_unit_websocket_frame_t *frame) -{ - int fin; - char *buf; - uint8_t code_buf[2], opcode; - uint16_t code; - PyObject *msg, *data, *type, *data_key; - uint64_t payload_len; - nxt_unit_websocket_frame_t *fin_frame; - - nxt_unit_req_debug(ws->req, "asgi_websocket_pop_msg"); - - fin_frame = NULL; - - if (nxt_queue_is_empty(&ws->pending_frames) - || (frame != NULL - && frame->header->opcode == NXT_WEBSOCKET_OP_CLOSE)) - { - payload_len = frame->payload_len; - - } else { - if (frame != NULL) { - payload_len = ws->pending_payload_len + frame->payload_len; - fin_frame = frame; - - } else { - payload_len = nxt_py_asgi_websocket_pending_len(ws); - } - - frame = nxt_py_asgi_websocket_pop_frame(ws); - } - - opcode = frame->header->opcode; - - if (nxt_slow_path(opcode == NXT_WEBSOCKET_OP_CONT)) { - nxt_unit_req_alert(ws->req, - "Invalid state: attempt to process CONT frame."); - - nxt_unit_websocket_done(frame); - - return PyErr_Format(PyExc_AssertionError, - "Invalid state: attempt to process CONT frame."); - } - - type = nxt_py_websocket_receive_str; - - switch (opcode) { - case NXT_WEBSOCKET_OP_TEXT: - buf = nxt_unit_malloc(frame->req->ctx, payload_len); - if (nxt_slow_path(buf == NULL)) { - nxt_unit_req_alert(ws->req, - "Failed to allocate buffer for payload (%d).", - (int) payload_len); - - nxt_unit_websocket_done(frame); - - return PyErr_Format(PyExc_RuntimeError, - "Failed to allocate buffer for payload (%d).", - (int) payload_len); - } - - data = NULL; - data_key = nxt_py_text_str; - - break; - - case NXT_WEBSOCKET_OP_BINARY: - data = PyBytes_FromStringAndSize(NULL, payload_len); - if (nxt_slow_path(data == NULL)) { - nxt_unit_req_alert(ws->req, - "Failed to create Bytes for payload (%d).", - (int) payload_len); - nxt_python_print_exception(); - - nxt_unit_websocket_done(frame); - - return PyErr_Format(PyExc_RuntimeError, - "Failed to create Bytes for payload."); - } - - buf = (char *) PyBytes_AS_STRING(data); - data_key = nxt_py_bytes_str; - - break; - - case NXT_WEBSOCKET_OP_CLOSE: - if (frame->payload_len >= 2) { - nxt_unit_websocket_read(frame, code_buf, 2); - code = ((uint16_t) code_buf[0]) << 8 | code_buf[1]; - - } else { - code = NXT_WEBSOCKET_CR_NORMAL; - } - - nxt_unit_websocket_done(frame); - - data = PyLong_FromLong(code); - if (nxt_slow_path(data == NULL)) { - nxt_unit_req_alert(ws->req, - "Failed to create Long from code %d.", - (int) code); - nxt_python_print_exception(); - - return PyErr_Format(PyExc_RuntimeError, - "Failed to create Long from code %d.", - (int) code); - } - - buf = NULL; - type = nxt_py_websocket_disconnect_str; - data_key = nxt_py_code_str; - - break; - - default: - nxt_unit_req_alert(ws->req, "Unexpected opcode %d", opcode); - - nxt_unit_websocket_done(frame); - - return PyErr_Format(PyExc_AssertionError, "Unexpected opcode %d", - opcode); - } - - if (buf != NULL) { - fin = frame->header->fin; - buf += nxt_unit_websocket_read(frame, buf, frame->payload_len); - - nxt_unit_websocket_done(frame); - - if (!fin) { - while (!nxt_queue_is_empty(&ws->pending_frames)) { - frame = nxt_py_asgi_websocket_pop_frame(ws); - fin = frame->header->fin; - - buf += nxt_unit_websocket_read(frame, buf, frame->payload_len); - - nxt_unit_websocket_done(frame); - - if (fin) { - break; - } - } - - if (fin_frame != NULL) { - buf += nxt_unit_websocket_read(fin_frame, buf, - fin_frame->payload_len); - nxt_unit_websocket_done(fin_frame); - } - } - - if (opcode == NXT_WEBSOCKET_OP_TEXT) { - buf -= payload_len; - - data = PyUnicode_DecodeUTF8(buf, payload_len, NULL); - - nxt_unit_free(ws->req->ctx, buf); - - if (nxt_slow_path(data == NULL)) { - nxt_unit_req_alert(ws->req, - "Failed to create Unicode for payload (%d).", - (int) payload_len); - nxt_python_print_exception(); - - return PyErr_Format(PyExc_RuntimeError, - "Failed to create Unicode."); - } - } - } - - msg = nxt_py_asgi_new_msg(ws->req, type); - if (nxt_slow_path(msg == NULL)) { - Py_DECREF(data); - return NULL; - } - - if (nxt_slow_path(PyDict_SetItem(msg, data_key, data) == -1)) { - nxt_unit_req_alert(ws->req, "Python failed to set 'msg.data' item"); - - Py_DECREF(msg); - Py_DECREF(data); - - return PyErr_Format(PyExc_RuntimeError, - "Python failed to set 'msg.data' item"); - } - - Py_DECREF(data); - - return msg; -} - - -static uint64_t -nxt_py_asgi_websocket_pending_len(nxt_py_asgi_websocket_t *ws) -{ - uint64_t res; - nxt_py_asgi_penging_frame_t *p; - - res = 0; - - nxt_queue_each(p, &ws->pending_frames, nxt_py_asgi_penging_frame_t, link) { - res += p->frame->payload_len; - - if (p->frame->header->fin) { - nxt_unit_req_debug(ws->req, "asgi_websocket_pending_len: %d", - (int) res); - return res; - } - } nxt_queue_loop; - - nxt_unit_req_debug(ws->req, "asgi_websocket_pending_len: %d (all)", - (int) res); - return res; -} - - -static nxt_unit_websocket_frame_t * -nxt_py_asgi_websocket_pop_frame(nxt_py_asgi_websocket_t *ws) -{ - nxt_queue_link_t *lnk; - nxt_unit_websocket_frame_t *frame; - nxt_py_asgi_penging_frame_t *p; - - lnk = nxt_queue_first(&ws->pending_frames); - nxt_queue_remove(lnk); - - p = nxt_queue_link_data(lnk, nxt_py_asgi_penging_frame_t, link); - - frame = p->frame; - ws->pending_payload_len -= frame->payload_len; - ws->pending_fins -= frame->header->fin; - - nxt_unit_free(frame->req->ctx, p); - - nxt_unit_req_debug(frame->req, "asgi_websocket_pop_frame: " - "%d, %"PRIu64", %d", - frame->header->opcode, frame->payload_len, - frame->header->fin); - - return frame; -} - - -void -nxt_py_asgi_websocket_close_handler(nxt_unit_request_info_t *req) -{ - PyObject *msg, *exc; - nxt_py_asgi_websocket_t *ws; - - ws = req->data; - - nxt_unit_req_debug(req, "asgi_websocket_close_handler"); - - if (nxt_slow_path(ws == NULL)) { - return; - } - - if (ws->receive_future == NULL) { - ws->state = NXT_WS_DISCONNECTED; - - return; - } - - msg = nxt_py_asgi_websocket_disconnect_msg(ws); - if (nxt_slow_path(msg == NULL)) { - exc = PyErr_Occurred(); - Py_INCREF(exc); - - nxt_py_asgi_websocket_receive_fail(ws, exc); - - } else { - nxt_py_asgi_websocket_receive_done(ws, msg); - } -} - - -static PyObject * -nxt_py_asgi_websocket_disconnect_msg(nxt_py_asgi_websocket_t *ws) -{ - PyObject *msg, *code; - - msg = nxt_py_asgi_new_msg(ws->req, nxt_py_websocket_disconnect_str); - if (nxt_slow_path(msg == NULL)) { - return NULL; - } - - code = PyLong_FromLong(NXT_WEBSOCKET_CR_GOING_AWAY); - if (nxt_slow_path(code == NULL)) { - nxt_unit_req_alert(ws->req, "Python failed to create long"); - nxt_python_print_exception(); - - Py_DECREF(msg); - - return PyErr_Format(PyExc_RuntimeError, "failed to create long"); - } - - if (nxt_slow_path(PyDict_SetItem(msg, nxt_py_code_str, code) == -1)) { - nxt_unit_req_alert(ws->req, "Python failed to set 'msg.code' item"); - - Py_DECREF(msg); - Py_DECREF(code); - - return PyErr_Format(PyExc_RuntimeError, - "Python failed to set 'msg.code' item"); - } - - Py_DECREF(code); - - return msg; -} - - -static PyObject * -nxt_py_asgi_websocket_done(PyObject *self, PyObject *future) -{ - int rc; - uint16_t status_code; - PyObject *res; - nxt_py_asgi_websocket_t *ws; - - ws = (nxt_py_asgi_websocket_t *) self; - - nxt_unit_req_debug(ws->req, "asgi_websocket_done: %p", self); - - /* - * Get Future.result() and it raises an exception, if coroutine exited - * with exception. - */ - res = PyObject_CallMethodObjArgs(future, nxt_py_result_str, NULL); - if (nxt_slow_path(res == NULL)) { - nxt_unit_req_error(ws->req, - "Python failed to call 'future.result()'"); - nxt_python_print_exception(); - - rc = NXT_UNIT_ERROR; - - } else { - Py_DECREF(res); - - rc = NXT_UNIT_OK; - } - - if (ws->state == NXT_WS_ACCEPTED) { - status_code = (rc == NXT_UNIT_OK) - ? htons(NXT_WEBSOCKET_CR_NORMAL) - : htons(NXT_WEBSOCKET_CR_INTERNAL_SERVER_ERROR); - - rc = nxt_unit_websocket_send(ws->req, NXT_WEBSOCKET_OP_CLOSE, - 1, &status_code, 2); - } - - while (!nxt_queue_is_empty(&ws->pending_frames)) { - nxt_unit_websocket_done(nxt_py_asgi_websocket_pop_frame(ws)); - } - - nxt_unit_request_done(ws->req, rc); - - Py_RETURN_NONE; -} - - -#endif /* NXT_HAVE_ASGI */ diff --git a/src/python/nxt_python_wsgi.c b/src/python/nxt_python_wsgi.c deleted file mode 100644 index c621097e..00000000 --- a/src/python/nxt_python_wsgi.c +++ /dev/null @@ -1,1414 +0,0 @@ - -/* - * Copyright (C) Max Romanov - * Copyright (C) Valentin V. Bartenev - * Copyright (C) NGINX, Inc. - */ - - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include NXT_PYTHON_MOUNTS_H - -/* - * According to "PEP 3333 / A Note On String Types" - * [https://www.python.org/dev/peps/pep-3333/#a-note-on-string-types] - * - * WSGI therefore defines two kinds of "string": - * - * - "Native" strings (which are always implemented using the type named str ) - * that are used for request/response headers and metadata - * - * will use PyString_* or corresponding PyUnicode_* functions - * - * - "Bytestrings" (which are implemented using the bytes type in Python 3, and - * str elsewhere), that are used for the bodies of requests and responses - * (e.g. POST/PUT input data and HTML page outputs). - * - * will use PyString_* or corresponding PyBytes_* functions - */ - - -typedef struct { - PyObject_HEAD - - uint64_t content_length; - uint64_t bytes_sent; - PyObject *environ; - PyObject *start_resp; - PyObject *write; - nxt_unit_request_info_t *req; - PyThreadState *thread_state; -} nxt_python_ctx_t; - - -static int nxt_python_wsgi_ctx_data_alloc(void **pdata, int main); -static void nxt_python_wsgi_ctx_data_free(void *data); -static int nxt_python_wsgi_run(nxt_unit_ctx_t *ctx); -static void nxt_python_wsgi_done(void); - -static void nxt_python_request_handler(nxt_unit_request_info_t *req); - -static PyObject *nxt_python_create_environ(nxt_python_app_conf_t *c); -static PyObject *nxt_python_copy_environ(nxt_unit_request_info_t *req); -static PyObject *nxt_python_get_environ(nxt_python_ctx_t *pctx, - nxt_python_target_t *app_target); -static int nxt_python_add_sptr(nxt_python_ctx_t *pctx, PyObject *name, - nxt_unit_sptr_t *sptr, uint32_t size); -static int nxt_python_add_char(nxt_python_ctx_t *pctx, PyObject *name, - char *src, uint32_t size); -static int nxt_python_add_py_string(nxt_python_ctx_t *pctx, PyObject *name, - PyObject *value); -static int nxt_python_add_field(nxt_python_ctx_t *pctx, - nxt_unit_field_t *field, int n, uint32_t vl); -static PyObject *nxt_python_field_name(const char *name, uint8_t len); -static PyObject *nxt_python_field_value(nxt_unit_field_t *f, int n, - uint32_t vl); -static int nxt_python_add_obj(nxt_python_ctx_t *pctx, PyObject *name, - PyObject *value); - -static PyObject *nxt_py_start_resp(PyObject *self, PyObject *args); -static int nxt_python_response_add_field(nxt_python_ctx_t *pctx, - PyObject *name, PyObject *value, int i); -static int nxt_python_str_buf(PyObject *str, char **buf, uint32_t *len, - PyObject **bytes); -static PyObject *nxt_py_write(PyObject *self, PyObject *args); - -static void nxt_py_input_dealloc(nxt_python_ctx_t *pctx); -static PyObject *nxt_py_input_read(nxt_python_ctx_t *pctx, PyObject *args); -static PyObject *nxt_py_input_readline(nxt_python_ctx_t *pctx, - PyObject *args); -static PyObject *nxt_py_input_getline(nxt_python_ctx_t *pctx, size_t size); -static PyObject *nxt_py_input_readlines(nxt_python_ctx_t *self, - PyObject *args); - -static PyObject *nxt_py_input_iter(PyObject *pctx); -static PyObject *nxt_py_input_next(PyObject *pctx); - -static int nxt_python_write(nxt_python_ctx_t *pctx, PyObject *bytes); - - -static PyMethodDef nxt_py_start_resp_method[] = { - {"unit_start_response", nxt_py_start_resp, METH_VARARGS, ""} -}; - - -static PyMethodDef nxt_py_write_method[] = { - {"unit_write", nxt_py_write, METH_O, ""} -}; - - -static PyMethodDef nxt_py_input_methods[] = { - { "read", (PyCFunction) nxt_py_input_read, METH_VARARGS, 0 }, - { "readline", (PyCFunction) nxt_py_input_readline, METH_VARARGS, 0 }, - { "readlines", (PyCFunction) nxt_py_input_readlines, METH_VARARGS, 0 }, - { NULL, NULL, 0, 0 } -}; - - -static PyTypeObject nxt_py_input_type = { - PyVarObject_HEAD_INIT(NULL, 0) - - .tp_name = "unit._input", - .tp_basicsize = sizeof(nxt_python_ctx_t), - .tp_dealloc = (destructor) nxt_py_input_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "unit input object.", - .tp_iter = nxt_py_input_iter, - .tp_iternext = nxt_py_input_next, - .tp_methods = nxt_py_input_methods, -}; - - -static PyObject *nxt_py_environ_ptyp; - -static PyObject *nxt_py_80_str; -static PyObject *nxt_py_close_str; -static PyObject *nxt_py_content_length_str; -static PyObject *nxt_py_content_type_str; -static PyObject *nxt_py_http_str; -static PyObject *nxt_py_https_str; -static PyObject *nxt_py_path_info_str; -static PyObject *nxt_py_query_string_str; -static PyObject *nxt_py_remote_addr_str; -static PyObject *nxt_py_request_method_str; -static PyObject *nxt_py_request_uri_str; -static PyObject *nxt_py_script_name_str; -static PyObject *nxt_py_server_addr_str; -static PyObject *nxt_py_server_name_str; -static PyObject *nxt_py_server_port_str; -static PyObject *nxt_py_server_protocol_str; -static PyObject *nxt_py_wsgi_input_str; -static PyObject *nxt_py_wsgi_uri_scheme_str; - -static nxt_python_string_t nxt_python_strings[] = { - { nxt_string("80"), &nxt_py_80_str }, - { nxt_string("close"), &nxt_py_close_str }, - { nxt_string("CONTENT_LENGTH"), &nxt_py_content_length_str }, - { nxt_string("CONTENT_TYPE"), &nxt_py_content_type_str }, - { nxt_string("http"), &nxt_py_http_str }, - { nxt_string("https"), &nxt_py_https_str }, - { nxt_string("PATH_INFO"), &nxt_py_path_info_str }, - { nxt_string("QUERY_STRING"), &nxt_py_query_string_str }, - { nxt_string("REMOTE_ADDR"), &nxt_py_remote_addr_str }, - { nxt_string("REQUEST_METHOD"), &nxt_py_request_method_str }, - { nxt_string("REQUEST_URI"), &nxt_py_request_uri_str }, - { nxt_string("SCRIPT_NAME"), &nxt_py_script_name_str }, - { nxt_string("SERVER_ADDR"), &nxt_py_server_addr_str }, - { nxt_string("SERVER_NAME"), &nxt_py_server_name_str }, - { nxt_string("SERVER_PORT"), &nxt_py_server_port_str }, - { nxt_string("SERVER_PROTOCOL"), &nxt_py_server_protocol_str }, - { nxt_string("wsgi.input"), &nxt_py_wsgi_input_str }, - { nxt_string("wsgi.url_scheme"), &nxt_py_wsgi_uri_scheme_str }, - { nxt_null_string, NULL }, -}; - -static nxt_python_proto_t nxt_py_wsgi_proto = { - .ctx_data_alloc = nxt_python_wsgi_ctx_data_alloc, - .ctx_data_free = nxt_python_wsgi_ctx_data_free, - .run = nxt_python_wsgi_run, - .done = nxt_python_wsgi_done, -}; - - -int -nxt_python_wsgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto) -{ - PyObject *obj; - - obj = NULL; - - if (nxt_slow_path(nxt_python_init_strings(nxt_python_strings) - != NXT_UNIT_OK)) - { - nxt_unit_alert(NULL, "Python failed to init string objects"); - goto fail; - } - - obj = nxt_python_create_environ(init->data); - if (nxt_slow_path(obj == NULL)) { - goto fail; - } - - nxt_py_environ_ptyp = obj; - obj = NULL; - - init->callbacks.request_handler = nxt_python_request_handler; - - *proto = nxt_py_wsgi_proto; - - return NXT_UNIT_OK; - -fail: - - Py_XDECREF(obj); - - return NXT_UNIT_ERROR; -} - - -static int -nxt_python_wsgi_ctx_data_alloc(void **pdata, int main) -{ - nxt_python_ctx_t *pctx; - - pctx = PyObject_New(nxt_python_ctx_t, &nxt_py_input_type); - if (nxt_slow_path(pctx == NULL)) { - nxt_unit_alert(NULL, - "Python failed to create the \"wsgi.input\" object"); - return NXT_UNIT_ERROR; - } - - pctx->write = NULL; - pctx->environ = NULL; - - pctx->start_resp = PyCFunction_New(nxt_py_start_resp_method, - (PyObject *) pctx); - if (nxt_slow_path(pctx->start_resp == NULL)) { - nxt_unit_alert(NULL, - "Python failed to initialize the \"start_response\" function"); - goto fail; - } - - pctx->write = PyCFunction_New(nxt_py_write_method, (PyObject *) pctx); - if (nxt_slow_path(pctx->write == NULL)) { - nxt_unit_alert(NULL, - "Python failed to initialize the \"write\" function"); - goto fail; - } - - pctx->environ = nxt_python_copy_environ(NULL); - if (nxt_slow_path(pctx->environ == NULL)) { - goto fail; - } - - *pdata = pctx; - - return NXT_UNIT_OK; - -fail: - - nxt_python_wsgi_ctx_data_free(pctx); - - return NXT_UNIT_ERROR; -} - - -static void -nxt_python_wsgi_ctx_data_free(void *data) -{ - nxt_python_ctx_t *pctx; - - pctx = data; - - Py_XDECREF(pctx->start_resp); - Py_XDECREF(pctx->write); - Py_XDECREF(pctx->environ); - Py_XDECREF(pctx); -} - - -static int -nxt_python_wsgi_run(nxt_unit_ctx_t *ctx) -{ - int rc; - nxt_python_ctx_t *pctx; - - pctx = ctx->data; - - pctx->thread_state = PyEval_SaveThread(); - - rc = nxt_unit_run(ctx); - - PyEval_RestoreThread(pctx->thread_state); - - return rc; -} - - -static void -nxt_python_wsgi_done(void) -{ - nxt_python_done_strings(nxt_python_strings); - - Py_XDECREF(nxt_py_environ_ptyp); -} - - -static void -nxt_python_request_handler(nxt_unit_request_info_t *req) -{ - int rc; - PyObject *environ, *args, *response, *iterator, *item; - PyObject *close, *result; - nxt_bool_t prepare_environ; - nxt_python_ctx_t *pctx; - nxt_python_target_t *target; - - pctx = req->ctx->data; - - pctx->content_length = -1; - pctx->bytes_sent = 0; - pctx->req = req; - - PyEval_RestoreThread(pctx->thread_state); - - if (nxt_slow_path(pctx->environ == NULL)) { - pctx->environ = nxt_python_copy_environ(req); - - if (pctx->environ == NULL) { - prepare_environ = 0; - - rc = NXT_UNIT_ERROR; - goto done; - } - } - - prepare_environ = 1; - - target = &nxt_py_targets->target[req->request->app_target]; - - environ = nxt_python_get_environ(pctx, target); - if (nxt_slow_path(environ == NULL)) { - rc = NXT_UNIT_ERROR; - goto done; - } - - args = PyTuple_New(2); - if (nxt_slow_path(args == NULL)) { - Py_DECREF(environ); - - nxt_unit_req_error(req, "Python failed to create arguments tuple"); - - rc = NXT_UNIT_ERROR; - goto done; - } - - PyTuple_SET_ITEM(args, 0, environ); - - Py_INCREF(pctx->start_resp); - PyTuple_SET_ITEM(args, 1, pctx->start_resp); - - response = PyObject_CallObject(target->application, args); - - Py_DECREF(args); - - if (nxt_slow_path(response == NULL)) { - nxt_unit_req_error(req, "Python failed to call the application"); - nxt_python_print_exception(); - - rc = NXT_UNIT_ERROR; - goto done; - } - - /* Shortcut: avoid iterate over response string symbols. */ - if (PyBytes_Check(response)) { - rc = nxt_python_write(pctx, response); - - } else { - iterator = PyObject_GetIter(response); - - if (nxt_fast_path(iterator != NULL)) { - rc = NXT_UNIT_OK; - - while (pctx->bytes_sent < pctx->content_length) { - item = PyIter_Next(iterator); - - if (item == NULL) { - if (nxt_slow_path(PyErr_Occurred() != NULL)) { - nxt_unit_req_error(req, "Python failed to iterate over " - "the application response object"); - nxt_python_print_exception(); - - rc = NXT_UNIT_ERROR; - } - - break; - } - - if (nxt_fast_path(PyBytes_Check(item))) { - rc = nxt_python_write(pctx, item); - - } else { - nxt_unit_req_error(req, "the application returned " - "not a bytestring object"); - rc = NXT_UNIT_ERROR; - } - - Py_DECREF(item); - - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - break; - } - } - - Py_DECREF(iterator); - - } else { - nxt_unit_req_error(req, - "the application returned not an iterable object"); - nxt_python_print_exception(); - - rc = NXT_UNIT_ERROR; - } - - close = PyObject_GetAttr(response, nxt_py_close_str); - - if (close != NULL) { - result = PyObject_CallFunction(close, NULL); - if (nxt_slow_path(result == NULL)) { - nxt_unit_req_error(req, "Python failed to call the close() " - "method of the application response"); - nxt_python_print_exception(); - - } else { - Py_DECREF(result); - } - - Py_DECREF(close); - - } else { - PyErr_Clear(); - } - } - - Py_DECREF(response); - -done: - - pctx->thread_state = PyEval_SaveThread(); - - pctx->req = NULL; - - nxt_unit_request_done(req, rc); - - if (nxt_fast_path(prepare_environ)) { - PyEval_RestoreThread(pctx->thread_state); - - pctx->environ = nxt_python_copy_environ(NULL); - - pctx->thread_state = PyEval_SaveThread(); - } -} - - -static PyObject * -nxt_python_create_environ(nxt_python_app_conf_t *c) -{ - PyObject *obj, *err, *environ; - - environ = PyDict_New(); - - if (nxt_slow_path(environ == NULL)) { - nxt_unit_alert(NULL, - "Python failed to create the \"environ\" dictionary"); - return NULL; - } - - obj = PyString_FromStringAndSize((char *) nxt_server.start, - nxt_server.length); - if (nxt_slow_path(obj == NULL)) { - nxt_unit_alert(NULL, - "Python failed to create the \"SERVER_SOFTWARE\" environ value"); - goto fail; - } - - if (nxt_slow_path(PyDict_SetItemString(environ, "SERVER_SOFTWARE", obj) - != 0)) - { - nxt_unit_alert(NULL, - "Python failed to set the \"SERVER_SOFTWARE\" environ value"); - goto fail; - } - - Py_DECREF(obj); - - obj = Py_BuildValue("(ii)", 1, 0); - - if (nxt_slow_path(obj == NULL)) { - nxt_unit_alert(NULL, - "Python failed to build the \"wsgi.version\" environ value"); - goto fail; - } - - if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.version", obj) != 0)) - { - nxt_unit_alert(NULL, - "Python failed to set the \"wsgi.version\" environ value"); - goto fail; - } - - Py_DECREF(obj); - obj = NULL; - - - if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.multithread", - c->threads > 1 ? Py_True : Py_False) - != 0)) - { - nxt_unit_alert(NULL, - "Python failed to set the \"wsgi.multithread\" environ value"); - goto fail; - } - - if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.multiprocess", - Py_True) - != 0)) - { - nxt_unit_alert(NULL, - "Python failed to set the \"wsgi.multiprocess\" environ value"); - goto fail; - } - - if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.run_once", - Py_False) - != 0)) - { - nxt_unit_alert(NULL, - "Python failed to set the \"wsgi.run_once\" environ value"); - goto fail; - } - - - if (nxt_slow_path(PyType_Ready(&nxt_py_input_type) != 0)) { - nxt_unit_alert(NULL, - "Python failed to initialize the \"wsgi.input\" type object"); - goto fail; - } - - - err = PySys_GetObject((char *) "stderr"); - - if (nxt_slow_path(err == NULL)) { - nxt_unit_alert(NULL, "Python failed to get \"sys.stderr\" object"); - goto fail; - } - - if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.errors", err) != 0)) - { - nxt_unit_alert(NULL, - "Python failed to set the \"wsgi.errors\" environ value"); - goto fail; - } - - return environ; - -fail: - - Py_XDECREF(obj); - Py_DECREF(environ); - - return NULL; -} - - -static PyObject * -nxt_python_copy_environ(nxt_unit_request_info_t *req) -{ - PyObject *environ; - - environ = PyDict_Copy(nxt_py_environ_ptyp); - - if (nxt_slow_path(environ == NULL)) { - nxt_unit_req_alert(req, - "Python failed to copy the \"environ\" dictionary"); - nxt_python_print_exception(); - } - - return environ; -} - - -static PyObject * -nxt_python_get_environ(nxt_python_ctx_t *pctx, - nxt_python_target_t *app_target) -{ - int rc; - char *path; - uint32_t i, j, vl, path_length; - PyObject *environ; - nxt_str_t prefix; - nxt_unit_field_t *f, *f2; - nxt_unit_request_t *r; - - r = pctx->req->request; - -#define RC(S) \ - do { \ - rc = (S); \ - if (nxt_slow_path(rc != NXT_UNIT_OK)) { \ - goto fail; \ - } \ - } while(0) - - RC(nxt_python_add_sptr(pctx, nxt_py_request_method_str, &r->method, - r->method_length)); - RC(nxt_python_add_sptr(pctx, nxt_py_request_uri_str, &r->target, - r->target_length)); - RC(nxt_python_add_sptr(pctx, nxt_py_query_string_str, &r->query, - r->query_length)); - - prefix = app_target->prefix; - path_length = r->path_length; - path = nxt_unit_sptr_get(&r->path); - if (prefix.length > 0 - && ((path_length > prefix.length && path[prefix.length] == '/') - || path_length == prefix.length) - && memcmp(prefix.start, path, prefix.length) == 0) - { - RC(nxt_python_add_py_string(pctx, nxt_py_script_name_str, - app_target->py_prefix)); - - path += prefix.length; - path_length -= prefix.length; - } - - RC(nxt_python_add_char(pctx, nxt_py_path_info_str, path, path_length)); - - RC(nxt_python_add_sptr(pctx, nxt_py_remote_addr_str, &r->remote, - r->remote_length)); - RC(nxt_python_add_sptr(pctx, nxt_py_server_addr_str, &r->local_addr, - r->local_addr_length)); - - if (r->tls) { - RC(nxt_python_add_obj(pctx, nxt_py_wsgi_uri_scheme_str, - nxt_py_https_str)); - } else { - RC(nxt_python_add_obj(pctx, nxt_py_wsgi_uri_scheme_str, - nxt_py_http_str)); - } - - RC(nxt_python_add_sptr(pctx, nxt_py_server_protocol_str, &r->version, - r->version_length)); - - RC(nxt_python_add_sptr(pctx, nxt_py_server_name_str, &r->server_name, - r->server_name_length)); - RC(nxt_python_add_obj(pctx, nxt_py_server_port_str, nxt_py_80_str)); - - nxt_unit_request_group_dup_fields(pctx->req); - - for (i = 0; i < r->fields_count;) { - f = r->fields + i; - vl = f->value_length; - - for (j = i + 1; j < r->fields_count; j++) { - f2 = r->fields + j; - - if (f2->hash != f->hash - || nxt_unit_sptr_get(&f2->name) != nxt_unit_sptr_get(&f->name)) - { - break; - } - - vl += 2 + f2->value_length; - } - - RC(nxt_python_add_field(pctx, f, j - i, vl)); - - i = j; - } - - if (r->content_length_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->content_length_field; - - RC(nxt_python_add_sptr(pctx, nxt_py_content_length_str, &f->value, - f->value_length)); - } - - if (r->content_type_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->content_type_field; - - RC(nxt_python_add_sptr(pctx, nxt_py_content_type_str, &f->value, - f->value_length)); - } - -#undef RC - - if (nxt_slow_path(PyDict_SetItem(pctx->environ, nxt_py_wsgi_input_str, - (PyObject *) pctx) != 0)) - { - nxt_unit_req_error(pctx->req, - "Python failed to set the \"wsgi.input\" environ value"); - goto fail; - } - - environ = pctx->environ; - pctx->environ = NULL; - - return environ; - -fail: - - Py_DECREF(pctx->environ); - pctx->environ = NULL; - - return NULL; -} - - -static int -nxt_python_add_sptr(nxt_python_ctx_t *pctx, PyObject *name, - nxt_unit_sptr_t *sptr, uint32_t size) -{ - return nxt_python_add_char(pctx, name, nxt_unit_sptr_get(sptr), size); -} - - -static int -nxt_python_add_char(nxt_python_ctx_t *pctx, PyObject *name, - char *src, uint32_t size) -{ - int res; - PyObject *value; - - value = PyString_FromStringAndSize(src, size); - if (nxt_slow_path(value == NULL)) { - nxt_unit_req_error(pctx->req, - "Python failed to create value string \"%.*s\"", - (int) size, src); - nxt_python_print_exception(); - - return NXT_UNIT_ERROR; - } - - res = nxt_python_add_py_string(pctx, name, value); - - Py_DECREF(value); - - return res; -} - - -static int nxt_python_add_py_string(nxt_python_ctx_t *pctx, PyObject *name, - PyObject *value) -{ - if (nxt_slow_path(PyDict_SetItem(pctx->environ, name, value) != 0)) { - nxt_unit_req_error(pctx->req, - "Python failed to set the \"%s\" environ value", - PyUnicode_AsUTF8(name)); - - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static int -nxt_python_add_field(nxt_python_ctx_t *pctx, nxt_unit_field_t *field, int n, - uint32_t vl) -{ - char *src; - PyObject *name, *value; - - src = nxt_unit_sptr_get(&field->name); - - name = nxt_python_field_name(src, field->name_length); - if (nxt_slow_path(name == NULL)) { - nxt_unit_req_error(pctx->req, - "Python failed to create name string \"%.*s\"", - (int) field->name_length, src); - nxt_python_print_exception(); - - return NXT_UNIT_ERROR; - } - - value = nxt_python_field_value(field, n, vl); - - if (nxt_slow_path(value == NULL)) { - nxt_unit_req_error(pctx->req, - "Python failed to create value string \"%.*s\"", - (int) field->value_length, - (char *) nxt_unit_sptr_get(&field->value)); - nxt_python_print_exception(); - - goto fail; - } - - if (nxt_slow_path(PyDict_SetItem(pctx->environ, name, value) != 0)) { - nxt_unit_req_error(pctx->req, - "Python failed to set the \"%s\" environ value", - PyUnicode_AsUTF8(name)); - goto fail; - } - - Py_DECREF(name); - Py_DECREF(value); - - return NXT_UNIT_OK; - -fail: - - Py_DECREF(name); - Py_XDECREF(value); - - return NXT_UNIT_ERROR; -} - - -static PyObject * -nxt_python_field_name(const char *name, uint8_t len) -{ - char *p, c; - uint8_t i; - PyObject *res; - -#if PY_MAJOR_VERSION == 3 - res = PyUnicode_New(len + 5, 255); -#else - res = PyString_FromStringAndSize(NULL, len + 5); -#endif - - if (nxt_slow_path(res == NULL)) { - return NULL; - } - - p = PyString_AS_STRING(res); - - p = nxt_cpymem(p, "HTTP_", 5); - - for (i = 0; i < len; i++) { - c = name[i]; - - if (c >= 'a' && c <= 'z') { - *p++ = (c & ~0x20); - continue; - } - - if (c == '-') { - *p++ = '_'; - continue; - } - - *p++ = c; - } - - return res; -} - - -static PyObject * -nxt_python_field_value(nxt_unit_field_t *f, int n, uint32_t vl) -{ - int i; - char *p, *src; - PyObject *res; - - src = nxt_unit_sptr_get(&f->value); - -#if PY_MAJOR_VERSION == 3 - if (nxt_slow_path(n > 1)) { - char *ptr; - - p = nxt_unit_malloc(NULL, vl + 1); - if (nxt_slow_path(p == NULL)) { - return NULL; - } - - ptr = p; - p = nxt_cpymem(p, src, f->value_length); - - for (i = 1; i < n; i++) { - p = nxt_cpymem(p, ", ", 2); - - src = nxt_unit_sptr_get(&f[i].value); - p = nxt_cpymem(p, src, f[i].value_length); - } - *p = '\0'; - - src = ptr; - } - - res = PyUnicode_DecodeCharmap(src, vl, NULL, NULL); - - if (nxt_slow_path(n > 1)) { - nxt_unit_free(NULL, src); - } -#else - res = PyString_FromStringAndSize(NULL, vl); - - if (nxt_slow_path(res == NULL)) { - return NULL; - } - - p = PyString_AS_STRING(res); - - p = nxt_cpymem(p, src, f->value_length); - - for (i = 1; i < n; i++) { - p = nxt_cpymem(p, ", ", 2); - - src = nxt_unit_sptr_get(&f[i].value); - p = nxt_cpymem(p, src, f[i].value_length); - } -#endif - - return res; -} - - -static int -nxt_python_add_obj(nxt_python_ctx_t *pctx, PyObject *name, PyObject *value) -{ - if (nxt_slow_path(PyDict_SetItem(pctx->environ, name, value) != 0)) { - nxt_unit_req_error(pctx->req, - "Python failed to set the \"%s\" environ value", - PyUnicode_AsUTF8(name)); - - return NXT_UNIT_ERROR; - } - - return NXT_UNIT_OK; -} - - -static PyObject * -nxt_py_start_resp(PyObject *self, PyObject *args) -{ - int rc, status; - char *status_str, *space_ptr; - uint32_t status_len; - PyObject *headers, *tuple, *string, *status_bytes; - Py_ssize_t i, n, fields_size, fields_count; - nxt_python_ctx_t *pctx; - - pctx = (nxt_python_ctx_t *) self; - if (nxt_slow_path(pctx->req == NULL)) { - return PyErr_Format(PyExc_RuntimeError, - "start_response() is called " - "outside of WSGI request processing"); - } - - n = PyTuple_GET_SIZE(args); - - if (n < 2 || n > 3) { - return PyErr_Format(PyExc_TypeError, "invalid number of arguments"); - } - - string = PyTuple_GET_ITEM(args, 0); - if (!PyBytes_Check(string) && !PyUnicode_Check(string)) { - return PyErr_Format(PyExc_TypeError, - "failed to write first argument (not a string?)"); - } - - headers = PyTuple_GET_ITEM(args, 1); - if (!PyList_Check(headers)) { - return PyErr_Format(PyExc_TypeError, - "the second argument is not a response headers list"); - } - - fields_size = 0; - fields_count = PyList_GET_SIZE(headers); - - for (i = 0; i < fields_count; i++) { - tuple = PyList_GET_ITEM(headers, i); - - if (!PyTuple_Check(tuple)) { - return PyErr_Format(PyExc_TypeError, - "the response headers must be a list of tuples"); - } - - if (PyTuple_GET_SIZE(tuple) != 2) { - return PyErr_Format(PyExc_TypeError, - "each header must be a tuple of two items"); - } - - string = PyTuple_GET_ITEM(tuple, 0); - if (PyBytes_Check(string)) { - fields_size += PyBytes_GET_SIZE(string); - - } else if (PyUnicode_Check(string)) { - fields_size += PyUnicode_GET_LENGTH(string); - - } else { - return PyErr_Format(PyExc_TypeError, - "header #%d name is not a string", (int) i); - } - - string = PyTuple_GET_ITEM(tuple, 1); - if (PyBytes_Check(string)) { - fields_size += PyBytes_GET_SIZE(string); - - } else if (PyUnicode_Check(string)) { - fields_size += PyUnicode_GET_LENGTH(string); - - } else { - return PyErr_Format(PyExc_TypeError, - "header #%d value is not a string", (int) i); - } - } - - pctx->content_length = -1; - - string = PyTuple_GET_ITEM(args, 0); - rc = nxt_python_str_buf(string, &status_str, &status_len, &status_bytes); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_TypeError, "status is not a string"); - } - - space_ptr = memchr(status_str, ' ', status_len); - if (space_ptr != NULL) { - status_len = space_ptr - status_str; - } - - status = nxt_int_parse((u_char *) status_str, status_len); - if (nxt_slow_path(status < 0)) { - return PyErr_Format(PyExc_TypeError, "failed to parse status code"); - } - - Py_XDECREF(status_bytes); - - /* - * PEP 3333: - * - * ... applications can replace their originally intended output with error - * output, up until the last possible moment. - */ - rc = nxt_unit_response_init(pctx->req, status, fields_count, fields_size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to allocate response object"); - } - - for (i = 0; i < fields_count; i++) { - tuple = PyList_GET_ITEM(headers, i); - - rc = nxt_python_response_add_field(pctx, PyTuple_GET_ITEM(tuple, 0), - PyTuple_GET_ITEM(tuple, 1), i); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to add header #%d", (int) i); - } - } - - /* - * PEP 3333: - * - * However, the start_response callable must not actually transmit the - * response headers. Instead, it must store them for the server or gateway - * to transmit only after the first iteration of the application return - * value that yields a non-empty bytestring, or upon the application's - * first invocation of the write() callable. In other words, response - * headers must not be sent until there is actual body data available, or - * until the application's returned iterable is exhausted. (The only - * possible exception to this rule is if the response headers explicitly - * include a Content-Length of zero.) - */ - if (pctx->content_length == 0) { - rc = nxt_unit_response_send(pctx->req); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to send response headers"); - } - } - - Py_INCREF(pctx->write); - return pctx->write; -} - - -static int -nxt_python_response_add_field(nxt_python_ctx_t *pctx, PyObject *name, - PyObject *value, int i) -{ - int rc; - char *name_str, *value_str; - uint32_t name_length, value_length; - PyObject *name_bytes, *value_bytes; - nxt_off_t content_length; - - name_bytes = NULL; - value_bytes = NULL; - - rc = nxt_python_str_buf(name, &name_str, &name_length, &name_bytes); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - rc = nxt_python_str_buf(value, &value_str, &value_length, &value_bytes); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - rc = nxt_unit_response_add_field(pctx->req, name_str, name_length, - value_str, value_length); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - if (pctx->req->response->fields[i].hash == NXT_UNIT_HASH_CONTENT_LENGTH) { - content_length = nxt_off_t_parse((u_char *) value_str, value_length); - if (nxt_slow_path(content_length < 0)) { - nxt_unit_req_error(pctx->req, "failed to parse Content-Length " - "value %.*s", (int) value_length, value_str); - - } else { - pctx->content_length = content_length; - } - } - -fail: - - Py_XDECREF(name_bytes); - Py_XDECREF(value_bytes); - - return rc; -} - - -static int -nxt_python_str_buf(PyObject *str, char **buf, uint32_t *len, PyObject **bytes) -{ - if (PyBytes_Check(str)) { - *buf = PyBytes_AS_STRING(str); - *len = PyBytes_GET_SIZE(str); - *bytes = NULL; - - } else { - *bytes = PyUnicode_AsLatin1String(str); - if (nxt_slow_path(*bytes == NULL)) { - return NXT_UNIT_ERROR; - } - - *buf = PyBytes_AS_STRING(*bytes); - *len = PyBytes_GET_SIZE(*bytes); - } - - return NXT_UNIT_OK; -} - - -static PyObject * -nxt_py_write(PyObject *self, PyObject *str) -{ - int rc; - - if (nxt_fast_path(!PyBytes_Check(str))) { - return PyErr_Format(PyExc_TypeError, "the argument is not a %s", - NXT_PYTHON_BYTES_TYPE); - } - - rc = nxt_python_write((nxt_python_ctx_t *) self, str); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return PyErr_Format(PyExc_RuntimeError, - "failed to write response value"); - } - - Py_RETURN_NONE; -} - - -static void -nxt_py_input_dealloc(nxt_python_ctx_t *self) -{ - PyObject_Del(self); -} - - -static PyObject * -nxt_py_input_read(nxt_python_ctx_t *pctx, PyObject *args) -{ - char *buf; - PyObject *content, *obj; - Py_ssize_t size, n; - - if (nxt_slow_path(pctx->req == NULL)) { - return PyErr_Format(PyExc_RuntimeError, - "wsgi.input.read() is called " - "outside of WSGI request processing"); - } - - size = pctx->req->content_length; - - n = PyTuple_GET_SIZE(args); - - if (n > 0) { - if (n != 1) { - return PyErr_Format(PyExc_TypeError, "invalid number of arguments"); - } - - obj = PyTuple_GET_ITEM(args, 0); - - size = PyNumber_AsSsize_t(obj, PyExc_OverflowError); - - if (nxt_slow_path(size < 0)) { - if (size == -1 && PyErr_Occurred()) { - return NULL; - } - - if (size != -1) { - return PyErr_Format(PyExc_ValueError, - "the read body size cannot be zero or less"); - } - } - - if (size == -1 || size > (Py_ssize_t) pctx->req->content_length) { - size = pctx->req->content_length; - } - } - - content = PyBytes_FromStringAndSize(NULL, size); - if (nxt_slow_path(content == NULL)) { - return NULL; - } - - buf = PyBytes_AS_STRING(content); - - size = nxt_unit_request_read(pctx->req, buf, size); - - return content; -} - - -static PyObject * -nxt_py_input_readline(nxt_python_ctx_t *pctx, PyObject *args) -{ - ssize_t ssize; - PyObject *obj; - Py_ssize_t n; - - if (nxt_slow_path(pctx->req == NULL)) { - return PyErr_Format(PyExc_RuntimeError, - "wsgi.input.readline() is called " - "outside of WSGI request processing"); - } - - n = PyTuple_GET_SIZE(args); - - if (n > 0) { - if (n != 1) { - return PyErr_Format(PyExc_TypeError, "invalid number of arguments"); - } - - obj = PyTuple_GET_ITEM(args, 0); - - ssize = PyNumber_AsSsize_t(obj, PyExc_OverflowError); - - if (nxt_fast_path(ssize > 0)) { - return nxt_py_input_getline(pctx, ssize); - } - - if (ssize == 0) { - return PyBytes_FromStringAndSize("", 0); - } - - if (ssize != -1) { - return PyErr_Format(PyExc_ValueError, - "the read line size cannot be zero or less"); - } - - if (PyErr_Occurred()) { - return NULL; - } - } - - return nxt_py_input_getline(pctx, SSIZE_MAX); -} - - -static PyObject * -nxt_py_input_getline(nxt_python_ctx_t *pctx, size_t size) -{ - void *buf; - ssize_t res; - PyObject *content; - - res = nxt_unit_request_readline_size(pctx->req, size); - if (nxt_slow_path(res < 0)) { - return NULL; - } - - if (res == 0) { - return PyBytes_FromStringAndSize("", 0); - } - - content = PyBytes_FromStringAndSize(NULL, res); - if (nxt_slow_path(content == NULL)) { - return NULL; - } - - buf = PyBytes_AS_STRING(content); - - res = nxt_unit_request_read(pctx->req, buf, res); - - return content; -} - - -static PyObject * -nxt_py_input_readlines(nxt_python_ctx_t *pctx, PyObject *args) -{ - PyObject *res; - - if (nxt_slow_path(pctx->req == NULL)) { - return PyErr_Format(PyExc_RuntimeError, - "wsgi.input.readlines() is called " - "outside of WSGI request processing"); - } - - res = PyList_New(0); - if (nxt_slow_path(res == NULL)) { - return NULL; - } - - for ( ;; ) { - PyObject *line = nxt_py_input_getline(pctx, SSIZE_MAX); - if (nxt_slow_path(line == NULL)) { - Py_DECREF(res); - return NULL; - } - - if (PyBytes_GET_SIZE(line) == 0) { - Py_DECREF(line); - return res; - } - - PyList_Append(res, line); - Py_DECREF(line); - } - - return res; -} - - -static PyObject * -nxt_py_input_iter(PyObject *self) -{ - Py_INCREF(self); - return self; -} - - -static PyObject * -nxt_py_input_next(PyObject *self) -{ - PyObject *line; - nxt_python_ctx_t *pctx; - - pctx = (nxt_python_ctx_t *) self; - if (nxt_slow_path(pctx->req == NULL)) { - return PyErr_Format(PyExc_RuntimeError, - "wsgi.input.next() is called " - "outside of WSGI request processing"); - } - - line = nxt_py_input_getline(pctx, SSIZE_MAX); - if (nxt_slow_path(line == NULL)) { - return NULL; - } - - if (PyBytes_GET_SIZE(line) == 0) { - Py_DECREF(line); - PyErr_SetNone(PyExc_StopIteration); - return NULL; - } - - return line; -} - - -static int -nxt_python_write(nxt_python_ctx_t *pctx, PyObject *bytes) -{ - int rc; - char *str_buf; - uint32_t str_length; - - str_buf = PyBytes_AS_STRING(bytes); - str_length = PyBytes_GET_SIZE(bytes); - - if (nxt_slow_path(str_length == 0)) { - return NXT_UNIT_OK; - } - - /* - * PEP 3333: - * - * If the application supplies a Content-Length header, the server should - * not transmit more bytes to the client than the header allows, and should - * stop iterating over the response when enough data has been sent, or raise - * an error if the application tries to write() past that point. - */ - if (nxt_slow_path(str_length > pctx->content_length - pctx->bytes_sent)) { - nxt_unit_req_error(pctx->req, "content length %"PRIu64" exceeded", - pctx->content_length); - - return NXT_UNIT_ERROR; - } - - rc = nxt_unit_response_write(pctx->req, str_buf, str_length); - if (nxt_fast_path(rc == NXT_UNIT_OK)) { - pctx->bytes_sent += str_length; - } - - return rc; -} diff --git a/src/ruby/nxt_ruby.c b/src/ruby/nxt_ruby.c deleted file mode 100644 index 27b868fe..00000000 --- a/src/ruby/nxt_ruby.c +++ /dev/null @@ -1,1510 +0,0 @@ -/* - * Copyright (C) Alexander Borisov - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include - -#include - -#include NXT_RUBY_MOUNTS_H - -#include - - -#define NXT_RUBY_RACK_API_VERSION_MAJOR 1 -#define NXT_RUBY_RACK_API_VERSION_MINOR 3 - - -typedef struct { - nxt_task_t *task; - nxt_str_t *script; - nxt_ruby_ctx_t *rctx; -} nxt_ruby_rack_init_t; - - -static nxt_int_t nxt_ruby_start(nxt_task_t *task, - nxt_process_data_t *data); -static VALUE nxt_ruby_init_basic(VALUE arg); - -static VALUE nxt_ruby_hook_procs_load(VALUE path); -static VALUE nxt_ruby_hook_register(VALUE arg); -static VALUE nxt_ruby_hook_call(VALUE name); - -static VALUE nxt_ruby_rack_init(nxt_ruby_rack_init_t *rack_init); - -static VALUE nxt_ruby_require_rubygems(VALUE arg); -static VALUE nxt_ruby_bundler_setup(VALUE arg); -static VALUE nxt_ruby_require_rack(VALUE arg); -static VALUE nxt_ruby_rack_parse_script(VALUE ctx); -static VALUE nxt_ruby_rack_env_create(VALUE arg); -static int nxt_ruby_init_io(nxt_ruby_ctx_t *rctx); -static void nxt_ruby_request_handler(nxt_unit_request_info_t *req); -static void *nxt_ruby_request_handler_gvl(void *req); -static int nxt_ruby_ready_handler(nxt_unit_ctx_t *ctx); -static void *nxt_ruby_thread_create_gvl(void *rctx); -static VALUE nxt_ruby_thread_func(VALUE arg); -static void *nxt_ruby_unit_run(void *ctx); -static void nxt_ruby_ubf(void *ctx); -static int nxt_ruby_init_threads(nxt_ruby_app_conf_t *c); -static void nxt_ruby_join_threads(nxt_unit_ctx_t *ctx, - nxt_ruby_app_conf_t *c); - -static VALUE nxt_ruby_rack_app_run(VALUE arg); -static int nxt_ruby_read_request(nxt_unit_request_info_t *req, VALUE hash_env); -nxt_inline void nxt_ruby_add_sptr(VALUE hash_env, VALUE name, - nxt_unit_sptr_t *sptr, uint32_t len); -static nxt_int_t nxt_ruby_rack_result_status(nxt_unit_request_info_t *req, - VALUE result); -static int nxt_ruby_rack_result_headers(nxt_unit_request_info_t *req, - VALUE result, nxt_int_t status); -static int nxt_ruby_hash_info(VALUE r_key, VALUE r_value, VALUE arg); -static int nxt_ruby_hash_add(VALUE r_key, VALUE r_value, VALUE arg); -static int nxt_ruby_rack_result_body(nxt_unit_request_info_t *req, - VALUE result); -static int nxt_ruby_rack_result_body_file_write(nxt_unit_request_info_t *req, - VALUE filepath); -static void *nxt_ruby_response_write_cb(void *read_info); -static VALUE nxt_ruby_rack_result_body_each(VALUE body, VALUE arg, - int argc, const VALUE *argv, VALUE blockarg); -static void *nxt_ruby_response_write(void *body); - -static void nxt_ruby_exception_log(nxt_unit_request_info_t *req, - uint32_t level, const char *desc); - -static void nxt_ruby_ctx_done(nxt_ruby_ctx_t *rctx); -static void nxt_ruby_atexit(void); - - -static uint32_t compat[] = { - NXT_VERNUM, NXT_DEBUG, -}; - -static VALUE nxt_ruby_hook_procs; -static VALUE nxt_ruby_rackup; -static VALUE nxt_ruby_call; - -static uint32_t nxt_ruby_threads; -static nxt_ruby_ctx_t *nxt_ruby_ctxs; - -NXT_EXPORT nxt_app_module_t nxt_app_module = { - sizeof(compat), - compat, - nxt_string("ruby"), - ruby_version, - nxt_ruby_mounts, - nxt_nitems(nxt_ruby_mounts), - NULL, - nxt_ruby_start, -}; - -typedef struct { - nxt_str_t string; - VALUE *v; -} nxt_ruby_string_t; - -static VALUE nxt_rb_80_str; -static VALUE nxt_rb_content_length_str; -static VALUE nxt_rb_content_type_str; -static VALUE nxt_rb_http_str; -static VALUE nxt_rb_https_str; -static VALUE nxt_rb_path_info_str; -static VALUE nxt_rb_query_string_str; -static VALUE nxt_rb_rack_url_scheme_str; -static VALUE nxt_rb_remote_addr_str; -static VALUE nxt_rb_request_method_str; -static VALUE nxt_rb_request_uri_str; -static VALUE nxt_rb_server_addr_str; -static VALUE nxt_rb_server_name_str; -static VALUE nxt_rb_server_port_str; -static VALUE nxt_rb_server_protocol_str; -static VALUE nxt_rb_on_worker_boot; -static VALUE nxt_rb_on_worker_shutdown; -static VALUE nxt_rb_on_thread_boot; -static VALUE nxt_rb_on_thread_shutdown; - -static nxt_ruby_string_t nxt_rb_strings[] = { - { nxt_string("80"), &nxt_rb_80_str }, - { nxt_string("CONTENT_LENGTH"), &nxt_rb_content_length_str }, - { nxt_string("CONTENT_TYPE"), &nxt_rb_content_type_str }, - { nxt_string("http"), &nxt_rb_http_str }, - { nxt_string("https"), &nxt_rb_https_str }, - { nxt_string("PATH_INFO"), &nxt_rb_path_info_str }, - { nxt_string("QUERY_STRING"), &nxt_rb_query_string_str }, - { nxt_string("rack.url_scheme"), &nxt_rb_rack_url_scheme_str }, - { nxt_string("REMOTE_ADDR"), &nxt_rb_remote_addr_str }, - { nxt_string("REQUEST_METHOD"), &nxt_rb_request_method_str }, - { nxt_string("REQUEST_URI"), &nxt_rb_request_uri_str }, - { nxt_string("SERVER_ADDR"), &nxt_rb_server_addr_str }, - { nxt_string("SERVER_NAME"), &nxt_rb_server_name_str }, - { nxt_string("SERVER_PORT"), &nxt_rb_server_port_str }, - { nxt_string("SERVER_PROTOCOL"), &nxt_rb_server_protocol_str }, - { nxt_string("on_worker_boot"), &nxt_rb_on_worker_boot }, - { nxt_string("on_worker_shutdown"), &nxt_rb_on_worker_shutdown }, - { nxt_string("on_thread_boot"), &nxt_rb_on_thread_boot }, - { nxt_string("on_thread_shutdown"), &nxt_rb_on_thread_shutdown }, - { nxt_null_string, NULL }, -}; - - -static int -nxt_ruby_init_strings(void) -{ - VALUE v; - nxt_ruby_string_t *pstr; - - pstr = nxt_rb_strings; - - while (pstr->string.start != NULL) { - v = rb_str_new_static((char *) pstr->string.start, pstr->string.length); - - if (nxt_slow_path(v == Qnil)) { - nxt_unit_alert(NULL, "Ruby: failed to create const string '%.*s'", - (int) pstr->string.length, - (char *) pstr->string.start); - - return NXT_UNIT_ERROR; - } - - *pstr->v = v; - - rb_gc_register_address(pstr->v); - - pstr++; - } - - return NXT_UNIT_OK; -} - - -static void -nxt_ruby_done_strings(void) -{ - nxt_ruby_string_t *pstr; - - pstr = nxt_rb_strings; - - while (pstr->string.start != NULL) { - rb_gc_unregister_address(pstr->v); - - *pstr->v = Qnil; - - pstr++; - } -} - - -static VALUE -nxt_ruby_hook_procs_load(VALUE path) -{ - VALUE module, file, file_obj; - - module = rb_define_module("Unit"); - - nxt_ruby_hook_procs = rb_hash_new(); - - rb_gc_register_address(&nxt_ruby_hook_procs); - - rb_define_module_function(module, "on_worker_boot", - &nxt_ruby_hook_register, 0); - rb_define_module_function(module, "on_worker_shutdown", - &nxt_ruby_hook_register, 0); - rb_define_module_function(module, "on_thread_boot", - &nxt_ruby_hook_register, 0); - rb_define_module_function(module, "on_thread_shutdown", - &nxt_ruby_hook_register, 0); - - file = rb_const_get(rb_cObject, rb_intern("File")); - file_obj = rb_funcall(file, rb_intern("read"), 1, path); - - return rb_funcall(module, rb_intern("module_eval"), 3, file_obj, path, - INT2NUM(1)); -} - - -static VALUE -nxt_ruby_hook_register(VALUE arg) -{ - VALUE kernel, callee, callee_str; - - rb_need_block(); - - kernel = rb_const_get(rb_cObject, rb_intern("Kernel")); - callee = rb_funcall(kernel, rb_intern("__callee__"), 0); - callee_str = rb_funcall(callee, rb_intern("to_s"), 0); - - rb_hash_aset(nxt_ruby_hook_procs, callee_str, rb_block_proc()); - - return Qnil; -} - - -static VALUE -nxt_ruby_hook_call(VALUE name) -{ - VALUE proc; - - proc = rb_hash_lookup(nxt_ruby_hook_procs, name); - if (proc == Qnil) { - return Qnil; - } - - return rb_funcall(proc, rb_intern("call"), 0); -} - - -static nxt_int_t -nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data) -{ - int state, rc; - VALUE res, path; - nxt_ruby_ctx_t ruby_ctx; - nxt_unit_ctx_t *unit_ctx; - nxt_unit_init_t ruby_unit_init; - nxt_ruby_app_conf_t *c; - nxt_ruby_rack_init_t rack_init; - nxt_common_app_conf_t *conf; - - static char *argv[2] = { (char *) "NGINX_Unit", (char *) "-e0" }; - - signal(SIGINT, SIG_IGN); - - conf = data->app; - c = &conf->u.ruby; - - nxt_ruby_threads = c->threads; - - setlocale(LC_CTYPE, ""); - - RUBY_INIT_STACK - ruby_init(); - ruby_options(2, argv); - ruby_script("NGINX_Unit"); - - ruby_ctx.env = Qnil; - ruby_ctx.io_input = Qnil; - ruby_ctx.io_error = Qnil; - ruby_ctx.thread = Qnil; - ruby_ctx.ctx = NULL; - ruby_ctx.req = NULL; - - rack_init.task = task; - rack_init.script = &c->script; - rack_init.rctx = &ruby_ctx; - - nxt_ruby_init_strings(); - - res = rb_protect(nxt_ruby_init_basic, - (VALUE) (uintptr_t) &rack_init, &state); - if (nxt_slow_path(res == Qnil || state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ALERT, - "Failed to init basic variables"); - return NXT_ERROR; - } - - nxt_ruby_call = Qnil; - nxt_ruby_hook_procs = Qnil; - - if (c->hooks.start != NULL) { - path = rb_str_new((const char *) c->hooks.start, - (long) c->hooks.length); - - rb_protect(nxt_ruby_hook_procs_load, path, &state); - rb_str_free(path); - if (nxt_slow_path(state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ALERT, - "Failed to setup hooks"); - return NXT_ERROR; - } - } - - if (nxt_ruby_hook_procs != Qnil) { - rb_protect(nxt_ruby_hook_call, nxt_rb_on_worker_boot, &state); - if (nxt_slow_path(state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ERR, - "Failed to call on_worker_boot()"); - return NXT_ERROR; - } - } - - nxt_ruby_rackup = nxt_ruby_rack_init(&rack_init); - if (nxt_slow_path(nxt_ruby_rackup == Qnil)) { - return NXT_ERROR; - } - - rb_gc_register_address(&nxt_ruby_rackup); - - nxt_ruby_call = rb_intern("call"); - if (nxt_slow_path(nxt_ruby_call == Qnil)) { - nxt_alert(task, "Ruby: Unable to find rack entry point"); - - goto fail; - } - - rb_gc_register_address(&nxt_ruby_call); - - ruby_ctx.env = rb_protect(nxt_ruby_rack_env_create, - (VALUE) (uintptr_t) &ruby_ctx, &state); - if (nxt_slow_path(ruby_ctx.env == Qnil || state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ALERT, - "Failed to create 'environ' variable"); - goto fail; - } - - rc = nxt_ruby_init_threads(c); - if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { - goto fail; - } - - nxt_unit_default_init(task, &ruby_unit_init, conf); - - ruby_unit_init.callbacks.request_handler = nxt_ruby_request_handler; - ruby_unit_init.callbacks.ready_handler = nxt_ruby_ready_handler; - ruby_unit_init.data = c; - ruby_unit_init.ctx_data = &ruby_ctx; - - unit_ctx = nxt_unit_init(&ruby_unit_init); - if (nxt_slow_path(unit_ctx == NULL)) { - goto fail; - } - - if (nxt_ruby_hook_procs != Qnil) { - rb_protect(nxt_ruby_hook_call, nxt_rb_on_thread_boot, &state); - if (nxt_slow_path(state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ERR, - "Failed to call on_thread_boot()"); - } - } - - rc = (intptr_t) rb_thread_call_without_gvl2(nxt_ruby_unit_run, unit_ctx, - nxt_ruby_ubf, unit_ctx); - - if (nxt_ruby_hook_procs != Qnil) { - rb_protect(nxt_ruby_hook_call, nxt_rb_on_thread_shutdown, &state); - if (nxt_slow_path(state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ERR, - "Failed to call on_thread_shutdown()"); - } - } - - nxt_ruby_join_threads(unit_ctx, c); - - if (nxt_ruby_hook_procs != Qnil) { - rb_protect(nxt_ruby_hook_call, nxt_rb_on_worker_shutdown, &state); - if (nxt_slow_path(state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ERR, - "Failed to call on_worker_shutdown()"); - } - } - - nxt_unit_done(unit_ctx); - - nxt_ruby_ctx_done(&ruby_ctx); - - nxt_ruby_atexit(); - - exit(rc); - - return NXT_OK; - -fail: - - nxt_ruby_join_threads(NULL, c); - - nxt_ruby_ctx_done(&ruby_ctx); - - nxt_ruby_atexit(); - - return NXT_ERROR; -} - - -static VALUE -nxt_ruby_init_basic(VALUE arg) -{ - int state; - nxt_ruby_rack_init_t *rack_init; - - rack_init = (nxt_ruby_rack_init_t *) (uintptr_t) arg; - - state = rb_enc_find_index("encdb"); - if (nxt_slow_path(state == 0)) { - nxt_alert(rack_init->task, - "Ruby: Failed to find encoding index 'encdb'"); - - return Qnil; - } - - rb_funcall(rb_cObject, rb_intern("require"), 1, - rb_str_new2("enc/trans/transdb")); - - return arg; -} - - -static VALUE -nxt_ruby_rack_init(nxt_ruby_rack_init_t *rack_init) -{ - int state; - VALUE rackup, err; - - rb_protect(nxt_ruby_require_rubygems, Qnil, &state); - if (nxt_slow_path(state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ALERT, - "Failed to require 'rubygems' package"); - return Qnil; - } - - rb_protect(nxt_ruby_bundler_setup, Qnil, &state); - if (state != 0) { - err = rb_errinfo(); - - if (rb_obj_is_kind_of(err, rb_eLoadError) == Qfalse) { - nxt_ruby_exception_log(NULL, NXT_LOG_ALERT, - "Failed to require 'bundler/setup' package"); - return Qnil; - } - - rb_set_errinfo(Qnil); - } - - rb_protect(nxt_ruby_require_rack, Qnil, &state); - if (nxt_slow_path(state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ALERT, - "Failed to require 'rack' package"); - return Qnil; - } - - rackup = rb_protect(nxt_ruby_rack_parse_script, - (VALUE) (uintptr_t) rack_init, &state); - - if (nxt_slow_path(state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ALERT, - "Failed to parse rack script"); - return Qnil; - } - - if (TYPE(rackup) != T_ARRAY) { - return rackup; - } - - if (nxt_slow_path(RARRAY_LEN(rackup) < 1)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ALERT, "Invalid rack config file"); - return Qnil; - } - - return RARRAY_PTR(rackup)[0]; -} - - -static VALUE -nxt_ruby_require_rubygems(VALUE arg) -{ - return rb_funcall(rb_cObject, rb_intern("require"), 1, - rb_str_new2("rubygems")); -} - - -static VALUE -nxt_ruby_bundler_setup(VALUE arg) -{ - return rb_funcall(rb_cObject, rb_intern("require"), 1, - rb_str_new2("bundler/setup")); -} - - -static VALUE -nxt_ruby_require_rack(VALUE arg) -{ - return rb_funcall(rb_cObject, rb_intern("require"), 1, rb_str_new2("rack")); -} - - -static VALUE -nxt_ruby_rack_parse_script(VALUE ctx) -{ - VALUE script, res, rack, builder; - nxt_ruby_rack_init_t *rack_init; - - rack_init = (nxt_ruby_rack_init_t *) (uintptr_t) ctx; - - rack = rb_const_get(rb_cObject, rb_intern("Rack")); - builder = rb_const_get(rack, rb_intern("Builder")); - - script = rb_str_new((const char *) rack_init->script->start, - (long) rack_init->script->length); - - res = rb_funcall(builder, rb_intern("parse_file"), 1, script); - - rb_str_free(script); - - return res; -} - - -static VALUE -nxt_ruby_rack_env_create(VALUE arg) -{ - int rc; - VALUE hash_env, version; - nxt_ruby_ctx_t *rctx; - - rctx = (nxt_ruby_ctx_t *) (uintptr_t) arg; - - rc = nxt_ruby_init_io(rctx); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return Qnil; - } - - hash_env = rb_hash_new(); - - rb_hash_aset(hash_env, rb_str_new2("SERVER_SOFTWARE"), - rb_str_new((const char *) nxt_server.start, - (long) nxt_server.length)); - - version = rb_ary_new(); - - rb_ary_push(version, UINT2NUM(NXT_RUBY_RACK_API_VERSION_MAJOR)); - rb_ary_push(version, UINT2NUM(NXT_RUBY_RACK_API_VERSION_MINOR)); - - rb_hash_aset(hash_env, rb_str_new2("SCRIPT_NAME"), rb_str_new("", 0)); - rb_hash_aset(hash_env, rb_str_new2("rack.version"), version); - rb_hash_aset(hash_env, rb_str_new2("rack.input"), rctx->io_input); - rb_hash_aset(hash_env, rb_str_new2("rack.errors"), rctx->io_error); - rb_hash_aset(hash_env, rb_str_new2("rack.multithread"), - nxt_ruby_threads > 1 ? Qtrue : Qfalse); - rb_hash_aset(hash_env, rb_str_new2("rack.multiprocess"), Qtrue); - rb_hash_aset(hash_env, rb_str_new2("rack.run_once"), Qfalse); - rb_hash_aset(hash_env, rb_str_new2("rack.hijack?"), Qfalse); - rb_hash_aset(hash_env, rb_str_new2("rack.hijack"), Qnil); - rb_hash_aset(hash_env, rb_str_new2("rack.hijack_io"), Qnil); - - rctx->env = hash_env; - - rb_gc_register_address(&rctx->env); - - return hash_env; -} - - -static int -nxt_ruby_init_io(nxt_ruby_ctx_t *rctx) -{ - VALUE io_input, io_error; - - io_input = nxt_ruby_stream_io_input_init(); - - rctx->io_input = rb_funcall(io_input, rb_intern("new"), 1, - (VALUE) (uintptr_t) rctx); - if (nxt_slow_path(rctx->io_input == Qnil)) { - nxt_unit_alert(NULL, - "Ruby: Failed to create environment 'rack.input' var"); - - return NXT_UNIT_ERROR; - } - - rb_gc_register_address(&rctx->io_input); - - io_error = nxt_ruby_stream_io_error_init(); - - rctx->io_error = rb_funcall(io_error, rb_intern("new"), 1, - (VALUE) (uintptr_t) rctx); - if (nxt_slow_path(rctx->io_error == Qnil)) { - nxt_unit_alert(NULL, - "Ruby: Failed to create environment 'rack.error' var"); - - return NXT_UNIT_ERROR; - } - - rb_gc_register_address(&rctx->io_error); - - return NXT_UNIT_OK; -} - - -static void -nxt_ruby_request_handler(nxt_unit_request_info_t *req) -{ - (void) rb_thread_call_with_gvl(nxt_ruby_request_handler_gvl, req); -} - - -static void * -nxt_ruby_request_handler_gvl(void *data) -{ - int state; - VALUE res; - nxt_ruby_ctx_t *rctx; - nxt_unit_request_info_t *req; - - req = data; - - rctx = req->ctx->data; - rctx->req = req; - - res = rb_protect(nxt_ruby_rack_app_run, (VALUE) (uintptr_t) req, &state); - if (nxt_slow_path(res == Qnil || state != 0)) { - nxt_ruby_exception_log(req, NXT_LOG_ERR, - "Failed to run ruby script"); - - nxt_unit_request_done(req, NXT_UNIT_ERROR); - - } else { - nxt_unit_request_done(req, NXT_UNIT_OK); - } - - rctx->req = NULL; - - return NULL; -} - - -static VALUE -nxt_ruby_rack_app_run(VALUE arg) -{ - int rc; - VALUE env, result; - nxt_int_t status; - nxt_ruby_ctx_t *rctx; - nxt_unit_request_info_t *req; - - req = (nxt_unit_request_info_t *) arg; - - rctx = req->ctx->data; - - env = rb_hash_dup(rctx->env); - - rc = nxt_ruby_read_request(req, env); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_req_alert(req, - "Ruby: Failed to process incoming request"); - - goto fail; - } - - result = rb_funcall(nxt_ruby_rackup, nxt_ruby_call, 1, env); - if (nxt_slow_path(TYPE(result) != T_ARRAY)) { - nxt_unit_req_error(req, - "Ruby: Invalid response format from application"); - - goto fail; - } - - if (nxt_slow_path(RARRAY_LEN(result) != 3)) { - nxt_unit_req_error(req, - "Ruby: Invalid response format from application. " - "Need 3 entries [Status, Headers, Body]"); - - goto fail; - } - - status = nxt_ruby_rack_result_status(req, result); - if (nxt_slow_path(status < 0)) { - nxt_unit_req_error(req, - "Ruby: Invalid response status from application."); - - goto fail; - } - - rc = nxt_ruby_rack_result_headers(req, result, status); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - rc = nxt_ruby_rack_result_body(req, result); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - rb_hash_delete(env, rb_obj_id(env)); - - return result; - -fail: - - rb_hash_delete(env, rb_obj_id(env)); - - return Qnil; -} - - -static int -nxt_ruby_read_request(nxt_unit_request_info_t *req, VALUE hash_env) -{ - VALUE name; - uint32_t i; - nxt_unit_field_t *f; - nxt_unit_request_t *r; - - r = req->request; - - nxt_ruby_add_sptr(hash_env, nxt_rb_request_method_str, &r->method, - r->method_length); - nxt_ruby_add_sptr(hash_env, nxt_rb_request_uri_str, &r->target, - r->target_length); - nxt_ruby_add_sptr(hash_env, nxt_rb_path_info_str, &r->path, r->path_length); - nxt_ruby_add_sptr(hash_env, nxt_rb_query_string_str, &r->query, - r->query_length); - nxt_ruby_add_sptr(hash_env, nxt_rb_server_protocol_str, &r->version, - r->version_length); - nxt_ruby_add_sptr(hash_env, nxt_rb_remote_addr_str, &r->remote, - r->remote_length); - nxt_ruby_add_sptr(hash_env, nxt_rb_server_addr_str, &r->local_addr, - r->local_addr_length); - nxt_ruby_add_sptr(hash_env, nxt_rb_server_name_str, &r->server_name, - r->server_name_length); - - rb_hash_aset(hash_env, nxt_rb_server_port_str, nxt_rb_80_str); - - rb_hash_aset(hash_env, nxt_rb_rack_url_scheme_str, - r->tls ? nxt_rb_https_str : nxt_rb_http_str); - - for (i = 0; i < r->fields_count; i++) { - f = r->fields + i; - - name = rb_str_new(nxt_unit_sptr_get(&f->name), f->name_length); - - nxt_ruby_add_sptr(hash_env, name, &f->value, f->value_length); - } - - if (r->content_length_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->content_length_field; - - nxt_ruby_add_sptr(hash_env, nxt_rb_content_length_str, - &f->value, f->value_length); - } - - if (r->content_type_field != NXT_UNIT_NONE_FIELD) { - f = r->fields + r->content_type_field; - - nxt_ruby_add_sptr(hash_env, nxt_rb_content_type_str, - &f->value, f->value_length); - } - - return NXT_UNIT_OK; -} - - -nxt_inline void -nxt_ruby_add_sptr(VALUE hash_env, VALUE name, - nxt_unit_sptr_t *sptr, uint32_t len) -{ - char *str; - - str = nxt_unit_sptr_get(sptr); - - rb_hash_aset(hash_env, name, rb_str_new(str, len)); -} - - -static nxt_int_t -nxt_ruby_rack_result_status(nxt_unit_request_info_t *req, VALUE result) -{ - VALUE status; - - status = rb_ary_entry(result, 0); - - if (TYPE(status) == T_FIXNUM) { - return FIX2INT(status); - } - - if (TYPE(status) == T_STRING) { - return nxt_int_parse((u_char *) RSTRING_PTR(status), - RSTRING_LEN(status)); - } - - nxt_unit_req_error(req, "Ruby: Invalid response 'status' " - "format from application"); - - return -2; -} - - -typedef struct { - int rc; - uint32_t fields; - uint32_t size; - nxt_unit_request_info_t *req; -} nxt_ruby_headers_info_t; - - -static int -nxt_ruby_rack_result_headers(nxt_unit_request_info_t *req, VALUE result, - nxt_int_t status) -{ - int rc; - VALUE headers; - nxt_ruby_headers_info_t headers_info; - - headers = rb_ary_entry(result, 1); - if (nxt_slow_path(TYPE(headers) != T_HASH)) { - nxt_unit_req_error(req, - "Ruby: Invalid response 'headers' format from " - "application"); - - return NXT_UNIT_ERROR; - } - - rc = NXT_UNIT_OK; - - headers_info.rc = NXT_UNIT_OK; - headers_info.fields = 0; - headers_info.size = 0; - headers_info.req = req; - - rb_hash_foreach(headers, nxt_ruby_hash_info, - (VALUE) (uintptr_t) &headers_info); - if (nxt_slow_path(headers_info.rc != NXT_UNIT_OK)) { - return headers_info.rc; - } - - rc = nxt_unit_response_init(req, status, - headers_info.fields, headers_info.size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - rb_hash_foreach(headers, nxt_ruby_hash_add, - (VALUE) (uintptr_t) &headers_info); - - return rc; -} - - -static int -nxt_ruby_hash_info(VALUE r_key, VALUE r_value, VALUE arg) -{ - const char *value, *value_end, *pos; - nxt_ruby_headers_info_t *headers_info; - - headers_info = (void *) (uintptr_t) arg; - - if (nxt_slow_path(TYPE(r_key) != T_STRING)) { - nxt_unit_req_error(headers_info->req, - "Ruby: Wrong header entry 'key' from application"); - - goto fail; - } - - if (nxt_slow_path(TYPE(r_value) != T_STRING && TYPE(r_value) != T_ARRAY)) { - nxt_unit_req_error(headers_info->req, - "Ruby: Wrong header entry 'value' from application"); - - goto fail; - } - - if (TYPE(r_value) == T_ARRAY) { - int i; - int arr_len = RARRAY_LEN(r_value); - VALUE item; - size_t len = 0; - - for (i = 0; i < arr_len; i++) { - item = rb_ary_entry(r_value, i); - if (TYPE(item) != T_STRING) { - nxt_unit_req_error(headers_info->req, - "Ruby: Wrong header entry in 'value' array " - "from application"); - goto fail; - } - - len += RSTRING_LEN(item) + 2; /* +2 for '; ' */ - } - - if (arr_len > 0) { - len -= 2; - } - - headers_info->fields++; - headers_info->size += RSTRING_LEN(r_key) + len; - - return ST_CONTINUE; - } - - value = RSTRING_PTR(r_value); - value_end = value + RSTRING_LEN(r_value); - - pos = value; - - for ( ;; ) { - pos = strchr(pos, '\n'); - - if (pos == NULL) { - break; - } - - headers_info->fields++; - headers_info->size += RSTRING_LEN(r_key) + (pos - value); - - pos++; - value = pos; - } - - if (value <= value_end) { - headers_info->fields++; - headers_info->size += RSTRING_LEN(r_key) + (value_end - value); - } - - return ST_CONTINUE; - -fail: - - headers_info->rc = NXT_UNIT_ERROR; - - return ST_STOP; -} - - -static int -nxt_ruby_hash_add(VALUE r_key, VALUE r_value, VALUE arg) -{ - int *rc; - uint32_t key_len; - const char *value, *value_end, *pos; - nxt_ruby_headers_info_t *headers_info; - - headers_info = (void *) (uintptr_t) arg; - rc = &headers_info->rc; - - key_len = RSTRING_LEN(r_key); - - if (TYPE(r_value) == T_ARRAY) { - int i; - int arr_len = RARRAY_LEN(r_value); - char *field, *p; - VALUE item; - size_t len = 0; - - for (i = 0; i < arr_len; i++) { - item = rb_ary_entry(r_value, i); - - len += RSTRING_LEN(item) + 2; /* +2 for '; ' */ - } - - field = nxt_unit_malloc(NULL, len); - if (field == NULL) { - goto fail; - } - - p = field; - - for (i = 0; i < arr_len; i++) { - item = rb_ary_entry(r_value, i); - - p = nxt_cpymem(p, RSTRING_PTR(item), RSTRING_LEN(item)); - p = nxt_cpymem(p, "; ", 2); - } - - if (arr_len > 0) { - len -= 2; - } - - *rc = nxt_unit_response_add_field(headers_info->req, - RSTRING_PTR(r_key), key_len, - field, len); - nxt_unit_free(NULL, field); - - if (nxt_slow_path(*rc != NXT_UNIT_OK)) { - goto fail; - } - - return ST_CONTINUE; - } - - value = RSTRING_PTR(r_value); - value_end = value + RSTRING_LEN(r_value); - - pos = value; - - for ( ;; ) { - pos = strchr(pos, '\n'); - - if (pos == NULL) { - break; - } - - *rc = nxt_unit_response_add_field(headers_info->req, - RSTRING_PTR(r_key), key_len, - value, pos - value); - if (nxt_slow_path(*rc != NXT_UNIT_OK)) { - goto fail; - } - - pos++; - value = pos; - } - - if (value <= value_end) { - *rc = nxt_unit_response_add_field(headers_info->req, - RSTRING_PTR(r_key), key_len, - value, value_end - value); - if (nxt_slow_path(*rc != NXT_UNIT_OK)) { - goto fail; - } - } - - return ST_CONTINUE; - -fail: - - *rc = NXT_UNIT_ERROR; - - return ST_STOP; -} - - -static int -nxt_ruby_rack_result_body(nxt_unit_request_info_t *req, VALUE result) -{ - int rc; - VALUE fn, body; - - body = rb_ary_entry(result, 2); - - if (rb_respond_to(body, rb_intern("to_path"))) { - - fn = rb_funcall(body, rb_intern("to_path"), 0); - if (nxt_slow_path(TYPE(fn) != T_STRING)) { - nxt_unit_req_error(req, - "Ruby: Failed to get 'body' file path from " - "application"); - - return NXT_UNIT_ERROR; - } - - rc = nxt_ruby_rack_result_body_file_write(req, fn); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - } else if (rb_respond_to(body, rb_intern("each"))) { - rb_block_call(body, rb_intern("each"), 0, 0, - nxt_ruby_rack_result_body_each, (VALUE) (uintptr_t) req); - - } else { - nxt_unit_req_error(req, - "Ruby: Invalid response 'body' format " - "from application"); - - return NXT_UNIT_ERROR; - } - - if (rb_respond_to(body, rb_intern("close"))) { - rb_funcall(body, rb_intern("close"), 0); - } - - return NXT_UNIT_OK; -} - - -typedef struct { - int fd; - off_t pos; - off_t rest; -} nxt_ruby_rack_file_t; - - -static ssize_t -nxt_ruby_rack_file_read(nxt_unit_read_info_t *read_info, void *dst, size_t size) -{ - ssize_t res; - nxt_ruby_rack_file_t *file; - - file = read_info->data; - - size = nxt_min(size, (size_t) file->rest); - - res = pread(file->fd, dst, size, file->pos); - - if (res >= 0) { - file->pos += res; - file->rest -= res; - - if (size > (size_t) res) { - file->rest = 0; - } - } - - read_info->eof = file->rest == 0; - - return res; -} - - -typedef struct { - nxt_unit_read_info_t read_info; - nxt_unit_request_info_t *req; -} nxt_ruby_read_info_t; - - -static int -nxt_ruby_rack_result_body_file_write(nxt_unit_request_info_t *req, - VALUE filepath) -{ - int fd, rc; - struct stat finfo; - nxt_ruby_rack_file_t ruby_file; - nxt_ruby_read_info_t ri; - - fd = open(RSTRING_PTR(filepath), O_RDONLY, 0); - if (nxt_slow_path(fd == -1)) { - nxt_unit_req_error(req, - "Ruby: Failed to open content file \"%s\": %s (%d)", - RSTRING_PTR(filepath), strerror(errno), errno); - - return NXT_UNIT_ERROR; - } - - rc = fstat(fd, &finfo); - if (nxt_slow_path(rc == -1)) { - nxt_unit_req_error(req, - "Ruby: Content file fstat(\"%s\") failed: %s (%d)", - RSTRING_PTR(filepath), strerror(errno), errno); - - close(fd); - - return NXT_UNIT_ERROR; - } - - ruby_file.fd = fd; - ruby_file.pos = 0; - ruby_file.rest = finfo.st_size; - - ri.read_info.read = nxt_ruby_rack_file_read; - ri.read_info.eof = ruby_file.rest == 0; - ri.read_info.buf_size = ruby_file.rest; - ri.read_info.data = &ruby_file; - ri.req = req; - - rc = (intptr_t) rb_thread_call_without_gvl(nxt_ruby_response_write_cb, - &ri, - nxt_ruby_ubf, - req->ctx); - - close(fd); - - return rc; -} - - -static void * -nxt_ruby_response_write_cb(void *data) -{ - int rc; - nxt_ruby_read_info_t *ri; - - ri = data; - - rc = nxt_unit_response_write_cb(ri->req, &ri->read_info); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_req_error(ri->req, "Ruby: Failed to write content file."); - } - - return (void *) (intptr_t) rc; -} - - -typedef struct { - VALUE body; - nxt_unit_request_info_t *req; -} nxt_ruby_write_info_t; - - -static VALUE -nxt_ruby_rack_result_body_each(VALUE body, VALUE arg, int argc, - const VALUE *argv, VALUE blockarg) -{ - nxt_ruby_write_info_t wi; - - if (TYPE(body) != T_STRING) { - return Qnil; - } - - wi.body = body; - wi.req = (void *) (uintptr_t) arg; - - (void) rb_thread_call_without_gvl(nxt_ruby_response_write, - (void *) (uintptr_t) &wi, - nxt_ruby_ubf, wi.req->ctx); - - return Qnil; -} - - -static void * -nxt_ruby_response_write(void *data) -{ - int rc; - nxt_ruby_write_info_t *wi; - - wi = data; - - rc = nxt_unit_response_write(wi->req, RSTRING_PTR(wi->body), - RSTRING_LEN(wi->body)); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - nxt_unit_req_error(wi->req, - "Ruby: Failed to write 'body' from application"); - } - - return (void *) (intptr_t) rc; -} - - -static void -nxt_ruby_exception_log(nxt_unit_request_info_t *req, uint32_t level, - const char *desc) -{ - int i; - VALUE err, ary, eclass, msg; - - nxt_unit_req_log(req, level, "Ruby: %s", desc); - - err = rb_errinfo(); - if (nxt_slow_path(err == Qnil)) { - return; - } - - eclass = rb_class_name(rb_class_of(err)); - - msg = rb_funcall(err, rb_intern("message"), 0); - ary = rb_funcall(err, rb_intern("backtrace"), 0); - - if (RARRAY_LEN(ary) == 0) { - nxt_unit_req_log(req, level, "Ruby: %s (%s)", RSTRING_PTR(msg), - RSTRING_PTR(eclass)); - - return; - } - - nxt_unit_req_log(req, level, "Ruby: %s: %s (%s)", - RSTRING_PTR(RARRAY_PTR(ary)[0]), - RSTRING_PTR(msg), RSTRING_PTR(eclass)); - - for (i = 1; i < RARRAY_LEN(ary); i++) { - nxt_unit_req_log(req, level, "from %s", - RSTRING_PTR(RARRAY_PTR(ary)[i])); - } -} - - -static void -nxt_ruby_ctx_done(nxt_ruby_ctx_t *rctx) -{ - if (rctx->io_input != Qnil) { - rb_gc_unregister_address(&rctx->io_input); - } - - if (rctx->io_error != Qnil) { - rb_gc_unregister_address(&rctx->io_error); - } - - if (rctx->env != Qnil) { - rb_gc_unregister_address(&rctx->env); - } -} - - -static void -nxt_ruby_atexit(void) -{ - if (nxt_ruby_rackup != Qnil) { - rb_gc_unregister_address(&nxt_ruby_rackup); - } - - if (nxt_ruby_call != Qnil) { - rb_gc_unregister_address(&nxt_ruby_call); - } - - if (nxt_ruby_hook_procs != Qnil) { - rb_gc_unregister_address(&nxt_ruby_hook_procs); - } - - nxt_ruby_done_strings(); - - ruby_cleanup(0); -} - - -static int -nxt_ruby_ready_handler(nxt_unit_ctx_t *ctx) -{ - VALUE res; - uint32_t i; - nxt_ruby_ctx_t *rctx; - nxt_ruby_app_conf_t *c; - - c = ctx->unit->data; - - if (c->threads <= 1) { - return NXT_UNIT_OK; - } - - for (i = 0; i < c->threads - 1; i++) { - rctx = &nxt_ruby_ctxs[i]; - - rctx->ctx = ctx; - - res = (VALUE) rb_thread_call_with_gvl(nxt_ruby_thread_create_gvl, rctx); - - if (nxt_fast_path(res != Qnil)) { - nxt_unit_debug(ctx, "thread #%d created", (int) (i + 1)); - - rctx->thread = res; - - } else { - nxt_unit_alert(ctx, "thread #%d create failed", (int) (i + 1)); - - return NXT_UNIT_ERROR; - } - } - - return NXT_UNIT_OK; -} - - -static void * -nxt_ruby_thread_create_gvl(void *rctx) -{ - VALUE res; - - res = rb_thread_create(RUBY_METHOD_FUNC(nxt_ruby_thread_func), rctx); - - return (void *) (uintptr_t) res; -} - - -static VALUE -nxt_ruby_thread_func(VALUE arg) -{ - int state; - nxt_unit_ctx_t *ctx; - nxt_ruby_ctx_t *rctx; - - rctx = (nxt_ruby_ctx_t *) (uintptr_t) arg; - - nxt_unit_debug(rctx->ctx, "worker thread start"); - - ctx = nxt_unit_ctx_alloc(rctx->ctx, rctx); - if (nxt_slow_path(ctx == NULL)) { - goto fail; - } - - if (nxt_ruby_hook_procs != Qnil) { - rb_protect(nxt_ruby_hook_call, nxt_rb_on_thread_boot, &state); - if (nxt_slow_path(state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ERR, - "Failed to call on_thread_boot()"); - } - } - - (void) rb_thread_call_without_gvl(nxt_ruby_unit_run, ctx, - nxt_ruby_ubf, ctx); - - if (nxt_ruby_hook_procs != Qnil) { - rb_protect(nxt_ruby_hook_call, nxt_rb_on_thread_shutdown, &state); - if (nxt_slow_path(state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ERR, - "Failed to call on_thread_shutdown()"); - } - } - - nxt_unit_done(ctx); - -fail: - - nxt_unit_debug(NULL, "worker thread end"); - - return Qnil; -} - - -static void * -nxt_ruby_unit_run(void *ctx) -{ - return (void *) (intptr_t) nxt_unit_run(ctx); -} - - -static void -nxt_ruby_ubf(void *ctx) -{ - nxt_unit_warn(ctx, "Ruby: UBF"); -} - - -static int -nxt_ruby_init_threads(nxt_ruby_app_conf_t *c) -{ - int state; - uint32_t i; - nxt_ruby_ctx_t *rctx; - - if (c->threads <= 1) { - return NXT_UNIT_OK; - } - - nxt_ruby_ctxs = nxt_unit_malloc(NULL, sizeof(nxt_ruby_ctx_t) - * (c->threads - 1)); - if (nxt_slow_path(nxt_ruby_ctxs == NULL)) { - nxt_unit_alert(NULL, "Failed to allocate run contexts array"); - - return NXT_UNIT_ERROR; - } - - for (i = 0; i < c->threads - 1; i++) { - rctx = &nxt_ruby_ctxs[i]; - - rctx->env = Qnil; - rctx->io_input = Qnil; - rctx->io_error = Qnil; - rctx->thread = Qnil; - } - - for (i = 0; i < c->threads - 1; i++) { - rctx = &nxt_ruby_ctxs[i]; - - rctx->env = rb_protect(nxt_ruby_rack_env_create, - (VALUE) (uintptr_t) rctx, &state); - if (nxt_slow_path(rctx->env == Qnil || state != 0)) { - nxt_ruby_exception_log(NULL, NXT_LOG_ALERT, - "Failed to create 'environ' variable"); - return NXT_UNIT_ERROR; - } - } - - return NXT_UNIT_OK; -} - - -static void -nxt_ruby_join_threads(nxt_unit_ctx_t *ctx, nxt_ruby_app_conf_t *c) -{ - uint32_t i; - nxt_ruby_ctx_t *rctx; - - if (nxt_ruby_ctxs == NULL) { - return; - } - - for (i = 0; i < c->threads - 1; i++) { - rctx = &nxt_ruby_ctxs[i]; - - if (rctx->thread != Qnil) { - rb_funcall(rctx->thread, rb_intern("join"), 0); - - nxt_unit_debug(ctx, "thread #%d joined", (int) (i + 1)); - - } else { - nxt_unit_debug(ctx, "thread #%d not started", (int) (i + 1)); - } - } - - for (i = 0; i < c->threads - 1; i++) { - nxt_ruby_ctx_done(&nxt_ruby_ctxs[i]); - } - - nxt_unit_free(ctx, nxt_ruby_ctxs); -} diff --git a/src/ruby/nxt_ruby.h b/src/ruby/nxt_ruby.h deleted file mode 100644 index 26430021..00000000 --- a/src/ruby/nxt_ruby.h +++ /dev/null @@ -1,36 +0,0 @@ - -/* - * Copyright (C) Alexander Borisov - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_RUBY_H_INCLUDED_ -#define _NXT_RUBY_H_INCLUDED_ - - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -typedef struct { - VALUE env; - VALUE io_input; - VALUE io_error; - VALUE thread; - nxt_unit_ctx_t *ctx; - nxt_unit_request_info_t *req; -} nxt_ruby_ctx_t; - - -VALUE nxt_ruby_stream_io_input_init(void); -VALUE nxt_ruby_stream_io_error_init(void); - -#endif /* _NXT_RUBY_H_INCLUDED_ */ diff --git a/src/ruby/nxt_ruby_stream_io.c b/src/ruby/nxt_ruby_stream_io.c deleted file mode 100644 index 4ef69cee..00000000 --- a/src/ruby/nxt_ruby_stream_io.c +++ /dev/null @@ -1,269 +0,0 @@ - -/* - * Copyright (C) Alexander Borisov - * Copyright (C) NGINX, Inc. - */ - -#include -#include - - -static VALUE nxt_ruby_stream_io_new(VALUE class, VALUE arg); -static VALUE nxt_ruby_stream_io_initialize(int argc, VALUE *argv, VALUE self); -static VALUE nxt_ruby_stream_io_gets(VALUE obj); -static VALUE nxt_ruby_stream_io_each(VALUE obj); -static VALUE nxt_ruby_stream_io_read(VALUE obj, VALUE args); -static VALUE nxt_ruby_stream_io_rewind(VALUE obj); -static VALUE nxt_ruby_stream_io_puts(VALUE obj, VALUE args); -static VALUE nxt_ruby_stream_io_write(VALUE obj, VALUE args); -nxt_inline long nxt_ruby_stream_io_s_write(nxt_ruby_ctx_t *rctx, VALUE val); -static VALUE nxt_ruby_stream_io_flush(VALUE obj); -static VALUE nxt_ruby_stream_io_close(VALUE obj); - - -VALUE -nxt_ruby_stream_io_input_init(void) -{ - VALUE stream_io; - - stream_io = rb_define_class("NGINX_Unit_Stream_IO_Read", rb_cObject); - - rb_undef_alloc_func(stream_io); - - rb_gc_register_address(&stream_io); - - rb_define_singleton_method(stream_io, "new", nxt_ruby_stream_io_new, 1); - rb_define_method(stream_io, "initialize", - nxt_ruby_stream_io_initialize, -1); - rb_define_method(stream_io, "gets", nxt_ruby_stream_io_gets, 0); - rb_define_method(stream_io, "each", nxt_ruby_stream_io_each, 0); - rb_define_method(stream_io, "read", nxt_ruby_stream_io_read, -2); - rb_define_method(stream_io, "rewind", nxt_ruby_stream_io_rewind, 0); - rb_define_method(stream_io, "close", nxt_ruby_stream_io_close, 0); - - return stream_io; -} - - -VALUE -nxt_ruby_stream_io_error_init(void) -{ - VALUE stream_io; - - stream_io = rb_define_class("NGINX_Unit_Stream_IO_Error", rb_cObject); - - rb_undef_alloc_func(stream_io); - - rb_gc_register_address(&stream_io); - - rb_define_singleton_method(stream_io, "new", nxt_ruby_stream_io_new, 1); - rb_define_method(stream_io, "initialize", - nxt_ruby_stream_io_initialize, -1); - rb_define_method(stream_io, "puts", nxt_ruby_stream_io_puts, -2); - rb_define_method(stream_io, "write", nxt_ruby_stream_io_write, -2); - rb_define_method(stream_io, "flush", nxt_ruby_stream_io_flush, 0); - rb_define_method(stream_io, "close", nxt_ruby_stream_io_close, 0); - - return stream_io; -} - - -static VALUE -nxt_ruby_stream_io_new(VALUE class, VALUE arg) -{ - VALUE self; - - self = Data_Wrap_Struct(class, 0, 0, (void *) (uintptr_t) arg); - - rb_obj_call_init(self, 0, NULL); - - return self; -} - - -static VALUE -nxt_ruby_stream_io_initialize(int argc, VALUE *argv, VALUE self) -{ - return self; -} - - -static VALUE -nxt_ruby_stream_io_gets(VALUE obj) -{ - VALUE buf; - ssize_t res; - nxt_ruby_ctx_t *rctx; - nxt_unit_request_info_t *req; - - Data_Get_Struct(obj, nxt_ruby_ctx_t, rctx); - req = rctx->req; - - if (req->content_length == 0) { - return Qnil; - } - - res = nxt_unit_request_readline_size(req, SSIZE_MAX); - if (nxt_slow_path(res < 0)) { - return Qnil; - } - - buf = rb_str_buf_new(res); - - if (nxt_slow_path(buf == Qnil)) { - return Qnil; - } - - res = nxt_unit_request_read(req, RSTRING_PTR(buf), res); - - rb_str_set_len(buf, res); - - return buf; -} - - -static VALUE -nxt_ruby_stream_io_each(VALUE obj) -{ - VALUE chunk; - - if (rb_block_given_p() == 0) { - rb_raise(rb_eArgError, "Expected block on rack.input 'each' method"); - } - - for ( ;; ) { - chunk = nxt_ruby_stream_io_gets(obj); - - if (chunk == Qnil) { - return Qnil; - } - - rb_yield(chunk); - } - - return Qnil; -} - - -static VALUE -nxt_ruby_stream_io_read(VALUE obj, VALUE args) -{ - VALUE buf; - long copy_size, u_size; - nxt_ruby_ctx_t *rctx; - - Data_Get_Struct(obj, nxt_ruby_ctx_t, rctx); - - copy_size = rctx->req->content_length; - - if (RARRAY_LEN(args) > 0 && TYPE(RARRAY_PTR(args)[0]) == T_FIXNUM) { - u_size = NUM2LONG(RARRAY_PTR(args)[0]); - - if (u_size < 0 || copy_size == 0) { - return Qnil; - } - - if (copy_size > u_size) { - copy_size = u_size; - } - } - - if (copy_size == 0) { - return rb_str_new_cstr(""); - } - - buf = rb_str_buf_new(copy_size); - - if (nxt_slow_path(buf == Qnil)) { - return Qnil; - } - - copy_size = nxt_unit_request_read(rctx->req, RSTRING_PTR(buf), copy_size); - - if (RARRAY_LEN(args) > 1 && TYPE(RARRAY_PTR(args)[1]) == T_STRING) { - - rb_str_set_len(RARRAY_PTR(args)[1], 0); - rb_str_cat(RARRAY_PTR(args)[1], RSTRING_PTR(buf), copy_size); - } - - rb_str_set_len(buf, copy_size); - - return buf; -} - - -static VALUE -nxt_ruby_stream_io_rewind(VALUE obj) -{ - return Qnil; -} - - -static VALUE -nxt_ruby_stream_io_puts(VALUE obj, VALUE args) -{ - nxt_ruby_ctx_t *rctx; - - if (RARRAY_LEN(args) != 1) { - return Qnil; - } - - Data_Get_Struct(obj, nxt_ruby_ctx_t, rctx); - - nxt_ruby_stream_io_s_write(rctx, RARRAY_PTR(args)[0]); - - return Qnil; -} - - -static VALUE -nxt_ruby_stream_io_write(VALUE obj, VALUE args) -{ - long len; - nxt_ruby_ctx_t *rctx; - - if (RARRAY_LEN(args) != 1) { - return Qnil; - } - - Data_Get_Struct(obj, nxt_ruby_ctx_t, rctx); - - len = nxt_ruby_stream_io_s_write(rctx, RARRAY_PTR(args)[0]); - - return LONG2FIX(len); -} - - -nxt_inline long -nxt_ruby_stream_io_s_write(nxt_ruby_ctx_t *rctx, VALUE val) -{ - if (nxt_slow_path(val == Qnil)) { - return 0; - } - - if (TYPE(val) != T_STRING) { - val = rb_funcall(val, rb_intern("to_s"), 0); - - if (TYPE(val) != T_STRING) { - return 0; - } - } - - nxt_unit_req_error(rctx->req, "Ruby: %s", RSTRING_PTR(val)); - - return RSTRING_LEN(val); -} - - -static VALUE -nxt_ruby_stream_io_flush(VALUE obj) -{ - return Qnil; -} - - -static VALUE -nxt_ruby_stream_io_close(VALUE obj) -{ - return Qnil; -} diff --git a/src/test/nxt_base64_test.c b/src/test/nxt_base64_test.c deleted file mode 100644 index 13a772b6..00000000 --- a/src/test/nxt_base64_test.c +++ /dev/null @@ -1,98 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -nxt_int_t -nxt_base64_test(nxt_thread_t *thr) -{ - ssize_t ret; - nxt_uint_t i; - - static struct { - nxt_str_t enc; - nxt_str_t dec; - - } tests[] = { - { nxt_string("ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+//+9876543210" - "zyxwvutsrqponmlkjihgfedcba" - "ZYXWVUTSRQPONMLKJIHGFEDCBA"), - nxt_string("\x00\x10\x83\x10\x51\x87\x20\x92\x8b\x30\xd3\x8f" - "\x41\x14\x93\x51\x55\x97\x61\x96\x9b\x71\xd7\x9f" - "\x82\x18\xa3\x92\x59\xa7\xa2\x9a\xab\xb2\xdb\xaf" - "\xc3\x1c\xb3\xd3\x5d\xb7\xe3\x9e\xbb\xf3\xdf\xbf" - "\xff\xef\x7c\xef\xae\x78\xdf\x6d\x74\xcf\x2c\x70" - "\xbe\xeb\x6c\xae\xaa\x68\x9e\x69\x64\x8e\x28\x60" - "\x7d\xe7\x5c\x6d\xa6\x58\x5d\x65\x54\x4d\x24\x50" - "\x3c\xe3\x4c\x2c\xa2\x48\x1c\x61\x44\x0c\x20\x40") }, - - { nxt_string("Aa=="), - nxt_string("\x01") }, - { nxt_string("0Z"), - nxt_string("\xd1") }, - { nxt_string("0aA="), - nxt_string("\xd1\xa0") }, - { nxt_string("z/+"), - nxt_string("\xcf\xff") }, - { nxt_string("z9+Npe=="), - nxt_string("\xcf\xdf\x8d\xa5") }, - { nxt_string("/+98765"), - nxt_string("\xff\xef\x7c\xef\xae") }, - - { nxt_string("aBc_"), - nxt_null_string }, - { nxt_string("5"), - nxt_null_string }, - { nxt_string("M==="), - nxt_null_string }, - { nxt_string("===="), - nxt_null_string }, - { nxt_string("Ab="), - nxt_null_string }, - { nxt_string("00=0"), - nxt_null_string }, - { nxt_string("\0"), - nxt_null_string }, - { nxt_string("\r\naaaa"), - nxt_null_string }, - { nxt_string("=0000"), - nxt_null_string }, - }; - - u_char buf[96]; - - nxt_thread_time_update(thr); - - for (i = 0; i < nxt_nitems(tests); i++) { - ret = nxt_base64_decode(NULL, tests[i].enc.start, tests[i].enc.length); - - if (ret == NXT_ERROR && tests[i].dec.start == NULL) { - continue; - } - - if ((size_t) ret != tests[i].dec.length) { - nxt_log_alert(thr->log, - "nxt_base64_decode() test \"%V\" failed: incorrect " - "length of decoded string %z, expected %uz", - &tests[i].enc, ret, tests[i].dec.length); - return NXT_ERROR; - } - - ret = nxt_base64_decode(buf, tests[i].enc.start, tests[i].enc.length); - - if (!nxt_str_eq(&tests[i].dec, buf, (size_t) ret)) { - nxt_log_alert(thr->log, "nxt_base64_decode() test \"%V\" failed"); - return NXT_ERROR; - } - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "nxt_base64_decode() test passed"); - - return NXT_OK; -} diff --git a/src/test/nxt_clone_test.c b/src/test/nxt_clone_test.c deleted file mode 100644 index 64b9ddea..00000000 --- a/src/test/nxt_clone_test.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright (C) NGINX, Inc. - * Copyright (C) Valentin V. Bartenev - */ - -#include -#include -#include "nxt_tests.h" - - -#define UIDMAP 1 -#define GIDMAP 2 - - -typedef struct { - nxt_int_t map_type; - nxt_str_t map_data; - nxt_int_t setid; - nxt_credential_t creds; - nxt_uid_t unit_euid; - nxt_gid_t unit_egid; - nxt_int_t result; - nxt_str_t errmsg; -} nxt_clone_creds_testcase_t; - -typedef struct { - nxt_clone_creds_testcase_t *tc; -} nxt_clone_creds_ctx_t; - - -nxt_int_t nxt_clone_test_mappings(nxt_task_t *task, nxt_mp_t *mp, - nxt_clone_creds_ctx_t *ctx, nxt_clone_creds_testcase_t *tc); -void nxt_cdecl nxt_clone_test_log_handler(nxt_uint_t level, nxt_log_t *log, - const char *fmt, ...); -nxt_int_t nxt_clone_test_map_assert(nxt_task_t *task, - nxt_clone_creds_testcase_t *tc, nxt_clone_credential_map_t *map); -static nxt_int_t nxt_clone_test_parse_map(nxt_task_t *task, - nxt_str_t *map_str, nxt_clone_credential_map_t *map); - - -nxt_log_t *test_log; - -static nxt_gid_t gids[] = {1000, 10000, 60000}; - -static nxt_clone_creds_testcase_t testcases[] = { - { - /* - * Unprivileged unit - * - * if no uid mapping and app creds and unit creds are the same, - * then we automatically add a map for the creds->uid. - * Then, child process can safely setuid(creds->uid) in - * the new namespace. - */ - UIDMAP, - nxt_string(""), - 0, - {"nobody", 65534, 65534, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - UIDMAP, - nxt_string(""), - 0, - {"johndoe", 10000, 10000, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - UIDMAP, - nxt_string("[{\"container\": 1000, \"host\": 1000, \"size\": 1}]"), - 0, - {"johndoe", 1000, 1000, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - UIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1}]"), - 0, - {"root", 0, 0, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - UIDMAP, - nxt_string("[{\"container\": 65534, \"host\": 1000, \"size\": 1}]"), - 0, - {"nobody", 65534, 0, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - UIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1}," - " {\"container\": 1000, \"host\": 2000, \"size\": 1}]"), - 0, - {"root", 0, 0, 0, NULL}, - 1000, 1000, - NXT_ERROR, - nxt_string("\"uidmap\" field has 2 entries but unprivileged unit has " - "a maximum of 1 map.") - }, - { - UIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1}," - " {\"container\": 1000, \"host\": 2000, \"size\": 1}]"), - 1, /* privileged */ - {"root", 0, 0, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - UIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1000}," - " {\"container\": 1000, \"host\": 2000, \"size\": 1000}]"), - 1, /* privileged */ - {"johndoe", 500, 0, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - UIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1000}," - " {\"container\": 1000, \"host\": 2000, \"size\": 1000}]"), - 1, /* privileged */ - {"johndoe", 1000, 0, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - UIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1000}," - " {\"container\": 1000, \"host\": 2000, \"size\": 1000}]"), - 1, /* privileged */ - {"johndoe", 1500, 0, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - UIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1000}," - " {\"container\": 1000, \"host\": 2000, \"size\": 1000}]"), - 1, /* privileged */ - {"johndoe", 1999, 0, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - UIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1000}," - " {\"container\": 1000, \"host\": 2000, \"size\": 1000}]"), - 1, /* privileged */ - {"johndoe", 2000, 0, 0, NULL}, - 1000, 1000, - NXT_ERROR, - nxt_string("\"uidmap\" field has no \"container\" entry for user " - "\"johndoe\" (uid 2000)") - }, - { - /* - * Unprivileged unit - * - * if no gid mapping and app creds and unit creds are the same, - * then we automatically add a map for the creds->base_gid. - * Then, child process can safely setgid(creds->base_gid) in - * the new namespace. - */ - GIDMAP, - nxt_string("[]"), - 0, - {"nobody", 65534, 65534, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - /* - * Unprivileged unit - * - * Inside the new namespace, we can have any gid but it - * should map to parent gid (in this case 1000) in parent - * namespace. - */ - GIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1}]"), - 0, - {"root", 0, 0, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - GIDMAP, - nxt_string("[{\"container\": 65534, \"host\": 1000, \"size\": 1}]"), - 0, - {"nobody", 65534, 65534, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - /* - * Unprivileged unit - * - * There's no mapping for "johndoe" (gid 1000) inside the namespace. - */ - GIDMAP, - nxt_string("[{\"container\": 65535, \"host\": 1000, \"size\": 1}]"), - 0, - {"johndoe", 1000, 1000, 0, NULL}, - 1000, 1000, - NXT_ERROR, - nxt_string("\"gidmap\" field has no \"container\" entry for " - "gid 1000.") - }, - { - GIDMAP, - nxt_string("[{\"container\": 1000, \"host\": 1000, \"size\": 2}]"), - 0, - {"johndoe", 1000, 1000, 0, NULL}, - 1000, 1000, - NXT_ERROR, - nxt_string("\"gidmap\" field has an entry with \"size\": 2, but " - "for unprivileged unit it must be 1.") - }, - { - GIDMAP, - nxt_string("[{\"container\": 1000, \"host\": 1001, \"size\": 1}]"), - 0, - {"johndoe", 1000, 1000, 0, NULL}, - 1000, 1000, - NXT_ERROR, - nxt_string("\"gidmap\" field has an entry for host gid 1001 but " - "unprivileged unit can only map itself (gid 1000) " - "into child namespaces.") - }, - { - GIDMAP, - nxt_string("[{\"container\": 1000, \"host\": 1000, \"size\": 1}]"), - 0, - {"johndoe", 1000, 1000, 3, gids}, - 1000, 1000, - NXT_ERROR, - nxt_string("unprivileged unit disallow supplementary groups for " - "new namespace (user \"johndoe\" has 3 groups).") - }, - - /* privileged unit */ - - /* not root with capabilities */ - { - GIDMAP, - nxt_string("[]"), - 1, - {"johndoe", 1000, 1000, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - GIDMAP, - nxt_string(""), - 1, - {"johndoe", 1000, 1000, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - /* missing gid of {"user": "nobody"} */ - GIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1}]"), - 1, - {"nobody", 65534, 65534, 0, NULL}, - 1000, 1000, - NXT_ERROR, - nxt_string("\"gidmap\" field has no \"container\" entry for " - "gid 65534.") - }, - { - /* solves the previous by mapping 65534 gids */ - GIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 65535}]"), - 1, - {"nobody", 65534, 65534, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - /* solves by adding a separate mapping */ - GIDMAP, - nxt_string("[{\"container\": 0, \"host\": 1000, \"size\": 1}," - " {\"container\": 65534, \"host\": 1000, \"size\": 1}]"), - 1, - {"nobody", 65534, 65534, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - /* - * Map a big range - */ - GIDMAP, - nxt_string("[{\"container\": 0, \"host\": 0, \"size\": 200000}]"), - 1, - {"johndoe", 100000, 100000, 0, NULL}, - 1000, 1000, - NXT_OK, - nxt_string("") - }, - { - /* - * Validate if supplementary groups are mapped - */ - GIDMAP, - nxt_string("[]"), - 1, - {"johndoe", 1000, 1000, 3, gids}, - 1000, 1000, - NXT_ERROR, - nxt_string("\"gidmap\" field has no entries but user \"johndoe\" " - "has 3 suplementary groups."), - }, - { - GIDMAP, - nxt_string("[{\"container\": 0, \"host\": 0, \"size\": 1}]"), - 1, - {"johndoe", 1000, 1000, 3, gids}, - 1000, 1000, - NXT_ERROR, - nxt_string("\"gidmap\" field has no \"container\" entry for " - "gid 1000."), - }, - { - GIDMAP, - nxt_string("[{\"container\": 1000, \"host\": 0, \"size\": 1}]"), - 1, - {"johndoe", 1000, 1000, 3, gids}, - 1000, 1000, - NXT_ERROR, - nxt_string("\"gidmap\" field has missing suplementary gid mappings " - "(found 1 out of 3)."), - }, - { - GIDMAP, - nxt_string("[{\"container\": 1000, \"host\": 0, \"size\": 1}," - " {\"container\": 10000, \"host\": 10000, \"size\": 1}]"), - 1, - {"johndoe", 1000, 1000, 3, gids}, - 1000, 1000, - NXT_ERROR, - nxt_string("\"gidmap\" field has missing suplementary gid mappings " - "(found 2 out of 3)."), - }, - { - /* - * Fix all mappings - */ - GIDMAP, - nxt_string("[{\"container\": 1000, \"host\": 0, \"size\": 1}," - "{\"container\": 10000, \"host\": 10000, \"size\": 1}," - " {\"container\": 60000, \"host\": 60000, \"size\": 1}]"), - 1, - {"johndoe", 1000, 1000, 3, gids}, - 1000, 1000, - NXT_OK, - nxt_string(""), - }, -}; - - -void nxt_cdecl -nxt_clone_test_log_handler(nxt_uint_t level, nxt_log_t *log, - const char *fmt, ...) -{ - u_char *p, *end; - va_list args; - nxt_clone_creds_ctx_t *ctx; - nxt_clone_creds_testcase_t *tc; - u_char msg[NXT_MAX_ERROR_STR]; - - p = msg; - end = msg + NXT_MAX_ERROR_STR; - - ctx = log->ctx; - tc = ctx->tc; - - va_start(args, fmt); - p = nxt_vsprintf(p, end, fmt, args); - va_end(args); - - *p++ = '\0'; - - if (tc->result == NXT_OK && level == NXT_LOG_DEBUG) { - return; - } - - if (tc->errmsg.length == 0) { - nxt_log_error(NXT_LOG_ERR, &nxt_main_log, "unexpected log: %s", msg); - return; - } - - if (!nxt_str_eq(&tc->errmsg, msg, (nxt_uint_t) (p - msg - 1))) { - nxt_log_error(NXT_LOG_ERR, &nxt_main_log, - "error log mismatch: got [%s] but wants [%V]", - msg, &tc->errmsg); - return; - } -} - - -nxt_int_t -nxt_clone_creds_test(nxt_thread_t *thr) -{ - nxt_mp_t *mp; - nxt_int_t ret; - nxt_uint_t count, i; - nxt_task_t *task; - nxt_runtime_t rt; - nxt_clone_creds_ctx_t ctx; - - nxt_log_t nxt_clone_creds_log = { - NXT_LOG_INFO, - 0, - nxt_clone_test_log_handler, - NULL, - &ctx - }; - - nxt_thread_time_update(thr); - - thr->runtime = &rt; - - task = thr->task; - - mp = nxt_mp_create(1024, 128, 256, 32); - if (mp == NULL) { - return NXT_ERROR; - } - - rt.mem_pool = mp; - - test_log = task->log; - task->log = &nxt_clone_creds_log; - task->thread = thr; - - count = sizeof(testcases)/sizeof(nxt_clone_creds_testcase_t); - - for (i = 0; i < count; i++) { - ret = nxt_clone_test_mappings(task, mp, &ctx, &testcases[i]); - - if (ret != NXT_OK) { - goto fail; - } - } - - ret = NXT_OK; - - nxt_log_error(NXT_LOG_NOTICE, test_log, "clone creds test passed"); - -fail: - task->log = test_log; - nxt_mp_destroy(mp); - - return ret; -} - - -nxt_int_t -nxt_clone_test_mappings(nxt_task_t *task, nxt_mp_t *mp, - nxt_clone_creds_ctx_t *ctx, nxt_clone_creds_testcase_t *tc) -{ - nxt_int_t ret; - nxt_runtime_t *rt; - nxt_clone_credential_map_t map; - - rt = task->thread->runtime; - - map.size = 0; - - if (tc->map_data.length > 0) { - ret = nxt_clone_test_parse_map(task, &tc->map_data, &map); - if (ret != NXT_OK) { - return NXT_ERROR; - } - } - - rt->capabilities.setid = tc->setid; - - nxt_euid = tc->unit_euid; - nxt_egid = tc->unit_egid; - - ctx->tc = tc; - - if (nxt_clone_test_map_assert(task, tc, &map) != NXT_OK) { - return NXT_ERROR; - } - - if (tc->setid && nxt_euid != 0) { - /* - * Running as root should have the same behavior as - * passing Linux capabilities. - */ - - nxt_euid = 0; - nxt_egid = 0; - - if (nxt_clone_test_map_assert(task, tc, &map) != NXT_OK) { - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -nxt_int_t -nxt_clone_test_map_assert(nxt_task_t *task, nxt_clone_creds_testcase_t *tc, - nxt_clone_credential_map_t *map) -{ - nxt_int_t ret; - - if (tc->map_type == UIDMAP) { - ret = nxt_clone_vldt_credential_uidmap(task, map, &tc->creds); - } else { - ret = nxt_clone_vldt_credential_gidmap(task, map, &tc->creds); - } - - if (ret != tc->result) { - nxt_log_error(NXT_LOG_ERR, &nxt_main_log, - "return %d instead of %d (map: %V)", ret, tc->result, - &tc->map_data); - - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_clone_test_parse_map(nxt_task_t *task, nxt_str_t *map_str, - nxt_clone_credential_map_t *map) -{ - nxt_uint_t i; - nxt_runtime_t *rt; - nxt_conf_value_t *array, *obj, *value; - - static nxt_str_t host_name = nxt_string("host"); - static nxt_str_t cont_name = nxt_string("container"); - static nxt_str_t size_name = nxt_string("size"); - - rt = task->thread->runtime; - - array = nxt_conf_json_parse_str(rt->mem_pool, map_str); - if (array == NULL) { - return NXT_ERROR; - } - - map->size = nxt_conf_array_elements_count(array); - - if (map->size == 0) { - return NXT_OK; - } - - map->map = nxt_mp_alloc(rt->mem_pool, - map->size * sizeof(nxt_clone_map_entry_t)); - - if (map->map == NULL) { - return NXT_ERROR; - } - - for (i = 0; i < map->size; i++) { - obj = nxt_conf_get_array_element(array, i); - - value = nxt_conf_get_object_member(obj, &host_name, NULL); - map->map[i].host = nxt_conf_get_number(value); - - value = nxt_conf_get_object_member(obj, &cont_name, NULL); - map->map[i].container = nxt_conf_get_number(value); - - value = nxt_conf_get_object_member(obj, &size_name, NULL); - map->map[i].size = nxt_conf_get_number(value); - } - - return NXT_OK; -} diff --git a/src/test/nxt_cq_test.c b/src/test/nxt_cq_test.c deleted file mode 100644 index ae69505a..00000000 --- a/src/test/nxt_cq_test.c +++ /dev/null @@ -1,578 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - -#ifndef NXT_NCQ_TEST -#define NXT_NCQ_TEST 1 -#endif - -#define NXT_QTEST_USE_THREAD 0 - -#if NXT_NCQ_TEST -#include -#else -#include -#endif - - -#define MAX_ITER 20 -#define STAT_ITER 5 -#define MIN_COV 0.02 - -extern char **environ; -static uintptr_t nops = 10000000; - -static uintptr_t nprocs_enq = 0; -static uintptr_t nprocs_deq = 0; -static uintptr_t nprocs_wenq = 0; -static uintptr_t nprocs_wdeq = 0; -static uintptr_t nprocs_enq_deq = 0; -static uintptr_t nprocs_cas = 0; -static uintptr_t nprocs_faa = 0; - -static uintptr_t nprocs = 1; - - -static size_t -elapsed_time(size_t us) -{ - struct timeval t; - - gettimeofday(&t, NULL); - - return t.tv_sec * 1000000 + t.tv_usec - us; -} - - -static double -mean(const double *times, int n) -{ - int i; - double sum; - - sum = 0; - - for (i = 0; i < n; i++) { - sum += times[i]; - } - - return sum / n; -} - - -static double -cov(const double *times, double mean, int n) -{ - int i; - double variance; - - variance = 0; - - for (i = 0; i < n; i++) { - variance += (times[i] - mean) * (times[i] - mean); - } - - variance /= n; - - return sqrt(variance) / mean; -} - -typedef struct { -#if NXT_NCQ_TEST - nxt_nncq_t free_queue; - nxt_nncq_t active_queue; -#else - nxt_nvbcq_t free_queue; - nxt_nvbcq_t active_queue; -#endif - uint32_t counter; -} nxt_cq_t; - - -static nxt_cq_t *pgq; - - -#if NXT_NCQ_TEST -#define nxt_cq_enqueue nxt_nncq_enqueue -#define nxt_cq_dequeue nxt_nncq_dequeue -#define nxt_cq_empty nxt_nncq_empty -#define nxt_cq_init nxt_nncq_init -#define NXT_CQ_SIZE NXT_NNCQ_SIZE -#else -#define nxt_cq_enqueue nxt_nvbcq_enqueue -#define nxt_cq_dequeue nxt_nvbcq_dequeue -#define nxt_cq_empty nxt_nvbcq_empty -#define nxt_cq_init nxt_nvbcq_init -#define NXT_CQ_SIZE NXT_NVBCQ_SIZE -#endif - -typedef struct { - int id; - uint64_t enq; - uint64_t deq; - uint64_t wait_enq; - uint64_t wait_deq; - uint64_t own_res; - uint64_t cas; - uint64_t faa; - -#if NXT_QTEST_USE_THREAD - nxt_thread_handle_t handle; -#else - nxt_pid_t pid; - int status; -#endif -} nxt_worker_info_t; - - -static void -cas_worker(void *p) -{ - nxt_cq_t *q; - uint32_t c; - uintptr_t i; - nxt_worker_info_t *wi; - - q = pgq; - wi = p; - - for (i = 0; i < nops / nprocs_cas; i++) { - c = q->counter; - - if (nxt_atomic_cmp_set(&q->counter, c, c + 1)) { - ++wi->cas; - } - } -} - - -static void -faa_worker(void *p) -{ - nxt_cq_t *q; - uintptr_t i; - nxt_worker_info_t *wi; - - q = pgq; - wi = p; - - for (i = 0; i < nops / nprocs_faa; i++) { - nxt_atomic_fetch_add(&q->counter, 1); - wi->faa++; - } -} - - -static void -enq_deq_worker(void *p) -{ - nxt_cq_t *q; - uintptr_t i, v; - nxt_worker_info_t *wi; - - q = pgq; - wi = p; - - for (i = 0; i < nops / nprocs_enq_deq; i++) { - v = nxt_cq_dequeue(&q->free_queue); - - if (v != nxt_cq_empty(&q->free_queue)) { - nxt_cq_enqueue(&q->active_queue, wi->id); - wi->enq++; - } - - v = nxt_cq_dequeue(&q->active_queue); - - if (v != nxt_cq_empty(&q->active_queue)) { - nxt_cq_enqueue(&q->free_queue, v); - wi->deq++; - - if ((int) v == wi->id) { - wi->own_res++; - } - } - } -} - - -static void -enq_worker(void *p) -{ - nxt_cq_t *q; - uintptr_t i, v; - nxt_worker_info_t *wi; - - q = pgq; - wi = p; - - for (i = 0; i < nops / nprocs_enq; i++) { - v = nxt_cq_dequeue(&q->free_queue); - - if (v != nxt_cq_empty(&q->free_queue)) { - nxt_cq_enqueue(&q->active_queue, v); - wi->enq++; - } - } -} - - -static void -deq_worker(void *p) -{ - nxt_cq_t *q; - uintptr_t i, v; - nxt_worker_info_t *wi; - - q = pgq; - wi = p; - - for (i = 0; i < nops / nprocs_deq; i++) { - v = nxt_cq_dequeue(&q->active_queue); - - if (v != nxt_cq_empty(&q->active_queue)) { - nxt_cq_enqueue(&q->free_queue, v); - ++wi->deq; - } - } -} - - -static void -wenq_worker(void *p) -{ - nxt_cq_t *q; - uintptr_t i, v; - nxt_worker_info_t *wi; - - q = pgq; - wi = p; - - for (i = 0; i < nops / nprocs_wenq; i++) { - - do { - wi->wait_enq++; - v = nxt_cq_dequeue(&q->free_queue); - } while (v == nxt_cq_empty(&q->free_queue)); - - nxt_cq_enqueue(&q->active_queue, v); - - wi->enq++; - wi->wait_enq--; - } -} - - -static void -wdeq_worker(void *p) -{ - nxt_cq_t *q; - uintptr_t i, v; - nxt_worker_info_t *wi; - - q = pgq; - wi = p; - - for (i = 0; i < nops / nprocs_wdeq; i++) { - - do { - wi->wait_deq++; - v = nxt_cq_dequeue(&q->active_queue); - } while (v == nxt_cq_empty(&q->active_queue)); - - nxt_cq_enqueue(&q->free_queue, v); - - wi->deq++; - wi->wait_deq--; - } -} - - -static nxt_int_t -worker_create(nxt_worker_info_t *wi, int id, nxt_thread_start_t start) -{ - wi->id = id; - -#if NXT_QTEST_USE_THREAD - nxt_thread_link_t *link; - - link = nxt_zalloc(sizeof(nxt_thread_link_t)); - - link->start = start; - link->work.data = wi; - - return nxt_thread_create(&wi->handle, link); - -#else - pid_t pid = fork(); - - if (pid == 0) { - start(wi); - exit(0); - - } else { - wi->pid = pid; - } - - return NXT_OK; -#endif -} - - -static void -worker_wait(nxt_worker_info_t *wi) -{ -#if NXT_QTEST_USE_THREAD - pthread_join(wi->handle, NULL); - -#else - waitpid(wi->pid, &wi->status, 0); -#endif -} - - -int nxt_cdecl -main(int argc, char **argv) -{ - int i, k, id, verbose, objective, rk; - char *a; - size_t start, elapsed; - double *stats, m, c; - uint64_t total_ops; - uintptr_t j; - nxt_task_t task; - nxt_thread_t *thr; - nxt_worker_info_t *wi; - double times[MAX_ITER], mopsec[MAX_ITER]; - - verbose = 0; - objective = 0; - - for (i = 1; i < argc; i++) { - a = argv[i]; - - if (strcmp(a, "-v") == 0) { - verbose++; - continue; - } - - if (strcmp(a, "-n") == 0 && (i + 1) < argc) { - nops = atoi(argv[++i]); - continue; - } - - if (strcmp(a, "--enq") == 0 && (i + 1) < argc) { - nprocs_enq = atoi(argv[++i]); - continue; - } - - if (strcmp(a, "--deq") == 0 && (i + 1) < argc) { - nprocs_deq = atoi(argv[++i]); - continue; - } - - if (strcmp(a, "--wenq") == 0 && (i + 1) < argc) { - nprocs_wenq = atoi(argv[++i]); - continue; - } - - if (strcmp(a, "--wdeq") == 0 && (i + 1) < argc) { - nprocs_wdeq = atoi(argv[++i]); - continue; - } - - if (strcmp(a, "--ed") == 0 && (i + 1) < argc) { - nprocs_enq_deq = atoi(argv[++i]); - continue; - } - - if (strcmp(a, "--cas") == 0 && (i + 1) < argc) { - nprocs_cas = atoi(argv[++i]); - continue; - } - - if (strcmp(a, "--faa") == 0 && (i + 1) < argc) { - nprocs_faa = atoi(argv[++i]); - continue; - } - - if (strcmp(a, "--obj") == 0 && (i + 1) < argc) { - objective = atoi(argv[++i]); - continue; - } - - printf("unknown option %s", a); - - return 1; - } - - if (nxt_lib_start("ncq_test", argv, &environ) != NXT_OK) { - return 1; - } - - nprocs = nprocs_enq + nprocs_deq + nprocs_wenq + nprocs_wdeq - + nprocs_enq_deq + nprocs_cas + nprocs_faa; - - if (nprocs == 0) { - return 0; - } - - nxt_main_log.level = NXT_LOG_INFO; - task.log = &nxt_main_log; - - thr = nxt_thread(); - thr->task = &task; - - pgq = mmap(NULL, sizeof(nxt_cq_t), PROT_READ | PROT_WRITE, - MAP_ANON | MAP_SHARED, -1, 0); - if (pgq == MAP_FAILED) { - return 2; - } - - nxt_cq_init(&pgq->free_queue); - nxt_cq_init(&pgq->active_queue); - - for(i = 0; i < NXT_CQ_SIZE; i++) { - nxt_cq_enqueue(&pgq->free_queue, i); - } - - if (verbose >= 1) { - printf("number of workers: %d\n", (int) nprocs); - printf("number of ops: %d\n", (int) nops); - } - - wi = mmap(NULL, nprocs * sizeof(nxt_worker_info_t), PROT_READ | PROT_WRITE, - MAP_ANON | MAP_SHARED, -1, 0); - if (wi == MAP_FAILED) { - return 3; - } - - for (k = 0; k < MAX_ITER; k++) { - nxt_memzero(wi, nprocs * sizeof(nxt_worker_info_t)); - - nxt_cq_init(&pgq->free_queue); - nxt_cq_init(&pgq->active_queue); - - for(i = 0; i < NXT_CQ_SIZE; i++) { - nxt_cq_enqueue(&pgq->free_queue, i); - } - - start = elapsed_time(0); - - id = 0; - - for (j = 0; j < nprocs_enq; j++, id++) { - worker_create(wi + id, id, enq_worker); - } - - for (j = 0; j < nprocs_deq; j++, id++) { - worker_create(wi + id, id, deq_worker); - } - - for (j = 0; j < nprocs_wenq; j++, id++) { - worker_create(wi + id, id, wenq_worker); - } - - for (j = 0; j < nprocs_wdeq; j++, id++) { - worker_create(wi + id, id, wdeq_worker); - } - - for (j = 0; j < nprocs_enq_deq; j++, id++) { - worker_create(wi + id, id, enq_deq_worker); - } - - for (j = 0; j < nprocs_cas; j++, id++) { - worker_create(wi + id, id, cas_worker); - } - - for (j = 0; j < nprocs_faa; j++, id++) { - worker_create(wi + id, id, faa_worker); - } - - for (j = 0; j < nprocs; j++) { - worker_wait(wi + j); - } - - elapsed = elapsed_time(start); - - for (j = 1; j < nprocs; j++) { - wi[0].enq += wi[j].enq; - wi[0].deq += wi[j].deq; - wi[0].wait_enq += wi[j].wait_enq; - wi[0].wait_deq += wi[j].wait_deq; - wi[0].own_res += wi[j].own_res; - wi[0].cas += wi[j].cas; - wi[0].faa += wi[j].faa; - } - - total_ops = wi[0].enq + wi[0].deq + wi[0].cas + wi[0].faa; - - if (total_ops == 0) { - total_ops = nops; - } - - times[k] = elapsed / 1000.0; - mopsec[k] = (double) total_ops / elapsed; - - if (verbose >= 2) { - printf("enq %10"PRIu64"\n", wi[0].enq); - printf("deq %10"PRIu64"\n", wi[0].deq); - printf("wait_enq %10"PRIu64"\n", wi[0].wait_enq); - printf("wait_deq %10"PRIu64"\n", wi[0].wait_deq); - printf("own_res %10"PRIu64"\n", wi[0].own_res); - printf("cas %10"PRIu64"\n", wi[0].cas); - printf("faa %10"PRIu64"\n", wi[0].faa); - printf("total ops %10"PRIu64"\n", total_ops); - printf("Mops/sec %13.2f\n", mopsec[k]); - - printf("elapsed %10d us\n", (int) elapsed); - printf("per op %10d ns\n", (int) ((1000 * elapsed) / total_ops)); - } - - if (k >= STAT_ITER) { - stats = (objective == 0) ? times : mopsec; - - m = mean(stats + k - STAT_ITER, STAT_ITER); - c = cov(stats + k - STAT_ITER, m, STAT_ITER); - - if (verbose >= 1) { - if (objective == 0) { - printf(" #%02d elapsed time: %.2f ms; Mops/sec %.2f; " - "mean time %.2f ms; cov %.4f\n", - (int) k + 1, times[k], mopsec[k], m, c); - - } else { - printf(" #%02d elapsed time: %.2f ms; Mops/sec %.2f; " - "mean Mop/sec %.2f; cov %.4f\n", - (int) k + 1, times[k], mopsec[k], m, c); - } - } - - if (c < MIN_COV) { - rk = k - STAT_ITER; - - for (i = rk + 1; i <= k; i++) { - if (fabs(stats[i] - m) < fabs(stats[rk] - m)) { - rk = i; - } - } - - printf("#%d %.2f ms; %.2f\n", rk, times[rk], mopsec[rk]); - - return 0; - } - - } else { - if (verbose >= 1) { - printf(" #%02d elapsed time: %.2f ms; Mops/sec %.2f\n", - (int) k + 1, times[k], mopsec[k]); - } - } - } - - return 0; -} diff --git a/src/test/nxt_gmtime_test.c b/src/test/nxt_gmtime_test.c deleted file mode 100644 index cec81ab4..00000000 --- a/src/test/nxt_gmtime_test.c +++ /dev/null @@ -1,84 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -#if (NXT_TIME_T_SIZE == 4) - -/* A 86400-fold number below 2^31. */ -#define NXT_GMTIME_MAX 2147472000 - -#else -/* - * March 19, 29398 is maximum valid data if nxt_uint_t - * is 4 bytes size whilst nxt_time_t is 8 bytes size. - */ -#define NXT_GMTIME_MAX 865550793600 -#endif - - -nxt_int_t -nxt_gmtime_test(nxt_thread_t *thr) -{ - struct tm tm0, *tm1; - nxt_time_t s; - nxt_nsec_t start, end; - - nxt_thread_time_update(thr); - nxt_log_error(NXT_LOG_NOTICE, thr->log, "gmtime test started"); - - for (s = 0; s < NXT_GMTIME_MAX; s += 86400) { - - nxt_gmtime(s, &tm0); - tm1 = gmtime(&s); - - if (tm0.tm_mday != tm1->tm_mday - || tm0.tm_mon != tm1->tm_mon - || tm0.tm_year != tm1->tm_year - || tm0.tm_yday != tm1->tm_yday - || tm0.tm_wday != tm1->tm_wday) - { - nxt_log_alert(thr->log, - "gmtime test failed: %T @ %02d.%02d.%d", - s, tm1->tm_mday, tm1->tm_mon + 1, - tm1->tm_year + 1900); - return NXT_ERROR; - } - } - - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - for (s = 0; s < 10000000; s++) { - nxt_gmtime(s, &tm0); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "nxt_gmtime(): %0.1fns", - (end - start) / 10000000.0); - - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - for (s = 0; s < 10000000; s++) { - (void) gmtime(&s); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "gmtime(): %0.1fns", - (end - start) / 10000000.0); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "gmtime test passed"); - return NXT_OK; -} diff --git a/src/test/nxt_http_parse_test.c b/src/test/nxt_http_parse_test.c deleted file mode 100644 index 5f1a518c..00000000 --- a/src/test/nxt_http_parse_test.c +++ /dev/null @@ -1,819 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - * Copyright (C) Valentin V. Bartenev - */ - -#include -#include "nxt_tests.h" - - -typedef struct { - nxt_str_t method; - nxt_str_t target; - nxt_str_t args; - u_char version[8]; - - /* target with "/." */ - unsigned complex_target:1; - /* target with "%" */ - unsigned quoted_target:1; - /* target with " " */ - unsigned space_in_target:1; -} nxt_http_parse_test_request_line_t; - - -typedef struct { - nxt_int_t result; - unsigned discard_unsafe_fields:1; -} nxt_http_parse_test_fields_t; - - -typedef union { - void *pointer; - nxt_http_parse_test_fields_t fields; - nxt_http_parse_test_request_line_t request_line; -} nxt_http_parse_test_data_t; - - -typedef struct { - nxt_str_t request; - nxt_int_t result; - nxt_int_t (*handler)(nxt_http_request_parse_t *rp, - nxt_http_parse_test_data_t *data, - nxt_str_t *request, nxt_log_t *log); - - nxt_http_parse_test_data_t data; -} nxt_http_parse_test_case_t; - - -static nxt_int_t nxt_http_parse_test_run(nxt_http_request_parse_t *rp, - nxt_str_t *request); -static nxt_int_t nxt_http_parse_test_bench(nxt_thread_t *thr, - nxt_str_t *request, nxt_lvlhsh_t *hash, const char *name, nxt_uint_t n); -static nxt_int_t nxt_http_parse_test_request_line(nxt_http_request_parse_t *rp, - nxt_http_parse_test_data_t *data, - nxt_str_t *request, nxt_log_t *log); -static nxt_int_t nxt_http_parse_test_fields(nxt_http_request_parse_t *rp, - nxt_http_parse_test_data_t *data, nxt_str_t *request, nxt_log_t *log); - - -static nxt_int_t nxt_http_test_header_return(void *ctx, nxt_http_field_t *field, - uintptr_t data); - - -static nxt_http_parse_test_case_t nxt_http_test_cases[] = { - { - nxt_string("GET / HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/"), - nxt_null_string, - "HTTP/1.0", - 0, 0, 0 - }} - }, - { - nxt_string("XXX-METHOD /d.ir/fi+le.ext?key=val HTTP/1.2\n\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("XXX-METHOD"), - nxt_string("/d.ir/fi+le.ext?key=val"), - nxt_string("key=val"), - "HTTP/1.2", - 0, 0, 0 - }} - }, - { - nxt_string("GET /di.r/? HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/di.r/?"), - nxt_string(""), - "HTTP/1.0", - 0, 0, 0 - }} - }, - { - nxt_string("GEt / HTTP/1.0\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET /\0 HTTP/1.0\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET /\r HTTP/1.0\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET /\n HTTP/1.0\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.0\r\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/2.0\r\n"), - NXT_HTTP_PARSE_UNSUPPORTED_VERSION, - NULL, { NULL } - }, - { - nxt_string("GET /. HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/."), - nxt_null_string, - "HTTP/1.0", - 1, 0, 0 - }} - }, - { - nxt_string("GET /# HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/#"), - nxt_null_string, - "HTTP/1.0", - 1, 0, 0 - }} - }, - { - nxt_string("GET /?# HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/?#"), - nxt_string(""), - "HTTP/1.0", - 1, 0, 0 - }} - }, - { - nxt_string("GET // HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("//"), - nxt_null_string, - "HTTP/1.0", - 1, 0, 0 - }} - }, - { - nxt_string("GET /%20 HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/%20"), - nxt_null_string, - "HTTP/1.0", - 0, 1, 0 - }} - }, - { - nxt_string("GET / a HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/ a"), - nxt_null_string, - "HTTP/1.0", - 0, 0, 1 - }} - }, - { - nxt_string("GET /na %20me.ext?args HTTP/1.0\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/na %20me.ext?args"), - nxt_string("args"), - "HTTP/1.0", - 0, 1, 1 - }} - }, - { - nxt_string("GET / HTTP/1.0 HTTP/1.1\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_request_line, - { .request_line = { - nxt_string("GET"), - nxt_string("/ HTTP/1.0"), - nxt_null_string, - "HTTP/1.1", - 0, 0, 1 - }} - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: example.com\r\n\r\n"), - NXT_DONE, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host:example.com \r\n\r\n"), - NXT_DONE, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host:\r\n\r\n"), - NXT_DONE, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host example.com\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - ":Host: example.com\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Ho_st: example.com\r\n\r\n"), - NXT_DONE, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Ho\0st: example.com\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Ho\rst: example.com\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Ho\nst: example.com\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host : example.com\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: exa\0mple.com\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: exa\rmple.com\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: exa\bmple.com\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: пример.испытание\r\n\r\n"), - NXT_DONE, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: xn--e1afmkfd.xn--80akhbyknj4f\r\n\r\n"), - NXT_DONE, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: exa\nmple.com\r\n\r\n"), - NXT_HTTP_PARSE_INVALID, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "Host: exa\tmple.com\r\n\r\n"), - NXT_DONE, - NULL, { NULL } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "X-Unknown-Header: value\r\n" - "X-Good-Header: value\r\n" - "!#$%&'*+.^_`|~: skipped\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_fields, - { .fields = { NXT_OK, 1 } } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "X-Good-Header: value\r\n" - "X-Unknown-Header: value\r\n" - "X-Bad-Header: value\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_fields, - { .fields = { NXT_ERROR, 1 } } - }, - { - nxt_string("GET / HTTP/1.1\r\n" - "!#$%&'*+.^_`|~: allowed\r\n\r\n"), - NXT_DONE, - &nxt_http_parse_test_fields, - { .fields = { NXT_ERROR, 0 } } - }, -}; - - -static nxt_http_field_proc_t nxt_http_test_fields[] = { - { nxt_string("X-Bad-Header"), - &nxt_http_test_header_return, - NXT_ERROR }, - - { nxt_string("X-Good-Header"), - &nxt_http_test_header_return, - NXT_OK }, - - { nxt_string("!#$%&'*+.^_`|~"), - &nxt_http_test_header_return, - NXT_ERROR }, -}; - - -static nxt_lvlhsh_t nxt_http_test_fields_hash; - - -static nxt_http_field_proc_t nxt_http_test_bench_fields[] = { - { nxt_string("Host"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("User-Agent"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Accept"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Accept-Encoding"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Accept-Language"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Connection"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Content-Length"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Content-Range"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Content-Type"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Cookie"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Range"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("If-Range"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Transfer-Encoding"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Expect"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Via"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("If-Modified-Since"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("If-Unmodified-Since"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("If-Match"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("If-None-Match"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Referer"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Date"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Upgrade"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Authorization"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Keep-Alive"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("X-Forwarded-For"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("X-Forwarded-Host"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("X-Forwarded-Proto"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("X-Http-Method-Override"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("X-Real-IP"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("X-Request-ID"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("TE"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Pragma"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Cache-Control"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Origin"), - &nxt_http_test_header_return, NXT_OK }, - { nxt_string("Upgrade-Insecure-Requests"), - &nxt_http_test_header_return, NXT_OK }, -}; - - -static nxt_str_t nxt_http_test_simple_request = nxt_string( - "GET /page HTTP/1.1\r\n" - "Host: example.com\r\n\r\n" -); - - -static nxt_str_t nxt_http_test_big_request = nxt_string( - "POST /path/to/very/interesting/article/on.this.site?arg1=value&arg2=value" - "2&very_big_arg=even_bigger_value HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "User-Agent: Mozilla/5.0 (X11; Gentoo Linux x86_64; rv:42.0) Firefox/42.0" - "\r\n" - "Accept: text/html,application/json,application/xml;q=0.9,*/*;q=0.8\r\n" - "Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4\r\n" - "Accept-Encoding: gzip, deflate, br\r\n" - "If-Modified-Since: Wed, 31 Dec 1986 16:00:00 GMT\r\n" - "Referer: https://example.org/path/to/not-interesting/article.html\r\n" - "Cookie: name=value; name2=value2; some_big_cookie=iVBORw0KGgoAAAANSUhEUgA" - "AAEAAAABACAMAAACdt4HsAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAABmelRY" - "dFJhdyBwcm9maWxlIHR5cGUgZXhpZgAAeNptitsJgEAMBP9ThSWsZy6PcvKhcB1YvjEni" - "ODAwjAs7ec4aCmkEXc1cREk7OwtUgyTFRA3BU+vFPjS7gUI/p46Q0u2fP/1B7oA1Scbwk" - "nkf9gAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACfUExURQwMDDw8PFBQUAICAhQUFAcHBxs" - "bGxEREQkJCTk5OTU1NSAgIFRUVB8fH0xMTCUlJVtbW0pKSikpKS8vL0BAQEZGRjMzM2Bg" - "YL6+vsDAwLS0tF1dXXJycrGxsWVlZWhoaKenp29vb6urq8TExHp6epSUlLu7u66urqOjo" - "5ycnH9/f4CAgJOTk5qamo6OjoWFhYiIiHd3d8nJyc/Pz9LS0ojXP1QAAAihSURBVFjDZV" - "eHdqM6EBUYEEh0EM3gCu41+/7/294dCSfZsxOHeM8yV3f6iGVGYohNEtJPGEjPiSLpMTz" - "zokg8DmGOCOm/P0I6MTPaBGDPCGEYV3kEzchjzPOSPIkk8BzuM8fSCOFfALER+6MdpnaV" - "55FMoOP7UliioK8QzpiT0Qv0Fl4lDJvFPwChETuHFjhw7vhRVcGAXDqcfhhnRaZUWeJTW" - "pYVCBEYAJihtCsUpIhyq6win3ueDCoRBIknJRwACtz3AJhDYBhESsmyEjhaKv0MRJIIFR" - "d4XyYqC1RWwQFeBF2CcApCmEFI2KwHTRIrsMq8UnYcRUkehKtlaGeq8BjowKHEQf7oEgH" - "JcKRWpSeZpTIrs5dKlGX9fF7GfrtdWqDAuce1IyOtLbWyRKRYIIIPBo63gswO07q20/p6" - "2txvj+flvUZUZeQ4IODBGDoYivoReREzugaAJKuX637dP0/DbnMGwuWyTTNlBYX0ItL3E" - "q2ptUmYZi9+ANLt9r2+nrqmORKD1/W9Xi3hirisEumQOz+qRv5hUL/H1bg7tG0znKbHCy" - "Zs16u6TgmiQH5rLW2Ltslhf6kjO1bjOJ4PTfu1PwDgeR0BsF6BBCBQIThee+P78QvAQNS" - "X17mD/tfXYaMBejAAhWWahqoiB5q8dmYQ9rc+AF7Trmn2BLC7vy4XQ0ADpHZmJRQPznVO" - "0YcABJRnBwBg+Tofm3a//2q7zYREIAAyAQRQQKqAJ/ksH4CPC4wJy9uma2eA2+syjtsVn" - "LicKzDTRYaqMgi/AQyHQNSPY0uyb7vdHVEcezDQBhAHJXLPqLOZxN8+CLJVehmapoUX2u" - "54okzsIXACucAOYyunov62AUDiN0IQd69+dyAf7PfdsLlRGAGwXekowIgySRzoMzZzcAj" - "gpxIs9Ti+TsTghLMvV1Lfbvt+vbTR9ZAJtlWoXxSIwaxuohCUt8Pp3LTd+XHt01KF9XZL" - "iRhXkSwKCzYg7X2NwGYYJsRvCHU6nndNO3SH4TauV9v3OK7rUKHnUJaiTxRl4XODwD8mC" - "Gptn0Q8j1e4oOmmfi0iZY/naRuWaIyiNI1bxDljs/7M4Hcxlta9fzTd/qubrrdYpNZ2GL" - "ZxgJboFkmFVhGLLPE/6ubPp5nNTphOAGj/QHavtZ292t3KLouiQocqbXhRKOlr+/9hoA0" - "og/d+dzi0/+2b7nTr60vXbtZhJkQZx2GaLsNMxZ8ozk5gphN/M4i79nBo/uwHdJPn1Db7" - "c40aUgoDRVdTmhn3awbsXxOs4PZfc2i+vrrTNCEe+/0JnTmkoZOiJcT2co4i5z9hnHu6Z" - "bxoT7sWAM3mfp9O7Vd7rnUV6E8ap2lk/MdmJzD2eyRohKrf4+DmON2ej6HZ31epnnqpLg" - "ZV8dmFMw6fB0vww0Gs903ToJaviOifdnrXS6SxhgjjxNEF9BH6VlUVMKqf+STqPTLpeHr" - "0l2HYHaYeHohVZiOIYUYjhjHfx0cLAHI96Qrzi4BXeYxiRi94PjeH4/k8xshgO8u0HYoI" - "EIDvQgzEPOJIaGAlSSQQye54nzbH3Wb3wFSJ9SJAi0XAZ33NwXUXC5dJFIRHvZo7n0Z3J" - "oDNaYef0zVd2bFZJjDzEmhByWfQ8bi/gDDpuz7NCa4RidhivT90w7B51tfXpV+F2CVEqd" - "eamC+gj5cYznSYawCYwSPvEIbP3ArqXXdeXze3MUUNBJbSAGHgGuOZ7maazAfAoXnnaP8" - "yN9kdj8fhjPY8TNt6FWchDTbsVB4s196jANI3XwNQPPXM9LSLmZ/Ae0f8nuGC2lhPK5md" - "++zbh76B8V0Wmaz0aOB7epHy5XA4b3ZIgt1puvYYrCkaQZyhCrjZ1ehw+B//An2skMYLh" - "GDCXB3b43Q6dhSL+7NHQ0YZYW3yyVfgyUwoOI1WABje3IkkBRMHRPmmPWxupyM4nF/jek" - "mrp8pSSSqap++aSADA1ZuTtsLTewPgKmfadx2q8YwNZVwhDzJVZnbGfEcDOB8A/Y1wDAV" - "iRxtHVLF321EiTJf3u0b+osLgglyTximcUQr6NJ2ZvwDAxwa9ejg8l7wcDsOAZLptwzgr" - "LUXLdOC5nF5yPi6giFAYsbTwbwQHcRCejFCHA/lwwoZFZRBjvZlbGJ4mGylj8E27giJDo" - "SQCsvJyR702xwGz8X5dp7qSMuy7lGcmhBrB13XxC8Asw7zIueBJ/brvEINHvzRLeSmS3C" - "SfTgHDwaXKIOd5c4/RoYzrRHiOtbpOm8391dNuhXW3rECBzwC+qWQS+IAZABSBE+VoJzV" - "6P+e5Wl9u9wlZRJtNjEXTLq1INwHdhvxZH9GkcFI8HFqAsWDLhYw5k0W8Hl8Y0fUSFxBs" - "9CquLGFKQBfcDODPrQGPnPpRlADAiZEMCVb1/r0lAkjD0kq9xSJnmj/7NoEiYUxAElOOA" - "SMoFgwAUhbKpnmANhTTFSXD+x6jEjJm+CaUXIdfJhFuN3RLy3GbcBcqYjJPKH8QwGWdod" - "nbEgqOMQD6xpXQJ/fjelXlgKU9vghk4S0KwZIC15YSvXjZ15awslAHzP00008iUEE7oC4" - "r7nKHerJAl18gGRGPAMwzez2GVpmFFhEAAKOe5CN6ZL6v0znPpVcluBMyj2ZDHhWLhciT" - "Ctq4UKb9uIIfV3ChqzvJpxvpWBIeAOheSXQ8ZEEig2DhyjyqSqVoJ9j2W0y2knLW16dCd" - "6EjyQ0a/E23IDDwowJ5IFJsMzJaRAEoxOFy1S+tXDAAcMdlxoP4w7UtnABQe0nhUa1HES" - "5kVennooC/WWEpANRLK4mYjplkcy/ViU+n627I8gjXIJ9L5APiCDYiqFD7IIYLWKoKySj" - "lUXleNM9TzcSfdxRGqlKijGALtTVJA7bgi0RVRaByyhjqP1S73BxPyjoeM47LPRqvVInU" - "cvGoCit3GRpZ5VC0XZ1zpg6pb1AqLAhDD8L/AcHH1p8sEFAHAAAAAElFTkSuQmCC\r\n" - "Connection: keep-alive\r\n" - "Content-Length: 0\r\n" - "Upgrade-Insecure-Requests: 1\r\n" - "Pragma: no-cache\r\n" - "Cache-Control: no-cache\r\n" - "X-Forwarded-For: 192.0.2.0, 198.51.100.0, 203.0.113.0\r\n" - "\r\n" -); - - -nxt_int_t -nxt_http_parse_test(nxt_thread_t *thr) -{ - nxt_mp_t *mp_temp; - nxt_int_t rc; - nxt_uint_t i, colls, lvl_colls; - nxt_lvlhsh_t hash; - nxt_http_request_parse_t rp; - nxt_http_parse_test_case_t *test; - - nxt_thread_time_update(thr); - - rc = nxt_http_fields_hash(&nxt_http_test_fields_hash, - nxt_http_test_fields, - nxt_nitems(nxt_http_test_fields)); - if (rc != NXT_OK) { - return NXT_ERROR; - } - - for (i = 0; i < nxt_nitems(nxt_http_test_cases); i++) { - test = &nxt_http_test_cases[i]; - - nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); - - mp_temp = nxt_mp_create(1024, 128, 256, 32); - if (mp_temp == NULL) { - return NXT_ERROR; - } - - if (nxt_http_parse_request_init(&rp, mp_temp) != NXT_OK) { - return NXT_ERROR; - } - - if (test->handler == &nxt_http_parse_test_fields) { - rp.discard_unsafe_fields = test->data.fields.discard_unsafe_fields; - } - - rc = nxt_http_parse_test_run(&rp, &test->request); - - if (rc != test->result) { - nxt_log_alert(thr->log, "http parse test case failed:\n" - " - request:\n\"%V\"\n" - " - result: %i (expected: %i)", - &test->request, rc, test->result); - return NXT_ERROR; - } - - if (test->handler != NULL - && test->handler(&rp, &test->data, &test->request, thr->log) - != NXT_OK) - { - return NXT_ERROR; - } - - nxt_mp_destroy(mp_temp); - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "http parse test passed"); - - nxt_memzero(&hash, sizeof(nxt_lvlhsh_t)); - - colls = nxt_http_fields_hash_collisions(&hash, - nxt_http_test_bench_fields, - nxt_nitems(nxt_http_test_bench_fields), - 0); - - nxt_memzero(&hash, sizeof(nxt_lvlhsh_t)); - - lvl_colls = nxt_http_fields_hash_collisions(&hash, - nxt_http_test_bench_fields, - nxt_nitems(nxt_http_test_bench_fields), - 1); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "http parse test hash collisions %ui out of %uz, level: %ui", - colls, nxt_nitems(nxt_http_test_bench_fields), lvl_colls); - - nxt_memzero(&hash, sizeof(nxt_lvlhsh_t)); - - rc = nxt_http_fields_hash(&hash, nxt_http_test_bench_fields, - nxt_nitems(nxt_http_test_bench_fields)); - if (rc != NXT_OK) { - return NXT_ERROR; - } - - if (nxt_http_parse_test_bench(thr, &nxt_http_test_simple_request, - &hash, "simple", 1000000) - != NXT_OK) - { - return NXT_ERROR; - } - - if (nxt_http_parse_test_bench(thr, &nxt_http_test_big_request, - &hash, "big", 100000) - != NXT_OK) - { - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_parse_test_run(nxt_http_request_parse_t *rp, nxt_str_t *request) -{ - nxt_int_t rc; - nxt_buf_mem_t buf; - - buf.start = request->start; - buf.end = request->start + request->length; - - buf.pos = buf.start; - buf.free = buf.pos + 1; - - do { - buf.free++; - rc = nxt_http_parse_request(rp, &buf); - } while (buf.free < buf.end && rc == NXT_AGAIN); - - return rc; -} - - -static nxt_int_t -nxt_http_parse_test_bench(nxt_thread_t *thr, nxt_str_t *request, - nxt_lvlhsh_t *hash, const char *name, nxt_uint_t n) -{ - nxt_mp_t *mp; - nxt_nsec_t start, end; - nxt_uint_t i; - nxt_buf_mem_t buf; - nxt_http_request_parse_t rp; - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "http parse %s request bench started: %uz bytes, %ui runs", - name, request->length, n); - - buf.start = request->start; - buf.end = request->start + request->length; - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - for (i = 0; nxt_fast_path(i < n); i++) { - nxt_memzero(&rp, sizeof(nxt_http_request_parse_t)); - - mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { - return NXT_ERROR; - } - - if (nxt_slow_path(nxt_http_parse_request_init(&rp, mp) != NXT_OK)) { - return NXT_ERROR; - } - - buf.pos = buf.start; - buf.free = buf.end; - - if (nxt_slow_path(nxt_http_parse_request(&rp, &buf) != NXT_DONE)) { - nxt_log_alert(thr->log, "http parse %s request bench failed " - "while parsing", name); - return NXT_ERROR; - } - - if (nxt_slow_path(nxt_http_fields_process(rp.fields, hash, NULL) - != NXT_OK)) - { - nxt_log_alert(thr->log, "http parse %s request bench failed " - "while fields processing", name); - return NXT_ERROR; - } - - nxt_mp_destroy(mp); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "http parse %s request bench: %0.3fs", - name, (end - start) / 1000000000.0); - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_parse_test_request_line(nxt_http_request_parse_t *rp, - nxt_http_parse_test_data_t *data, nxt_str_t *request, nxt_log_t *log) -{ - nxt_str_t str; - - nxt_http_parse_test_request_line_t *test = &data->request_line; - - if (rp->method.start != test->method.start - && !nxt_strstr_eq(&rp->method, &test->method)) - { - nxt_log_alert(log, "http parse test case failed:\n" - " - request:\n\"%V\"\n" - " - method: \"%V\" (expected: \"%V\")", - request, &rp->method, &test->method); - return NXT_ERROR; - } - - str.length = rp->target_end - rp->target_start; - str.start = rp->target_start; - - if (str.start != test->target.start - && !nxt_strstr_eq(&str, &test->target)) - { - nxt_log_alert(log, "http parse test case failed:\n" - " - request:\n\"%V\"\n" - " - target: \"%V\" (expected: \"%V\")", - request, &str, &test->target); - return NXT_ERROR; - } - - if (rp->args.start != test->args.start - && !nxt_strstr_eq(&rp->args, &test->args)) - { - nxt_log_alert(log, "http parse test case failed:\n" - " - request:\n\"%V\"\n" - " - args: \"%V\" (expected: \"%V\")", - request, &rp->args, &test->args); - return NXT_ERROR; - } - - if (memcmp(rp->version.str, test->version, 8) != 0) { - nxt_log_alert(log, "http parse test case failed:\n" - " - request:\n\"%V\"\n" - " - version: \"%*s\" (expected: \"%*s\")", request, - (size_t) 8, rp->version.str, - (size_t) 8, test->version); - return NXT_ERROR; - } - - if (rp->complex_target != (test->complex_target | test->quoted_target)) { - nxt_log_alert(log, "http parse test case failed:\n" - " - request:\n\"%V\"\n" - " - complex_target: %d (expected: %d)", - request, rp->complex_target, test->complex_target); - return NXT_ERROR; - } - -#if 0 - if (rp->quoted_target != test->quoted_target) { - nxt_log_alert(log, "http parse test case failed:\n" - " - request:\n\"%V\"\n" - " - quoted_target: %d (expected: %d)", - request, rp->quoted_target, test->quoted_target); - return NXT_ERROR; - } - - if (rp->space_in_target != test->space_in_target) { - nxt_log_alert(log, "http parse test case failed:\n" - " - request:\n\"%V\"\n" - " - space_in_target: %d (expected: %d)", - request, rp->space_in_target, test->space_in_target); - return NXT_ERROR; - } -#endif - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_parse_test_fields(nxt_http_request_parse_t *rp, - nxt_http_parse_test_data_t *data, nxt_str_t *request, nxt_log_t *log) -{ - nxt_int_t rc; - - rc = nxt_http_fields_process(rp->fields, &nxt_http_test_fields_hash, NULL); - - if (rc != data->fields.result) { - nxt_log_alert(log, "http parse test hash failed:\n" - " - request:\n\"%V\"\n" - " - result: %i (expected: %i)", - request, rc, data->fields.result); - return NXT_ERROR; - } - - return NXT_OK; -} - - -static nxt_int_t -nxt_http_test_header_return(void *ctx, nxt_http_field_t *field, uintptr_t data) -{ - return data; -} diff --git a/src/test/nxt_lvlhsh_test.c b/src/test/nxt_lvlhsh_test.c deleted file mode 100644 index baa6d0e1..00000000 --- a/src/test/nxt_lvlhsh_test.c +++ /dev/null @@ -1,263 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -static nxt_int_t -nxt_lvlhsh_test_key_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - if (*(uintptr_t *) lhq->key.start == (uintptr_t) data) { - return NXT_OK; - } - - return NXT_DECLINED; -} - - -static const nxt_lvlhsh_proto_t malloc_proto nxt_aligned(64) = { - //NXT_LVLHSH_LARGE_MEMALIGN, - NXT_LVLHSH_DEFAULT, - nxt_lvlhsh_test_key_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - -static const nxt_lvlhsh_proto_t pool_proto nxt_aligned(64) = { - NXT_LVLHSH_LARGE_SLAB, - nxt_lvlhsh_test_key_test, - nxt_mp_lvlhsh_alloc, - nxt_mp_lvlhsh_free, -}; - - -static nxt_int_t -nxt_lvlhsh_test_add(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto, - void *pool, uintptr_t key) -{ - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = key; - lhq.replace = 0; - lhq.key.length = sizeof(uintptr_t); - lhq.key.start = (u_char *) &key; - lhq.value = (void *) key; - lhq.proto = proto; - lhq.pool = pool; - - switch (nxt_lvlhsh_insert(lh, &lhq)) { - - case NXT_OK: - return NXT_OK; - - case NXT_DECLINED: - nxt_thread_log_alert("lvlhsh test failed: " - "key %p is already in hash", key); - /* Fall through. */ - default: - return NXT_ERROR; - } -} - - -static nxt_int_t -nxt_lvlhsh_test_get(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto, - uintptr_t key) -{ - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = key; - lhq.key.length = sizeof(uintptr_t); - lhq.key.start = (u_char *) &key; - lhq.proto = proto; - - if (nxt_lvlhsh_find(lh, &lhq) == NXT_OK) { - - if (key == (uintptr_t) lhq.value) { - return NXT_OK; - } - } - - nxt_thread_log_alert("lvlhsh test failed: " - "key %p not found in hash", key); - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_lvlhsh_test_delete(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto, - void *pool, uintptr_t key) -{ - nxt_int_t ret; - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = key; - lhq.key.length = sizeof(uintptr_t); - lhq.key.start = (u_char *) &key; - lhq.proto = proto; - lhq.pool = pool; - - ret = nxt_lvlhsh_delete(lh, &lhq); - - if (ret != NXT_OK) { - nxt_thread_log_alert("lvlhsh test failed: " - "key %p not found in hash", key); - } - - return ret; -} - - -nxt_int_t -nxt_lvlhsh_test(nxt_thread_t *thr, nxt_uint_t n, nxt_bool_t use_pool) -{ - void *value; - uint32_t key; - nxt_mp_t *mp; - nxt_nsec_t start, end; - nxt_uint_t i; - nxt_lvlhsh_t lh; - nxt_lvlhsh_each_t lhe; - const nxt_lvlhsh_proto_t *proto; - - const size_t min_chunk_size = 32; - const size_t page_size = 1024; - const size_t page_alignment = 128; - const size_t cluster_size = 4096; - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - if (use_pool) { - mp = nxt_mp_create(cluster_size, page_alignment, page_size, - min_chunk_size); - if (mp == NULL) { - return NXT_ERROR; - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh test started: %uD pool", n); - proto = &pool_proto; - - } else { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh test started: %uD malloc", n); - proto = &malloc_proto; - mp = NULL; - } - - nxt_memzero(&lh, sizeof(nxt_lvlhsh_t)); - - key = 0; - for (i = 0; i < n; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - - if (nxt_lvlhsh_test_add(&lh, proto, mp, key) != NXT_OK) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh add test failed at %ui", i); - return NXT_ERROR; - } - } - - key = 0; - for (i = 0; i < n; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - - if (nxt_lvlhsh_test_get(&lh, proto, key) != NXT_OK) { - return NXT_ERROR; - } - } - - nxt_lvlhsh_each_init(&lhe, proto); - - for (i = 0; i < n + 1; i++) { - if (nxt_lvlhsh_each(&lh, &lhe) == NULL) { - break; - } - } - - if (i != n) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh each test failed at %ui of %ui", i, n); - return NXT_ERROR; - } - - for (i = 0; i < n; i++) { - value = nxt_lvlhsh_peek(&lh, proto); - - if (value == NULL) { - break; - } - - key = (uintptr_t) value; - - if (nxt_lvlhsh_test_delete(&lh, proto, mp, key) != NXT_OK) { - return NXT_ERROR; - } - } - - if (i != n) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh peek test failed at %ui of %ui", i, n); - return NXT_ERROR; - } - - if (!nxt_lvlhsh_is_empty(&lh)) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh is not empty after deletion"); - return NXT_ERROR; - } - - key = 0; - for (i = 0; i < n; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - - if (nxt_lvlhsh_test_add(&lh, proto, mp, key) != NXT_OK) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh add test failed at %ui", i); - return NXT_ERROR; - } - } - - for (i = 0; i < n; i++) { - value = nxt_lvlhsh_retrieve(&lh, proto, mp); - - if (value == NULL) { - break; - } - } - - if (i != n) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh retrieve test failed at %ui of %ui", i, n); - return NXT_ERROR; - } - - if (!nxt_lvlhsh_is_empty(&lh)) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "lvlhsh is not empty after retrieving"); - return NXT_ERROR; - } - - if (mp != NULL) { - if (!nxt_mp_is_empty(mp)) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool is not empty"); - return NXT_ERROR; - } - - nxt_mp_destroy(mp); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "lvlhsh test passed: %0.3fs", - (end - start) / 1000000000.0); - - return NXT_OK; -} diff --git a/src/test/nxt_malloc_test.c b/src/test/nxt_malloc_test.c deleted file mode 100644 index daa609b1..00000000 --- a/src/test/nxt_malloc_test.c +++ /dev/null @@ -1,123 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -#define TIMES 1000 - - -typedef struct { - size_t size; - size_t alignment; - nxt_bool_t tight; -} nxt_malloc_size_t; - - -static nxt_malloc_size_t * -nxt_malloc_run_test(nxt_thread_t *thr, nxt_malloc_size_t *last, size_t size, - nxt_uint_t times) -{ - size_t a, s, alignment; - uintptr_t n; - nxt_uint_t i, tight; - static u_char *p[TIMES + 1]; - - alignment = (size_t) -1; - tight = 0; - - for (i = 1; i < times; i++) { - - p[i] = nxt_malloc(size); - if (p[i] == NULL) { - return NULL; - } - - n = (uintptr_t) p[i]; - a = 0; - - while ((n & 1) == 0) { - a++; - n >>= 1; - } - - alignment = nxt_min(alignment, a); - } - - - for (i = 1; i < times; i++) { - s = size; - nxt_malloc_usable_size(p[i], s); - - if (p[i - 1] + s == p[i] || p[i - 1] == p[i] + s) { - tight++; - } - - nxt_free(p[i]); - } - - alignment = 1 << alignment; - -#if 0 - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "malloc: %uz, %uz, %ui", size, alignment, tight); -#endif - - while (last->alignment >= alignment) { - last--; - } - - last++; - - last->size = size; - last->alignment = alignment; - last->tight = times * 9 / 10 < tight; - - return last; -} - - -nxt_int_t -nxt_malloc_test(nxt_thread_t *thr) -{ - size_t size; - nxt_malloc_size_t *last, *s; - static nxt_malloc_size_t sizes[100]; - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "malloc test started"); - - last = &sizes[0]; - - for (size = 1; size < 64; size++) { - last = nxt_malloc_run_test(thr, last, size, TIMES); - if (last == NULL) { - return NXT_ERROR; - } - } - - for (size = 64; size < 16384; size += 8) { - last = nxt_malloc_run_test(thr, last, size, TIMES / 4); - if (last == NULL) { - return NXT_ERROR; - } - } - - for (size = 16384; size < 512 * 1024 + 129; size += 128) { - last = nxt_malloc_run_test(thr, last, size, TIMES / 16); - if (last == NULL) { - return NXT_ERROR; - } - } - - for (s = &sizes[1]; s <= last; s++) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "malloc sizes: %uz-%uz alignment:%uz tight:%ui", - s[-1].size + 1, s->size, s->alignment, s->tight); - } - - return NXT_OK; -} diff --git a/src/test/nxt_mem_zone_test.c b/src/test/nxt_mem_zone_test.c deleted file mode 100644 index faf0feee..00000000 --- a/src/test/nxt_mem_zone_test.c +++ /dev/null @@ -1,74 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -nxt_int_t -nxt_mem_zone_test(nxt_thread_t *thr, nxt_uint_t runs, nxt_uint_t nblocks, - size_t max_size) -{ - void *start, **blocks; - size_t total, zone_size; - uint32_t size; - nxt_uint_t i, n; - nxt_mem_zone_t *zone; - const size_t page_size = 4096; - - nxt_thread_time_update(thr); - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "mem zone test started, max:%uz", max_size); - - zone_size = (max_size + 1) * nblocks; - - start = nxt_memalign(page_size, zone_size); - if (start == NULL) { - return NXT_ERROR; - } - - zone = nxt_mem_zone_init(start, zone_size, page_size); - if (zone == NULL) { - return NXT_ERROR; - } - - blocks = nxt_malloc(nblocks * sizeof(void *)); - if (blocks == NULL) { - return NXT_ERROR; - } - - size = 0; - - for (i = 0; i < runs; i++) { - - total = 0; - - for (n = 0; n < nblocks; n++) { - size = nxt_murmur_hash2(&size, sizeof(uint32_t)); - - total += size & max_size; - blocks[n] = nxt_mem_zone_alloc(zone, size & max_size); - - if (blocks[n] == NULL) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "mem zone test failed: %uz", total); - return NXT_ERROR; - } - } - - for (n = 0; n < nblocks; n++) { - nxt_mem_zone_free(zone, blocks[n]); - } - } - - nxt_free(blocks); - nxt_free(zone); - - nxt_thread_time_update(thr); - nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem zone test passed"); - - return NXT_OK; -} diff --git a/src/test/nxt_mp_test.c b/src/test/nxt_mp_test.c deleted file mode 100644 index 39aa939d..00000000 --- a/src/test/nxt_mp_test.c +++ /dev/null @@ -1,90 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -nxt_int_t -nxt_mp_test(nxt_thread_t *thr, nxt_uint_t runs, nxt_uint_t nblocks, - size_t max_size) -{ - void **blocks; - size_t total; - uint32_t value, size; - nxt_mp_t *mp; - nxt_bool_t valid; - nxt_uint_t i, n; - - const size_t min_chunk_size = 16; - const size_t page_size = 128; - const size_t page_alignment = 128; - const size_t cluster_size = page_size * 8; - - nxt_thread_time_update(thr); - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "mem pool test started, max:%uz", max_size); - - blocks = nxt_malloc(nblocks * sizeof(void *)); - if (blocks == NULL) { - return NXT_ERROR; - } - - valid = nxt_mp_test_sizes(cluster_size, page_alignment, page_size, - min_chunk_size); - if (!valid) { - return NXT_ERROR; - } - - mp = nxt_mp_create(cluster_size, page_alignment, page_size, min_chunk_size); - if (mp == NULL) { - return NXT_ERROR; - } - - value = 0; - - for (i = 0; i < runs; i++) { - - total = 0; - - for (n = 0; n < nblocks; n++) { - value = nxt_murmur_hash2(&value, sizeof(uint32_t)); - - size = value & max_size; - - if (size == 0) { - size++; - } - - total += size; - blocks[n] = nxt_mp_alloc(mp, size); - - if (blocks[n] == NULL) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "mem pool test failed: %uz", total); - return NXT_ERROR; - } - } - - for (n = 0; n < nblocks; n++) { - nxt_mp_free(mp, blocks[n]); - } - } - - if (!nxt_mp_is_empty(mp)) { - nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool is not empty"); - return NXT_ERROR; - } - - nxt_mp_destroy(mp); - - nxt_free(blocks); - - nxt_thread_time_update(thr); - nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool test passed"); - - return NXT_OK; -} diff --git a/src/test/nxt_msec_diff_test.c b/src/test/nxt_msec_diff_test.c deleted file mode 100644 index 0059b246..00000000 --- a/src/test/nxt_msec_diff_test.c +++ /dev/null @@ -1,46 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -static const nxt_msec_t pairs[] = { - - 0x00000000, 0x00000001, - 0x00000000, 0x7FFFFFFF, - - 0x7FFFFFFF, 0x80000000, - 0x7FFFFFFF, 0x80000001, - - 0x80000000, 0x80000001, - 0x80000000, 0xFFFFFFFF, - - 0xFFFFFFFF, 0x00000000, - 0xFFFFFFFF, 0x00000001, -}; - - -nxt_int_t -nxt_msec_diff_test(nxt_thread_t *thr, nxt_msec_less_t less) -{ - nxt_uint_t i; - - nxt_thread_time_update(thr); - - for (i = 0; i < nxt_nitems(pairs); i += 2) { - - if (!less(pairs[i], pairs[i + 1])) { - nxt_log_alert(thr->log, - "msec diff test failed: 0x%08XM 0x%08XM", - pairs[i], pairs[i + 1]); - return NXT_ERROR; - } - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "msec diff test passed"); - return NXT_OK; -} diff --git a/src/test/nxt_rbtree1.c b/src/test/nxt_rbtree1.c deleted file mode 100644 index ec024858..00000000 --- a/src/test/nxt_rbtree1.c +++ /dev/null @@ -1,382 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - - -#include -#include "nxt_rbtree1.h" - - -/* - * The red-black tree code is based on the algorithm described in - * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest. - */ - - -nxt_inline void nxt_rbtree1_left_rotate(nxt_rbtree1_node_t **root, - nxt_rbtree1_node_t *sentinel, nxt_rbtree1_node_t *node); -nxt_inline void nxt_rbtree1_right_rotate(nxt_rbtree1_node_t **root, - nxt_rbtree1_node_t *sentinel, nxt_rbtree1_node_t *node); - - -void -nxt_rbtree1_insert(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node) -{ - nxt_rbtree1_node_t **root, *temp, *sentinel; - - /* a binary tree insert */ - - root = (nxt_rbtree1_node_t **) &tree->root; - sentinel = tree->sentinel; - - if (*root == sentinel) { - node->parent = NULL; - node->left = sentinel; - node->right = sentinel; - nxt_rbtree1_black(node); - *root = node; - - return; - } - - tree->insert(*root, node, sentinel); - - /* re-balance tree */ - - while (node != *root && nxt_rbtree1_is_red(node->parent)) { - - if (node->parent == node->parent->parent->left) { - temp = node->parent->parent->right; - - if (nxt_rbtree1_is_red(temp)) { - nxt_rbtree1_black(node->parent); - nxt_rbtree1_black(temp); - nxt_rbtree1_red(node->parent->parent); - node = node->parent->parent; - - } else { - if (node == node->parent->right) { - node = node->parent; - nxt_rbtree1_left_rotate(root, sentinel, node); - } - - nxt_rbtree1_black(node->parent); - nxt_rbtree1_red(node->parent->parent); - nxt_rbtree1_right_rotate(root, sentinel, node->parent->parent); - } - - } else { - temp = node->parent->parent->left; - - if (nxt_rbtree1_is_red(temp)) { - nxt_rbtree1_black(node->parent); - nxt_rbtree1_black(temp); - nxt_rbtree1_red(node->parent->parent); - node = node->parent->parent; - - } else { - if (node == node->parent->left) { - node = node->parent; - nxt_rbtree1_right_rotate(root, sentinel, node); - } - - nxt_rbtree1_black(node->parent); - nxt_rbtree1_red(node->parent->parent); - nxt_rbtree1_left_rotate(root, sentinel, node->parent->parent); - } - } - } - - nxt_rbtree1_black(*root); -} - - -void -nxt_rbtree1_insert_value(nxt_rbtree1_node_t *temp, nxt_rbtree1_node_t *node, - nxt_rbtree1_node_t *sentinel) -{ - nxt_rbtree1_node_t **p; - - for ( ;; ) { - - p = (node->key < temp->key) ? &temp->left : &temp->right; - - if (*p == sentinel) { - break; - } - - temp = *p; - } - - *p = node; - node->parent = temp; - node->left = sentinel; - node->right = sentinel; - nxt_rbtree1_red(node); -} - - -void -nxt_rbtree1_insert_timer_value(nxt_rbtree1_node_t *temp, - nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel) -{ - nxt_rbtree1_node_t **p; - - for ( ;; ) { - - /* - * Timer values - * 1) are spread in small range, usually several minutes, - * 2) and overflow each 49 days, if milliseconds are stored in 32 bits. - * The comparison takes into account that overflow. - */ - - /* node->key < temp->key */ - - p = ((nxt_rbtree1_key_int_t) (node->key - temp->key) < 0) - ? &temp->left : &temp->right; - - if (*p == sentinel) { - break; - } - - temp = *p; - } - - *p = node; - node->parent = temp; - node->left = sentinel; - node->right = sentinel; - nxt_rbtree1_red(node); -} - - -void -nxt_rbtree1_delete(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node) -{ - nxt_uint_t red; - nxt_rbtree1_node_t **root, *sentinel, *subst, *temp, *w; - - /* a binary tree delete */ - - root = (nxt_rbtree1_node_t **) &tree->root; - sentinel = tree->sentinel; - - if (node->left == sentinel) { - temp = node->right; - subst = node; - - } else if (node->right == sentinel) { - temp = node->left; - subst = node; - - } else { - subst = nxt_rbtree1_min(node->right, sentinel); - - if (subst->left != sentinel) { - temp = subst->left; - } else { - temp = subst->right; - } - } - - if (subst == *root) { - *root = temp; - nxt_rbtree1_black(temp); - - /* DEBUG stuff */ - node->left = NULL; - node->right = NULL; - node->parent = NULL; - node->key = 0; - - return; - } - - red = nxt_rbtree1_is_red(subst); - - if (subst == subst->parent->left) { - subst->parent->left = temp; - - } else { - subst->parent->right = temp; - } - - if (subst == node) { - - temp->parent = subst->parent; - - } else { - - if (subst->parent == node) { - temp->parent = subst; - - } else { - temp->parent = subst->parent; - } - - subst->left = node->left; - subst->right = node->right; - subst->parent = node->parent; - nxt_rbtree1_copy_color(subst, node); - - if (node == *root) { - *root = subst; - - } else { - if (node == node->parent->left) { - node->parent->left = subst; - } else { - node->parent->right = subst; - } - } - - if (subst->left != sentinel) { - subst->left->parent = subst; - } - - if (subst->right != sentinel) { - subst->right->parent = subst; - } - } - - /* DEBUG stuff */ - node->left = NULL; - node->right = NULL; - node->parent = NULL; - node->key = 0; - - if (red) { - return; - } - - /* a delete fixup */ - - while (temp != *root && nxt_rbtree1_is_black(temp)) { - - if (temp == temp->parent->left) { - w = temp->parent->right; - - if (nxt_rbtree1_is_red(w)) { - nxt_rbtree1_black(w); - nxt_rbtree1_red(temp->parent); - nxt_rbtree1_left_rotate(root, sentinel, temp->parent); - w = temp->parent->right; - } - - if (nxt_rbtree1_is_black(w->left) && nxt_rbtree1_is_black(w->right)) - { - nxt_rbtree1_red(w); - temp = temp->parent; - - } else { - if (nxt_rbtree1_is_black(w->right)) { - nxt_rbtree1_black(w->left); - nxt_rbtree1_red(w); - nxt_rbtree1_right_rotate(root, sentinel, w); - w = temp->parent->right; - } - - nxt_rbtree1_copy_color(w, temp->parent); - nxt_rbtree1_black(temp->parent); - nxt_rbtree1_black(w->right); - nxt_rbtree1_left_rotate(root, sentinel, temp->parent); - temp = *root; - } - - } else { - w = temp->parent->left; - - if (nxt_rbtree1_is_red(w)) { - nxt_rbtree1_black(w); - nxt_rbtree1_red(temp->parent); - nxt_rbtree1_right_rotate(root, sentinel, temp->parent); - w = temp->parent->left; - } - - if (nxt_rbtree1_is_black(w->left) && nxt_rbtree1_is_black(w->right)) - { - nxt_rbtree1_red(w); - temp = temp->parent; - - } else { - if (nxt_rbtree1_is_black(w->left)) { - nxt_rbtree1_black(w->right); - nxt_rbtree1_red(w); - nxt_rbtree1_left_rotate(root, sentinel, w); - w = temp->parent->left; - } - - nxt_rbtree1_copy_color(w, temp->parent); - nxt_rbtree1_black(temp->parent); - nxt_rbtree1_black(w->left); - nxt_rbtree1_right_rotate(root, sentinel, temp->parent); - temp = *root; - } - } - } - - nxt_rbtree1_black(temp); -} - - -nxt_inline void -nxt_rbtree1_left_rotate(nxt_rbtree1_node_t **root, nxt_rbtree1_node_t *sentinel, - nxt_rbtree1_node_t *node) -{ - nxt_rbtree1_node_t *temp; - - temp = node->right; - node->right = temp->left; - - if (temp->left != sentinel) { - temp->left->parent = node; - } - - temp->parent = node->parent; - - if (node == *root) { - *root = temp; - - } else if (node == node->parent->left) { - node->parent->left = temp; - - } else { - node->parent->right = temp; - } - - temp->left = node; - node->parent = temp; -} - - -nxt_inline void -nxt_rbtree1_right_rotate(nxt_rbtree1_node_t **root, - nxt_rbtree1_node_t *sentinel, nxt_rbtree1_node_t *node) -{ - nxt_rbtree1_node_t *temp; - - temp = node->left; - node->left = temp->right; - - if (temp->right != sentinel) { - temp->right->parent = node; - } - - temp->parent = node->parent; - - if (node == *root) { - *root = temp; - - } else if (node == node->parent->right) { - node->parent->right = temp; - - } else { - node->parent->left = temp; - } - - temp->right = node; - node->parent = temp; -} diff --git a/src/test/nxt_rbtree1.h b/src/test/nxt_rbtree1.h deleted file mode 100644 index d6230ab0..00000000 --- a/src/test/nxt_rbtree1.h +++ /dev/null @@ -1,73 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - - -typedef nxt_uint_t nxt_rbtree1_key_t; -typedef nxt_int_t nxt_rbtree1_key_int_t; - - -typedef struct nxt_rbtree1_node_s nxt_rbtree1_node_t; - -struct nxt_rbtree1_node_s { - nxt_rbtree1_key_t key; - nxt_rbtree1_node_t *left; - nxt_rbtree1_node_t *right; - nxt_rbtree1_node_t *parent; - u_char color; - u_char data; -}; - - -typedef struct nxt_rbtree1_s nxt_rbtree1_t; - -typedef void (*nxt_rbtree1_insert_pt) (nxt_rbtree1_node_t *root, - nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel); - -struct nxt_rbtree1_s { - nxt_rbtree1_node_t *root; - nxt_rbtree1_node_t *sentinel; - nxt_rbtree1_insert_pt insert; -}; - - -#define nxt_rbtree1_init(tree, s, i) \ - nxt_rbtree1_sentinel_init(s); \ - (tree)->root = s; \ - (tree)->sentinel = s; \ - (tree)->insert = i - - -NXT_EXPORT void nxt_rbtree1_insert(nxt_rbtree1_t *tree, - nxt_rbtree1_node_t *node); -NXT_EXPORT void nxt_rbtree1_delete(nxt_rbtree1_t *tree, - nxt_rbtree1_node_t *node); -NXT_EXPORT void nxt_rbtree1_insert_value(nxt_rbtree1_node_t *root, - nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel); -NXT_EXPORT void nxt_rbtree1_insert_timer_value(nxt_rbtree1_node_t *root, - nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel); - - -#define nxt_rbtree1_red(node) ((node)->color = 1) -#define nxt_rbtree1_black(node) ((node)->color = 0) -#define nxt_rbtree1_is_red(node) ((node)->color) -#define nxt_rbtree1_is_black(node) (!nxt_rbtree1_is_red(node)) -#define nxt_rbtree1_copy_color(n1, n2) (n1->color = n2->color) - - -/* a sentinel must be black */ - -#define nxt_rbtree1_sentinel_init(node) nxt_rbtree1_black(node) - - -nxt_inline nxt_rbtree1_node_t * -nxt_rbtree1_min(nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel) -{ - while (node->left != sentinel) { - node = node->left; - } - - return node; -} diff --git a/src/test/nxt_rbtree1_test.c b/src/test/nxt_rbtree1_test.c deleted file mode 100644 index 1f23998c..00000000 --- a/src/test/nxt_rbtree1_test.c +++ /dev/null @@ -1,341 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" -#include "nxt_rbtree1.h" - - -#define nxt_rbtree1_is_empty(tree) \ - (((tree)->root) == (tree)->sentinel) - - -#define nxt_rbtree1_is_there_successor(tree, node) \ - ((node) != (tree)->sentinel) - - -nxt_inline nxt_rbtree1_node_t * -nxt_rbtree1_node_successor(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node) -{ - nxt_rbtree1_node_t *parent; - - if (node->right != tree->sentinel) { - return nxt_rbtree1_min(node->right, tree->sentinel); - } - - for ( ;; ) { - parent = node->parent; - - if (parent == NULL) { - return tree->sentinel; - } - - if (node == parent->left) { - return parent; - } - - node = parent; - } -} - - -static void nxt_rbtree1_test_insert_value(nxt_rbtree1_node_t *temp, - nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel); -static nxt_int_t nxt_rbtree1_test_compare(nxt_rbtree1_node_t *node1, - nxt_rbtree1_node_t *node2); -static int nxt_cdecl nxt_rbtree1_test_sort_cmp(const void *one, - const void *two); -static nxt_rbtree1_node_t *nxt_rbtree1_test_find(nxt_rbtree1_t *tree, - nxt_rbtree1_node_t *node); - - -nxt_int_t -nxt_rbtree1_test(nxt_thread_t *thr, nxt_uint_t n) -{ - uint32_t key, *keys; - nxt_uint_t i; - nxt_nsec_t start, end; - nxt_rbtree1_t tree; - nxt_rbtree1_node_t *node, *nodes, sentinel; - - nxt_thread_time_update(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree1 test started: %ui", n); - - nxt_rbtree1_init(&tree, &sentinel, nxt_rbtree1_test_insert_value); - - nodes = nxt_malloc(n * sizeof(nxt_rbtree1_node_t)); - if (nodes == NULL) { - return NXT_ERROR; - } - - keys = nxt_malloc(n * sizeof(uint32_t)); - if (keys == NULL) { - nxt_free(keys); - return NXT_ERROR; - } - - key = 0; - - for (i = 0; i < n; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - - keys[i] = key; - nodes[i].key = key; - } - - nxt_qsort(keys, n, sizeof(uint32_t), nxt_rbtree1_test_sort_cmp); - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - for (i = 0; i < n; i++) { - nxt_rbtree1_insert(&tree, &nodes[i]); - } - - for (i = 0; i < n; i++) { - if (nxt_rbtree1_test_find(&tree, &nodes[i]) != &nodes[i]) { - nxt_log_alert(thr->log, "rbtree1 test failed: %08XD not found", - nodes[i].key); - goto fail; - } - } - - i = 0; - node = nxt_rbtree1_min(tree.root, tree.sentinel); - - while (nxt_rbtree1_is_there_successor(&tree, node)) { - - if (keys[i] != node->key) { - nxt_log_alert(thr->log, "rbtree1 test failed: %i: %08XD %08XD", - i, keys[i], node->key); - goto fail; - } - - i++; - node = nxt_rbtree1_node_successor(&tree, node); - } - - if (i != n) { - nxt_log_alert(thr->log, "rbtree1 test failed: %ui", i); - goto fail; - } - - for (i = 0; i < n; i++) { - nxt_rbtree1_delete(&tree, &nodes[i]); - nxt_memset(&nodes[i], 0xA5, sizeof(nxt_rbtree1_node_t)); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - if (!nxt_rbtree1_is_empty(&tree)) { - nxt_log_alert(thr->log, "rbtree1 test failed: tree is not empty"); - goto fail; - } - - nxt_free(keys); - nxt_free(nodes); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree1 test passed %0.3fs", - (end - start) / 1000000000.0); - - return NXT_OK; - -fail: - - nxt_free(keys); - nxt_free(nodes); - - return NXT_ERROR; -} - - -static void -nxt_rbtree1_test_insert_value(nxt_rbtree1_node_t *temp, - nxt_rbtree1_node_t *node, nxt_rbtree1_node_t *sentinel) -{ - nxt_rbtree1_node_t **p; - - for ( ;; ) { - nxt_prefetch(temp->left); - nxt_prefetch(temp->right); - - p = (node->key < temp->key) ? &temp->left : &temp->right; - - if (*p == sentinel) { - break; - } - - temp = *p; - } - - *p = node; - node->parent = temp; - node->left = sentinel; - node->right = sentinel; - nxt_rbtree1_red(node); -} - - -/* - * Subtraction cannot be used in these comparison functions because the key - * values are spread uniform in whole 0 .. 2^32 range but are not grouped - * around some value as timeout values are. - */ - -nxt_inline nxt_int_t -nxt_rbtree1_test_compare(nxt_rbtree1_node_t *node1, nxt_rbtree1_node_t *node2) -{ - if (node1->key < node2->key) { - return -1; - } - - if (node1->key == node2->key) { - return 0; - } - - return 1; -} - - -static int nxt_cdecl -nxt_rbtree1_test_sort_cmp(const void *one, const void *two) -{ - const uint32_t *first, *second; - - first = one; - second = two; - - if (*first < *second) { - return -1; - } - - if (*first == *second) { - return 0; - } - - return 1; -} - - -static nxt_rbtree1_node_t * -nxt_rbtree1_test_find(nxt_rbtree1_t *tree, nxt_rbtree1_node_t *node) -{ - nxt_int_t n; - nxt_rbtree1_node_t *next, *sentinel; - - next = tree->root; - sentinel = tree->sentinel; - - while (next != sentinel) { - nxt_prefetch(next->left); - nxt_prefetch(next->right); - - n = nxt_rbtree1_test_compare(node, next); - - if (n < 0) { - next = next->left; - - } else if (n > 0) { - next = next->right; - - } else { - return next; - } - } - - return NULL; -} - - -#if (NXT_TEST_RTDTSC) - -#define NXT_RBT_STEP (21 * nxt_pagesize / 10 / sizeof(nxt_rbtree1_node_t)) - -static nxt_rbtree1_t mb_tree; -static nxt_rbtree1_node_t mb_sentinel; -static nxt_rbtree1_node_t *mb_nodes; - - -nxt_int_t -nxt_rbtree1_mb_start(nxt_thread_t *thr) -{ - uint32_t key; - uint64_t start, end; - nxt_uint_t i, n; - - n = NXT_RBT_STEP; - - mb_nodes = nxt_malloc(NXT_RBT_NODES * n * sizeof(nxt_rbtree1_node_t)); - if (mb_nodes == NULL) { - return NXT_ERROR; - } - - nxt_rbtree1_init(&mb_tree, &mb_sentinel, nxt_rbtree1_test_insert_value); - - key = 0; - - for (i = 0; i < NXT_RBT_NODES; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - mb_nodes[n * i].key = key; - } - - for (i = 0; i < NXT_RBT_NODES - 2; i++) { - nxt_rbtree1_insert(&mb_tree, &mb_nodes[n * i]); - } - - n *= (NXT_RBT_NODES - 2); - - start = nxt_rdtsc(); - nxt_rbtree1_insert(&mb_tree, &mb_nodes[n]); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree1 mb cached insert: %L cycles", end - start); - - return NXT_OK; -} - - -void -nxt_rbtree1_mb_insert(nxt_thread_t *thr) -{ - uint64_t start, end; - nxt_uint_t n; - - n = NXT_RBT_STEP; - n *= (NXT_RBT_NODES - 1); - - start = nxt_rdtsc(); - nxt_rbtree1_insert(&mb_tree, &mb_nodes[n]); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree1 mb insert: %L cycles", end - start); -} - - -void -nxt_rbtree1_mb_delete(nxt_thread_t *thr) -{ - uint64_t start, end; - nxt_uint_t n; - - n = NXT_RBT_STEP; - n *= (NXT_RBT_NODES / 4 + 1); - - start = nxt_rdtsc(); - nxt_rbtree1_delete(&mb_tree, &mb_nodes[n]); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree1 mb delete: %L cycles", end - start); - - nxt_free(mb_nodes); -} - -#endif diff --git a/src/test/nxt_rbtree_test.c b/src/test/nxt_rbtree_test.c deleted file mode 100644 index 41375d92..00000000 --- a/src/test/nxt_rbtree_test.c +++ /dev/null @@ -1,279 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -typedef struct { - NXT_RBTREE_NODE (node); - uint32_t key; -} nxt_rbtree_test_t; - - -static intptr_t nxt_rbtree_test_comparison(nxt_rbtree_node_t *node1, - nxt_rbtree_node_t *node2); -static nxt_int_t nxt_rbtree_test_compare(uint32_t key1, uint32_t key2); -static int nxt_cdecl nxt_rbtree_test_sort_cmp(const void *one, const void *two); - - -nxt_int_t -nxt_rbtree_test(nxt_thread_t *thr, nxt_uint_t n) -{ - void *mark; - uint32_t key, *keys; - nxt_uint_t i; - nxt_nsec_t start, end; - nxt_rbtree_t tree; - nxt_rbtree_node_t *node; - nxt_rbtree_test_t *items, *item; - - nxt_thread_time_update(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree test started: %ui", n); - - nxt_rbtree_init(&tree, nxt_rbtree_test_comparison); - - mark = tree.sentinel.right; - - items = nxt_malloc(n * sizeof(nxt_rbtree_test_t)); - if (items == NULL) { - return NXT_ERROR; - } - - keys = nxt_malloc(n * sizeof(uint32_t)); - if (keys == NULL) { - nxt_free(keys); - return NXT_ERROR; - } - - key = 0; - - for (i = 0; i < n; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - - keys[i] = key; - items[i].key = key; - } - - nxt_qsort(keys, n, sizeof(uint32_t), nxt_rbtree_test_sort_cmp); - - nxt_thread_time_update(thr); - start = nxt_thread_monotonic_time(thr); - - for (i = 0; i < n; i++) { - nxt_rbtree_insert(&tree, &items[i].node); - } - - for (i = 0; i < n; i++) { - node = nxt_rbtree_find(&tree, &items[i].node); - - if (node != (nxt_rbtree_node_t *) &items[i].node) { - nxt_log_alert(thr->log, "rbtree test failed: %08XD not found", - items[i].key); - goto fail; - } - } - - i = 0; - node = nxt_rbtree_min(&tree); - - while (nxt_rbtree_is_there_successor(&tree, node)) { - - item = (nxt_rbtree_test_t *) node; - - if (keys[i] != item->key) { - nxt_log_alert(thr->log, "rbtree test failed: %i: %08XD %08XD", - i, keys[i], item->key); - goto fail; - } - - i++; - node = nxt_rbtree_node_successor(&tree, node); - } - - if (i != n) { - nxt_log_alert(thr->log, "rbtree test failed: %ui", i); - goto fail; - } - - for (i = 0; i < n; i++) { - nxt_rbtree_delete(&tree, &items[i].node); - nxt_memset(&items[i], 0xA5, sizeof(nxt_rbtree_test_t)); - } - - nxt_thread_time_update(thr); - end = nxt_thread_monotonic_time(thr); - - if (!nxt_rbtree_is_empty(&tree)) { - nxt_log_alert(thr->log, "rbtree test failed: tree is not empty"); - goto fail; - } - - /* Check that the sentinel callback was not modified. */ - - if (mark != tree.sentinel.right) { - nxt_log_alert(thr->log, "rbtree sentinel test failed"); - goto fail; - } - - nxt_free(keys); - nxt_free(items); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "rbtree test passed %0.3fs", - (end - start) / 1000000000.0); - - return NXT_OK; - -fail: - - nxt_free(keys); - nxt_free(items); - - return NXT_ERROR; -} - - -static intptr_t -nxt_rbtree_test_comparison(nxt_rbtree_node_t *node1, - nxt_rbtree_node_t *node2) -{ - nxt_rbtree_test_t *item1, *item2; - - item1 = (nxt_rbtree_test_t *) node1; - item2 = (nxt_rbtree_test_t *) node2; - - return nxt_rbtree_test_compare(item1->key, item2->key); -} - - -/* - * Subtraction cannot be used in these comparison functions because - * the key values are spread uniform in whole 0 .. 2^32 range but are - * not grouped around some value as timeout values are. - */ - -static nxt_int_t -nxt_rbtree_test_compare(uint32_t key1, uint32_t key2) -{ - if (key1 < key2) { - return -1; - } - - if (key1 == key2) { - return 0; - } - - return 1; -} - - -static int nxt_cdecl -nxt_rbtree_test_sort_cmp(const void *one, const void *two) -{ - const uint32_t *first, *second; - - first = one; - second = two; - - if (*first < *second) { - return -1; - } - - if (*first == *second) { - return 0; - } - - return 1; -} - - -#if (NXT_TEST_RTDTSC) - -#define NXT_RBT_STEP (21 * nxt_pagesize / 10 / sizeof(nxt_rbtree_test_t)) - -static nxt_rbtree_t mb_tree; -static nxt_rbtree_test_t *mb_nodes; - - -nxt_int_t -nxt_rbtree_mb_start(nxt_thread_t *thr) -{ - uint32_t key; - uint64_t start, end; - nxt_uint_t i, n; - - n = NXT_RBT_STEP; - - mb_nodes = nxt_malloc(NXT_RBT_NODES * n * sizeof(nxt_rbtree_test_t)); - if (mb_nodes == NULL) { - return NXT_ERROR; - } - - nxt_rbtree_init(&mb_tree, nxt_rbtree_test_comparison); - - key = 0; - - for (i = 0; i < NXT_RBT_NODES; i++) { - key = nxt_murmur_hash2(&key, sizeof(uint32_t)); - mb_nodes[n * i].key = key; - } - - for (i = 0; i < NXT_RBT_NODES - 2; i++) { - nxt_rbtree_insert(&mb_tree, &mb_nodes[n * i].node); - } - - n *= (NXT_RBT_NODES - 2); - - start = nxt_rdtsc(); - nxt_rbtree_insert(&mb_tree, &mb_nodes[n].node); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree mb cached insert: %L cycles", end - start); - - return NXT_OK; -} - - -void -nxt_rbtree_mb_insert(nxt_thread_t *thr) -{ - uint64_t start, end; - nxt_uint_t n; - - n = NXT_RBT_STEP; - n *= (NXT_RBT_NODES - 1); - - start = nxt_rdtsc(); - nxt_rbtree_insert(&mb_tree, &mb_nodes[n].node); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree mb insert: %L cycles", end - start); -} - - -void -nxt_rbtree_mb_delete(nxt_thread_t *thr) -{ - uint64_t start, end; - nxt_uint_t n; - - n = NXT_RBT_STEP; - n *= (NXT_RBT_NODES / 4 + 1); - - start = nxt_rdtsc(); - nxt_rbtree_delete(&mb_tree, &mb_nodes[n].node); - end = nxt_rdtsc(); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "rbtree mb delete: %L cycles", end - start); - - nxt_free(mb_nodes); -} - -#endif diff --git a/src/test/nxt_sprintf_test.c b/src/test/nxt_sprintf_test.c deleted file mode 100644 index 7c6e2019..00000000 --- a/src/test/nxt_sprintf_test.c +++ /dev/null @@ -1,71 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -typedef struct { - const char *format; - const char *test; - double number; -} nxt_sprintf_double_test_t; - - -static const nxt_sprintf_double_test_t double_test[] = -{ - { "%3.5f", "1234.56700", 1234.567 }, - { "%3.0f", "1234", 1234.567 }, - { "%f", "1234.567", 1234.567 }, - { "%f", "0.1", 0.1 }, - { "%f", "0.000001", 0.000001 }, - { "%f", "4503599627370495", 4503599627370495.0 }, -}; - - -static nxt_int_t -nxt_sprintf_test_double(u_char *buf, u_char *end, const char *fmt, - const char *test, double n) -{ - u_char *p; - - p = nxt_sprintf(buf, end, fmt, n); - *p = '\0'; - - return nxt_strcmp(buf, test); -} - - -nxt_int_t -nxt_sprintf_test(nxt_thread_t *thr) -{ - nxt_int_t ret; - nxt_uint_t i; - u_char *end, buf[64]; - - nxt_thread_time_update(thr); - - end = buf + 64; - - for (i = 0; i < nxt_nitems(double_test); i++) { - - ret = nxt_sprintf_test_double(buf, end, double_test[i].format, - double_test[i].test, - double_test[i].number); - - if (ret == NXT_OK) { - continue; - } - - nxt_log_alert(thr->log, "nxt_sprintf(\"%s\") failed: \"%s\" vs \"%s\"", - double_test[i].format, double_test[i].test, buf); - - return NXT_ERROR; - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "nxt_sprintf() test passed"); - return NXT_OK; -} diff --git a/src/test/nxt_strverscmp_test.c b/src/test/nxt_strverscmp_test.c deleted file mode 100644 index 40adbfb2..00000000 --- a/src/test/nxt_strverscmp_test.c +++ /dev/null @@ -1,94 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - * Copyright (C) Valentin V. Bartenev - */ - -#include -#include "nxt_tests.h" - - -typedef struct { - const char *v1; - const char res; - const char *v2; -} nxt_strverscmp_test_t; - - -nxt_int_t -nxt_strverscmp_test(nxt_thread_t *thr) -{ - nxt_int_t ret; - nxt_uint_t i; - - static const nxt_strverscmp_test_t tests[] = { - { "word", '=', "word" }, - { "42", '=', "42" }, - { "000", '=', "000" }, - { "2", '>', "1" }, - { "2", '<', "10" }, - { "rc2", '>', "rc" }, - { "rc2", '<', "rc3" }, - { "1.13.8", '>', "1.1.9" }, - { "1.9", '<', "1.13.8" }, - { "9.9", '<', "10.0" }, - { "1", '>', "007" }, - { "2b01", '<', "2b013" }, - { "011", '>', "01" }, - { "011", '>', "01.1" }, - { "011", '>', "01+1" }, - { "011", '<', "01:1" }, - { "011", '<', "01b" }, - { "020", '>', "01b" }, - { "a0", '>', "a01" }, - { "b00", '<', "b01" }, - { "c000", '<', "c01" }, - { "000", '<', "00" }, - { "000", '<', "00a" }, - { "00.", '>', "000" }, - { "a.0", '<', "a0" }, - { "b11", '>', "b0" }, - }; - - nxt_thread_time_update(thr); - - for (i = 0; i < nxt_nitems(tests); i++) { - - ret = nxt_strverscmp((u_char *) tests[i].v1, (u_char *) tests[i].v2); - - switch (tests[i].res) { - - case '<': - if (ret < 0) { - continue; - } - - break; - - case '=': - if (ret == 0) { - continue; - } - - break; - - case '>': - if (ret > 0) { - continue; - } - - break; - } - - nxt_log_alert(thr->log, - "nxt_strverscmp() test \"%s\" %c \"%s\" failed: %i", - tests[i].v1, tests[i].res, tests[i].v2, ret); - - return NXT_ERROR; - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, - "nxt_strverscmp() test passed"); - - return NXT_OK; -} diff --git a/src/test/nxt_term_parse_test.c b/src/test/nxt_term_parse_test.c deleted file mode 100644 index 83ae4931..00000000 --- a/src/test/nxt_term_parse_test.c +++ /dev/null @@ -1,60 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -typedef struct { - nxt_str_t string; - nxt_bool_t is_sec; - nxt_int_t value; -} nxt_term_parse_test_t; - - -static const nxt_term_parse_test_t terms[] = { - { nxt_string("1y"), 1, 365 * 24 * 60 * 60 }, - { nxt_string("1w"), 1, 7 * 24 * 60 * 60 }, - { nxt_string("1w"), 0, 7 * 24 * 60 * 60 * 1000 }, - { nxt_string("1w 1d"), 0, 8 * 24 * 60 * 60 * 1000 }, - { nxt_string("1w d"), 0, -1 }, - { nxt_string("w"), 0, -1 }, - { nxt_string("1d 1w"), 0, -1 }, - { nxt_string("25d"), 0, -2 }, - { nxt_string("300"), 1, 300 }, - { nxt_string("300"), 0, 300000 }, - { nxt_string("300s"), 1, 300 }, - { nxt_string("300ms"), 0, 300 }, - { nxt_string("1y 1M 1w1d1h1m1s"), 1, - (((((365 + 30 + 7 + 1) * 24 + 1) * 60) + 1) * 60) + 1 }, -}; - - -nxt_int_t -nxt_term_parse_test(nxt_thread_t *thr) -{ - nxt_int_t val; - nxt_uint_t i; - const nxt_str_t *s; - - nxt_thread_time_update(thr); - - for (i = 0; i < nxt_nitems(terms); i++) { - - s = &terms[i].string; - val = nxt_term_parse(s->start, s->length, terms[i].is_sec); - - if (val != terms[i].value) { - nxt_log_alert(thr->log, - "term parse test failed: \"%V\": %i %i", - s, terms[i].value, val); - return NXT_ERROR; - } - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "term parse test passed"); - return NXT_OK; -} diff --git a/src/test/nxt_tests.c b/src/test/nxt_tests.c deleted file mode 100644 index 03a2a1df..00000000 --- a/src/test/nxt_tests.c +++ /dev/null @@ -1,176 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -extern char **environ; - -nxt_module_init_t nxt_init_modules[1]; -nxt_uint_t nxt_init_modules_n; - - -/* The function is defined here to prevent inline optimizations. */ -static nxt_bool_t -nxt_msec_less(nxt_msec_t first, nxt_msec_t second) -{ - return (nxt_msec_diff(first, second) < 0); -} - - -int nxt_cdecl -main(int argc, char **argv) -{ - nxt_task_t task; - nxt_thread_t *thr; - - if (nxt_lib_start("tests", argv, &environ) != NXT_OK) { - return 1; - } - - nxt_main_log.level = NXT_LOG_INFO; - task.log = &nxt_main_log; - - thr = nxt_thread(); - thr->task = &task; - -#if (NXT_TEST_RTDTSC) - - if (nxt_process_argv[1] != NULL - && memcmp(nxt_process_argv[1], "rbm", 3) == 0) - { - if (nxt_rbtree1_mb_start(thr) != NXT_OK) { - return 1; - } - - if (nxt_rbtree_mb_start(thr) != NXT_OK) { - return 1; - } - - if (nxt_lvlhsh_test(thr, 500 * 1000, 0) != NXT_OK) { - return 1; - } - - nxt_rbtree1_mb_insert(thr); - nxt_rbtree_mb_insert(thr); - - if (nxt_lvlhsh_test(thr, 500 * 1000, 0) != NXT_OK) { - return 1; - } - - nxt_rbtree1_mb_delete(thr); - nxt_rbtree_mb_delete(thr); - - return 0; - } - -#endif - - if (nxt_random_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_term_parse_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_msec_diff_test(thr, nxt_msec_less) != NXT_OK) { - return 1; - } - - if (nxt_rbtree_test(thr, 100 * 1000) != NXT_OK) { - return 1; - } - - if (nxt_rbtree_test(thr, 1000 * 1000) != NXT_OK) { - return 1; - } - - if (nxt_rbtree1_test(thr, 100 * 1000) != NXT_OK) { - return 1; - } - - if (nxt_rbtree1_test(thr, 1000 * 1000) != NXT_OK) { - return 1; - } - - if (nxt_mp_test(thr, 100, 40000, 128 - 1) != NXT_OK) { - return 1; - } - - if (nxt_mp_test(thr, 100, 1000, 4096 - 1) != NXT_OK) { - return 1; - } - - if (nxt_mp_test(thr, 1000, 100, 64 * 1024 - 1) != NXT_OK) { - return 1; - } - - if (nxt_mem_zone_test(thr, 100, 20000, 128 - 1) != NXT_OK) { - return 1; - } - - if (nxt_mem_zone_test(thr, 100, 10000, 4096 - 1) != NXT_OK) { - return 1; - } - - if (nxt_mem_zone_test(thr, 1000, 40, 64 * 1024 - 1) != NXT_OK) { - return 1; - } - - if (nxt_lvlhsh_test(thr, 2, 1) != NXT_OK) { - return 1; - } - - if (nxt_lvlhsh_test(thr, 100 * 1000, 1) != NXT_OK) { - return 1; - } - - if (nxt_lvlhsh_test(thr, 100 * 1000, 0) != NXT_OK) { - return 1; - } - - if (nxt_lvlhsh_test(thr, 1000 * 1000, 1) != NXT_OK) { - return 1; - } - - if (nxt_gmtime_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_sprintf_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_malloc_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_utf8_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_http_parse_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_strverscmp_test(thr) != NXT_OK) { - return 1; - } - - if (nxt_base64_test(thr) != NXT_OK) { - return 1; - } - -#if (NXT_HAVE_CLONE_NEWUSER) - if (nxt_clone_creds_test(thr) != NXT_OK) { - return 1; - } -#endif - - return 0; -} diff --git a/src/test/nxt_tests.h b/src/test/nxt_tests.h deleted file mode 100644 index 463dc851..00000000 --- a/src/test/nxt_tests.h +++ /dev/null @@ -1,71 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_TESTS_H_INCLUDED_ -#define _NXT_TESTS_H_INCLUDED_ - - -typedef nxt_bool_t (*nxt_msec_less_t)(nxt_msec_t first, nxt_msec_t second); - - -#define NXT_RBT_NODES 1500 - - -#if (__i386__ || __i386 || __amd64__ || __amd64) -#if (NXT_GCC || NXT_CLANG) - -#define NXT_TEST_RTDTSC 1 - -nxt_inline uint64_t -nxt_rdtsc(void) -{ - uint32_t eax, edx; - - __asm__ volatile ("rdtsc" : "=a" (eax), "=d" (edx)); - - return ((uint64_t) edx << 32) | eax; -} - -#endif -#endif - - -nxt_int_t nxt_term_parse_test(nxt_thread_t *thr); -nxt_int_t nxt_msec_diff_test(nxt_thread_t *thr, nxt_msec_less_t); - -nxt_int_t nxt_rbtree_test(nxt_thread_t *thr, nxt_uint_t n); -nxt_int_t nxt_rbtree1_test(nxt_thread_t *thr, nxt_uint_t n); - -#if (NXT_TEST_RTDTSC) - -nxt_int_t nxt_rbtree_mb_start(nxt_thread_t *thr); -void nxt_rbtree_mb_insert(nxt_thread_t *thr); -void nxt_rbtree_mb_delete(nxt_thread_t *thr); - -nxt_int_t nxt_rbtree1_mb_start(nxt_thread_t *thr); -void nxt_rbtree1_mb_insert(nxt_thread_t *thr); -void nxt_rbtree1_mb_delete(nxt_thread_t *thr); - -#endif - -nxt_int_t nxt_mp_test(nxt_thread_t *thr, nxt_uint_t runs, nxt_uint_t nblocks, - size_t max_size); -nxt_int_t nxt_mem_zone_test(nxt_thread_t *thr, nxt_uint_t runs, - nxt_uint_t nblocks, size_t max_size); -nxt_int_t nxt_lvlhsh_test(nxt_thread_t *thr, nxt_uint_t n, - nxt_bool_t use_pool); - -nxt_int_t nxt_gmtime_test(nxt_thread_t *thr); -nxt_int_t nxt_sprintf_test(nxt_thread_t *thr); -nxt_int_t nxt_malloc_test(nxt_thread_t *thr); -nxt_int_t nxt_utf8_test(nxt_thread_t *thr); -nxt_int_t nxt_http_parse_test(nxt_thread_t *thr); -nxt_int_t nxt_strverscmp_test(nxt_thread_t *thr); -nxt_int_t nxt_base64_test(nxt_thread_t *thr); -nxt_int_t nxt_clone_creds_test(nxt_thread_t *thr); - - -#endif /* _NXT_TESTS_H_INCLUDED_ */ diff --git a/src/test/nxt_unit_app_test.c b/src/test/nxt_unit_app_test.c deleted file mode 100644 index 5dcebe18..00000000 --- a/src/test/nxt_unit_app_test.c +++ /dev/null @@ -1,281 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include -#include -#include - - -#define CONTENT_TYPE "Content-Type" -#define TEXT_PLAIN "text/plain" -#define HELLO_WORLD "Hello world!\n" - -#define NEW_LINE "\n" - -#define REQUEST_DATA "Request data:\n" -#define METHOD " Method: " -#define PROTOCOL " Protocol: " -#define REMOTE_ADDR " Remote addr: " -#define LOCAL_ADDR " Local addr: " -#define TARGET " Target: " -#define PATH " Path: " -#define QUERY " Query: " -#define FIELDS " Fields:\n" -#define FIELD_PAD " " -#define FIELD_SEP ": " -#define BODY " Body:\n" - - -static int ready_handler(nxt_unit_ctx_t *ctx); -static void *worker(void *main_ctx); -static void greeting_app_request_handler(nxt_unit_request_info_t *req); -static inline char *copy(char *p, const void *src, uint32_t len); - - -static int thread_count; -static pthread_t *threads; - - -int -main(int argc, char **argv) -{ - int i, err; - nxt_unit_ctx_t *ctx; - nxt_unit_init_t init; - - if (argc == 3 && strcmp(argv[1], "-t") == 0) { - thread_count = atoi(argv[2]); - } - - memset(&init, 0, sizeof(nxt_unit_init_t)); - - init.callbacks.request_handler = greeting_app_request_handler; - init.callbacks.ready_handler = ready_handler; - - ctx = nxt_unit_init(&init); - if (ctx == NULL) { - return 1; - } - - err = nxt_unit_run(ctx); - - nxt_unit_debug(ctx, "main worker finished with %d code", err); - - if (thread_count > 1) { - for (i = 0; i < thread_count - 1; i++) { - err = pthread_join(threads[i], NULL); - - if (nxt_fast_path(err == 0)) { - nxt_unit_debug(ctx, "join thread #%d", i); - - } else { - nxt_unit_alert(ctx, "pthread_join(#%d) failed: %s (%d)", - i, strerror(err), err); - } - } - - nxt_unit_free(ctx, threads); - } - - nxt_unit_done(ctx); - - nxt_unit_debug(NULL, "main worker done"); - - return 0; -} - - -static int -ready_handler(nxt_unit_ctx_t *ctx) -{ - int i, err; - - nxt_unit_debug(ctx, "ready"); - - if (thread_count <= 1) { - return NXT_UNIT_OK; - } - - threads = nxt_unit_malloc(ctx, sizeof(pthread_t) * (thread_count - 1)); - if (threads == NULL) { - return NXT_UNIT_ERROR; - } - - for (i = 0; i < thread_count - 1; i++) { - err = pthread_create(&threads[i], NULL, worker, ctx); - if (err != 0) { - return NXT_UNIT_ERROR; - } - } - - return NXT_UNIT_OK; -} - - -static void * -worker(void *main_ctx) -{ - int rc; - nxt_unit_ctx_t *ctx; - - ctx = nxt_unit_ctx_alloc(main_ctx, NULL); - if (ctx == NULL) { - return NULL; - } - - nxt_unit_debug(ctx, "start worker"); - - rc = nxt_unit_run(ctx); - - nxt_unit_debug(ctx, "worker finished with %d code", rc); - - nxt_unit_done(ctx); - - return (void *) (intptr_t) rc; -} - - -static void -greeting_app_request_handler(nxt_unit_request_info_t *req) -{ - int rc; - char *p; - ssize_t res; - uint32_t i; - nxt_unit_buf_t *buf; - nxt_unit_field_t *f; - nxt_unit_request_t *r; - - rc = nxt_unit_response_init(req, 200 /* Status code. */, - 1 /* Number of response headers. */, - nxt_length(CONTENT_TYPE) - + nxt_length(TEXT_PLAIN) - + nxt_length(HELLO_WORLD)); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - rc = nxt_unit_response_add_field(req, - CONTENT_TYPE, nxt_length(CONTENT_TYPE), - TEXT_PLAIN, nxt_length(TEXT_PLAIN)); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - rc = nxt_unit_response_add_content(req, HELLO_WORLD, - nxt_length(HELLO_WORLD)); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - rc = nxt_unit_response_send(req); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - r = req->request; - - buf = nxt_unit_response_buf_alloc(req, (req->request_buf->end - - req->request_buf->start) - + nxt_length(REQUEST_DATA) - + nxt_length(METHOD) - + nxt_length(NEW_LINE) - + nxt_length(PROTOCOL) - + nxt_length(NEW_LINE) - + nxt_length(REMOTE_ADDR) - + nxt_length(NEW_LINE) - + nxt_length(LOCAL_ADDR) - + nxt_length(NEW_LINE) - + nxt_length(TARGET) - + nxt_length(NEW_LINE) - + nxt_length(PATH) - + nxt_length(NEW_LINE) - + nxt_length(QUERY) - + nxt_length(NEW_LINE) - + nxt_length(FIELDS) - + r->fields_count * ( - nxt_length(FIELD_PAD) - + nxt_length(FIELD_SEP)) - + nxt_length(BODY)); - if (nxt_slow_path(buf == NULL)) { - rc = NXT_UNIT_ERROR; - - goto fail; - } - - p = buf->free; - - p = copy(p, REQUEST_DATA, nxt_length(REQUEST_DATA)); - - p = copy(p, METHOD, nxt_length(METHOD)); - p = copy(p, nxt_unit_sptr_get(&r->method), r->method_length); - *p++ = '\n'; - - p = copy(p, PROTOCOL, nxt_length(PROTOCOL)); - p = copy(p, nxt_unit_sptr_get(&r->version), r->version_length); - *p++ = '\n'; - - p = copy(p, REMOTE_ADDR, nxt_length(REMOTE_ADDR)); - p = copy(p, nxt_unit_sptr_get(&r->remote), r->remote_length); - *p++ = '\n'; - - p = copy(p, LOCAL_ADDR, nxt_length(LOCAL_ADDR)); - p = copy(p, nxt_unit_sptr_get(&r->local_addr), r->local_addr_length); - *p++ = '\n'; - - p = copy(p, TARGET, nxt_length(TARGET)); - p = copy(p, nxt_unit_sptr_get(&r->target), r->target_length); - *p++ = '\n'; - - p = copy(p, PATH, nxt_length(PATH)); - p = copy(p, nxt_unit_sptr_get(&r->path), r->path_length); - *p++ = '\n'; - - if (r->query.offset) { - p = copy(p, QUERY, nxt_length(QUERY)); - p = copy(p, nxt_unit_sptr_get(&r->query), r->query_length); - *p++ = '\n'; - } - - p = copy(p, FIELDS, nxt_length(FIELDS)); - - for (i = 0; i < r->fields_count; i++) { - f = r->fields + i; - - p = copy(p, FIELD_PAD, nxt_length(FIELD_PAD)); - p = copy(p, nxt_unit_sptr_get(&f->name), f->name_length); - p = copy(p, FIELD_SEP, nxt_length(FIELD_SEP)); - p = copy(p, nxt_unit_sptr_get(&f->value), f->value_length); - *p++ = '\n'; - } - - if (r->content_length > 0) { - p = copy(p, BODY, nxt_length(BODY)); - - res = nxt_unit_request_read(req, p, buf->end - p); - p += res; - - } - - buf->free = p; - - rc = nxt_unit_buf_send(buf); - -fail: - - nxt_unit_request_done(req, rc); -} - - -static inline char * -copy(char *p, const void *src, uint32_t len) -{ - memcpy(p, src, len); - - return p + len; -} diff --git a/src/test/nxt_unit_websocket_chat.c b/src/test/nxt_unit_websocket_chat.c deleted file mode 100644 index ec7c2cc3..00000000 --- a/src/test/nxt_unit_websocket_chat.c +++ /dev/null @@ -1,348 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - - -#define CONTENT_TYPE "Content-Type" -#define CONTENT_LENGTH "Content-Length" -#define TEXT_HTML "text/html" - -typedef struct { - nxt_queue_link_t link; - int id; -} ws_chat_request_data_t; - - -static int ws_chat_root(nxt_unit_request_info_t *req); -static void ws_chat_broadcast(const char *buf, size_t size); - - -static const char ws_chat_index_html[]; -static const int ws_chat_index_html_size; - -static char ws_chat_index_content_length[34]; -static int ws_chat_index_content_length_size; - -static nxt_queue_t ws_chat_sessions; -static int ws_chat_next_id = 0; - - -static void -ws_chat_request_handler(nxt_unit_request_info_t *req) -{ - static char buf[1024]; - int buf_size; - int rc = NXT_UNIT_OK; - nxt_unit_request_t *r; - ws_chat_request_data_t *data; - - r = req->request; - - const char* target = nxt_unit_sptr_get(&r->target); - - if (strcmp(target, "/") == 0) { - rc = ws_chat_root(req); - goto fail; - } - - if (strcmp(target, "/chat") == 0) { - if (!nxt_unit_request_is_websocket_handshake(req)) { - goto notfound; - } - - rc = nxt_unit_response_init(req, 101, 0, 0); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - data = req->data; - nxt_queue_insert_tail(&ws_chat_sessions, &data->link); - - data->id = ws_chat_next_id++; - - nxt_unit_response_upgrade(req); - nxt_unit_response_send(req); - - - buf_size = snprintf(buf, sizeof(buf), "Guest #%d has joined.", data->id); - - ws_chat_broadcast(buf, buf_size); - - return; - } - -notfound: - - rc = nxt_unit_response_init(req, 404, 0, 0); - -fail: - - nxt_unit_request_done(req, rc); -} - - -static int -ws_chat_root(nxt_unit_request_info_t *req) -{ - int rc; - - rc = nxt_unit_response_init(req, 200 /* Status code. */, - 2 /* Number of response headers. */, - nxt_length(CONTENT_TYPE) - + nxt_length(TEXT_HTML) - + nxt_length(CONTENT_LENGTH) - + ws_chat_index_content_length_size - + ws_chat_index_html_size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - rc = nxt_unit_response_add_field(req, - CONTENT_TYPE, nxt_length(CONTENT_TYPE), - TEXT_HTML, nxt_length(TEXT_HTML)); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - rc = nxt_unit_response_add_field(req, - CONTENT_LENGTH, nxt_length(CONTENT_LENGTH), - ws_chat_index_content_length, - ws_chat_index_content_length_size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - rc = nxt_unit_response_add_content(req, ws_chat_index_html, - ws_chat_index_html_size); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - return rc; - } - - return nxt_unit_response_send(req); -} - - -static void -ws_chat_broadcast(const char *buf, size_t size) -{ - ws_chat_request_data_t *data; - nxt_unit_request_info_t *req; - - nxt_unit_debug(NULL, "broadcast: %*.s", (int) size, buf); - - nxt_queue_each(data, &ws_chat_sessions, ws_chat_request_data_t, link) { - - req = nxt_unit_get_request_info_from_data(data); - - nxt_unit_req_debug(req, "send: %*.s", (int) size, buf); - - nxt_unit_websocket_send(req, NXT_WEBSOCKET_OP_TEXT, 1, buf, size); - } nxt_queue_loop; -} - - -static void -ws_chat_websocket_handler(nxt_unit_websocket_frame_t *ws) -{ - int buf_size; - static char buf[1024]; - ws_chat_request_data_t *data; - - if (ws->header->opcode != NXT_WEBSOCKET_OP_TEXT) { - return; - } - - data = ws->req->data; - - buf_size = snprintf(buf, sizeof(buf), "Guest #%d: ", data->id); - - buf_size += nxt_unit_websocket_read(ws, buf + buf_size, - nxt_min(sizeof(buf), - ws->content_length)); - - ws_chat_broadcast(buf, buf_size); - - nxt_unit_websocket_done(ws); -} - - -static void -ws_chat_close_handler(nxt_unit_request_info_t *req) -{ - int buf_size; - static char buf[1024]; - ws_chat_request_data_t *data; - - data = req->data; - buf_size = snprintf(buf, sizeof(buf), "Guest #%d has disconnected.", - data->id); - - nxt_queue_remove(&data->link); - nxt_unit_request_done(req, NXT_UNIT_OK); - - ws_chat_broadcast(buf, buf_size); -} - - -int -main(void) -{ - nxt_unit_ctx_t *ctx; - nxt_unit_init_t init; - - ws_chat_index_content_length_size = - snprintf(ws_chat_index_content_length, - sizeof(ws_chat_index_content_length), "%d", - ws_chat_index_html_size); - - nxt_queue_init(&ws_chat_sessions); - - memset(&init, 0, sizeof(nxt_unit_init_t)); - - init.callbacks.request_handler = ws_chat_request_handler; - init.callbacks.websocket_handler = ws_chat_websocket_handler; - init.callbacks.close_handler = ws_chat_close_handler; - - init.request_data_size = sizeof(ws_chat_request_data_t); - - ctx = nxt_unit_init(&init); - if (ctx == NULL) { - return 1; - } - - nxt_unit_run(ctx); - - nxt_unit_done(ctx); - - return 0; -} - - -static const char ws_chat_index_html[] = -"\n" -"\n" -" WebSocket Chat Examples\n" -" \n" -" \n" -"\n" -"\n" -"

Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable\n" -" Javascript and reload this page!

\n" -"
\n" -"

\n" -"
\n" -"
\n" -"
\n" -"
\n" -"\n" -"\n" -; - -static const int ws_chat_index_html_size = nxt_length(ws_chat_index_html); diff --git a/src/test/nxt_unit_websocket_echo.c b/src/test/nxt_unit_websocket_echo.c deleted file mode 100644 index eab2e45f..00000000 --- a/src/test/nxt_unit_websocket_echo.c +++ /dev/null @@ -1,105 +0,0 @@ - -/* - * Copyright (C) NGINX, Inc. - */ - -#include -#include - -#include -#include -#include -#include -#include - - -static void -ws_echo_request_handler(nxt_unit_request_info_t *req) -{ - int rc; - const char *target; - - rc = NXT_UNIT_OK; - target = nxt_unit_sptr_get(&req->request->target); - - if (strcmp(target, "/") == 0) { - if (!nxt_unit_request_is_websocket_handshake(req)) { - goto notfound; - } - - rc = nxt_unit_response_init(req, 101, 0, 0); - if (nxt_slow_path(rc != NXT_UNIT_OK)) { - goto fail; - } - - nxt_unit_response_upgrade(req); - nxt_unit_response_send(req); - - return; - } - -notfound: - - rc = nxt_unit_response_init(req, 404, 0, 0); - -fail: - - nxt_unit_request_done(req, rc); -} - - -static void -ws_echo_websocket_handler(nxt_unit_websocket_frame_t *ws) -{ - uint8_t opcode; - ssize_t size; - nxt_unit_request_info_t *req; - - static size_t buf_size = 0; - static uint8_t *buf = NULL; - - if (buf_size < ws->content_length) { - buf = realloc(buf, ws->content_length); - buf_size = ws->content_length; - } - - req = ws->req; - opcode = ws->header->opcode; - - if (opcode == NXT_WEBSOCKET_OP_PONG) { - nxt_unit_websocket_done(ws); - return; - } - - size = nxt_unit_websocket_read(ws, buf, ws->content_length); - - nxt_unit_websocket_send(req, opcode, ws->header->fin, buf, size); - nxt_unit_websocket_done(ws); - - if (opcode == NXT_WEBSOCKET_OP_CLOSE) { - nxt_unit_request_done(req, NXT_UNIT_OK); - } -} - - -int -main(void) -{ - nxt_unit_ctx_t *ctx; - nxt_unit_init_t init; - - memset(&init, 0, sizeof(nxt_unit_init_t)); - - init.callbacks.request_handler = ws_echo_request_handler; - init.callbacks.websocket_handler = ws_echo_websocket_handler; - - ctx = nxt_unit_init(&init); - if (ctx == NULL) { - return 1; - } - - nxt_unit_run(ctx); - nxt_unit_done(ctx); - - return 0; -} diff --git a/src/test/nxt_utf8_file_name_test.c b/src/test/nxt_utf8_file_name_test.c deleted file mode 100644 index 5723e19b..00000000 --- a/src/test/nxt_utf8_file_name_test.c +++ /dev/null @@ -1,148 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include - - -extern char **environ; - -static nxt_int_t nxt_utf8_file_name_test(nxt_thread_t *thr); - - -nxt_module_init_t nxt_init_modules[1]; -nxt_uint_t nxt_init_modules_n; - - -int nxt_cdecl -main(int argc, char **argv) -{ - nxt_thread_t *thr; - - if (nxt_lib_start("utf8_file_name_test", argv, &environ) != NXT_OK) { - return 1; - } - - nxt_main_log.level = NXT_LOG_INFO; - - thr = nxt_thread(); - - if (nxt_utf8_file_name_test(thr) != NXT_OK) { - return 1; - } - - return 0; -} - - -static nxt_int_t -nxt_utf8_file_name_test(nxt_thread_t *thr) -{ - u_char *p, test[4], buf[32]; - ssize_t n; - uint32_t uc, lc; - nxt_int_t ret; - nxt_task_t task; - nxt_file_t uc_file, lc_file; - const u_char *pp; - nxt_file_name_t uc_name[10], lc_name[10]; - static const u_char utf8[4] = "UTF8"; - - nxt_thread_time_update(thr); - - uc_name[0] = 'u'; - uc_name[1] = 't'; - uc_name[2] = 'f'; - uc_name[3] = '8'; - uc_name[4] = '_'; - - lc_name[0] = 'u'; - lc_name[1] = 't'; - lc_name[2] = 'f'; - lc_name[3] = '8'; - lc_name[4] = '_'; - - nxt_memzero(&uc_file, sizeof(nxt_file_t)); - - uc_file.name = uc_name; - uc_file.log_level = NXT_LOG_ALERT; - - nxt_memzero(&lc_file, sizeof(nxt_file_t)); - - lc_file.name = lc_name; - - task.thread = thr; - task.log = thr->log; - - for (uc = 0x41; uc < 0x110000; uc++) { - - p = nxt_utf8_encode(&uc_name[5], uc); - - if (p == NULL) { - nxt_log_alert(thr->log, "nxt_utf8_encode(%05uxD) failed", uc); - return NXT_ERROR; - } - - *p = '\0'; - - pp = &uc_name[5]; - lc = nxt_utf8_lowcase(&pp, p); - - if (lc == 0xFFFFFFFF) { - nxt_log_alert(thr->log, "nxt_utf8_lowcase(%05uxD) failed: %05uxD", - uc, lc); - return NXT_ERROR; - } - - if (uc == lc) { - continue; - } - - p = nxt_utf8_encode(&lc_name[5], lc); - - if (p == NULL) { - nxt_log_alert(thr->log, "nxt_utf8_encode(%05uxD) failed", lc); - return NXT_ERROR; - } - - *p = '\0'; - - ret = nxt_file_open(&task, &uc_file, NXT_FILE_WRONLY, NXT_FILE_TRUNCATE, - NXT_FILE_DEFAULT_ACCESS); - if (ret != NXT_OK) { - return NXT_ERROR; - } - - if (nxt_file_write(&uc_file, utf8, 4, 0) != 4) { - return NXT_ERROR; - } - - nxt_file_close(&task, &uc_file); - - ret = nxt_file_open(&task, &lc_file, NXT_FILE_RDONLY, NXT_FILE_OPEN, - NXT_FILE_DEFAULT_ACCESS); - - if (ret == NXT_OK) { - n = nxt_file_read(&lc_file, test, 4, 0); - - nxt_file_close(&task, &lc_file); - - if (n != 4 || memcmp(utf8, test, 4) != 0) { - nxt_log_alert(thr->log, "nxt_file_read() mismatch"); - - nxt_file_delete(lc_file.name); - } - - p = nxt_sprintf(buf, buf + 32, "%04uXD; C; %04uXD;%n", uc, lc); - - nxt_fd_write(nxt_stdout, buf, p - buf); - } - - nxt_file_delete(uc_file.name); - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "utf8 file name test passed"); - return NXT_OK; -} diff --git a/src/test/nxt_utf8_test.c b/src/test/nxt_utf8_test.c deleted file mode 100644 index 31e5bff9..00000000 --- a/src/test/nxt_utf8_test.c +++ /dev/null @@ -1,191 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include "nxt_tests.h" - - -#define NXT_UTF8_START_TEST 0xC2 -//#define NXT_UTF8_START_TEST 0 - - -static u_char invalid[] = { - - /* Invalid first byte less than 0xC2. */ - 1, 0x80, 0x00, 0x00, 0x00, - 1, 0xC0, 0x00, 0x00, 0x00, - 2, 0xC0, 0x00, 0x00, 0x00, - 3, 0xC0, 0x00, 0x00, 0x00, - 4, 0xC0, 0x00, 0x00, 0x00, - - /* Invalid 0x110000 value. */ - 4, 0xF4, 0x90, 0x80, 0x80, - - /* Incomplete length. */ - 2, 0xE0, 0xAF, 0xB5, 0x00, - - /* Overlong values. */ - 2, 0xC0, 0x80, 0x00, 0x00, - 2, 0xC1, 0xB3, 0x00, 0x00, - 3, 0xE0, 0x80, 0x80, 0x00, - 3, 0xE0, 0x81, 0xB3, 0x00, - 3, 0xE0, 0x90, 0x9A, 0x00, - 4, 0xF0, 0x80, 0x8A, 0x80, - 4, 0xF0, 0x80, 0x81, 0xB3, - 4, 0xF0, 0x80, 0xAF, 0xB5, -}; - - -static nxt_int_t -nxt_utf8_overlong(nxt_thread_t *thr, u_char *overlong, size_t len) -{ - u_char *p, utf8[4]; - size_t size; - uint32_t u, d; - nxt_uint_t i; - const u_char *pp; - - pp = overlong; - - d = nxt_utf8_decode(&pp, overlong + len); - - len = pp - overlong; - - if (d != 0xFFFFFFFF) { - p = nxt_utf8_encode(utf8, d); - - size = (p != NULL) ? p - utf8 : 0; - - if (len != size || memcmp(overlong, utf8, size) != 0) { - - u = 0; - for (i = 0; i < len; i++) { - u = (u << 8) + overlong[i]; - } - - nxt_log_alert(thr->log, - "nxt_utf8_decode(%05uxD, %uz) failed: %05uxD, %uz", - u, len, d, size); - - return NXT_ERROR; - } - } - - return NXT_OK; -} - - -nxt_int_t -nxt_utf8_test(nxt_thread_t *thr) -{ - u_char *p, utf8[4]; - size_t len; - int32_t n; - uint32_t u, d; - nxt_uint_t i, k, l, m; - const u_char *pp; - - nxt_thread_time_update(thr); - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "utf8 test started"); - - /* Test valid UTF-8. */ - - for (u = 0; u < 0x110000; u++) { - - p = nxt_utf8_encode(utf8, u); - - if (p == NULL) { - nxt_log_alert(thr->log, "nxt_utf8_encode(%05uxD) failed", u); - return NXT_ERROR; - } - - pp = utf8; - - d = nxt_utf8_decode(&pp, p); - - if (u != d) { - nxt_log_alert(thr->log, "nxt_utf8_decode(%05uxD) failed: %05uxD", - u, d); - return NXT_ERROR; - } - } - - /* Test some invalid UTF-8. */ - - for (i = 0; i < sizeof(invalid); i += 5) { - - len = invalid[i]; - utf8[0] = invalid[i + 1]; - utf8[1] = invalid[i + 2]; - utf8[2] = invalid[i + 3]; - utf8[3] = invalid[i + 4]; - - pp = utf8; - - d = nxt_utf8_decode(&pp, utf8 + len); - - if (d != 0xFFFFFFFF) { - - u = 0; - for (i = 0; i < len; i++) { - u = (u << 8) + utf8[i]; - } - - nxt_log_alert(thr->log, - "nxt_utf8_decode(%05uxD, %uz) failed: %05uxD", - u, len, d); - return NXT_ERROR; - } - } - - /* Test all overlong UTF-8. */ - - for (i = NXT_UTF8_START_TEST; i < 256; i++) { - utf8[0] = i; - - if (nxt_utf8_overlong(thr, utf8, 1) != NXT_OK) { - return NXT_ERROR; - } - - for (k = 0; k < 256; k++) { - utf8[1] = k; - - if (nxt_utf8_overlong(thr, utf8, 2) != NXT_OK) { - return NXT_ERROR; - } - - for (l = 0; l < 256; l++) { - utf8[2] = l; - - if (nxt_utf8_overlong(thr, utf8, 3) != NXT_OK) { - return NXT_ERROR; - } - - for (m = 0; m < 256; m++) { - utf8[3] = m; - - if (nxt_utf8_overlong(thr, utf8, 4) != NXT_OK) { - return NXT_ERROR; - } - } - } - } - } - - n = nxt_utf8_casecmp((u_char *) "ABC АБВ ΑΒΓ", - (u_char *) "abc абв αβγ", - nxt_length("ABC АБВ ΑΒΓ"), - nxt_length("abc абв αβγ")); - - if (n != 0) { - nxt_log_alert(thr->log, "nxt_utf8_casecmp() failed"); - return NXT_ERROR; - } - - nxt_log_error(NXT_LOG_NOTICE, thr->log, "utf8 test passed"); - return NXT_OK; -} diff --git a/src/unit.pc.in b/src/unit.pc.in deleted file mode 100644 index 4de0556f..00000000 --- a/src/unit.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@PREFIX@ -libdir=@LIBDIR@ -confargs=@CONFARGS@ -modulesdir=@MODULESDIR@ - -Name: unit -Description: library to embed Unit -Version: @VERSION@ -URL: https://unit.nginx.org -Cflags: @CFLAGS@ -Libs: -L${libdir} -lunit @EXTRA_LIBS@ diff --git a/src/wasm-wasi-component/.gitignore b/src/wasm-wasi-component/.gitignore deleted file mode 100644 index eb5a316c..00000000 --- a/src/wasm-wasi-component/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/src/wasm-wasi-component/Cargo.lock b/src/wasm-wasi-component/Cargo.lock deleted file mode 100644 index bc09e96a..00000000 --- a/src/wasm-wasi-component/Cargo.lock +++ /dev/null @@ -1,2293 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ahash" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "ambient-authority" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" - -[[package]] -name = "arbitrary" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" - -[[package]] -name = "async-trait" -version = "0.1.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bindgen" -version = "0.68.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" -dependencies = [ - "bitflags 2.4.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", - "which", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cap-fs-ext" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88e341d15ac1029aadce600be764a1a1edafe40e03cde23285bc1d261b3a4866" -dependencies = [ - "cap-primitives", - "cap-std", - "io-lifetimes", - "windows-sys 0.52.0", -] - -[[package]] -name = "cap-net-ext" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434168fe6533055f0f4204039abe3ff6d7db338ef46872a5fa39e9d5ad5ab7a9" -dependencies = [ - "cap-primitives", - "cap-std", - "rustix", - "smallvec", -] - -[[package]] -name = "cap-primitives" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe16767ed8eee6d3f1f00d6a7576b81c226ab917eb54b96e5f77a5216ef67abb" -dependencies = [ - "ambient-authority", - "fs-set-times", - "io-extras", - "io-lifetimes", - "ipnet", - "maybe-owned", - "rustix", - "windows-sys 0.52.0", - "winx", -] - -[[package]] -name = "cap-rand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20e5695565f0cd7106bc3c7170323597540e772bb73e0be2cd2c662a0f8fa4ca" -dependencies = [ - "ambient-authority", - "rand", -] - -[[package]] -name = "cap-std" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "593db20e4c51f62d3284bae7ee718849c3214f93a3b94ea1899ad85ba119d330" -dependencies = [ - "cap-primitives", - "io-extras", - "io-lifetimes", - "rustix", -] - -[[package]] -name = "cap-time-ext" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03261630f291f425430a36f38c847828265bc928f517cdd2004c56f4b02f002b" -dependencies = [ - "ambient-authority", - "cap-primitives", - "iana-time-zone", - "once_cell", - "rustix", - "winx", -] - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cranelift-bforest" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d819feeda4c420a18f1e28236ca0ce1177b22bf7c8a44ddee92dfe40de15bcf0" -dependencies = [ - "cranelift-entity", -] - -[[package]] -name = "cranelift-codegen" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9b8d03d5bdbca7e5f72b0e0a0f69933ed1f09e24be6c075aa6fe3f802b0cc0c" -dependencies = [ - "bumpalo", - "cranelift-bforest", - "cranelift-codegen-meta", - "cranelift-codegen-shared", - "cranelift-control", - "cranelift-entity", - "cranelift-isle", - "gimli", - "hashbrown 0.14.3", - "log", - "regalloc2", - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cranelift-codegen-meta" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3fd3664e38e51649b17dc30cfdd561273fe2f590dcd013fb75d9eabc6272dfb" -dependencies = [ - "cranelift-codegen-shared", -] - -[[package]] -name = "cranelift-codegen-shared" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b031ec5e605828975952622b5a77d49126f20ffe88d33719a0af66b23a0fc36" - -[[package]] -name = "cranelift-control" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fada054d017cf2ed8f7ed2336e0517fc1b19e6825be1790de9eb00c94788362b" -dependencies = [ - "arbitrary", -] - -[[package]] -name = "cranelift-entity" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177b6f94ae8de6348eb45bf977c79ab9e3c40fc3ac8cb7ed8109560ea39bee7d" -dependencies = [ - "serde", - "serde_derive", -] - -[[package]] -name = "cranelift-frontend" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebebd23a69a23e3ddea78e98ff3a2de222e88c8e045d81ef4a72f042e0d79dbd" -dependencies = [ - "cranelift-codegen", - "log", - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cranelift-isle" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1571bfc14df8966d12c6121b5325026591a4b4009e22fea0fe3765ab7cd33b96" - -[[package]] -name = "cranelift-native" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a69c37e0c10b46fe5527f2397ac821046efbf5f7ec112c8b84df25712f465b" -dependencies = [ - "cranelift-codegen", - "libc", - "target-lexicon", -] - -[[package]] -name = "cranelift-wasm" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3fef8bbceb8cb56d3f1778b0418d75c5cf12ec571a35fc01eb41abb0227a25" -dependencies = [ - "cranelift-codegen", - "cranelift-entity", - "cranelift-frontend", - "itertools", - "log", - "smallvec", - "wasmparser 0.118.1", - "wasmtime-types", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fd-lock" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" -dependencies = [ - "cfg-if", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs-set-times" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033b337d725b97690d86893f9de22b67b80dcc4e9ad815f348254c38119db8fb" -dependencies = [ - "io-lifetimes", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-core", - "futures-sink", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -dependencies = [ - "fallible-iterator", - "indexmap", - "stable_deref_trait", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "h2" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" -dependencies = [ - "ahash", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "http" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" -dependencies = [ - "bytes", - "futures-util", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "tokio", - "want", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" -dependencies = [ - "equivalent", - "hashbrown 0.14.3", - "serde", -] - -[[package]] -name = "io-extras" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c301e73fb90e8a29e600a9f402d095765f74310d582916a952f618836a1bd1ed" -dependencies = [ - "io-lifetimes", - "windows-sys 0.52.0", -] - -[[package]] -name = "io-lifetimes" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a611371471e98973dbcab4e0ec66c31a10bc356eeb4d54a0e05eac8158fe38c" - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "js-sys" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libloading" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "libredox" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" -dependencies = [ - "bitflags 2.4.2", - "libc", - "redox_syscall", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "mach" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" -dependencies = [ - "libc", -] - -[[package]] -name = "maybe-owned" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "memfd" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" -dependencies = [ - "rustix", -] - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "crc32fast", - "hashbrown 0.14.3", - "indexmap", - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "psm" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" -dependencies = [ - "cc", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_users" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[package]] -name = "regalloc2" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" -dependencies = [ - "hashbrown 0.13.2", - "log", - "rustc-hash", - "slice-group-by", - "smallvec", -] - -[[package]] -name = "regex" -version = "1.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "ring" -version = "0.17.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" -dependencies = [ - "cc", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" -dependencies = [ - "bitflags 2.4.2", - "errno", - "itoa", - "libc", - "linux-raw-sys", - "once_cell", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.21.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "semver" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" - -[[package]] -name = "serde" -version = "1.0.196" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.196" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "shellexpand" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" -dependencies = [ - "dirs", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "slice-group-by" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" - -[[package]] -name = "smallvec" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "sptr" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "syn" -version = "2.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "system-interface" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0682e006dd35771e392a6623ac180999a9a854b1d4a6c12fb2e804941c2b1f58" -dependencies = [ - "bitflags 2.4.2", - "cap-fs-ext", - "cap-std", - "fd-lock", - "io-lifetimes", - "rustix", - "windows-sys 0.52.0", - "winx", -] - -[[package]] -name = "target-lexicon" -version = "0.12.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae" - -[[package]] -name = "thiserror" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "pin-project-lite", - "socket2", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasi-cap-std-sync" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db014d2ced91f17d1f1a8f2b76d6ea8d731bc1dbc8c2bbaec689d6a242568e5d" -dependencies = [ - "anyhow", - "async-trait", - "cap-fs-ext", - "cap-rand", - "cap-std", - "cap-time-ext", - "fs-set-times", - "io-extras", - "io-lifetimes", - "once_cell", - "rustix", - "system-interface", - "tracing", - "wasi-common", - "windows-sys 0.52.0", -] - -[[package]] -name = "wasi-common" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449d17849e3c83a931374442fe2deee4d6bd1ebf469719ef44192e9e82e19c89" -dependencies = [ - "anyhow", - "bitflags 2.4.2", - "cap-rand", - "cap-std", - "io-extras", - "log", - "rustix", - "thiserror", - "tracing", - "wasmtime", - "wiggle", - "windows-sys 0.52.0", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" - -[[package]] -name = "wasm-encoder" -version = "0.38.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-wasi-component" -version = "0.1.0" -dependencies = [ - "anyhow", - "bindgen", - "bytes", - "cc", - "futures-util", - "http", - "http-body", - "http-body-util", - "tokio", - "wasmtime", - "wasmtime-wasi", - "wasmtime-wasi-http", -] - -[[package]] -name = "wasmparser" -version = "0.118.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9" -dependencies = [ - "indexmap", - "semver", -] - -[[package]] -name = "wasmparser" -version = "0.121.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953cf6a7606ab31382cb1caa5ae403e77ba70c7f8e12eeda167e7040d42bfda8" -dependencies = [ - "bitflags 2.4.2", - "indexmap", - "semver", -] - -[[package]] -name = "wasmprinter" -version = "0.2.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e32c13c59fdc64d3f6998a1d52eb1d362b6904a88b754190ccb85661ad577a" -dependencies = [ - "anyhow", - "wasmparser 0.121.0", -] - -[[package]] -name = "wasmtime" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "910fabce77e660f0e0e41cfd5f69fc8bf020a025f059718846e918db7177f469" -dependencies = [ - "anyhow", - "async-trait", - "bincode", - "bumpalo", - "cfg-if", - "encoding_rs", - "indexmap", - "libc", - "log", - "object", - "once_cell", - "paste", - "serde", - "serde_derive", - "serde_json", - "target-lexicon", - "wasmparser 0.118.1", - "wasmtime-component-macro", - "wasmtime-component-util", - "wasmtime-cranelift", - "wasmtime-environ", - "wasmtime-fiber", - "wasmtime-jit", - "wasmtime-runtime", - "wasmtime-winch", - "windows-sys 0.52.0", -] - -[[package]] -name = "wasmtime-asm-macros" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37288142e9b4a61655a3bcbdc7316c2e4bb9e776b10ce3dd758f8186b4469572" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "wasmtime-component-macro" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad63de18eb42e586386b6091f787c82707cbd5ac5e9343216dba1976190cd03a" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn", - "wasmtime-component-util", - "wasmtime-wit-bindgen", - "wit-parser", -] - -[[package]] -name = "wasmtime-component-util" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e0a160c0c44369aa4bee6d311a8e4366943bab1651040cc8b0fcec2c9eb8906" - -[[package]] -name = "wasmtime-cranelift" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3734cc01b7cd37bc62fdbcd9529ca9547440052d4b3886cfdec3b8081a5d3647" -dependencies = [ - "anyhow", - "cfg-if", - "cranelift-codegen", - "cranelift-control", - "cranelift-entity", - "cranelift-frontend", - "cranelift-native", - "cranelift-wasm", - "gimli", - "log", - "object", - "target-lexicon", - "thiserror", - "wasmparser 0.118.1", - "wasmtime-cranelift-shared", - "wasmtime-environ", - "wasmtime-versioned-export-macros", -] - -[[package]] -name = "wasmtime-cranelift-shared" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0eb33cd30c47844aa228d4d0030587e65c1108343f311fe9f7248b5bd9cb65c" -dependencies = [ - "anyhow", - "cranelift-codegen", - "cranelift-control", - "cranelift-native", - "gimli", - "object", - "target-lexicon", - "wasmtime-environ", -] - -[[package]] -name = "wasmtime-environ" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a056b041fdea604f0972e2fae97958e7748d629a55180228348baefdfc217" -dependencies = [ - "anyhow", - "cranelift-entity", - "gimli", - "indexmap", - "log", - "object", - "serde", - "serde_derive", - "target-lexicon", - "thiserror", - "wasm-encoder", - "wasmparser 0.118.1", - "wasmprinter", - "wasmtime-component-util", - "wasmtime-types", -] - -[[package]] -name = "wasmtime-fiber" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43987d0977c07f15c3608c2f255870c127ffd19e35eeedb1ac1dccedf9932a42" -dependencies = [ - "anyhow", - "cc", - "cfg-if", - "rustix", - "wasmtime-asm-macros", - "wasmtime-versioned-export-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "wasmtime-jit" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3e48395ac672b386ed588d97a9612aa13a345008f26466f0dfb2a91628aa9f" -dependencies = [ - "anyhow", - "bincode", - "cfg-if", - "gimli", - "log", - "object", - "rustix", - "serde", - "serde_derive", - "target-lexicon", - "wasmtime-environ", - "wasmtime-jit-icache-coherence", - "wasmtime-runtime", - "windows-sys 0.52.0", -] - -[[package]] -name = "wasmtime-jit-icache-coherence" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdc26415bb89e9ccd3bdc498fef63aabf665c4c0dd710c107691deb9694955da" -dependencies = [ - "cfg-if", - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "wasmtime-runtime" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0abddaf17912aabaf39be0802d5eba9a002e956e902d1ebd438a2fe1c88769a2" -dependencies = [ - "anyhow", - "cc", - "cfg-if", - "encoding_rs", - "indexmap", - "libc", - "log", - "mach", - "memfd", - "memoffset", - "paste", - "psm", - "rustix", - "sptr", - "wasm-encoder", - "wasmtime-asm-macros", - "wasmtime-environ", - "wasmtime-fiber", - "wasmtime-versioned-export-macros", - "wasmtime-wmemcheck", - "windows-sys 0.52.0", -] - -[[package]] -name = "wasmtime-types" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35a95cdc1433729085beab42c0a5c742b431f25b17c40d7718e46df63d5ffc7" -dependencies = [ - "cranelift-entity", - "serde", - "serde_derive", - "thiserror", - "wasmparser 0.118.1", -] - -[[package]] -name = "wasmtime-versioned-export-macros" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad322733fe67e45743784d8b1df452bcb54f581572a4f1a646a4332deecbcc2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "wasmtime-wasi" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "902cc299b73655c36679b77efdfce4bb5971992f1a4a8a436dd3809a6848ff0e" -dependencies = [ - "anyhow", - "async-trait", - "bitflags 2.4.2", - "bytes", - "cap-fs-ext", - "cap-net-ext", - "cap-rand", - "cap-std", - "cap-time-ext", - "fs-set-times", - "futures", - "io-extras", - "io-lifetimes", - "libc", - "log", - "once_cell", - "rustix", - "system-interface", - "thiserror", - "tokio", - "tracing", - "url", - "wasi-cap-std-sync", - "wasi-common", - "wasmtime", - "wiggle", - "windows-sys 0.52.0", -] - -[[package]] -name = "wasmtime-wasi-http" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "151fc711fad35034b8a6df00a5bcd5a7b1acb89ca12c2407f564a36ebd382e26" -dependencies = [ - "anyhow", - "async-trait", - "bytes", - "futures", - "http", - "http-body", - "http-body-util", - "hyper", - "rustls", - "tokio", - "tokio-rustls", - "tracing", - "wasmtime", - "wasmtime-wasi", - "webpki-roots", -] - -[[package]] -name = "wasmtime-winch" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e63aeca929f84560eec52c5af43bf5d623b92683b0195d9fb06da8ed860e092" -dependencies = [ - "anyhow", - "cranelift-codegen", - "gimli", - "object", - "target-lexicon", - "wasmparser 0.118.1", - "wasmtime-cranelift-shared", - "wasmtime-environ", - "winch-codegen", -] - -[[package]] -name = "wasmtime-wit-bindgen" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e5675998fdc74495afdd90ad2bd221206a258075b23048af0535a969b07893" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "wit-parser", -] - -[[package]] -name = "wasmtime-wmemcheck" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b20a19e10d8cb50b45412fb21192982b7ce85c0122dc33bb71f1813e25dc6e52" - -[[package]] -name = "wast" -version = "35.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" -dependencies = [ - "leb128", -] - -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "wiggle" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "737728db69a7657a5f6a7bac445c02d8564d603d62c46c95edf928554e67d072" -dependencies = [ - "anyhow", - "async-trait", - "bitflags 2.4.2", - "thiserror", - "tracing", - "wasmtime", - "wiggle-macro", -] - -[[package]] -name = "wiggle-generate" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2460c7163b79ffefd9a564eaeab0a5b0e84bb91afdfeeb84d36f304ddbe08982" -dependencies = [ - "anyhow", - "heck", - "proc-macro2", - "quote", - "shellexpand", - "syn", - "witx", -] - -[[package]] -name = "wiggle-macro" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8d8412375ba8325d61fbae56dead51dabfaec85d620ce36427922fb9cece83" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wiggle-generate", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "winch-codegen" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2b346bad5397b219b4ff0a8fa7230936061ff07c61f05d589d8d81e06fb7b2" -dependencies = [ - "anyhow", - "cranelift-codegen", - "gimli", - "regalloc2", - "smallvec", - "target-lexicon", - "wasmparser 0.118.1", - "wasmtime-environ", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winx" -version = "0.36.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9643b83820c0cd246ecabe5fa454dd04ba4fa67996369466d0747472d337346" -dependencies = [ - "bitflags 2.4.2", - "windows-sys 0.52.0", -] - -[[package]] -name = "wit-parser" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df4913a2219096373fd6512adead1fb77ecdaa59d7fc517972a7d30b12f625be" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", -] - -[[package]] -name = "witx" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" -dependencies = [ - "anyhow", - "log", - "thiserror", - "wast", -] - -[[package]] -name = "zerocopy" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/src/wasm-wasi-component/Cargo.toml b/src/wasm-wasi-component/Cargo.toml deleted file mode 100644 index feb7f53c..00000000 --- a/src/wasm-wasi-component/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "wasm-wasi-component" -version = "0.1.0" -edition = "2021" -publish = false - -[lib] -crate-type = ["cdylib"] - -[dependencies] -anyhow = "1.0.75" -bytes = "1.5.0" -futures-util = { version = "0.3.29", default-features = false } -http = "1.0.0" -http-body = { version = "1.0.0", default-features = false } -http-body-util = "0.1.0" -tokio = { version = "1.33.0", default-features = false } -wasmtime = { version = "17.0.0", default-features = false, features = ['component-model', 'cranelift'] } -wasmtime-wasi = "17.0.0" -wasmtime-wasi-http = "17.0.0" - -[build-dependencies] -bindgen = "0.68.1" -cc = "1.0.83" - -[profile.dev] -panic = 'abort' - -[profile.release] -panic = 'abort' diff --git a/src/wasm-wasi-component/build.rs b/src/wasm-wasi-component/build.rs deleted file mode 100644 index 5ea74f17..00000000 --- a/src/wasm-wasi-component/build.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::env; -use std::path::PathBuf; - -fn main() { - // Tell cargo to invalidate the built crate whenever the wrapper changes - println!("cargo:rerun-if-changed=wrapper.h"); - - let bindings = bindgen::Builder::default() - .clang_args(["-I", "../"]) - .clang_args(["-I", "../../build/include"]) - .header("./wrapper.h") - // only generate bindings for `nxt_*` header files - .allowlist_file(".*nxt_.*.h") - // generates an "improper_ctypes" warning and we don't need it anyway - .blocklist_function("nxt_vsprintf") - // Tell cargo to invalidate the built crate whenever any of the - // included header files changed. - .parse_callbacks(Box::new(bindgen::CargoCallbacks)) - // disable some features which aren't necessary - .layout_tests(false) - .derive_debug(false) - .generate() - .expect("Unable to generate bindings"); - - cc::Build::new() - .object("../../build/src/nxt_unit.o") - .compile("nxt-unit"); - - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - bindings - .write_to_file(out_path.join("bindings.rs")) - .expect("Couldn't write bindings!"); -} diff --git a/src/wasm-wasi-component/src/lib.rs b/src/wasm-wasi-component/src/lib.rs deleted file mode 100644 index b0552e81..00000000 --- a/src/wasm-wasi-component/src/lib.rs +++ /dev/null @@ -1,620 +0,0 @@ -use anyhow::{bail, Context, Result}; -use bytes::{Bytes, BytesMut}; -use http_body_util::combinators::BoxBody; -use http_body_util::{BodyExt, Full}; -use std::ffi::{CStr, CString}; -use std::mem::MaybeUninit; -use std::process::exit; -use std::ptr; -use std::sync::OnceLock; -use tokio::sync::mpsc; -use wasmtime::component::{Component, InstancePre, Linker, ResourceTable}; -use wasmtime::{Config, Engine, Store}; -use wasmtime_wasi::preview2::{ - DirPerms, FilePerms, WasiCtx, WasiCtxBuilder, WasiView, -}; -use wasmtime_wasi::{ambient_authority, Dir}; -use wasmtime_wasi_http::bindings::http::types::ErrorCode; -use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpView}; - -#[allow( - non_camel_case_types, - non_upper_case_globals, - non_snake_case, - dead_code -)] -mod bindings { - include!(concat!(env!("OUT_DIR"), "/bindings.rs")); - - pub const fn nxt_string(s: &'static str) -> nxt_str_t { - nxt_str_t { - start: s.as_ptr().cast_mut(), - length: s.len(), - } - } - - pub unsafe fn nxt_unit_sptr_get(sptr: &nxt_unit_sptr_t) -> *const u8 { - sptr.base.as_ptr().offset(sptr.offset as isize) - } -} - -#[no_mangle] -pub static mut nxt_app_module: bindings::nxt_app_module_t = { - const COMPAT: [u32; 2] = [bindings::NXT_VERNUM, bindings::NXT_DEBUG]; - let version = "0.1\0"; - bindings::nxt_app_module_t { - compat: COMPAT.as_ptr().cast_mut(), - compat_length: COMPAT.len() * 4, - mounts: ptr::null(), - nmounts: 0, - type_: bindings::nxt_string("wasm-wasi-component"), - version: version.as_ptr().cast(), - setup: Some(setup), - start: Some(start), - } -}; - -static GLOBAL_CONFIG: OnceLock = OnceLock::new(); -static GLOBAL_STATE: OnceLock = OnceLock::new(); - -unsafe extern "C" fn setup( - task: *mut bindings::nxt_task_t, - // TODO: should this get used? - _process: *mut bindings::nxt_process_t, - conf: *mut bindings::nxt_common_app_conf_t, -) -> bindings::nxt_int_t { - handle_result(task, || { - let wasm_conf = &(*conf).u.wasm_wc; - let component = CStr::from_ptr(wasm_conf.component).to_str()?; - let mut dirs = Vec::new(); - if !wasm_conf.access.is_null() { - let dirs_ptr = bindings::nxt_conf_get_object_member( - wasm_conf.access, - &mut bindings::nxt_string("filesystem"), - ptr::null_mut(), - ); - for i in 0..bindings::nxt_conf_object_members_count(dirs_ptr) { - let value = bindings::nxt_conf_get_array_element( - dirs_ptr, - i.try_into().unwrap(), - ); - let mut s = bindings::nxt_string(""); - bindings::nxt_conf_get_string(value, &mut s); - dirs.push( - std::str::from_utf8(std::slice::from_raw_parts( - s.start, s.length, - ))? - .to_string(), - ); - } - } - - let result = GLOBAL_CONFIG.set(GlobalConfig { - component: component.to_string(), - dirs, - }); - assert!(result.is_ok()); - Ok(()) - }) -} - -unsafe extern "C" fn start( - task: *mut bindings::nxt_task_t, - data: *mut bindings::nxt_process_data_t, -) -> bindings::nxt_int_t { - let mut rc: i32 = 0; - - let result = handle_result(task, || { - let config = GLOBAL_CONFIG.get().unwrap(); - let state = GlobalState::new(&config) - .context("failed to create initial state")?; - let res = GLOBAL_STATE.set(state); - assert!(res.is_ok()); - - let conf = (*data).app; - let mut wasm_init = MaybeUninit::uninit(); - let ret = - bindings::nxt_unit_default_init(task, wasm_init.as_mut_ptr(), conf); - if ret != bindings::NXT_OK as bindings::nxt_int_t { - bail!("nxt_unit_default_init() failed"); - } - let mut wasm_init = wasm_init.assume_init(); - wasm_init.callbacks.request_handler = Some(request_handler); - - let unit_ctx = bindings::nxt_unit_init(&mut wasm_init); - if unit_ctx.is_null() { - bail!("nxt_unit_init() failed"); - } - - rc = bindings::nxt_unit_run(unit_ctx); - bindings::nxt_unit_done(unit_ctx); - - Ok(()) - }); - - if result != bindings::NXT_OK as bindings::nxt_int_t { - return result; - } - - exit(rc); -} - -unsafe fn handle_result( - task: *mut bindings::nxt_task_t, - func: impl FnOnce() -> Result<()>, -) -> bindings::nxt_int_t { - let rc = match func() { - Ok(()) => bindings::NXT_OK as bindings::nxt_int_t, - Err(e) => { - alert(task, &format!("{e:?}")); - bindings::NXT_ERROR as bindings::nxt_int_t - } - }; - return rc; - - unsafe fn alert(task: *mut bindings::nxt_task_t, msg: &str) { - let log = (*task).log; - let msg = CString::new(msg).unwrap(); - ((*log).handler).unwrap()( - bindings::NXT_LOG_ALERT as bindings::nxt_uint_t, - log, - "%s\0".as_ptr().cast(), - msg.as_ptr(), - ); - } -} - -unsafe extern "C" fn request_handler( - info: *mut bindings::nxt_unit_request_info_t, -) { - // Enqueue this request to get processed by the Tokio event loop, and - // otherwise immediately return. - let state = GLOBAL_STATE.get().unwrap(); - state.sender.blocking_send(NxtRequestInfo { info }).unwrap(); -} - -struct GlobalConfig { - component: String, - dirs: Vec, -} - -struct GlobalState { - engine: Engine, - component: InstancePre, - global_config: &'static GlobalConfig, - sender: mpsc::Sender, -} - -impl GlobalState { - fn new(global_config: &'static GlobalConfig) -> Result { - // Configure Wasmtime, e.g. the component model and async support are - // enabled here. Other configuration can include: - // - // * Epochs/fuel - enables async yielding to prevent any one request - // starving others. - // * Pooling allocator - accelerates instantiation at the cost of a - // large virtual memory reservation. - // * Memory limits/etc. - let mut config = Config::new(); - config.wasm_component_model(true); - config.async_support(true); - let engine = Engine::new(&config)?; - - // Compile the binary component on disk in Wasmtime. This is then - // pre-instantiated with host APIs defined by WASI. The result of - // this is a "pre-instantiated instance" which can be used to - // repeatedly instantiate later on. This will frontload - // compilation/linking/type-checking/etc to happen once rather than on - // each request. - let component = Component::from_file(&engine, &global_config.component) - .context("failed to compile component")?; - let mut linker = Linker::::new(&engine); - wasmtime_wasi::preview2::command::add_to_linker(&mut linker)?; - wasmtime_wasi_http::proxy::add_only_http_to_linker(&mut linker)?; - let component = linker - .instantiate_pre(&component) - .context("failed to pre-instantiate the provided component")?; - - // Spin up the Tokio async runtime in a separate thread with a - // communication channel into it. This thread will send requests to - // Tokio and the results will be calculated there. - let (sender, receiver) = mpsc::channel(10); - std::thread::spawn(|| GlobalState::run(receiver)); - - Ok(GlobalState { - engine, - component, - sender, - global_config, - }) - } - - /// Worker thread that executes the Tokio runtime, infinitely receiving - /// messages from the provided `receiver` and handling those requests. - /// - /// Each request is handled in a separate subtask so processing can all - /// happen concurrently. - fn run(mut receiver: mpsc::Receiver) { - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - while let Some(msg) = receiver.recv().await { - let state = GLOBAL_STATE.get().unwrap(); - tokio::task::spawn(async move { - state.handle(msg).await.expect("failed to handle request") - }); - } - }); - } - - async fn handle(&'static self, mut info: NxtRequestInfo) -> Result<()> { - // Create a "Store" which is the unit of per-request isolation in - // Wasmtime. - let data = StoreState { - ctx: { - let mut cx = WasiCtxBuilder::new(); - // NB: while useful for debugging untrusted code probably - // shouldn't get raw access to stdout/stderr. - cx.inherit_stdout(); - cx.inherit_stderr(); - for dir in self.global_config.dirs.iter() { - let fd = Dir::open_ambient_dir(dir, ambient_authority()) - .with_context(|| { - format!("failed to open directory '{dir}'") - })?; - cx.preopened_dir( - fd, - DirPerms::all(), - FilePerms::all(), - dir, - ); - } - cx.build() - }, - table: ResourceTable::default(), - http: WasiHttpCtx, - }; - let mut store = Store::new(&self.engine, data); - - // Convert the `nxt_*` representation into the representation required - // by Wasmtime's `wasi-http` implementation using the Rust `http` - // crate. - let request = self.to_request_builder(&info)?; - let body = self.to_request_body(&mut info); - let request = request.body(body)?; - - let (sender, receiver) = tokio::sync::oneshot::channel(); - - // Instantiate the WebAssembly component and invoke its `handle` - // function which receives a request and where to put a response. - // - // Note that this is done in a sub-task to work concurrently with - // writing the response when it's available. This enables wasm to - // generate headers, write those below, and then compute the body - // afterwards. - let task = tokio::spawn(async move { - let (proxy, _) = wasmtime_wasi_http::proxy::Proxy::instantiate_pre( - &mut store, - &self.component, - ) - .await - .context("failed to instantiate")?; - let req = store.data_mut().new_incoming_request(request)?; - let out = store.data_mut().new_response_outparam(sender)?; - proxy - .wasi_http_incoming_handler() - .call_handle(&mut store, req, out) - .await - .context("failed to invoke wasm `handle`")?; - Ok::<_, anyhow::Error>(()) - }); - - // Wait for the wasm to produce the initial response. If this succeeds - // then propagate that failure. If this fails then wait for the above - // task to complete to see if it failed, otherwise panic since that's - // unexpected. - let response = match receiver.await { - Ok(response) => response.context("response generation failed")?, - Err(_) => { - task.await.unwrap()?; - panic!("sender of response disappeared"); - } - }; - - // Send the headers/status which will extract the body for the next - // phase. - let body = self.send_response(&mut info, response); - - // Send the body, a blocking operation, over time as it becomes - // available. - self.send_response_body(&mut info, body) - .await - .context("failed to write response body")?; - - // Join on completion of the wasm task which should be done by this - // point. - task.await.unwrap()?; - - // And finally signal that we're done. - info.request_done(); - - Ok(()) - } - - fn to_request_builder( - &self, - info: &NxtRequestInfo, - ) -> Result { - let mut request = http::Request::builder(); - - request = request.method(info.method()); - request = match info.version() { - "HTTP/0.9" => request.version(http::Version::HTTP_09), - "HTTP/1.0" => request.version(http::Version::HTTP_10), - "HTTP/1.1" => request.version(http::Version::HTTP_11), - "HTTP/2.0" => request.version(http::Version::HTTP_2), - "HTTP/3.0" => request.version(http::Version::HTTP_3), - version => { - println!("unknown version: {version}"); - request - } - }; - - let uri = http::Uri::builder() - .scheme(if info.tls() { "https" } else { "http" }) - .authority(info.server_name()) - .path_and_query(info.target()) - .build() - .context("failed to build URI")?; - request = request.uri(uri); - - for (name, value) in info.fields() { - request = request.header(name, value); - } - Ok(request) - } - - fn to_request_body( - &self, - info: &mut NxtRequestInfo, - ) -> BoxBody { - // TODO: should convert the body into a form of `Stream` to become an - // async stream of frames. The return value can represent that here - // but for now this slurps up the entire body into memory and puts it - // all in a single `BytesMut` which is then converted to `Bytes`. - let mut body = - BytesMut::with_capacity(info.content_length().try_into().unwrap()); - - // TODO: can this perform a partial read? - // TODO: how to make this async at the nxt level? - info.request_read(&mut body); - - Full::new(body.freeze()).map_err(|e| match e {}).boxed() - } - - fn send_response( - &self, - info: &mut NxtRequestInfo, - response: http::Response, - ) -> T { - info.init_response( - response.status().as_u16(), - response.headers().len().try_into().unwrap(), - response - .headers() - .iter() - .map(|(k, v)| k.as_str().len() + v.len()) - .sum::() - .try_into() - .unwrap(), - ); - for (k, v) in response.headers() { - info.add_field(k.as_str().as_bytes(), v.as_bytes()); - } - info.send_response(); - - response.into_body() - } - - async fn send_response_body( - &self, - info: &mut NxtRequestInfo, - mut body: BoxBody, - ) -> Result<()> { - loop { - // Acquire the next frame, and because nothing is actually async - // at the moment this should never block meaning that the - // `Pending` case should not happen. - let frame = match body.frame().await { - Some(Ok(frame)) => frame, - Some(Err(e)) => break Err(e.into()), - None => break Ok(()), - }; - match frame.data_ref() { - Some(data) => { - info.response_write(&data); - } - None => { - // TODO: what to do with trailers? - } - } - } - } -} - -struct NxtRequestInfo { - info: *mut bindings::nxt_unit_request_info_t, -} - -// TODO: is this actually safe? -unsafe impl Send for NxtRequestInfo {} -unsafe impl Sync for NxtRequestInfo {} - -impl NxtRequestInfo { - fn method(&self) -> &str { - unsafe { - let raw = (*self.info).request; - self.get_str(&(*raw).method, (*raw).method_length.into()) - } - } - - fn tls(&self) -> bool { - unsafe { (*(*self.info).request).tls != 0 } - } - - fn version(&self) -> &str { - unsafe { - let raw = (*self.info).request; - self.get_str(&(*raw).version, (*raw).version_length.into()) - } - } - - fn server_name(&self) -> &str { - unsafe { - let raw = (*self.info).request; - self.get_str(&(*raw).server_name, (*raw).server_name_length.into()) - } - } - - fn target(&self) -> &str { - unsafe { - let raw = (*self.info).request; - self.get_str(&(*raw).target, (*raw).target_length.into()) - } - } - - fn content_length(&self) -> u64 { - unsafe { - let raw_request = (*self.info).request; - (*raw_request).content_length - } - } - - fn fields(&self) -> impl Iterator { - unsafe { - let raw = (*self.info).request; - (0..(*raw).fields_count).map(move |i| { - let field = (*raw).fields.as_ptr().add(i as usize); - let name = - self.get_str(&(*field).name, (*field).name_length.into()); - let value = - self.get_str(&(*field).value, (*field).value_length.into()); - (name, value) - }) - } - } - - fn request_read(&mut self, dst: &mut BytesMut) { - unsafe { - let rest = dst.spare_capacity_mut(); - let mut total_bytes_read = 0; - loop { - let amt = bindings::nxt_unit_request_read( - self.info, - rest.as_mut_ptr().wrapping_add(total_bytes_read).cast(), - 32 * 1024 * 1024, - ); - total_bytes_read += amt as usize; - if total_bytes_read >= rest.len() { - break; - } - } - // TODO: handle failure when `amt` is negative - let total_bytes_read: usize = total_bytes_read.try_into().unwrap(); - dst.set_len(dst.len() + total_bytes_read); - } - } - - fn response_write(&mut self, data: &[u8]) { - unsafe { - let rc = bindings::nxt_unit_response_write( - self.info, - data.as_ptr().cast(), - data.len(), - ); - assert_eq!(rc, 0); - } - } - - fn init_response(&mut self, status: u16, headers: u32, headers_size: u32) { - unsafe { - let rc = bindings::nxt_unit_response_init( - self.info, - status, - headers, - headers_size, - ); - assert_eq!(rc, 0); - } - } - - fn add_field(&mut self, key: &[u8], val: &[u8]) { - unsafe { - let rc = bindings::nxt_unit_response_add_field( - self.info, - key.as_ptr().cast(), - key.len().try_into().unwrap(), - val.as_ptr().cast(), - val.len().try_into().unwrap(), - ); - assert_eq!(rc, 0); - } - } - - fn send_response(&mut self) { - unsafe { - let rc = bindings::nxt_unit_response_send(self.info); - assert_eq!(rc, 0); - } - } - - fn request_done(self) { - unsafe { - bindings::nxt_unit_request_done( - self.info, - bindings::NXT_UNIT_OK as i32, - ); - } - } - - unsafe fn get_str( - &self, - ptr: &bindings::nxt_unit_sptr_t, - len: u32, - ) -> &str { - let ptr = bindings::nxt_unit_sptr_get(ptr); - let slice = std::slice::from_raw_parts(ptr, len.try_into().unwrap()); - std::str::from_utf8(slice).unwrap() - } -} - -struct StoreState { - ctx: WasiCtx, - http: WasiHttpCtx, - table: ResourceTable, -} - -impl WasiView for StoreState { - fn table(&self) -> &ResourceTable { - &self.table - } - fn table_mut(&mut self) -> &mut ResourceTable { - &mut self.table - } - fn ctx(&self) -> &WasiCtx { - &self.ctx - } - fn ctx_mut(&mut self) -> &mut WasiCtx { - &mut self.ctx - } -} - -impl WasiHttpView for StoreState { - fn ctx(&mut self) -> &mut WasiHttpCtx { - &mut self.http - } - fn table(&mut self) -> &mut ResourceTable { - &mut self.table - } -} - -impl StoreState {} diff --git a/src/wasm-wasi-component/wrapper.h b/src/wasm-wasi-component/wrapper.h deleted file mode 100644 index 93f3014a..00000000 --- a/src/wasm-wasi-component/wrapper.h +++ /dev/null @@ -1,5 +0,0 @@ -#include -#include -#include -#include -#include diff --git a/src/wasm/nxt_rt_wasmtime.c b/src/wasm/nxt_rt_wasmtime.c deleted file mode 100644 index bf0b0a0f..00000000 --- a/src/wasm/nxt_rt_wasmtime.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright (C) Andrew Clayton - * Copyright (C) F5, Inc. - */ - -#include -#include -#include - -#include -#include -#include - -#include "nxt_wasm.h" - - -typedef struct nxt_wasmtime_ctx_s nxt_wasmtime_ctx_t; - -struct nxt_wasmtime_ctx_s { - wasm_engine_t *engine; - wasmtime_store_t *store; - wasmtime_memory_t memory; - wasmtime_module_t *module; - wasmtime_linker_t *linker; - wasmtime_context_t *ctx; -}; - -static nxt_wasmtime_ctx_t nxt_wasmtime_ctx; - - -static void -nxt_wasmtime_err_msg(wasmtime_error_t *error, wasm_trap_t *trap, - const char *fmt, ...) -{ - va_list args; - wasm_byte_vec_t error_message; - - fprintf(stderr, "WASMTIME ERROR: "); - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, "\n"); - - if (error == NULL && trap == NULL) { - return; - } - - if (error != NULL) { - wasmtime_error_message(error, &error_message); - wasmtime_error_delete(error); - } else { - wasm_trap_message(trap, &error_message); - wasm_trap_delete(trap); - } - fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data); - - wasm_byte_vec_delete(&error_message); -} - - -static wasm_trap_t * -nxt_wasm_get_init_mem_size(void *env, wasmtime_caller_t *caller, - const wasmtime_val_t *args, size_t nargs, - wasmtime_val_t *results, size_t nresults) -{ - results[0].of.i32 = NXT_WASM_MEM_SIZE; - - return NULL; -} - - -static wasm_trap_t * -nxt_wasm_response_end(void *env, wasmtime_caller_t *caller, - const wasmtime_val_t *args, size_t nargs, - wasmtime_val_t *results, size_t nresults) -{ - nxt_wasm_do_response_end(env); - - return NULL; -} - - -static wasm_trap_t * -nxt_wasm_send_response(void *env, wasmtime_caller_t *caller, - const wasmtime_val_t *args, size_t nargs, - wasmtime_val_t *results, size_t nresults) -{ - nxt_wasm_do_send_response(env, args[0].of.i32); - - return NULL; -} - - -static wasm_trap_t * -nxt_wasm_send_headers(void *env, wasmtime_caller_t *caller, - const wasmtime_val_t *args, size_t nargs, - wasmtime_val_t *results, size_t nresults) -{ - nxt_wasm_do_send_headers(env, args[0].of.i32); - - return NULL; -} - - -static wasm_trap_t * -nxt_wasm_set_resp_status(void *env, wasmtime_caller_t *caller, - const wasmtime_val_t *args, size_t nargs, - wasmtime_val_t *results, size_t nresults) -{ - nxt_wasm_ctx_t *ctx = env; - - ctx->status = args[0].of.i32; - - return NULL; -} - - -static void -nxt_wasmtime_execute_hook(const nxt_wasm_ctx_t *ctx, nxt_wasm_fh_t hook) -{ - const char *name = ctx->fh[hook].func_name; - wasm_trap_t *trap = NULL; - wasmtime_error_t *error; - nxt_wasmtime_ctx_t *rt_ctx = &nxt_wasmtime_ctx; - const nxt_wasm_func_t *func = &ctx->fh[hook].func; - - if (name == NULL) { - return; - } - - error = wasmtime_func_call(rt_ctx->ctx, func, NULL, 0, NULL, 0, &trap); - if (error != NULL || trap != NULL) { - nxt_wasmtime_err_msg(error, trap, "failed to call hook function [%s]", - name); - } -} - - -static int -nxt_wasmtime_execute_request(const nxt_wasm_ctx_t *ctx) -{ - int i = 0; - wasm_trap_t *trap = NULL; - wasmtime_val_t args[1] = { }; - wasmtime_val_t results[1] = { }; - wasmtime_error_t *error; - nxt_wasmtime_ctx_t *rt_ctx = &nxt_wasmtime_ctx; - const nxt_wasm_func_t *func = &ctx->fh[NXT_WASM_FH_REQUEST].func; - - args[i].kind = WASMTIME_I32; - args[i++].of.i32 = ctx->baddr_off; - - error = wasmtime_func_call(rt_ctx->ctx, func, args, i, results, 1, &trap); - if (error != NULL || trap != NULL) { - nxt_wasmtime_err_msg(error, trap, - "failed to call function [->wasm_request_handler]" - ); - return -1; - } - - return results[0].of.i32; -} - - -static void -nxt_wasmtime_set_function_imports(nxt_wasm_ctx_t *ctx) -{ - nxt_wasmtime_ctx_t *rt_ctx = &nxt_wasmtime_ctx; - - static const struct { - const char *func_name; - - wasmtime_func_callback_t func; - wasm_valkind_t params[1]; - wasm_valkind_t results[1]; - - enum { - NXT_WASM_FT_0_0, - NXT_WASM_FT_1_0, - NXT_WASM_FT_0_1, - } ft; - } import_functions[] = { - { - .func_name = "nxt_wasm_get_init_mem_size", - .func = nxt_wasm_get_init_mem_size, - .results = { WASM_I32 }, - .ft = NXT_WASM_FT_0_1 - }, { - .func_name = "nxt_wasm_response_end", - .func = nxt_wasm_response_end, - .ft = NXT_WASM_FT_0_0 - }, { - .func_name = "nxt_wasm_send_response", - .func = nxt_wasm_send_response, - .params = { WASM_I32 }, - .ft = NXT_WASM_FT_1_0 - }, { - .func_name = "nxt_wasm_send_headers", - .func = nxt_wasm_send_headers, - .params = { WASM_I32 }, - .ft = NXT_WASM_FT_1_0 - }, { - .func_name = "nxt_wasm_set_resp_status", - .func = nxt_wasm_set_resp_status, - .params = { WASM_I32 }, - .ft = NXT_WASM_FT_1_0 - }, - - { } - }, *imf; - - for (imf = import_functions; imf->func_name != NULL; imf++) { - wasm_functype_t *func_ty; - - switch (imf->ft) { - case NXT_WASM_FT_0_0: - func_ty = wasm_functype_new_0_0(); - break; - case NXT_WASM_FT_1_0: - func_ty = wasm_functype_new_1_0(wasm_valtype_new(imf->params[0])); - break; - case NXT_WASM_FT_0_1: - func_ty = wasm_functype_new_0_1(wasm_valtype_new(imf->results[0])); - break; - default: - /* Stop GCC complaining about func_ty being used uninitialised */ - func_ty = NULL; - } - - wasmtime_linker_define_func(rt_ctx->linker, "env", 3, - imf->func_name, strlen(imf->func_name), - func_ty, imf->func, ctx, NULL); - wasm_functype_delete(func_ty); - } -} - - -static int -nxt_wasmtime_get_function_exports(nxt_wasm_ctx_t *ctx) -{ - int i; - nxt_wasmtime_ctx_t *rt_ctx = &nxt_wasmtime_ctx; - - for (i = 0; i < NXT_WASM_FH_NR; i++) { - bool ok; - wasmtime_extern_t item; - - if (ctx->fh[i].func_name == NULL) { - continue; - } - - ok = wasmtime_linker_get(rt_ctx->linker, rt_ctx->ctx, "", 0, - ctx->fh[i].func_name, - strlen(ctx->fh[i].func_name), &item); - if (!ok) { - nxt_wasmtime_err_msg(NULL, NULL, - "couldn't get (%s) export from module", - ctx->fh[i].func_name); - return -1; - } - ctx->fh[i].func = item.of.func; - } - - return 0; -} - - -static int -nxt_wasmtime_wasi_init(const nxt_wasm_ctx_t *ctx) -{ - char **dir; - wasi_config_t *wasi_config; - wasmtime_error_t *error; - nxt_wasmtime_ctx_t *rt_ctx = &nxt_wasmtime_ctx; - - wasi_config = wasi_config_new(); - - wasi_config_inherit_env(wasi_config); - wasi_config_inherit_stdin(wasi_config); - wasi_config_inherit_stdout(wasi_config); - wasi_config_inherit_stderr(wasi_config); - - for (dir = ctx->dirs; dir != NULL && *dir != NULL; dir++) { - wasi_config_preopen_dir(wasi_config, *dir, *dir); - } - - error = wasmtime_context_set_wasi(rt_ctx->ctx, wasi_config); - if (error != NULL) { - nxt_wasmtime_err_msg(error, NULL, "failed to instantiate WASI"); - return -1; - } - - return 0; -} - - -static int -nxt_wasmtime_init_memory(nxt_wasm_ctx_t *ctx) -{ - int i = 0; - bool ok; - wasm_trap_t *trap = NULL; - wasmtime_val_t args[1] = { }; - wasmtime_val_t results[1] = { }; - wasmtime_error_t *error; - wasmtime_extern_t item; - nxt_wasmtime_ctx_t *rt_ctx = &nxt_wasmtime_ctx; - const nxt_wasm_func_t *func = &ctx->fh[NXT_WASM_FH_MALLOC].func; - - args[i].kind = WASMTIME_I32; - args[i++].of.i32 = NXT_WASM_MEM_SIZE + NXT_WASM_PAGE_SIZE; - - error = wasmtime_func_call(rt_ctx->ctx, func, args, i, results, 1, &trap); - if (error != NULL || trap != NULL) { - nxt_wasmtime_err_msg(error, trap, - "failed to call function [->wasm_malloc_handler]" - ); - return -1; - } - - ok = wasmtime_linker_get(rt_ctx->linker, rt_ctx->ctx, "", 0, "memory", - strlen("memory"), &item); - if (!ok) { - nxt_wasmtime_err_msg(NULL, NULL, "couldn't get 'memory' from module\n"); - return -1; - } - rt_ctx->memory = item.of.memory; - - ctx->baddr_off = results[0].of.i32; - ctx->baddr = wasmtime_memory_data(rt_ctx->ctx, &rt_ctx->memory); - - ctx->baddr += ctx->baddr_off; - - return 0; -} - - -static int -nxt_wasmtime_init(nxt_wasm_ctx_t *ctx) -{ - int err; - FILE *fp; - size_t file_size; - wasm_byte_vec_t wasm; - wasmtime_error_t *error; - nxt_wasmtime_ctx_t *rt_ctx = &nxt_wasmtime_ctx; - - rt_ctx->engine = wasm_engine_new(); - rt_ctx->store = wasmtime_store_new(rt_ctx->engine, NULL, NULL); - rt_ctx->ctx = wasmtime_store_context(rt_ctx->store); - - rt_ctx->linker = wasmtime_linker_new(rt_ctx->engine); - error = wasmtime_linker_define_wasi(rt_ctx->linker); - if (error != NULL) { - nxt_wasmtime_err_msg(error, NULL, "failed to link wasi"); - return -1; - } - - fp = fopen(ctx->module_path, "r"); - if (!fp) { - nxt_wasmtime_err_msg(NULL, NULL, - "error opening file (%s)", ctx->module_path); - return -1; - } - fseek(fp, 0L, SEEK_END); - file_size = ftell(fp); - wasm_byte_vec_new_uninitialized(&wasm, file_size); - fseek(fp, 0L, SEEK_SET); - if (fread(wasm.data, file_size, 1, fp) != 1) { - nxt_wasmtime_err_msg(NULL, NULL, "error loading module"); - fclose(fp); - return -1; - } - fclose(fp); - - error = wasmtime_module_new(rt_ctx->engine, (uint8_t *)wasm.data, wasm.size, - &rt_ctx->module); - if (!rt_ctx->module) { - nxt_wasmtime_err_msg(error, NULL, "failed to compile module"); - return -1; - } - wasm_byte_vec_delete(&wasm); - - nxt_wasmtime_set_function_imports(ctx); - - nxt_wasmtime_wasi_init(ctx); - - error = wasmtime_linker_module(rt_ctx->linker, rt_ctx->ctx, "", 0, - rt_ctx->module); - if (error != NULL) { - nxt_wasmtime_err_msg(error, NULL, "failed to instantiate"); - return -1; - } - - err = nxt_wasmtime_get_function_exports(ctx); - if (err) { - return -1; - } - - err = nxt_wasmtime_init_memory(ctx); - if (err) { - return -1; - } - - return 0; -} - - -static void -nxt_wasmtime_destroy(const nxt_wasm_ctx_t *ctx) -{ - int i = 0; - wasmtime_val_t args[1] = { }; - nxt_wasmtime_ctx_t *rt_ctx = &nxt_wasmtime_ctx; - const nxt_wasm_func_t *func = &ctx->fh[NXT_WASM_FH_FREE].func; - - args[i].kind = WASMTIME_I32; - args[i++].of.i32 = ctx->baddr_off; - - wasmtime_func_call(rt_ctx->ctx, func, args, i, NULL, 0, NULL); - - wasmtime_module_delete(rt_ctx->module); - wasmtime_store_delete(rt_ctx->store); - wasm_engine_delete(rt_ctx->engine); -} - - -const nxt_wasm_operations_t nxt_wasm_ops = { - .init = nxt_wasmtime_init, - .destroy = nxt_wasmtime_destroy, - .exec_request = nxt_wasmtime_execute_request, - .exec_hook = nxt_wasmtime_execute_hook, -}; diff --git a/src/wasm/nxt_wasm.c b/src/wasm/nxt_wasm.c deleted file mode 100644 index 92ed57ab..00000000 --- a/src/wasm/nxt_wasm.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) Andrew Clayton - * Copyright (C) F5, Inc. - */ - -#include -#include -#include -#include - -#include "nxt_wasm.h" - - -#define NXT_WASM_VERSION "0.1" - -#define NXT_WASM_DO_HOOK(hook) nxt_wops->exec_hook(&nxt_wasm_ctx, hook); - - -static uint32_t compat[] = { - NXT_VERNUM, NXT_DEBUG, -}; - -static nxt_wasm_ctx_t nxt_wasm_ctx; - -static const nxt_wasm_operations_t *nxt_wops; - -enum { - NXT_WASM_HTTP_OK = 200, - NXT_WASM_HTTP_ERROR = 500 -}; - - -void -nxt_wasm_do_response_end(nxt_wasm_ctx_t *ctx) -{ - nxt_unit_request_done(ctx->req, NXT_UNIT_OK); - - NXT_WASM_DO_HOOK(NXT_WASM_FH_RESPONSE_END); -} - - -void -nxt_wasm_do_send_headers(nxt_wasm_ctx_t *ctx, uint32_t offset) -{ - size_t fields_len; - unsigned int i; - nxt_wasm_response_fields_t *rh; - - rh = (nxt_wasm_response_fields_t *)(ctx->baddr + offset); - - fields_len = 0; - for (i = 0; i < rh->nfields; i++) { - fields_len += rh->fields[i].name_len + rh->fields[i].value_len; - } - - nxt_unit_response_init(ctx->req, ctx->status, rh->nfields, fields_len); - - for (i = 0; i < rh->nfields; i++) { - const char *name; - const char *val; - - name = (const char *)rh + rh->fields[i].name_off; - val = (const char *)rh + rh->fields[i].value_off; - - nxt_unit_response_add_field(ctx->req, name, rh->fields[i].name_len, - val, rh->fields[i].value_len); - } - - nxt_unit_response_send(ctx->req); -} - - -void -nxt_wasm_do_send_response(nxt_wasm_ctx_t *ctx, uint32_t offset) -{ - nxt_wasm_response_t *resp; - nxt_unit_request_info_t *req = ctx->req; - - if (!nxt_unit_response_is_init(req)) { - nxt_unit_response_init(req, ctx->status, 0, 0); - } - - resp = (nxt_wasm_response_t *)(nxt_wasm_ctx.baddr + offset); - - nxt_unit_response_write(req, (const char *)resp->data, resp->size); -} - - -static void -nxt_wasm_request_handler(nxt_unit_request_info_t *req) -{ - int err; - size_t offset, read_bytes, content_sent, content_len; - ssize_t bytes_read; - nxt_unit_field_t *sf, *sf_end; - nxt_unit_request_t *r; - nxt_wasm_request_t *wr; - nxt_wasm_http_field_t *df; - - NXT_WASM_DO_HOOK(NXT_WASM_FH_REQUEST_INIT); - - wr = (nxt_wasm_request_t *)nxt_wasm_ctx.baddr; - -#define SET_REQ_MEMBER(dmember, smember) \ - do { \ - const char *str = nxt_unit_sptr_get(&r->smember); \ - wr->dmember##_off = offset; \ - wr->dmember##_len = strlen(str); \ - memcpy((uint8_t *)wr + offset, str, wr->dmember##_len + 1); \ - offset += wr->dmember##_len + 1; \ - } while (0) - - r = req->request; - offset = sizeof(nxt_wasm_request_t) - + (r->fields_count * sizeof(nxt_wasm_http_field_t)); - - SET_REQ_MEMBER(path, path); - SET_REQ_MEMBER(method, method); - SET_REQ_MEMBER(version, version); - SET_REQ_MEMBER(query, query); - SET_REQ_MEMBER(remote, remote); - SET_REQ_MEMBER(local_addr, local_addr); - SET_REQ_MEMBER(local_port, local_port); - SET_REQ_MEMBER(server_name, server_name); -#undef SET_REQ_MEMBER - - df = wr->fields; - sf_end = r->fields + r->fields_count; - for (sf = r->fields; sf < sf_end; sf++) { - const char *name = nxt_unit_sptr_get(&sf->name); - const char *value = nxt_unit_sptr_get(&sf->value); - - df->name_off = offset; - df->name_len = strlen(name); - memcpy((uint8_t *)wr + offset, name, df->name_len + 1); - offset += df->name_len + 1; - - df->value_off = offset; - df->value_len = strlen(value); - memcpy((uint8_t *)wr + offset, value, df->value_len + 1); - offset += df->value_len + 1; - - df++; - } - - wr->tls = r->tls; - wr->nfields = r->fields_count; - wr->content_off = offset; - wr->content_len = content_len = r->content_length; - - read_bytes = nxt_min(wr->content_len, NXT_WASM_MEM_SIZE - offset); - - bytes_read = nxt_unit_request_read(req, (uint8_t *)wr + offset, read_bytes); - wr->content_sent = wr->total_content_sent = content_sent = bytes_read; - - wr->request_size = offset + bytes_read; - - nxt_wasm_ctx.status = NXT_WASM_HTTP_OK; - nxt_wasm_ctx.req = req; - err = nxt_wops->exec_request(&nxt_wasm_ctx); - if (err) { - goto out_err_500; - } - - if (content_len == content_sent) { - goto request_done; - } - - offset = sizeof(nxt_wasm_request_t); - do { - read_bytes = nxt_min(content_len - content_sent, - NXT_WASM_MEM_SIZE - offset); - bytes_read = nxt_unit_request_read(req, (uint8_t *)wr + offset, - read_bytes); - - content_sent += bytes_read; - wr->request_size = wr->content_sent = bytes_read; - wr->total_content_sent = content_sent; - wr->content_off = offset; - - err = nxt_wops->exec_request(&nxt_wasm_ctx); - if (err) { - goto out_err_500; - } - } while (content_sent < content_len); - - goto request_done; - -out_err_500: - nxt_unit_response_init(req, NXT_WASM_HTTP_ERROR, 0, 0); - nxt_unit_request_done(req, NXT_UNIT_OK); - -request_done: - NXT_WASM_DO_HOOK(NXT_WASM_FH_REQUEST_END); -} - - -static nxt_int_t -nxt_wasm_start(nxt_task_t *task, nxt_process_data_t *data) -{ - nxt_int_t ret; - nxt_unit_ctx_t *unit_ctx; - nxt_unit_init_t wasm_init; - nxt_common_app_conf_t *conf; - - conf = data->app; - - ret = nxt_unit_default_init(task, &wasm_init, conf); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_alert(task, "nxt_unit_default_init() failed"); - return ret; - } - - wasm_init.callbacks.request_handler = nxt_wasm_request_handler; - - unit_ctx = nxt_unit_init(&wasm_init); - if (nxt_slow_path(unit_ctx == NULL)) { - return NXT_ERROR; - } - - NXT_WASM_DO_HOOK(NXT_WASM_FH_MODULE_INIT); - nxt_unit_run(unit_ctx); - nxt_unit_done(unit_ctx); - NXT_WASM_DO_HOOK(NXT_WASM_FH_MODULE_END); - - if (nxt_wasm_ctx.dirs != NULL) { - char **p; - - for (p = nxt_wasm_ctx.dirs; *p != NULL; p++) { - nxt_free(*p); - } - nxt_free(nxt_wasm_ctx.dirs); - } - - nxt_wops->destroy(&nxt_wasm_ctx); - - exit(EXIT_SUCCESS); -} - - -static nxt_int_t -nxt_wasm_setup(nxt_task_t *task, nxt_process_t *process, - nxt_common_app_conf_t *conf) -{ - int n, i, err; - nxt_conf_value_t *dirs = NULL; - nxt_wasm_app_conf_t *c; - nxt_wasm_func_handler_t *fh; - static nxt_str_t filesystem_str = nxt_string("filesystem"); - - c = &conf->u.wasm; - - nxt_wops = &nxt_wasm_ops; - - nxt_wasm_ctx.module_path = c->module; - - fh = nxt_wasm_ctx.fh; - - fh[NXT_WASM_FH_REQUEST].func_name = c->request_handler; - fh[NXT_WASM_FH_MALLOC].func_name = c->malloc_handler; - fh[NXT_WASM_FH_FREE].func_name = c->free_handler; - - /* Optional function handlers (hooks) */ - fh[NXT_WASM_FH_MODULE_INIT].func_name = c->module_init_handler; - fh[NXT_WASM_FH_MODULE_END].func_name = c->module_end_handler; - fh[NXT_WASM_FH_REQUEST_INIT].func_name = c->request_init_handler; - fh[NXT_WASM_FH_REQUEST_END].func_name = c->request_end_handler; - fh[NXT_WASM_FH_RESPONSE_END].func_name = c->response_end_handler; - - /* Get any directories to pass through to the WASM module */ - if (c->access != NULL) { - dirs = nxt_conf_get_object_member(c->access, &filesystem_str, NULL); - } - - n = (dirs != NULL) ? nxt_conf_object_members_count(dirs) : 0; - if (n == 0) { - goto out_init; - } - - nxt_wasm_ctx.dirs = nxt_zalloc((n + 1) * sizeof(char *)); - if (nxt_slow_path(nxt_wasm_ctx.dirs == NULL)) { - return NXT_ERROR; - } - - for (i = 0; i < n; i++) { - nxt_str_t str; - nxt_conf_value_t *value; - - value = nxt_conf_get_array_element(dirs, i); - nxt_conf_get_string(value, &str); - - nxt_wasm_ctx.dirs[i] = nxt_zalloc(str.length + 1); - memcpy(nxt_wasm_ctx.dirs[i], str.start, str.length); - } - -out_init: - err = nxt_wops->init(&nxt_wasm_ctx); - if (err) { - exit(EXIT_FAILURE); - } - - return NXT_OK; -} - - -NXT_EXPORT nxt_app_module_t nxt_app_module = { - .compat_length = sizeof(compat), - .compat = compat, - .type = nxt_string("wasm"), - .version = NXT_WASM_VERSION, - .mounts = NULL, - .nmounts = 0, - .setup = nxt_wasm_setup, - .start = nxt_wasm_start, -}; diff --git a/src/wasm/nxt_wasm.h b/src/wasm/nxt_wasm.h deleted file mode 100644 index 6bc3ae35..00000000 --- a/src/wasm/nxt_wasm.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) Andrew Clayton - * Copyright (C) F5, Inc. - */ - -#ifndef _NXT_WASM_H_INCLUDED_ -#define _NXT_WASM_H_INCLUDED_ - -#include -#include - -#include - -#include -#if defined(NXT_HAVE_WASM_WASMTIME) -#include -#endif - - -#define NXT_WASM_PAGE_SIZE (64 * 1024) -#define NXT_WASM_MEM_SIZE (32UL * 1024 * 1024) - -#if defined(NXT_HAVE_WASM_WASMTIME) -typedef wasmtime_func_t nxt_wasm_func_t; -#endif - - -typedef struct nxt_wasm_http_field_s nxt_wasm_http_field_t; -typedef struct nxt_wasm_request_s nxt_wasm_request_t; -typedef struct nxt_wasm_response_s nxt_wasm_response_t; -typedef struct nxt_wasm_response_fields_s nxt_wasm_response_fields_t; -typedef enum nxt_wasm_fh_e nxt_wasm_fh_t; -typedef struct nxt_wasm_func_handler_s nxt_wasm_func_handler_t; -typedef struct nxt_wasm_ctx_s nxt_wasm_ctx_t; -typedef struct nxt_wasm_operations_s nxt_wasm_operations_t; - -struct nxt_wasm_http_field_s { - uint32_t name_off; - uint32_t name_len; - uint32_t value_off; - uint32_t value_len; -}; - -struct nxt_wasm_request_s { - uint32_t method_off; - uint32_t method_len; - uint32_t version_off; - uint32_t version_len; - uint32_t path_off; - uint32_t path_len; - uint32_t query_off; - uint32_t query_len; - uint32_t remote_off; - uint32_t remote_len; - uint32_t local_addr_off; - uint32_t local_addr_len; - uint32_t local_port_off; - uint32_t local_port_len; - uint32_t server_name_off; - uint32_t server_name_len; - - uint64_t content_len; - uint64_t total_content_sent; - uint32_t content_sent; - uint32_t content_off; - - uint32_t request_size; - - uint32_t nfields; - - uint32_t tls; - - char __pad[4]; - - nxt_wasm_http_field_t fields[]; -}; - -struct nxt_wasm_response_s { - uint32_t size; - - uint8_t data[]; -}; - -struct nxt_wasm_response_fields_s { - uint32_t nfields; - - nxt_wasm_http_field_t fields[]; -}; - -enum nxt_wasm_fh_e { - NXT_WASM_FH_REQUEST = 0, - NXT_WASM_FH_MALLOC, - NXT_WASM_FH_FREE, - - /* Optional handlers */ - NXT_WASM_FH_MODULE_INIT, - NXT_WASM_FH_MODULE_END, - NXT_WASM_FH_REQUEST_INIT, - NXT_WASM_FH_REQUEST_END, - NXT_WASM_FH_RESPONSE_END, - - NXT_WASM_FH_NR -}; - -struct nxt_wasm_func_handler_s { - const char *func_name; - nxt_wasm_func_t func; -}; - -struct nxt_wasm_ctx_s { - const char *module_path; - - nxt_wasm_func_handler_t fh[NXT_WASM_FH_NR]; - - char **dirs; - - nxt_unit_request_info_t *req; - - uint8_t *baddr; - size_t baddr_off; - - size_t response_off; - - uint16_t status; -}; - -struct nxt_wasm_operations_s { - int (*init)(nxt_wasm_ctx_t *ctx); - void (*destroy)(const nxt_wasm_ctx_t *ctx); - int (*exec_request)(const nxt_wasm_ctx_t *ctx); - void (*exec_hook)(const nxt_wasm_ctx_t *ctx, nxt_wasm_fh_t hook); -}; - -extern const nxt_wasm_operations_t nxt_wasm_ops; - - -/* Exported to the WASM module */ -extern void nxt_wasm_do_response_end(nxt_wasm_ctx_t *ctx); -extern void nxt_wasm_do_send_response(nxt_wasm_ctx_t *ctx, uint32_t offset); -extern void nxt_wasm_do_send_headers(nxt_wasm_ctx_t *ctx, uint32_t offset); - -#endif /* _NXT_WASM_H_INCLUDED_ */ diff --git a/test/conftest.py b/test/conftest.py deleted file mode 100644 index 2fe4d8dc..00000000 --- a/test/conftest.py +++ /dev/null @@ -1,709 +0,0 @@ -import fcntl -import inspect -import json -import os -import re -import shutil -import signal -import stat -import subprocess -import sys -import tempfile -import time -from multiprocessing import Process -from pathlib import Path - -import pytest - -from unit.check.check_prerequisites import check_prerequisites -from unit.check.discover_available import discover_available -from unit.http import HTTP1 -from unit.log import Log -from unit.log import print_log_on_assert -from unit.option import option -from unit.status import Status -from unit.utils import check_findmnt -from unit.utils import public_dir -from unit.utils import waitforfiles -from unit.utils import waitforunmount - - -def pytest_addoption(parser): - parser.addoption( - "--detailed", - default=False, - action="store_true", - help="Detailed output for tests", - ) - parser.addoption( - "--print-log", - default=False, - action="store_true", - help="Print unit.log to stdout in case of errors", - ) - parser.addoption( - "--save-log", - default=False, - action="store_true", - help="Save unit.log after the test execution", - ) - parser.addoption( - "--unsafe", - default=False, - action="store_true", - help="Run unsafe tests", - ) - parser.addoption( - "--user", - type=str, - help="Default user for non-privileged processes of unitd", - ) - parser.addoption( - "--fds-threshold", - type=int, - default=0, - help="File descriptors threshold", - ) - parser.addoption( - "--restart", - default=False, - action="store_true", - help="Force Unit to restart after every test", - ) - - -unit_instance = {} -_processes = [] -_fds_info = { - 'main': {'fds': 0, 'skip': False}, - 'router': {'name': 'unit: router', 'pid': -1, 'fds': 0, 'skip': False}, - 'controller': { - 'name': 'unit: controller', - 'pid': -1, - 'fds': 0, - 'skip': False, - }, -} -http = HTTP1() -is_findmnt = check_findmnt() - - -def pytest_configure(config): - option.config = config.option - - option.detailed = config.option.detailed - option.fds_threshold = config.option.fds_threshold - option.print_log = config.option.print_log - option.save_log = config.option.save_log - option.unsafe = config.option.unsafe - option.user = config.option.user - option.restart = config.option.restart - - option.generated_tests = {} - option.current_dir = os.path.abspath( - os.path.join(os.path.dirname(__file__), os.pardir) - ) - option.test_dir = f'{option.current_dir}/test' - - option.cache_dir = tempfile.mkdtemp(prefix='unit-test-cache-') - public_dir(option.cache_dir) - - # set stdout to non-blocking - - if option.detailed or option.print_log: - fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, 0) - - -def pytest_generate_tests(metafunc): - module = metafunc.module - if ( - not hasattr(module, 'client') - or not hasattr(module.client, 'application_type') - or module.client.application_type is None - or module.client.application_type == 'external' - ): - return - - app_type = module.client.application_type - - def generate_tests(versions): - if not versions: - pytest.skip('no available module versions') - - metafunc.fixturenames.append('tmp_ct') - metafunc.parametrize('tmp_ct', versions) - - for version in versions: - option.generated_tests[ - f'{metafunc.function.__name__} [{version}]' - ] = f'{app_type} {version}' - - # take available module from option and generate tests for each version - - available_modules = option.available['modules'] - - for module, version in metafunc.module.prerequisites['modules'].items(): - if module in available_modules and available_modules[module]: - available_versions = available_modules[module] - - if version == 'all': - generate_tests(available_versions) - - elif version == 'any': - option.generated_tests[ - metafunc.function.__name__ - ] = f'{app_type} {available_versions[0]}' - elif callable(version): - generate_tests(list(filter(version, available_versions))) - - else: - raise ValueError( - f''' -Unexpected prerequisite version "{version}" for module "{module}". -'all', 'any' or callable expected.''' - ) - - -def pytest_sessionstart(): - unit = unit_run() - - discover_available(unit) - - _clear_conf() - - unit_stop() - - Log.check_alerts() - - if option.restart: - shutil.rmtree(unit['temp_dir']) - else: - _clear_temp_dir() - - -@pytest.hookimpl(tryfirst=True, hookwrapper=True) -def pytest_runtest_makereport(item): - # execute all other hooks to obtain the report object - outcome = yield - rep = outcome.get_result() - - # set a report attribute for each phase of a call, which can - # be "setup", "call", "teardown" - - setattr(item, f'rep_{rep.when}', rep) - - -@pytest.fixture(scope='module', autouse=True) -def check_prerequisites_module(request): - if hasattr(request.module, 'prerequisites'): - check_prerequisites(request.module.prerequisites) - - -@pytest.fixture(autouse=True) -def run(request): - unit = unit_run() - - option.skip_alerts = [ - r'read signalfd\(4\) failed', - r'sendmsg.+failed', - r'recvmsg.+failed', - ] - option.skip_sanitizer = False - - _fds_info['main']['skip'] = False - _fds_info['router']['skip'] = False - _fds_info['controller']['skip'] = False - - yield - - # stop unit - - error_stop_unit = unit_stop() - error_stop_processes = stop_processes() - - # prepare log - - with Log.open() as f: - log = f.read() - Log.set_pos(f.tell()) - - if not option.save_log and option.restart: - shutil.rmtree(unit['temp_dir']) - Log.set_pos(0) - - # clean temp_dir before the next test - - if not option.restart: - _clear_conf(log=log) - _clear_temp_dir() - - # check descriptors - - _check_fds(log=log) - - # check processes id's and amount - - _check_processes() - - # print unit.log in case of error - - if hasattr(request.node, 'rep_call') and request.node.rep_call.failed: - Log.print_log(log) - - if error_stop_unit or error_stop_processes: - Log.print_log(log) - - # check unit.log for errors - - assert error_stop_unit is None, 'stop unit' - assert error_stop_processes is None, 'stop processes' - - Log.check_alerts(log=log) - - -def unit_run(state_dir=None): - global unit_instance - - if not option.restart and 'unitd' in unit_instance: - return unit_instance - - builddir = f'{option.current_dir}/build' - libdir = f'{builddir}/lib' - modulesdir = f'{libdir}/unit/modules' - sbindir = f'{builddir}/sbin' - unitd = f'{sbindir}/unitd' - - if not Path(unitd).is_file(): - sys.exit('Could not find unit') - - temporary_dir = tempfile.mkdtemp(prefix='unit-test-') - option.temp_dir = temporary_dir - public_dir(temporary_dir) - - if oct(stat.S_IMODE(Path(builddir).stat().st_mode)) != '0o777': - public_dir(builddir) - - statedir = f'{temporary_dir}/state' if state_dir is None else state_dir - Path(statedir).mkdir(exist_ok=True) - - control_sock = f'{temporary_dir}/control.unit.sock' - - unitd_args = [ - unitd, - '--no-daemon', - '--modulesdir', - modulesdir, - '--statedir', - statedir, - '--pid', - f'{temporary_dir}/unit.pid', - '--log', - f'{temporary_dir}/unit.log', - '--control', - f'unix:{temporary_dir}/control.unit.sock', - '--tmpdir', - temporary_dir, - ] - - if option.user: - unitd_args.extend(['--user', option.user]) - - with open(f'{temporary_dir}/unit.log', 'w', encoding='utf-8') as log: - unit_instance['process'] = subprocess.Popen(unitd_args, stderr=log) - - if not waitforfiles(control_sock): - Log.print_log() - sys.exit('Could not start unit') - - unit_instance['temp_dir'] = temporary_dir - unit_instance['control_sock'] = control_sock - unit_instance['unitd'] = unitd - - unit_instance['pid'] = ( - Path(f'{temporary_dir}/unit.pid').read_text(encoding='utf-8').rstrip() - ) - - if state_dir is None: - _clear_conf() - - _fds_info['main']['fds'] = _count_fds(unit_instance['pid']) - - router = _fds_info['router'] - router['pid'] = pid_by_name(router['name']) - router['fds'] = _count_fds(router['pid']) - - controller = _fds_info['controller'] - controller['pid'] = pid_by_name(controller['name']) - controller['fds'] = _count_fds(controller['pid']) - - Status._check_zeros() - - return unit_instance - - -def unit_stop(): - if not option.restart: - if inspect.stack()[1].function.startswith('test_'): - pytest.skip('no restart mode') - - return - - # check zombies - - out = subprocess.check_output( - ['ps', 'ax', '-o', 'state', '-o', 'ppid'] - ).decode() - z_ppids = re.findall(r'Z\s*(\d+)', out) - assert unit_instance['pid'] not in z_ppids, 'no zombies' - - # terminate unit - - p = unit_instance['process'] - - if p.poll() is not None: - return - - p.send_signal(signal.SIGQUIT) - - try: - retcode = p.wait(15) - if retcode: - return f'Child process terminated with code {retcode}' - - except KeyboardInterrupt: - p.kill() - raise - - except: - p.kill() - return 'Could not terminate unit' - - -@print_log_on_assert -def _clear_conf(*, log=None): - sock = unit_instance['control_sock'] - - resp = http.put( - url='/config', - sock_type='unix', - addr=sock, - body=json.dumps({"listeners": {}, "applications": {}}), - )['body'] - - assert 'success' in resp, 'clear conf' - - def get(url): - return http.get(url=url, sock_type='unix', addr=sock)['body'] - - def delete(url): - return http.delete(url=url, sock_type='unix', addr=sock)['body'] - - if ( - 'openssl' in option.available['modules'] - and option.available['modules']['openssl'] - ): - try: - certs = json.loads(get('/certificates')).keys() - - except json.JSONDecodeError: - pytest.fail("Can't parse certificates list.") - - for cert in certs: - assert 'success' in delete(f'/certificates/{cert}'), 'delete cert' - - if ( - 'njs' in option.available['modules'] - and option.available['modules']['njs'] - ): - try: - scripts = json.loads(get('/js_modules')).keys() - - except json.JSONDecodeError: - pytest.fail("Can't parse njs modules list.") - - for script in scripts: - assert 'success' in delete(f'/js_modules/{script}'), 'delete script' - - -def _clear_temp_dir(): - temporary_dir = unit_instance['temp_dir'] - - if is_findmnt and not waitforunmount(temporary_dir, timeout=600): - sys.exit('Could not unmount filesystems in tmpdir ({temporary_dir}).') - - for item in Path(temporary_dir).iterdir(): - if item.name not in [ - 'control.unit.sock', - 'state', - 'unit.pid', - 'unit.log', - ]: - - public_dir(item) - - if item.is_file() or stat.S_ISSOCK(item.stat().st_mode): - item.unlink() - else: - for _ in range(10): - try: - shutil.rmtree(item) - break - except OSError as err: - # OSError: [Errno 16] Device or resource busy - # OSError: [Errno 39] Directory not empty - if err.errno not in [16, 39]: - raise - time.sleep(1) - - -def _check_processes(): - router_pid = _fds_info['router']['pid'] - controller_pid = _fds_info['controller']['pid'] - main_pid = unit_instance['pid'] - - for _ in range(600): - out = ( - subprocess.check_output( - ['ps', '-ax', '-o', 'pid', '-o', 'ppid', '-o', 'command'] - ) - .decode() - .splitlines() - ) - out = [l for l in out if main_pid in l] - - if len(out) <= 3: - break - - time.sleep(0.1) - - if option.restart: - assert len(out) == 0, 'all termimated' - return - - assert len(out) == 3, 'main, router, and controller expected' - - out = [l for l in out if 'unit: main' not in l] - assert len(out) == 2, 'one main' - - out = [ - l - for l in out - if re.search(fr'{router_pid}\s+{main_pid}.*unit: router', l) is None - ] - assert len(out) == 1, 'one router' - - out = [ - l - for l in out - if re.search(fr'{controller_pid}\s+{main_pid}.*unit: controller', l) - is None - ] - assert len(out) == 0, 'one controller' - - -@print_log_on_assert -def _check_fds(*, log=None): - def waitforfds(diff): - for _ in range(600): - fds_diff = diff() - - if fds_diff <= option.fds_threshold: - break - - time.sleep(0.1) - - return fds_diff - - ps = _fds_info['main'] - if not ps['skip']: - fds_diff = waitforfds( - lambda: _count_fds(unit_instance['pid']) - ps['fds'] - ) - ps['fds'] += fds_diff - - assert fds_diff <= option.fds_threshold, 'descriptors leak main process' - - else: - ps['fds'] = _count_fds(unit_instance['pid']) - - for name in ['controller', 'router']: - ps = _fds_info[name] - ps_pid = ps['pid'] - ps['pid'] = pid_by_name(ps['name']) - - if not ps['skip']: - fds_diff = waitforfds(lambda: _count_fds(ps['pid']) - ps['fds']) - ps['fds'] += fds_diff - - if not option.restart: - assert ps['pid'] == ps_pid, f'same pid {name}' - - assert fds_diff <= option.fds_threshold, f'descriptors leak {name}' - - else: - ps['fds'] = _count_fds(ps['pid']) - - -def _count_fds(pid): - procfile = Path(f'/proc/{pid}/fd') - if procfile.is_dir(): - return len(list(procfile.iterdir())) - - try: - out = subprocess.check_output( - ['procstat', '-f', pid], - stderr=subprocess.STDOUT, - ).decode() - return len(out.splitlines()) - - except (FileNotFoundError, TypeError, subprocess.CalledProcessError): - pass - - try: - out = subprocess.check_output( - ['lsof', '-n', '-p', pid], - stderr=subprocess.STDOUT, - ).decode() - return len(out.splitlines()) - - except (FileNotFoundError, TypeError, subprocess.CalledProcessError): - pass - - return 0 - - -def run_process(target, *args): - global _processes - - process = Process(target=target, args=args) - process.start() - - _processes.append(process) - - -def stop_processes(): - if not _processes: - return - - fail = False - for process in _processes: - if process.is_alive(): - process.terminate() - process.join(timeout=15) - - if process.is_alive(): - fail = True - - if fail: - return 'Fail to stop process(es)' - - -def pid_by_name(name): - output = subprocess.check_output(['ps', 'ax', '-O', 'ppid']).decode() - m = re.search(fr'\s*(\d+)\s*{unit_instance["pid"]}.*{name}', output) - return None if m is None else m.group(1) - - -def find_proc(name, ps_output): - return re.findall(f'{unit_instance["pid"]}.*{name}', ps_output) - - -def pytest_sessionfinish(): - if not option.restart and option.save_log: - Log.print_path() - - option.restart = True - - unit_stop() - - public_dir(option.cache_dir) - shutil.rmtree(option.cache_dir) - - if not option.save_log and Path(option.temp_dir).is_dir(): - public_dir(option.temp_dir) - shutil.rmtree(option.temp_dir) - - -@pytest.fixture -def date_to_sec_epoch(): - def _date_to_sec_epoch(date, template='%a, %d %b %Y %X %Z'): - return time.mktime(time.strptime(date, template)) - - return _date_to_sec_epoch - - -@pytest.fixture -def findall(): - def _findall(*args, **kwargs): - return Log.findall(*args, **kwargs) - - return _findall - - -@pytest.fixture -def is_su(): - return option.is_privileged - - -@pytest.fixture -def is_unsafe(request): - return request.config.getoption("--unsafe") - - -@pytest.fixture -def require(): - return check_prerequisites - - -@pytest.fixture -def search_in_file(): - def _search_in_file(pattern, name='unit.log', flags=re.M): - return re.search(pattern, Log.read(name), flags) - - return _search_in_file - - -@pytest.fixture -def sec_epoch(): - return time.mktime(time.gmtime()) - - -@pytest.fixture() -def skip_alert(): - def _skip(*alerts): - option.skip_alerts.extend(alerts) - - return _skip - - -@pytest.fixture() -def skip_fds_check(): - def _skip(main=False, router=False, controller=False): - _fds_info['main']['skip'] = main - _fds_info['router']['skip'] = router - _fds_info['controller']['skip'] = controller - - return _skip - - -@pytest.fixture() -def system(): - return option.system - - -@pytest.fixture -def temp_dir(): - return unit_instance['temp_dir'] - - -@pytest.fixture -def unit_pid(): - return unit_instance['process'].pid - - -@pytest.fixture -def wait_for_record(): - def _wait_for_record(*args, **kwargs): - return Log.wait_for_record(*args, **kwargs) - - return _wait_for_record diff --git a/test/go/404/404.html b/test/go/404/404.html deleted file mode 100644 index 6d0c635a..00000000 --- a/test/go/404/404.html +++ /dev/null @@ -1,6 +0,0 @@ - -404 Not Found - -

404 Not Found

- - diff --git a/test/go/404/app.go b/test/go/404/app.go deleted file mode 100644 index 255f5dac..00000000 --- a/test/go/404/app.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "io" - "io/ioutil" - "net/http" - "unit.nginx.org/go" -) - -func handler(w http.ResponseWriter, r *http.Request) { - b, e := ioutil.ReadFile("404.html") - - if e == nil { - w.WriteHeader(http.StatusNotFound) - io.WriteString(w, string(b)) - } -} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe(":8080", nil) -} diff --git a/test/go/command_line_arguments/app.go b/test/go/command_line_arguments/app.go deleted file mode 100644 index 5da12ffe..00000000 --- a/test/go/command_line_arguments/app.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import ( - "fmt" - "io" - "net/http" - "unit.nginx.org/go" - "os" - "strings" -) - -func handler(w http.ResponseWriter, r *http.Request) { - args := strings.Join(os.Args[1:], ",") - - w.Header().Add("X-Arg-0", fmt.Sprintf("%v", os.Args[0])) - w.Header().Add("Content-Length", fmt.Sprintf("%v", len(args))) - io.WriteString(w, args) -} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe(":8080", nil) -} diff --git a/test/go/cookies/app.go b/test/go/cookies/app.go deleted file mode 100644 index 49779d35..00000000 --- a/test/go/cookies/app.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "net/http" - "unit.nginx.org/go" -) - -func handler(w http.ResponseWriter, r *http.Request) { - cookie1, _ := r.Cookie("var1") - cookie2, _ := r.Cookie("var2") - - w.Header().Set("X-Cookie-1", cookie1.Value) - w.Header().Set("X-Cookie-2", cookie2.Value) -} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe(":8080", nil) -} diff --git a/test/go/empty/app.go b/test/go/empty/app.go deleted file mode 100644 index 61e27f67..00000000 --- a/test/go/empty/app.go +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import ( - "net/http" - "unit.nginx.org/go" -) - -func handler(w http.ResponseWriter, r *http.Request) {} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe(":8080", nil) -} diff --git a/test/go/get_variables/app.go b/test/go/get_variables/app.go deleted file mode 100644 index d70669f2..00000000 --- a/test/go/get_variables/app.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "net/http" - "unit.nginx.org/go" -) - -func handler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-Var-1", r.URL.Query().Get("var1")) - w.Header().Set("X-Var-2", r.URL.Query().Get("var2")) - w.Header().Set("X-Var-3", r.URL.Query().Get("var3")) -} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe(":8080", nil) -} diff --git a/test/go/mirror/app.go b/test/go/mirror/app.go deleted file mode 100644 index daf55df8..00000000 --- a/test/go/mirror/app.go +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import ( - "fmt" - "io" - "net/http" - "unit.nginx.org/go" -) - -func handler(w http.ResponseWriter, r *http.Request) { - var buf [32768]byte - len, _ := r.Body.Read(buf[:]) - - w.Header().Add("Content-Length", fmt.Sprintf("%v", len)) - io.WriteString(w, string(buf[:len])) -} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe(":8080", nil) -} diff --git a/test/go/ns_inspect/app.go b/test/go/ns_inspect/app.go deleted file mode 100644 index 977f0d9c..00000000 --- a/test/go/ns_inspect/app.go +++ /dev/null @@ -1,101 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "net/http" - "unit.nginx.org/go" - "os" - "strconv" - "io/ioutil" -) - -type ( - NS struct { - USER uint64 - PID uint64 - IPC uint64 - CGROUP uint64 - UTS uint64 - MNT uint64 - NET uint64 - } - - Output struct { - PID int - UID int - GID int - NS NS - FileExists bool - Mounts string - } -) - -func abortonerr(err error) { - if err != nil { - panic(err) - } -} - -// returns: [nstype]:[4026531835] -func getns(nstype string) uint64 { - str, err := os.Readlink(fmt.Sprintf("/proc/self/ns/%s", nstype)) - if err != nil { - return 0 - } - - str = str[len(nstype)+2:] - str = str[:len(str)-1] - val, err := strconv.ParseUint(str, 10, 64) - abortonerr(err) - return val -} - -func handler(w http.ResponseWriter, r *http.Request) { - pid := os.Getpid() - out := &Output{ - PID: pid, - UID: os.Getuid(), - GID: os.Getgid(), - NS: NS{ - PID: getns("pid"), - USER: getns("user"), - MNT: getns("mnt"), - IPC: getns("ipc"), - UTS: getns("uts"), - NET: getns("net"), - CGROUP: getns("cgroup"), - }, - } - - err := r.ParseForm() - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - if fname := r.Form.Get("file"); fname != "" { - _, err = os.Stat(fname); - out.FileExists = err == nil - } - - if mounts := r.Form.Get("mounts"); mounts != "" { - data, _ := ioutil.ReadFile("/proc/self/mountinfo") - out.Mounts = string(data) - } - - data, err := json.Marshal(out) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.Header().Add("Content-Type", "application/json") - - w.Write(data) -} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe(":8080", nil) -} diff --git a/test/go/post_variables/app.go b/test/go/post_variables/app.go deleted file mode 100644 index 06900d4c..00000000 --- a/test/go/post_variables/app.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "net/http" - "unit.nginx.org/go" -) - -func handler(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - - w.Header().Set("X-Var-1", r.Form.Get("var1")) - w.Header().Set("X-Var-2", r.Form.Get("var2")) - w.Header().Set("X-Var-3", r.Form.Get("var3")) -} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe(":8080", nil) -} diff --git a/test/go/variables/app.go b/test/go/variables/app.go deleted file mode 100644 index 9ef18aae..00000000 --- a/test/go/variables/app.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -import ( - "fmt" - "io" - "net/http" - "unit.nginx.org/go" -) - -func handler(w http.ResponseWriter, r *http.Request) { - var buf [4096]byte - len, _ := r.Body.Read(buf[:]) - - w.Header().Set("Request-Method", r.Method) - w.Header().Set("Request-Uri", r.RequestURI) - w.Header().Set("Server-Protocol", r.Proto) - w.Header().Set("Server-Protocol-Major", fmt.Sprintf("%v", r.ProtoMajor)) - w.Header().Set("Server-Protocol-Minor", fmt.Sprintf("%v", r.ProtoMinor)) - w.Header().Set("Content-Length", fmt.Sprintf("%v", len)) - w.Header().Set("Content-Type", r.Header.Get("Content-Type")) - w.Header().Set("Custom-Header", r.Header.Get("Custom-Header")) - w.Header().Set("Http-Host", r.Header.Get("Host")) - - io.WriteString(w, string(buf[:len])) -} - -func main() { - http.HandleFunc("/", handler) - unit.ListenAndServe(":8080", nil) -} diff --git a/test/java/content_type/app.java b/test/java/content_type/app.java deleted file mode 100644 index 7d8a7418..00000000 --- a/test/java/content_type/app.java +++ /dev/null @@ -1,89 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - if (request.getServletPath().equals("/1")) { - response.setContentType("text/plain;charset=utf-8"); - response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); - response.setHeader("X-Content-Type", response.getContentType()); - return; - } - - if (request.getServletPath().equals("/2")) { - response.setContentType("text/plain"); - response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); - response.setHeader("X-Content-Type", response.getContentType()); - return; - } - - if (request.getServletPath().equals("/3")) { - response.setContentType("text/plain;charset=utf-8"); - response.setCharacterEncoding("windows-1251"); - response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); - response.setHeader("X-Content-Type", response.getContentType()); - return; - } - - if (request.getServletPath().equals("/4")) { - response.setCharacterEncoding("windows-1251"); - response.setContentType("text/plain"); - response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); - response.setHeader("X-Content-Type", response.getContentType()); - return; - } - - if (request.getServletPath().equals("/5")) { - response.setContentType("text/plain;charset=utf-8"); - response.setCharacterEncoding(null); - response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); - response.setHeader("X-Content-Type", response.getContentType()); - return; - } - - if (request.getServletPath().equals("/6")) { - response.setContentType("text/plain;charset=utf-8"); - response.setContentType(null); - response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); - response.setHeader("X-Content-Type", response.getContentType()); - return; - } - - if (request.getServletPath().equals("/7")) { - response.setContentType("text/plain;charset=utf-8"); - - PrintWriter out = response.getWriter(); - - response.setCharacterEncoding("windows-1251"); - response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); - response.setHeader("X-Content-Type", response.getContentType()); - return; - } - - if (request.getServletPath().equals("/8")) { - response.setContentType("text/plain;charset=utf-8"); - - PrintWriter out = response.getWriter(); - - response.setContentType("text/html;charset=windows-1251"); - response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); - response.setHeader("X-Content-Type", response.getContentType()); - return; - } - - response.sendError(404); - } -} diff --git a/test/java/cookies/app.java b/test/java/cookies/app.java deleted file mode 100644 index 13cea6d1..00000000 --- a/test/java/cookies/app.java +++ /dev/null @@ -1,30 +0,0 @@ - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet(urlPatterns = "/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - Cookie[] cookies = request.getCookies(); - if (cookies != null) { - for (Cookie c : cookies) { - if (c.getName().equals("var1")) { - response.addHeader("X-Cookie-1", c.getValue()); - } - if (c.getName().equals("var2")) { - response.addHeader("X-Cookie-2", c.getValue()); - } - } - } - } -} diff --git a/test/java/empty/app.java b/test/java/empty/app.java deleted file mode 100644 index b0fca631..00000000 --- a/test/java/empty/app.java +++ /dev/null @@ -1,18 +0,0 @@ - -import java.io.IOException; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { } -} diff --git a/test/java/empty_war/empty.war b/test/java/empty_war/empty.war deleted file mode 100644 index 4985e804e0a982454d480ded92efa9ab970f9451..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 484 zcmWIWW@h1H0Du0-P*SNM8o|RLYONaUC|VKol~IHt0H{ZVfddH9 z_3**jvUak+Sf;RO9ZT#EzuSSzroxjW zxR;ij|7GkByBL`w^sKsnddtafwZ{*1xDKj*{F)ZHY{gs^QA0C{X?GTB7M0Xo|7y9i z*~Tq?X5)1YwJA#KQVs77U%JZQm|Q$-{hv?r+m62GefxgP)g?N=b{{|QGC4u4#pnK{ zm}L{59f}f&VxGnqnwGdAU6eWg<1&Zjl(x4k#l=*NPh`COd+&4O%U>dHmwqH}=ZxOJ z?9RyxcMm<-z3juU7rHTyXS2QmLx7#bW=A6DF;KWMG64CEOrp%V!jT6StPXD-K}=Yv ua==3sq8|~a$Y%2~AoMS3G=b|!gfIs@gaf=;*+4ch0bvJ_b_2SNfdK&cf|=?7 diff --git a/test/java/filter/app.java b/test/java/filter/app.java deleted file mode 100644 index a5da3997..00000000 --- a/test/java/filter/app.java +++ /dev/null @@ -1,54 +0,0 @@ - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.annotation.WebFilter; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -@WebServlet(urlPatterns = "/") -public class app extends HttpServlet -{ - @WebFilter(urlPatterns = "") - public static class filter implements Filter - { - @Override - public void init(FilterConfig filterConfig) - { - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException - { - response.getOutputStream().println("Extra Info"); - response.setCharacterEncoding("utf-8"); - - ((HttpServletResponse) response).addHeader("X-Filter-Before", "1"); - - chain.doFilter(request, response); - - ((HttpServletResponse) response).setHeader("X-Filter-After", "1"); - } - - @Override - public void destroy() - { - } - } - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.getOutputStream().println("This is servlet response"); - response.setHeader("X-Filter-After", "0"); - } -} diff --git a/test/java/forward/app.java b/test/java/forward/app.java deleted file mode 100644 index 0dea17d6..00000000 --- a/test/java/forward/app.java +++ /dev/null @@ -1,138 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; - -import java.util.Map; - -import javax.servlet.DispatcherType; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -public class app extends HttpServlet -{ - private String id; - - private class RequestWrapper extends HttpServletRequestWrapper - { - public RequestWrapper(HttpServletRequest r) - { - super(r); - } - } - - private class ResponseWrapper extends HttpServletResponseWrapper - { - public ResponseWrapper(HttpServletResponse r) - { - super(r); - } - } - - @Override - public void init(ServletConfig sc) - throws ServletException - { - id = sc.getInitParameter("id"); - } - - private RequestDispatcher getRequestDispatcher(HttpServletRequest request, String str) - { - String disp = request.getParameter("disp"); - - if (disp != null && disp.equals("ctx")) { - return request.getServletContext().getRequestDispatcher(str); - } - - if (disp != null && disp.equals("name")) { - return request.getServletContext().getNamedDispatcher(str); - } - - if (disp == null || disp.equals("req")) { - return request.getRequestDispatcher(str); - } - - return null; - } - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - String dtype = "" + request.getDispatcherType(); - - response.addHeader("X-" + dtype + "-Id", id); - response.addHeader("X-" + dtype + "-Request-URI", "" + request.getRequestURI()); - response.addHeader("X-" + dtype + "-Servlet-Path", "" + request.getServletPath()); - response.addHeader("X-" + dtype + "-Path-Info", "" + request.getPathInfo()); - response.addHeader("X-" + dtype + "-Query-String", "" + request.getQueryString()); - response.addHeader("X-" + dtype + "-Dispatcher-Type", "" + request.getDispatcherType()); - - response.setContentType("text/plain; charset=utf-8"); - - Map pmap = request.getParameterMap(); - - for (Map.Entry p : pmap.entrySet()) { - response.addHeader("X-" + dtype + "-Param-" + p.getKey(), "" + String.join(",", p.getValue())); - } - - PrintWriter out = response.getWriter(); - - if (id.equals("fwd")) { - String uri = request.getParameter("uri"); - - if (uri != null && request.getDispatcherType() != DispatcherType.FORWARD) { - response.addHeader("X-Forward-To", "" + uri); - - out.println("Before forwarding."); - - RequestDispatcher d = getRequestDispatcher(request, uri); - - if (d == null) { - out.println("Dispatcher is null"); - return; - } - - try { - d.forward(new RequestWrapper(request), new ResponseWrapper(response)); - } catch(Exception e) { - response.addHeader("X-Exception", "" + e); - } - - response.addHeader("X-After-Forwarding", "you-should-not-see-this"); - - out.println("After forwarding."); - - return; - } - } - - if (id.equals("data")) { - response.addHeader("X-" + RequestDispatcher.FORWARD_REQUEST_URI, "" + request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI)); - response.addHeader("X-" + RequestDispatcher.FORWARD_CONTEXT_PATH, "" + request.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH)); - response.addHeader("X-" + RequestDispatcher.FORWARD_SERVLET_PATH, "" + request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH)); - response.addHeader("X-" + RequestDispatcher.FORWARD_PATH_INFO, "" + request.getAttribute(RequestDispatcher.FORWARD_PATH_INFO)); - response.addHeader("X-" + RequestDispatcher.FORWARD_QUERY_STRING, "" + request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING)); - - out.println("app.doGet(): #" + this + ", " + id); - out.println("RequestURI: " + request.getRequestURI()); - out.println("ServletPath: " + request.getServletPath()); - out.println("PathInfo: " + request.getPathInfo()); - out.println("DispType: " + request.getDispatcherType()); - out.println("QueryString: " + request.getQueryString()); - - for (Map.Entry p : pmap.entrySet()) { - out.println("- " + p.getKey() + "=" + String.join(",", p.getValue())); - } - - return; - } - - response.sendError(404); - } -} diff --git a/test/java/forward/index.html b/test/java/forward/index.html deleted file mode 100644 index 4f5a6379..00000000 --- a/test/java/forward/index.html +++ /dev/null @@ -1 +0,0 @@ -This is index.html. diff --git a/test/java/forward/web.xml b/test/java/forward/web.xml deleted file mode 100644 index 994adb37..00000000 --- a/test/java/forward/web.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - fwd - app - idfwd - - - - fwd - /fwd/* - - - - - data - app - iddata - - - - data - /data/* - - - - data - /WEB-INF/index.html - /index.html - - - - diff --git a/test/java/get_header/app.java b/test/java/get_header/app.java deleted file mode 100644 index c981835d..00000000 --- a/test/java/get_header/app.java +++ /dev/null @@ -1,21 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.addHeader("X-Reply", request.getHeader("X-Header")); - } -} diff --git a/test/java/get_header_names/app.java b/test/java/get_header_names/app.java deleted file mode 100644 index cd2f3097..00000000 --- a/test/java/get_header_names/app.java +++ /dev/null @@ -1,27 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Enumeration; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - Enumeration header_names = request.getHeaderNames(); - - for (int i = 0; header_names.hasMoreElements(); i++) { - response.addHeader("X-Reply-" + Integer.toString(i), - header_names.nextElement()); - } - } -} diff --git a/test/java/get_headers/app.java b/test/java/get_headers/app.java deleted file mode 100644 index f2930a61..00000000 --- a/test/java/get_headers/app.java +++ /dev/null @@ -1,27 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Enumeration; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - Enumeration headers = request.getHeaders("X-Header"); - - for (int i = 0; headers.hasMoreElements(); i++) { - response.addHeader("X-Reply-" + Integer.toString(i), - headers.nextElement()); - } - } -} diff --git a/test/java/get_params/app.java b/test/java/get_params/app.java deleted file mode 100644 index 1965ae2a..00000000 --- a/test/java/get_params/app.java +++ /dev/null @@ -1,50 +0,0 @@ - -import java.io.IOException; - -import java.util.Enumeration; -import java.util.Map; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet(urlPatterns = "/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.addHeader("X-Var-1", request.getParameter("var1")); - response.addHeader("X-Var-2", "" + (request.getParameter("var2") != null)); - response.addHeader("X-Var-3", "" + (request.getParameter("var3") != null)); - response.addHeader("X-Var-4", request.getParameter("var4")); - - Enumeration parameter_names = request.getParameterNames(); - - String names = ""; - for (int i = 0; parameter_names.hasMoreElements(); i++) { - names = names.concat(parameter_names.nextElement() + " "); - } - response.addHeader("X-Param-Names", names); - - String[] parameter_values = request.getParameterValues("var4"); - - String values = ""; - for (int i = 0; i < parameter_values.length; i++) { - values = values.concat(parameter_values[i] + " "); - } - response.addHeader("X-Param-Values", values); - - Map parameter_map = request.getParameterMap(); - - String map = ""; - for (Map.Entry p : parameter_map.entrySet()) { - map = map.concat(p.getKey() + "=" + String.join(",", p.getValue()) + " "); - } - response.addHeader("X-Param-Map", map); - } -} diff --git a/test/java/header/app.java b/test/java/header/app.java deleted file mode 100644 index 02d56f4d..00000000 --- a/test/java/header/app.java +++ /dev/null @@ -1,34 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.setHeader("X-Set-Utf8-Value", "тест"); - response.setHeader("X-Set-Utf8-Name-Имя", "x"); - - response.addHeader("X-Add-Utf8-Value", "тест"); - response.addHeader("X-Add-Utf8-Name-Имя", "y"); - - response.addHeader("X-Add-Test", "v1"); - response.addHeader("X-Add-Test", null); - - response.setHeader("X-Set-Test1", "v1"); - response.setHeader("X-Set-Test1", null); - - response.setHeader("X-Set-Test2", "v1"); - response.setHeader("X-Set-Test2", ""); - } -} diff --git a/test/java/header_date/app.java b/test/java/header_date/app.java deleted file mode 100644 index cedd569c..00000000 --- a/test/java/header_date/app.java +++ /dev/null @@ -1,22 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.setDateHeader("X-Set-Date", 1000); - response.addDateHeader("X-Get-Date", request.getDateHeader("X-Header")); - } -} diff --git a/test/java/header_int/app.java b/test/java/header_int/app.java deleted file mode 100644 index 3ac5478e..00000000 --- a/test/java/header_int/app.java +++ /dev/null @@ -1,22 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.setIntHeader("X-Set-Int", 1); - response.addHeader("X-Get-Int", Integer.toString(request.getIntHeader("X-Header"))); - } -} diff --git a/test/java/include/app.java b/test/java/include/app.java deleted file mode 100644 index d7e36fc6..00000000 --- a/test/java/include/app.java +++ /dev/null @@ -1,136 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; - -import java.util.Map; - -import javax.servlet.DispatcherType; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -public class app extends HttpServlet -{ - private String id; - - private class RequestWrapper extends HttpServletRequestWrapper - { - public RequestWrapper(HttpServletRequest r) - { - super(r); - } - } - - private class ResponseWrapper extends HttpServletResponseWrapper - { - public ResponseWrapper(HttpServletResponse r) - { - super(r); - } - } - - @Override - public void init(ServletConfig sc) - throws ServletException - { - id = sc.getInitParameter("id"); - } - - private RequestDispatcher getRequestDispatcher(HttpServletRequest request, String str) - { - String disp = request.getParameter("disp"); - - if (disp != null && disp.equals("ctx")) { - return request.getServletContext().getRequestDispatcher(str); - } - - if (disp != null && disp.equals("name")) { - return request.getServletContext().getNamedDispatcher(str); - } - - if (disp == null || disp.equals("req")) { - return request.getRequestDispatcher(str); - } - - return null; - } - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - String dtype = "" + request.getDispatcherType(); - - response.addHeader("X-" + dtype + "-Id", id); - response.addHeader("X-" + dtype + "-Request-URI", "" + request.getRequestURI()); - response.addHeader("X-" + dtype + "-Servlet-Path", "" + request.getServletPath()); - response.addHeader("X-" + dtype + "-Path-Info", "" + request.getPathInfo()); - response.addHeader("X-" + dtype + "-Query-String", "" + request.getQueryString()); - response.addHeader("X-" + dtype + "-Dispatcher-Type", "" + request.getDispatcherType()); - - response.setContentType("text/plain; charset=utf-8"); - - PrintWriter out = response.getWriter(); - - if (id.equals("inc")) { - String uri = request.getParameter("uri"); - - if (uri != null && request.getDispatcherType() != DispatcherType.INCLUDE) { - response.addHeader("X-Include", "" + uri); - - out.println("Before include."); - - RequestDispatcher d = getRequestDispatcher(request, uri); - - if (d == null) { - out.println("Dispatcher is null"); - return; - } - - try { - d.include(new RequestWrapper(request), new ResponseWrapper(response)); - } catch(Exception e) { - response.addHeader("X-Exception", "" + e); - out.println("Exception: " + e); - } - - response.addHeader("X-After-Include", "you-should-see-this"); - - out.println("After include."); - - return; - } - } - - if (id.equals("data")) { - out.println("app.doGet(): #" + this + ", " + id); - out.println("RequestURI: " + request.getRequestURI()); - out.println("ServletPath: " + request.getServletPath()); - out.println("PathInfo: " + request.getPathInfo()); - out.println("DispType: " + request.getDispatcherType()); - out.println("QueryString: " + request.getQueryString()); - - Map pmap = request.getParameterMap(); - - for (Map.Entry p : pmap.entrySet()) { - out.println("- " + p.getKey() + "=" + String.join(",", p.getValue())); - } - - out.println(RequestDispatcher.INCLUDE_REQUEST_URI + ": " + request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI)); - out.println(RequestDispatcher.INCLUDE_CONTEXT_PATH + ": " + request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH)); - out.println(RequestDispatcher.INCLUDE_SERVLET_PATH + ": " + request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH)); - out.println(RequestDispatcher.INCLUDE_PATH_INFO + ": " + request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO)); - out.println(RequestDispatcher.INCLUDE_QUERY_STRING + ": " + request.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING)); - - return; - } - - response.sendError(404); - } -} diff --git a/test/java/include/index.html b/test/java/include/index.html deleted file mode 100644 index 4f5a6379..00000000 --- a/test/java/include/index.html +++ /dev/null @@ -1 +0,0 @@ -This is index.html. diff --git a/test/java/include/web.xml b/test/java/include/web.xml deleted file mode 100644 index 2ed86f1d..00000000 --- a/test/java/include/web.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - inc - app - idinc - - - - data - app - iddata - - - - inc - /inc/* - - - - data - /data/* - - - - data - /WEB-INF/index.html - /index.html - - - - diff --git a/test/java/jsp/index.jsp b/test/java/jsp/index.jsp deleted file mode 100644 index 0af00a46..00000000 --- a/test/java/jsp/index.jsp +++ /dev/null @@ -1,2 +0,0 @@ -<%@ page contentType="text/plain"%>This is plain text response for "<%= request.getMethod() %> <%= request.getRequestURI() %>". -<% response.addHeader("X-Unit-JSP", "ok"); %> diff --git a/test/java/mirror/app.java b/test/java/mirror/app.java deleted file mode 100644 index 45bc1d0d..00000000 --- a/test/java/mirror/app.java +++ /dev/null @@ -1,37 +0,0 @@ - -import java.io.*; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -public class app extends HttpServlet -{ - @Override - public void doPost(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - StringBuilder buffer = new StringBuilder(); - BufferedReader reader = request.getReader(); - String line; - - while ((line = reader.readLine()) != null) { - buffer.append(line); - } - - String data = buffer.toString(); - - String dataLength = Integer.toString(data.length()); - response.setHeader("Content-Length", dataLength); - - response.setContentType("text/html"); - - PrintWriter out = response.getWriter(); - out.print(data); - out.flush(); - } -} diff --git a/test/java/multipart/app.java b/test/java/multipart/app.java deleted file mode 100644 index c4c89ffb..00000000 --- a/test/java/multipart/app.java +++ /dev/null @@ -1,93 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; - -import java.util.Map; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; - -import javax.servlet.annotation.WebServlet; -import javax.servlet.annotation.MultipartConfig; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.FileOutputStream; -import java.io.OutputStream; -import javax.servlet.http.Part; - -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -@MultipartConfig( - fileSizeThreshold = 1024 * 1024 * 1, // 1 MB - maxFileSize = 1024 * 1024 * 10, // 10 MB - maxRequestSize = 1024 * 1024 * 15 // 15 MB -) -public class app extends HttpServlet -{ - @Override - public void doPost(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.setContentType("text/html;charset=UTF-8"); - - // Create path components to save the file - final String path = request.getParameter("destination"); - final Part filePart = request.getPart("file"); - final String fileName = getFileName(filePart); - - OutputStream out = null; - InputStream filecontent = null; - final PrintWriter writer = response.getWriter(); - - try { - out = new FileOutputStream(new File(path + File.separator - + fileName)); - filecontent = filePart.getInputStream(); - - int read = 0; - final byte[] bytes = new byte[1024]; - - while ((read = filecontent.read(bytes)) != -1) { - out.write(bytes, 0, read); - } - writer.println(fileName + " created at " + path); - - } catch (FileNotFoundException fne) { - writer.println("You either did not specify a file to upload or are " - + "trying to upload a file to a protected or nonexistent " - + "location."); - writer.println("
ERROR: " + fne.getMessage()); - - } finally { - if (out != null) { - out.close(); - } - if (filecontent != null) { - filecontent.close(); - } - if (writer != null) { - writer.close(); - } - } - - return; - } - - private String getFileName(final Part part) { - final String partHeader = part.getHeader("content-disposition"); - - for (String content : part.getHeader("content-disposition").split(";")) - { - if (content.trim().startsWith("filename")) { - return content.substring( - content.indexOf("=") + 1).trim().replace("\"", ""); - } - } - return null; - } -} diff --git a/test/java/path_translation/app.java b/test/java/path_translation/app.java deleted file mode 100644 index ce0b9368..00000000 --- a/test/java/path_translation/app.java +++ /dev/null @@ -1,56 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.InputStream; - -import java.util.Set; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet( urlPatterns = { "/", "/pt/*" } ) -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.addHeader("X-Request-URI", "" + request.getRequestURI()); - response.addHeader("X-Servlet-Path", "" + request.getServletPath()); - response.addHeader("X-Path-Info", "" + request.getPathInfo()); - response.addHeader("X-Query-String", "" + request.getQueryString()); - response.addHeader("X-Path-Translated", "" + request.getPathTranslated()); - - response.setContentType("text/plain; charset=utf-8"); - - PrintWriter out = response.getWriter(); - ServletContext ctx = request.getServletContext(); - - String path = request.getParameter("path"); - - if (path != null) { - response.addHeader("X-Real-Path", "" + ctx.getRealPath(path)); - response.addHeader("X-Resource", "" + ctx.getResource(path)); - - Set paths = ctx.getResourcePaths(path); - - response.addHeader("X-Resource-Paths", "" + paths); - - InputStream is = ctx.getResourceAsStream(path); - - response.addHeader("X-Resource-As-Stream", "" + is); - - if (is != null) { - final byte[] buf = new byte[1024]; - int r = is.read(buf); - - out.println(new String(buf, 0, r, "utf-8")); - } - } - } -} diff --git a/test/java/path_translation/index.html b/test/java/path_translation/index.html deleted file mode 100644 index 4f5a6379..00000000 --- a/test/java/path_translation/index.html +++ /dev/null @@ -1 +0,0 @@ -This is index.html. diff --git a/test/java/post_params/app.java b/test/java/post_params/app.java deleted file mode 100644 index 0ed73d42..00000000 --- a/test/java/post_params/app.java +++ /dev/null @@ -1,22 +0,0 @@ - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet(urlPatterns = "/") -public class app extends HttpServlet -{ - @Override - public void doPost(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.addHeader("X-Var-1", request.getParameter("var1")); - response.addHeader("X-Var-2", "" + (request.getParameter("var2") != null)); - response.addHeader("X-Var-3", "" + (request.getParameter("var3") != null)); - } -} diff --git a/test/java/query_string/app.java b/test/java/query_string/app.java deleted file mode 100644 index 7962336b..00000000 --- a/test/java/query_string/app.java +++ /dev/null @@ -1,20 +0,0 @@ - -import java.io.IOException; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet( urlPatterns = { "/" } ) -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.addHeader("X-Query-String", "" + request.getQueryString()); - } -} diff --git a/test/java/request_listeners/app.java b/test/java/request_listeners/app.java deleted file mode 100644 index 6cbf7860..00000000 --- a/test/java/request_listeners/app.java +++ /dev/null @@ -1,79 +0,0 @@ - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.ServletRequestEvent; -import javax.servlet.ServletRequestListener; -import javax.servlet.ServletRequestAttributeEvent; -import javax.servlet.ServletRequestAttributeListener; -import javax.servlet.annotation.WebServlet; -import javax.servlet.annotation.WebListener; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebListener -@WebServlet(urlPatterns = "/") -public class app extends HttpServlet implements - ServletRequestListener, - ServletRequestAttributeListener -{ - private static String request_initialized = ""; - private static String request_destroyed = ""; - private static String attribute_added = ""; - private static String attribute_removed = ""; - private static String attribute_replaced = ""; - - @Override - public void requestInitialized(ServletRequestEvent sre) - { - HttpServletRequest r = (HttpServletRequest) sre.getServletRequest(); - - request_initialized = r.getRequestURI(); - } - - @Override - public void requestDestroyed(ServletRequestEvent sre) - { - HttpServletRequest r = (HttpServletRequest) sre.getServletRequest(); - - request_destroyed = r.getRequestURI(); - - attribute_added = ""; - attribute_removed = ""; - attribute_replaced = ""; - } - - @Override - public void attributeAdded(ServletRequestAttributeEvent event) - { - attribute_added += event.getName() + "=" + event.getValue() + ";"; - } - - @Override - public void attributeRemoved(ServletRequestAttributeEvent event) - { - attribute_removed += event.getName() + "=" + event.getValue() + ";"; - } - - @Override - public void attributeReplaced(ServletRequestAttributeEvent event) - { - attribute_replaced += event.getName() + "=" + event.getValue() + ";"; - } - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - request.setAttribute("var", request.getParameter("var1")); - request.setAttribute("var", request.getParameter("var2")); - request.setAttribute("var", request.getParameter("var3")); - - response.addHeader("X-Request-Initialized", request_initialized); - response.addHeader("X-Request-Destroyed", request_destroyed); - response.addHeader("X-Attr-Added", attribute_added); - response.addHeader("X-Attr-Removed", attribute_removed); - response.addHeader("X-Attr-Replaced", attribute_replaced); - } -} diff --git a/test/java/session/app.java b/test/java/session/app.java deleted file mode 100644 index 84d3fa55..00000000 --- a/test/java/session/app.java +++ /dev/null @@ -1,30 +0,0 @@ -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -@WebServlet(urlPatterns = "/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - HttpSession s = request.getSession(); - String old_var1 = (String) s.getAttribute("var1"); - s.setAttribute("var1", request.getParameter("var1")); - - if (old_var1 == null) { - response.addHeader("X-Var-1", "null"); - } else { - response.addHeader("X-Var-1", old_var1); - } - - response.addHeader("X-Session-Id", s.getId()); - response.addHeader("X-Session-New", "" + s.isNew()); - } -} diff --git a/test/java/session_inactive/app.java b/test/java/session_inactive/app.java deleted file mode 100644 index 618e4d67..00000000 --- a/test/java/session_inactive/app.java +++ /dev/null @@ -1,33 +0,0 @@ -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -@WebServlet(urlPatterns = "/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - HttpSession s = request.getSession(); - - if (s.isNew()) { - String interval = request.getHeader("X-Interval"); - - if (interval == null) { - s.setMaxInactiveInterval(0); - } else { - s.setMaxInactiveInterval(Integer.parseInt(interval)); - } - } - - response.addHeader("X-Session-Id", s.getId()); - response.addDateHeader("X-Session-Last-Access-Time", s.getLastAccessedTime()); - response.addIntHeader("X-Session-Interval", s.getMaxInactiveInterval()); - } -} diff --git a/test/java/session_invalidate/app.java b/test/java/session_invalidate/app.java deleted file mode 100644 index 3f66290f..00000000 --- a/test/java/session_invalidate/app.java +++ /dev/null @@ -1,23 +0,0 @@ -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -@WebServlet(urlPatterns = "/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - HttpSession s = request.getSession(); - - s.invalidate(); - - response.addHeader("X-Session-Id", s.getId()); - } -} diff --git a/test/java/session_listeners/app.java b/test/java/session_listeners/app.java deleted file mode 100644 index 603cc932..00000000 --- a/test/java/session_listeners/app.java +++ /dev/null @@ -1,80 +0,0 @@ - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionAttributeListener; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionIdListener; -import javax.servlet.http.HttpSessionListener; - -@WebServlet(urlPatterns = "/") -public class app extends HttpServlet implements - HttpSessionListener, - HttpSessionIdListener, - HttpSessionAttributeListener -{ - private static String session_created = ""; - private static String session_destroyed = ""; - private static String session_id_changed = ""; - private static String attribute_added = ""; - private static String attribute_removed = ""; - private static String attribute_replaced = ""; - - @Override - public void sessionCreated(HttpSessionEvent se) - { - session_created += se.getSession().getId(); - } - - @Override - public void sessionDestroyed(HttpSessionEvent se) - { - session_destroyed += se.getSession().getId(); - } - - @Override - public void sessionIdChanged(HttpSessionEvent event, String oldId) - { - session_id_changed += " " + oldId + "->" + event.getSession().getId(); - } - - @Override - public void attributeAdded(HttpSessionBindingEvent event) - { - attribute_added += event.getName() + "=" + event.getValue(); - } - - @Override - public void attributeRemoved(HttpSessionBindingEvent event) - { - attribute_removed += event.getName() + "=" + event.getValue(); - } - - @Override - public void attributeReplaced(HttpSessionBindingEvent event) - { - attribute_replaced += event.getName() + "=" + event.getValue(); - } - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - HttpSession s = request.getSession(); - s.setAttribute("var1", request.getParameter("var1")); - - response.addHeader("X-Session-Id", s.getId()); - response.addHeader("X-Session-Created", session_created); - response.addHeader("X-Session-Destroyed", session_destroyed); - response.addHeader("X-Attr-Added", attribute_added); - response.addHeader("X-Attr-Removed", attribute_removed); - response.addHeader("X-Attr-Replaced", attribute_replaced); - } -} diff --git a/test/java/session_listeners/web.xml b/test/java/session_listeners/web.xml deleted file mode 100644 index aedfe175..00000000 --- a/test/java/session_listeners/web.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - app - - - app - - - diff --git a/test/java/threads/app.java b/test/java/threads/app.java deleted file mode 100644 index d0dd3fcc..00000000 --- a/test/java/threads/app.java +++ /dev/null @@ -1,32 +0,0 @@ - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet("/") -public class app extends HttpServlet -{ - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - int delay = 0; - - String x_delay = request.getHeader("X-Delay"); - if (x_delay != null) { - delay = Integer.parseInt(x_delay); - } - - try { - Thread.sleep(delay * 1000); - } catch (InterruptedException ex) { - ex.printStackTrace(); - } - - response.addHeader("X-Thread", "" + Thread.currentThread().getId()); - } -} diff --git a/test/java/url_pattern/app.java b/test/java/url_pattern/app.java deleted file mode 100644 index 88b071a2..00000000 --- a/test/java/url_pattern/app.java +++ /dev/null @@ -1,39 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -public class app extends HttpServlet -{ - private String id; - - @Override - public void init(ServletConfig sc) - throws ServletException - { - id = sc.getInitParameter("id"); - } - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.addHeader("X-Id", id); - response.addHeader("X-Request-URI", "" + request.getRequestURI()); - response.addHeader("X-Servlet-Path", "" + request.getServletPath()); - response.setHeader("X-Path-Info", "" + request.getPathInfo()); - - response.setContentType("text/plain; charset=utf-8"); - - PrintWriter out = response.getWriter(); - out.println("app.doGet(): #" + this + ", " + id); - out.println("RequestURI: " + request.getRequestURI()); - out.println("ServletPath: " + request.getServletPath()); - out.println("PathInfo: " + request.getPathInfo()); - } -} diff --git a/test/java/url_pattern/web.xml b/test/java/url_pattern/web.xml deleted file mode 100644 index 048400a6..00000000 --- a/test/java/url_pattern/web.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - servlet0 - app - idservlet0 - - - - servlet1 - app - idservlet1 - - - - servlet2 - app - idservlet2 - - - - servlet3 - app - idservlet3 - - - - servlet4 - app - idservlet4 - - - - default - app - iddefault - - - - servlet0 - /foo/* - - - - servlet1 - /foo/bar/* - - - - servlet2 - /baz/* - - - - servlet3 - /catalog - - - - servlet4 - *.bop - - - - default - / - - - - diff --git a/test/java/websockets_mirror/app.java b/test/java/websockets_mirror/app.java deleted file mode 100644 index ada60231..00000000 --- a/test/java/websockets_mirror/app.java +++ /dev/null @@ -1,57 +0,0 @@ -import java.io.IOException; -import java.nio.ByteBuffer; - -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.PongMessage; -import javax.websocket.Session; -import javax.websocket.server.ServerEndpoint; - -@ServerEndpoint("/") -public class app { - - @OnOpen - public void onOpen(Session session) { - session.setMaxTextMessageBufferSize(8388608); - } - - @OnMessage - public void echoTextMessage(Session session, String msg) { - try { - if (session.isOpen()) { - session.getBasicRemote().sendText(msg, true); - } - } catch (IOException e) { - try { - session.close(); - } catch (IOException e1) { - // Ignore - } - } - } - - @OnMessage - public void echoBinaryMessage(Session session, ByteBuffer bb) { - try { - if (session.isOpen()) { - session.getBasicRemote().sendBinary(bb, true); - } - } catch (IOException e) { - try { - session.close(); - } catch (IOException e1) { - // Ignore - } - } - } - - /** - * Process a received pong. This is a NO-OP. - * - * @param pm Ignored. - */ - @OnMessage - public void echoPongMessage(PongMessage pm) { - // NO-OP - } -} diff --git a/test/java/welcome_files/app.java b/test/java/welcome_files/app.java deleted file mode 100644 index ce922531..00000000 --- a/test/java/welcome_files/app.java +++ /dev/null @@ -1,67 +0,0 @@ - -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import javax.servlet.annotation.WebFilter; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -public class app extends HttpServlet -{ - @WebFilter(urlPatterns = "*.jsp") - public static class jsp_filter implements Filter - { - @Override - public void init(FilterConfig filterConfig) { } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException - { - ((HttpServletResponse) response).addHeader("X-JSP-Filter", "1"); - - chain.doFilter(request, response); - } - - @Override - public void destroy() { } - } - - @WebFilter(urlPatterns = "*.txt") - public static class txt_filter implements Filter - { - @Override - public void init(FilterConfig filterConfig) { } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException - { - ((HttpServletResponse) response).addHeader("X-TXT-Filter", "1"); - - chain.doFilter(request, response); - } - - @Override - public void destroy() { } - } - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - response.addHeader("X-App-Servlet", "1"); - response.setContentType("text/plain; charset=utf-8"); - - PrintWriter out = response.getWriter(); - out.println("App Servlet"); - } -} diff --git a/test/java/welcome_files/dir1/index.txt b/test/java/welcome_files/dir1/index.txt deleted file mode 100644 index e7784d20..00000000 --- a/test/java/welcome_files/dir1/index.txt +++ /dev/null @@ -1 +0,0 @@ -This is index.txt. diff --git a/test/java/welcome_files/dir2/default.jsp b/test/java/welcome_files/dir2/default.jsp deleted file mode 100644 index 48627641..00000000 --- a/test/java/welcome_files/dir2/default.jsp +++ /dev/null @@ -1,3 +0,0 @@ -<%@ page contentType="text/html"%> -

You should see this on /dir2/ URL.

-<% response.addHeader("X-Unit-JSP", "ok"); %> diff --git a/test/java/welcome_files/dir2/index.html b/test/java/welcome_files/dir2/index.html deleted file mode 100644 index 5b111825..00000000 --- a/test/java/welcome_files/dir2/index.html +++ /dev/null @@ -1 +0,0 @@ -

You should see this on /dir2/ URL.

diff --git a/test/java/welcome_files/dir3/index.txt b/test/java/welcome_files/dir3/index.txt deleted file mode 100644 index 8a2b7dea..00000000 --- a/test/java/welcome_files/dir3/index.txt +++ /dev/null @@ -1 +0,0 @@ -You should never see this. diff --git a/test/java/welcome_files/dir4/index.html b/test/java/welcome_files/dir4/index.html deleted file mode 100644 index 2cef75e2..00000000 --- a/test/java/welcome_files/dir4/index.html +++ /dev/null @@ -1 +0,0 @@ -

You should see this for /dir4/index.html or /dir4/ url. diff --git a/test/java/welcome_files/index.htm b/test/java/welcome_files/index.htm deleted file mode 100644 index 97e34cf5..00000000 --- a/test/java/welcome_files/index.htm +++ /dev/null @@ -1 +0,0 @@ -

You should see this ONLY for /index.htm url. diff --git a/test/java/welcome_files/web.xml b/test/java/welcome_files/web.xml deleted file mode 100644 index 6bbc7c8e..00000000 --- a/test/java/welcome_files/web.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - index.txt - default.jsp - index.html - - - - app - app - - - - app - /dir3/index.txt - /dir4/index.txt - /dir5/index.html - - - - diff --git a/test/njs/global_this/script.js b/test/njs/global_this/script.js deleted file mode 100644 index cf9bc078..00000000 --- a/test/njs/global_this/script.js +++ /dev/null @@ -1,3 +0,0 @@ -export default { - "str" : function () {return typeof globalThis.njs.version} -} diff --git a/test/njs/import_from/script.js b/test/njs/import_from/script.js deleted file mode 100644 index 99d1b80e..00000000 --- a/test/njs/import_from/script.js +++ /dev/null @@ -1,5 +0,0 @@ -import cr from 'crypto'; - -export default { - "num" : function () {return typeof cr.createHash('md5').digest().length} -} diff --git a/test/njs/invalid/script.js b/test/njs/invalid/script.js deleted file mode 100644 index a9d79797..00000000 --- a/test/njs/invalid/script.js +++ /dev/null @@ -1,3 +0,0 @@ -export default { - "route": function() {blah 'next'} -} diff --git a/test/njs/next/script.js b/test/njs/next/script.js deleted file mode 100644 index 86e49e82..00000000 --- a/test/njs/next/script.js +++ /dev/null @@ -1,3 +0,0 @@ -export default { - "route": function() {return 'next'} -} diff --git a/test/node/404/404.html b/test/node/404/404.html deleted file mode 100644 index 6d0c635a..00000000 --- a/test/node/404/404.html +++ /dev/null @@ -1,6 +0,0 @@ - -404 Not Found - -

404 Not Found

- - diff --git a/test/node/404/app.js b/test/node/404/app.js deleted file mode 100644 index 8beec34a..00000000 --- a/test/node/404/app.js +++ /dev/null @@ -1,6 +0,0 @@ - -var fs = require('fs'); - -require('http').createServer(function (req, res) { - res.writeHead(404, {}).end(fs.readFileSync('404.html')); -}).listen(8080); diff --git a/test/node/basic/app.js b/test/node/basic/app.js deleted file mode 100644 index 2d870003..00000000 --- a/test/node/basic/app.js +++ /dev/null @@ -1,5 +0,0 @@ - -require('http').createServer(function (req, res) { - res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) - .end('Hello World\n'); -}).listen(8080); diff --git a/test/node/double_end/app.js b/test/node/double_end/app.js deleted file mode 100644 index e721db77..00000000 --- a/test/node/double_end/app.js +++ /dev/null @@ -1,4 +0,0 @@ - -require('http').createServer(function (req, res) { - res.end().end(); -}).listen(8080); diff --git a/test/node/flush_headers/app.js b/test/node/flush_headers/app.js deleted file mode 100644 index 4c0e93bc..00000000 --- a/test/node/flush_headers/app.js +++ /dev/null @@ -1,7 +0,0 @@ - -require('http').createServer(function (req, res) { - res.setHeader('X-Header', 'blah'); - res.flushHeaders(); - res.flushHeaders(); // Should be idempotent. - res.end(); -}).listen(8080); diff --git a/test/node/get_header_names/app.js b/test/node/get_header_names/app.js deleted file mode 100644 index 77aa0327..00000000 --- a/test/node/get_header_names/app.js +++ /dev/null @@ -1,7 +0,0 @@ - -require('http').createServer(function (req, res) { - res.setHeader('DATE', ['date1', 'date2']); - res.setHeader('X-Header', 'blah'); - res.setHeader('X-Names', res.getHeaderNames()); - res.end(); -}).listen(8080); diff --git a/test/node/get_header_type/app.js b/test/node/get_header_type/app.js deleted file mode 100644 index d5a591e8..00000000 --- a/test/node/get_header_type/app.js +++ /dev/null @@ -1,6 +0,0 @@ - -require('http').createServer(function (req, res) { - res.setHeader('X-Number', 100); - res.setHeader('X-Type', typeof(res.getHeader('X-Number'))); - res.end(); -}).listen(8080); diff --git a/test/node/get_variables/app.js b/test/node/get_variables/app.js deleted file mode 100644 index 8f317cb4..00000000 --- a/test/node/get_variables/app.js +++ /dev/null @@ -1,8 +0,0 @@ - -require('http').createServer(function (req, res) { - let query = require('url').parse(req.url, true).query; - res.setHeader('X-Var-1', query.var1); - res.setHeader('X-Var-2', query.var2); - res.setHeader('X-Var-3', query.var3); - res.end(); -}).listen(8080); diff --git a/test/node/has_header/app.js b/test/node/has_header/app.js deleted file mode 100644 index 30e75e4d..00000000 --- a/test/node/has_header/app.js +++ /dev/null @@ -1,5 +0,0 @@ - -require('http').createServer(function (req, res) { - res.setHeader('X-Has-Header', res.hasHeader(req.headers['x-header']) + ''); - res.end(); -}).listen(8080); diff --git a/test/node/header_name_case/app.js b/test/node/header_name_case/app.js deleted file mode 100644 index 45acd507..00000000 --- a/test/node/header_name_case/app.js +++ /dev/null @@ -1,7 +0,0 @@ - -require('http').createServer(function (req, res) { - res.setHeader('X-Header', '1'); - res.setHeader('X-header', '2'); - res.setHeader('X-HEADER', '3'); - res.end(); -}).listen(8080); diff --git a/test/node/header_name_valid/app.js b/test/node/header_name_valid/app.js deleted file mode 100644 index 9ac0c3a2..00000000 --- a/test/node/header_name_valid/app.js +++ /dev/null @@ -1,6 +0,0 @@ - -require('http').createServer(function (req, res) { - res.writeHead(200, {}); - res.setHeader('@$', 'test'); - res.end(); -}).listen(8080); diff --git a/test/node/header_value_object/app.js b/test/node/header_value_object/app.js deleted file mode 100644 index 6f3d74bc..00000000 --- a/test/node/header_value_object/app.js +++ /dev/null @@ -1,5 +0,0 @@ - -require('http').createServer(function (req, res) { - res.setHeader('X-Header', {}); - res.end(); -}).listen(8080); diff --git a/test/node/loader/es_modules_http/app.mjs b/test/node/loader/es_modules_http/app.mjs deleted file mode 100644 index 28ff08d8..00000000 --- a/test/node/loader/es_modules_http/app.mjs +++ /dev/null @@ -1,6 +0,0 @@ -import http from "http" - -http.createServer(function (req, res) { - res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) - .end('Hello World\n'); -}).listen(8080); diff --git a/test/node/loader/es_modules_http_indirect/app.js b/test/node/loader/es_modules_http_indirect/app.js deleted file mode 100644 index 535befba..00000000 --- a/test/node/loader/es_modules_http_indirect/app.js +++ /dev/null @@ -1 +0,0 @@ -import("./module.mjs") diff --git a/test/node/loader/es_modules_http_indirect/module.mjs b/test/node/loader/es_modules_http_indirect/module.mjs deleted file mode 100644 index 28ff08d8..00000000 --- a/test/node/loader/es_modules_http_indirect/module.mjs +++ /dev/null @@ -1,6 +0,0 @@ -import http from "http" - -http.createServer(function (req, res) { - res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) - .end('Hello World\n'); -}).listen(8080); diff --git a/test/node/loader/es_modules_websocket/app.mjs b/test/node/loader/es_modules_websocket/app.mjs deleted file mode 100644 index 361d855b..00000000 --- a/test/node/loader/es_modules_websocket/app.mjs +++ /dev/null @@ -1,30 +0,0 @@ -import http from "http" -import websocket from "websocket" - -let server = http.createServer(function() {}); -let webSocketServer = websocket.server; - -server.listen(8080, function() {}); - -var wsServer = new webSocketServer({ - maxReceivedMessageSize: 0x1000000000, - maxReceivedFrameSize: 0x1000000000, - fragmentOutgoingMessages: false, - fragmentationThreshold: 0x1000000000, - httpServer: server, -}); - -wsServer.on('request', function(request) { - var connection = request.accept(null); - - connection.on('message', function(message) { - if (message.type === 'utf8') { - connection.send(message.utf8Data); - } else if (message.type === 'binary') { - connection.send(message.binaryData); - } - - }); - - connection.on('close', function(r) {}); -}); diff --git a/test/node/loader/es_modules_websocket_indirect/app.js b/test/node/loader/es_modules_websocket_indirect/app.js deleted file mode 100644 index 535befba..00000000 --- a/test/node/loader/es_modules_websocket_indirect/app.js +++ /dev/null @@ -1 +0,0 @@ -import("./module.mjs") diff --git a/test/node/loader/es_modules_websocket_indirect/module.mjs b/test/node/loader/es_modules_websocket_indirect/module.mjs deleted file mode 100644 index 361d855b..00000000 --- a/test/node/loader/es_modules_websocket_indirect/module.mjs +++ /dev/null @@ -1,30 +0,0 @@ -import http from "http" -import websocket from "websocket" - -let server = http.createServer(function() {}); -let webSocketServer = websocket.server; - -server.listen(8080, function() {}); - -var wsServer = new webSocketServer({ - maxReceivedMessageSize: 0x1000000000, - maxReceivedFrameSize: 0x1000000000, - fragmentOutgoingMessages: false, - fragmentationThreshold: 0x1000000000, - httpServer: server, -}); - -wsServer.on('request', function(request) { - var connection = request.accept(null); - - connection.on('message', function(message) { - if (message.type === 'utf8') { - connection.send(message.utf8Data); - } else if (message.type === 'binary') { - connection.send(message.binaryData); - } - - }); - - connection.on('close', function(r) {}); -}); diff --git a/test/node/loader/transitive_dependency/app.js b/test/node/loader/transitive_dependency/app.js deleted file mode 100644 index aaca5216..00000000 --- a/test/node/loader/transitive_dependency/app.js +++ /dev/null @@ -1 +0,0 @@ -require("./transitive_http") diff --git a/test/node/loader/transitive_dependency/transitive_http.js b/test/node/loader/transitive_dependency/transitive_http.js deleted file mode 100644 index 171758ed..00000000 --- a/test/node/loader/transitive_dependency/transitive_http.js +++ /dev/null @@ -1,8 +0,0 @@ -const http = require("http"); - -http.createServer(function (req, res) { - res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) - .end('Hello World\n'); -}).listen(8080); - -module.exports = http; diff --git a/test/node/loader/unit_http/app.js b/test/node/loader/unit_http/app.js deleted file mode 100644 index 0e0c2b24..00000000 --- a/test/node/loader/unit_http/app.js +++ /dev/null @@ -1,4 +0,0 @@ -require("unit-http").createServer(function (req, res) { - res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) - .end('Hello World\n'); -}).listen(8080); diff --git a/test/node/mirror/app.js b/test/node/mirror/app.js deleted file mode 100644 index bdb89489..00000000 --- a/test/node/mirror/app.js +++ /dev/null @@ -1,11 +0,0 @@ - -require('http').createServer(function (req, res) { - let body = ''; - req.on('data', chunk => { - body += chunk.toString(); - }); - req.on('end', () => { - res.writeHead(200, {'Content-Length': Buffer.byteLength(body)}) - .end(body); - }); -}).listen(8080); diff --git a/test/node/options/app.js b/test/node/options/app.js deleted file mode 100644 index bc538080..00000000 --- a/test/node/options/app.js +++ /dev/null @@ -1,4 +0,0 @@ -require('http').createServer({}, function (req, res) { - res.writeHead(200, {'Content-Length': 12, 'Content-Type': 'text/plain'}) - .end('Hello World\n'); -}).listen(8080); diff --git a/test/node/post_variables/app.js b/test/node/post_variables/app.js deleted file mode 100644 index 4d88434d..00000000 --- a/test/node/post_variables/app.js +++ /dev/null @@ -1,14 +0,0 @@ - -require('http').createServer(function (req, res) { - let body = ''; - req.on('data', chunk => { - body += chunk.toString(); - }); - req.on('end', () => { - let query = require('querystring').parse(body); - res.setHeader('X-Var-1', query.var1); - res.setHeader('X-Var-2', query.var2); - res.setHeader('X-Var-3', query.var3); - res.end(); - }); -}).listen(8080); diff --git a/test/node/promise_end/app.js b/test/node/promise_end/app.js deleted file mode 100644 index 75c2ef7d..00000000 --- a/test/node/promise_end/app.js +++ /dev/null @@ -1,15 +0,0 @@ - -var fs = require('fs'); - -require('http').createServer(function (req, res) { - res.write('blah'); - - Promise.resolve().then(() => { - res.end(); - }); - - req.on('data', (data) => { - fs.appendFile('callback', '', function() {}); - }); - -}).listen(8080); diff --git a/test/node/promise_handler/app.js b/test/node/promise_handler/app.js deleted file mode 100644 index 7bcb1ae9..00000000 --- a/test/node/promise_handler/app.js +++ /dev/null @@ -1,16 +0,0 @@ - -var fs = require('fs'); - -require('http').createServer(function (req, res) { - res.end(); - - if (req.headers['x-write-call']) { - res.writeHead(200, {'Content-Type': 'text/plain'}).write('blah'); - } - - Promise.resolve().then(() => { - req.on('data', (data) => { - fs.appendFile(data.toString(), '', function() {}); - }); - }); -}).listen(8080); diff --git a/test/node/remove_header/app.js b/test/node/remove_header/app.js deleted file mode 100644 index 877a7351..00000000 --- a/test/node/remove_header/app.js +++ /dev/null @@ -1,10 +0,0 @@ - -require('http').createServer(function (req, res) { - res.setHeader('X-Header', 'test'); - res.setHeader('Was-Header', res.hasHeader('X-Header').toString()); - - res.removeHeader(req.headers['x-remove']); - res.setHeader('Has-Header', res.hasHeader('X-Header').toString()); - - res.end(); -}).listen(8080); diff --git a/test/node/set_header_array/app.js b/test/node/set_header_array/app.js deleted file mode 100644 index 0dee477e..00000000 --- a/test/node/set_header_array/app.js +++ /dev/null @@ -1,5 +0,0 @@ - -require('http').createServer(function (req, res) { - res.setHeader('Set-Cookie', ['tc=one,two,three', 'tc=four,five,six']); - res.end(); -}).listen(8080); diff --git a/test/node/status_message/app.js b/test/node/status_message/app.js deleted file mode 100644 index 53eea5c7..00000000 --- a/test/node/status_message/app.js +++ /dev/null @@ -1,4 +0,0 @@ - -require('http').createServer(function (req, res) { - res.writeHead(200, 'blah', {'Content-Type': 'text/plain'}).end(); -}).listen(8080); diff --git a/test/node/update_header/app.js b/test/node/update_header/app.js deleted file mode 100644 index dc3415e6..00000000 --- a/test/node/update_header/app.js +++ /dev/null @@ -1,6 +0,0 @@ - -require('http').createServer(function (req, res) { - res.setHeader('X-Header', 'test'); - res.setHeader('X-Header', 'new'); - res.end(); -}).listen(8080); diff --git a/test/node/variables/app.js b/test/node/variables/app.js deleted file mode 100644 index b6f36f37..00000000 --- a/test/node/variables/app.js +++ /dev/null @@ -1,18 +0,0 @@ - -require('http').createServer(function (req, res) { - let body = ''; - req.on('data', chunk => { - body += chunk.toString(); - }); - req.on('end', () => { - res.setHeader('Request-Method', req.method); - res.setHeader('Request-Uri', req.url); - res.setHeader('Server-Protocol', req.httpVersion); - res.setHeader('Request-Raw-Headers', req.rawHeaders.join()); - res.setHeader('Content-Length', Buffer.byteLength(body)); - res.setHeader('Content-Type', req.headers['content-type']); - res.setHeader('Custom-Header', req.headers['custom-header']); - res.setHeader('Http-Host', req.headers['host']); - res.writeHead(200, {}).end(body); - }); -}).listen(8080); diff --git a/test/node/websockets/mirror/app.js b/test/node/websockets/mirror/app.js deleted file mode 100644 index ee2bdd18..00000000 --- a/test/node/websockets/mirror/app.js +++ /dev/null @@ -1,28 +0,0 @@ - -server = require('http').createServer(function() {}); -webSocketServer = require('websocket').server; - -server.listen(8080, function() {}); - -var wsServer = new webSocketServer({ - maxReceivedMessageSize: 0x1000000000, - maxReceivedFrameSize: 0x1000000000, - fragmentOutgoingMessages: false, - fragmentationThreshold: 0x1000000000, - httpServer: server, -}); - -wsServer.on('request', function(request) { - var connection = request.accept(null); - - connection.on('message', function(message) { - if (message.type === 'utf8') { - connection.send(message.utf8Data); - } else if (message.type === 'binary') { - connection.send(message.binaryData); - } - - }); - - connection.on('close', function(r) {}); -}); diff --git a/test/node/websockets/mirror_fragmentation/app.js b/test/node/websockets/mirror_fragmentation/app.js deleted file mode 100644 index ca539ad6..00000000 --- a/test/node/websockets/mirror_fragmentation/app.js +++ /dev/null @@ -1,23 +0,0 @@ - -server = require('http').createServer(function() {}); -webSocketServer = require('websocket').server; - -server.listen(8080, function() {}); - -var wsServer = new webSocketServer({ - httpServer: server -}); - -wsServer.on('request', function(request) { - //console.log('request'); - var connection = request.accept(null); - - connection.on('message', function(message) { - //console.log('message'); - connection.send(message.utf8Data); - }); - - connection.on('close', function(r) { - //console.log('close'); - }); -}); diff --git a/test/node/write_array/app.js b/test/node/write_array/app.js deleted file mode 100644 index 761e8537..00000000 --- a/test/node/write_array/app.js +++ /dev/null @@ -1,4 +0,0 @@ -require('http').createServer(function (req, res) { - res.writeHead(200, {'Content-Length': 5, 'Content-Type': 'text/plain'}) - .end(new Uint8Array(Buffer.from('array', 'utf8'))); -}).listen(8080); diff --git a/test/node/write_before_write_head/app.js b/test/node/write_before_write_head/app.js deleted file mode 100644 index 10c8b9d6..00000000 --- a/test/node/write_before_write_head/app.js +++ /dev/null @@ -1,5 +0,0 @@ - -require('http').createServer(function (req, res) { - res.write('blah'); - res.writeHead(200, {'Content-Type': 'text/plain'}).end(); -}).listen(8080); diff --git a/test/node/write_buffer/app.js b/test/node/write_buffer/app.js deleted file mode 100644 index 24585ef2..00000000 --- a/test/node/write_buffer/app.js +++ /dev/null @@ -1,5 +0,0 @@ - -require('http').createServer(function (req, res) { - res.writeHead(200, {'Content-Type': 'text/plain'}) - .end(Buffer.from('buffer', 'utf8')); -}).listen(8080); diff --git a/test/node/write_callback/app.js b/test/node/write_callback/app.js deleted file mode 100644 index f03cb213..00000000 --- a/test/node/write_callback/app.js +++ /dev/null @@ -1,12 +0,0 @@ - -var fs = require('fs'); - -require('http').createServer(function (req, res) { - res.writeHead(200, {'Content-Type': 'text/plain'}); - var a = 'world'; - res.write('hello', 'utf8', function() { - a = 'blah'; - fs.appendFile('callback', '', function() {}); - }); - res.end(a); -}).listen(8080); diff --git a/test/node/write_multiple/app.js b/test/node/write_multiple/app.js deleted file mode 100644 index b1e485e7..00000000 --- a/test/node/write_multiple/app.js +++ /dev/null @@ -1,7 +0,0 @@ - -require('http').createServer(function (req, res) { - res.writeHead(200, {'Content-Type': 'text/plain', 'Content-Length': 14}); - res.write('write'); - res.write('write2'); - res.end('end'); -}).listen(8080); diff --git a/test/node/write_return/app.js b/test/node/write_return/app.js deleted file mode 100644 index d0b3d850..00000000 --- a/test/node/write_return/app.js +++ /dev/null @@ -1,5 +0,0 @@ - -require('http').createServer(function (req, res) { - res.writeHead(200, {'Content-Type': 'text/plain'}) - .end(res.write('body').toString()); -}).listen(8080); diff --git a/test/perl/body_array/psgi.pl b/test/perl/body_array/psgi.pl deleted file mode 100644 index 19c89abb..00000000 --- a/test/perl/body_array/psgi.pl +++ /dev/null @@ -1,5 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - return ['200', ['Content-Length' => '10'], ['012', '345', '678', '9']]; -}; diff --git a/test/perl/body_empty/psgi.pl b/test/perl/body_empty/psgi.pl deleted file mode 100644 index a05921f4..00000000 --- a/test/perl/body_empty/psgi.pl +++ /dev/null @@ -1,5 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - return ['200', [], []]; -}; diff --git a/test/perl/body_io_empty/psgi.pl b/test/perl/body_io_empty/psgi.pl deleted file mode 100644 index 0a203dec..00000000 --- a/test/perl/body_io_empty/psgi.pl +++ /dev/null @@ -1,9 +0,0 @@ -use IO::Handle; - -my $app = sub { - my ($environ) = @_; - - my $io = IO::Handle->new(); - - return ['200', [], $io]; -}; diff --git a/test/perl/body_io_fake/IOFake.pm b/test/perl/body_io_fake/IOFake.pm deleted file mode 100644 index d2542aa5..00000000 --- a/test/perl/body_io_fake/IOFake.pm +++ /dev/null @@ -1,33 +0,0 @@ -package IOFake; - -sub new { - my $class = shift; - my $errors = shift; - my $self = {}; - - $self->{_count} = 2; - $self->{_errors} = $errors; - - bless $self, $class; - return $self; -} - -sub getline() { - my $self = shift; - - if ($self->{_count} > 0) { - return $self->{_count}--; - } - - $self->{_errors}->print('IOFake getline() $/ is ' . ${ $/ }); - - return; -} - -sub close() { - my $self = shift; - - $self->{_errors}->print('IOFake close() called'); -}; - -1; diff --git a/test/perl/body_io_fake/psgi.pl b/test/perl/body_io_fake/psgi.pl deleted file mode 100644 index 6990bfaf..00000000 --- a/test/perl/body_io_fake/psgi.pl +++ /dev/null @@ -1,11 +0,0 @@ -use File::Basename; -use lib dirname (__FILE__); -use IOFake; - -my $app = sub { - my ($environ) = @_; - - my $io = IOFake->new($environ->{'psgi.errors'}); - - return ['200', [ 'Content-Length' => '2' ], $io]; -}; diff --git a/test/perl/body_io_file/file b/test/perl/body_io_file/file deleted file mode 100644 index 273a402f..00000000 --- a/test/perl/body_io_file/file +++ /dev/null @@ -1 +0,0 @@ -body diff --git a/test/perl/body_io_file/psgi.pl b/test/perl/body_io_file/psgi.pl deleted file mode 100644 index 2612ae18..00000000 --- a/test/perl/body_io_file/psgi.pl +++ /dev/null @@ -1,7 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - open my $io, ' 5], $io]; -}; diff --git a/test/perl/delayed_response/psgi.pl b/test/perl/delayed_response/psgi.pl deleted file mode 100644 index f934c3a7..00000000 --- a/test/perl/delayed_response/psgi.pl +++ /dev/null @@ -1,10 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - return sub { - (my $responder = shift)->([200, [ - 'Content-Type' => 'text/plain', - 'Content-Length' => '12' - ], ["Hello World!"]]); - } -}; diff --git a/test/perl/errors_print/psgi.pl b/test/perl/errors_print/psgi.pl deleted file mode 100644 index e50ec65d..00000000 --- a/test/perl/errors_print/psgi.pl +++ /dev/null @@ -1,7 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - my $result = $environ->{'psgi.errors'}->print('Error in application'); - - return ['200', ['Content-Length' => '1'], [$result]]; -}; diff --git a/test/perl/header_equal_names/psgi.pl b/test/perl/header_equal_names/psgi.pl deleted file mode 100644 index 70bc8aa6..00000000 --- a/test/perl/header_equal_names/psgi.pl +++ /dev/null @@ -1,9 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - return ['200', [ - 'Content-Length' => 0, - 'Set-Cookie' => 'tc=one,two,three', - 'Set-Cookie' => 'tc=four,five,six' - ], []]; -}; diff --git a/test/perl/header_pairs/psgi.pl b/test/perl/header_pairs/psgi.pl deleted file mode 100644 index 63d241bc..00000000 --- a/test/perl/header_pairs/psgi.pl +++ /dev/null @@ -1,5 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - return ['200', ['Content-Length', 0, 'blah', 'blah'], []]; -}; diff --git a/test/perl/input_buffered_read/psgi.pl b/test/perl/input_buffered_read/psgi.pl deleted file mode 100644 index 4ca699d7..00000000 --- a/test/perl/input_buffered_read/psgi.pl +++ /dev/null @@ -1,17 +0,0 @@ -use FileHandle; - -my $app = sub { - my ($environ) = @_; - - $environ->{'psgi.input'}->read(my $body, 1024); - - open my $io, "<", \$body; - - # This makes $io work as FileHandle under 5.8, .10 and .11. - bless $io, 'FileHandle'; - - $environ->{'psgix.input.buffered'} = 1; - $environ->{'psgi.input'} = $io; - - return ['200', ['Content-Length' => length $body], [$body]]; -}; diff --git a/test/perl/input_close/psgi.pl b/test/perl/input_close/psgi.pl deleted file mode 100644 index 4a2d9bb9..00000000 --- a/test/perl/input_close/psgi.pl +++ /dev/null @@ -1,8 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - $environ->{'psgi.input'}->read(my $body, 1024); - $environ->{'psgi.input'}->close(); - - return ['200', ['Content-Length' => length $body], [$body]]; -}; diff --git a/test/perl/input_copy/psgi.pl b/test/perl/input_copy/psgi.pl deleted file mode 100644 index 449e4027..00000000 --- a/test/perl/input_copy/psgi.pl +++ /dev/null @@ -1,10 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - open(my $fh, ">&", $environ->{'psgi.input'}); - - my $len = int($environ->{'CONTENT_LENGTH'}); - $fh->read(my $body, $len); - - return ['200', ['Content-Length' => $len], [$body]]; -}; diff --git a/test/perl/input_read_empty/psgi.pl b/test/perl/input_read_empty/psgi.pl deleted file mode 100644 index caa894f4..00000000 --- a/test/perl/input_read_empty/psgi.pl +++ /dev/null @@ -1,7 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - $len = $environ->{'psgi.input'}->read(my $body, 1024); - - return ['200', ['Content-Length' => $len], [$body]]; -}; diff --git a/test/perl/input_read_offset/psgi.pl b/test/perl/input_read_offset/psgi.pl deleted file mode 100644 index 420b7d89..00000000 --- a/test/perl/input_read_offset/psgi.pl +++ /dev/null @@ -1,7 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - $environ->{'psgi.input'}->read(my $body, 4, 4); - - return ['200', ['Content-Length' => 4], [$body]]; -}; diff --git a/test/perl/input_read_parts/psgi.pl b/test/perl/input_read_parts/psgi.pl deleted file mode 100644 index f68ac49c..00000000 --- a/test/perl/input_read_parts/psgi.pl +++ /dev/null @@ -1,10 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - $len_1 = $environ->{'psgi.input'}->read(my $body_1, 4); - $len_2 = $environ->{'psgi.input'}->read(my $body_2, 4); - $len_3 = $environ->{'psgi.input'}->read(my $body_3, 2); - - return ['200', ['Content-Length' => $len_1 + $len_2 + $len_3], - [$body_1 . $body_2 . $body_3]]; -}; diff --git a/test/perl/query_string/psgi.pl b/test/perl/query_string/psgi.pl deleted file mode 100644 index 87ecc368..00000000 --- a/test/perl/query_string/psgi.pl +++ /dev/null @@ -1,8 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - return ['200', [ - 'Content-Length' => 0, - 'Query-String' => $environ->{'QUERY_STRING'} - ], []]; -}; diff --git a/test/perl/server_port/psgi.pl b/test/perl/server_port/psgi.pl deleted file mode 100644 index 49ef1330..00000000 --- a/test/perl/server_port/psgi.pl +++ /dev/null @@ -1,8 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - return ['200', [ - 'Content-Length' => 0, - 'Server-Port' => $environ->{'SERVER_PORT'} - ], []]; -}; diff --git a/test/perl/streaming_body/psgi.pl b/test/perl/streaming_body/psgi.pl deleted file mode 100644 index a3e54ee0..00000000 --- a/test/perl/streaming_body/psgi.pl +++ /dev/null @@ -1,13 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - return sub { - my $writer = (my $responder = shift)->([200, [ - 'Content-Type' => 'text/plain', - 'Content-Length' => '12' - ]]); - - $writer->write("Hello World!"); - $writer->close; - }; -}; diff --git a/test/perl/streaming_body_multiple_responses/psgi.pl b/test/perl/streaming_body_multiple_responses/psgi.pl deleted file mode 100644 index ffd026bd..00000000 --- a/test/perl/streaming_body_multiple_responses/psgi.pl +++ /dev/null @@ -1,11 +0,0 @@ -my $counter = 2; - -my $app = sub { - my $env = shift; - - return sub { - my $responder = shift; - $responder->([200, ['Content-Type'=>'text/plain'], [$counter++]]); - $responder->([200, ['Content-Type'=>'text/plain'], [$counter++]]); - }; -}; diff --git a/test/perl/syntax_error/psgi.pl b/test/perl/syntax_error/psgi.pl deleted file mode 100644 index 2b6dbbea..00000000 --- a/test/perl/syntax_error/psgi.pl +++ /dev/null @@ -1,5 +0,0 @@ -my $app = sub { - my ($environ) = @_ - - return ['200', [], []]; -}; diff --git a/test/perl/threads/psgi.pl b/test/perl/threads/psgi.pl deleted file mode 100644 index dce28f7d..00000000 --- a/test/perl/threads/psgi.pl +++ /dev/null @@ -1,11 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - sleep int($environ->{'HTTP_X_DELAY'}); - - return ['200', [ - 'Content-Length' => 0, - 'Psgi-Multithread' => $environ->{'psgi.multithread'}, - 'X-Thread' => $environ->{'psgi.input'} - ], []]; -}; diff --git a/test/perl/variables/psgi.pl b/test/perl/variables/psgi.pl deleted file mode 100644 index 58232c53..00000000 --- a/test/perl/variables/psgi.pl +++ /dev/null @@ -1,26 +0,0 @@ -my $app = sub { - my ($environ) = @_; - - my $len = int($environ->{'CONTENT_LENGTH'}); - $environ->{'psgi.input'}->read(my $body, $len); - - my $version = join('', @{$environ->{'psgi.version'}}); - - return ['200', [ - 'Content-Type' => $environ->{'CONTENT_TYPE'}, - 'Content-Length' => $len, - 'Request-Method' => $environ->{'REQUEST_METHOD'}, - 'Request-Uri' => $environ->{'REQUEST_URI'}, - 'Http-Host' => $environ->{'HTTP_HOST'}, - 'Server-Protocol' => $environ->{'SERVER_PROTOCOL'}, - 'Server-Software' => $environ->{'SERVER_SOFTWARE'}, - 'Custom-Header' => $environ->{'HTTP_CUSTOM_HEADER'}, - 'Psgi-Version' => $version, - 'Psgi-Url-Scheme' => $environ->{'psgi.url_scheme'}, - 'Psgi-Multithread' => $environ->{'psgi.multithread'}, - 'Psgi-Multiprocess' => $environ->{'psgi.multiprocess'}, - 'Psgi-Run-Once' => $environ->{'psgi.run_once'}, - 'Psgi-Nonblocking' => $environ->{'psgi.nonblocking'}, - 'Psgi-Streaming' => $environ->{'psgi.streaming'} - ], [$body]]; -}; diff --git a/test/php/404/404.html b/test/php/404/404.html deleted file mode 100644 index 6d0c635a..00000000 --- a/test/php/404/404.html +++ /dev/null @@ -1,6 +0,0 @@ - -404 Not Found - -

404 Not Found

- - diff --git a/test/php/404/index.php b/test/php/404/index.php deleted file mode 100644 index 561dbec2..00000000 --- a/test/php/404/index.php +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/test/php/auth/index.php b/test/php/auth/index.php deleted file mode 100644 index d77076d8..00000000 --- a/test/php/auth/index.php +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/test/php/conditional/index.php b/test/php/conditional/index.php deleted file mode 100644 index 421e1a2d..00000000 --- a/test/php/conditional/index.php +++ /dev/null @@ -1,5 +0,0 @@ - -True - -False - diff --git a/test/php/cookies/index.php b/test/php/cookies/index.php deleted file mode 100644 index 72a3f092..00000000 --- a/test/php/cookies/index.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/test/php/cwd/index.php b/test/php/cwd/index.php deleted file mode 100644 index eb2cc5b3..00000000 --- a/test/php/cwd/index.php +++ /dev/null @@ -1,20 +0,0 @@ - diff --git a/test/php/cwd/subdir/index.php b/test/php/cwd/subdir/index.php deleted file mode 100644 index 597bcac4..00000000 --- a/test/php/cwd/subdir/index.php +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/php/date_time/index.php b/test/php/date_time/index.php deleted file mode 100644 index 42992c3f..00000000 --- a/test/php/date_time/index.php +++ /dev/null @@ -1,5 +0,0 @@ -format('u'); -?> diff --git a/test/php/error_log/index.php b/test/php/error_log/index.php deleted file mode 100644 index fd90adfe..00000000 --- a/test/php/error_log/index.php +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/test/php/fastcgi_finish_request/index.php b/test/php/fastcgi_finish_request/index.php deleted file mode 100644 index fbfae71b..00000000 --- a/test/php/fastcgi_finish_request/index.php +++ /dev/null @@ -1,13 +0,0 @@ - diff --git a/test/php/fastcgi_finish_request/server.php b/test/php/fastcgi_finish_request/server.php deleted file mode 100644 index af71c5f2..00000000 --- a/test/php/fastcgi_finish_request/server.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/test/php/get_variables/index.php b/test/php/get_variables/index.php deleted file mode 100644 index d6eb7d6b..00000000 --- a/test/php/get_variables/index.php +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/test/php/header/index.php b/test/php/header/index.php deleted file mode 100644 index 1aa5ca04..00000000 --- a/test/php/header/index.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/test/php/ini_precision/index.php b/test/php/ini_precision/index.php deleted file mode 100644 index a0c5db32..00000000 --- a/test/php/ini_precision/index.php +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/test/php/ini_precision/ini/php.ini b/test/php/ini_precision/ini/php.ini deleted file mode 100644 index 51dbdede..00000000 --- a/test/php/ini_precision/ini/php.ini +++ /dev/null @@ -1 +0,0 @@ -precision = 4 diff --git a/test/php/list-extensions/index.php b/test/php/list-extensions/index.php deleted file mode 100644 index d6eb40d0..00000000 --- a/test/php/list-extensions/index.php +++ /dev/null @@ -1,11 +0,0 @@ - diff --git a/test/php/list-extensions/php.ini b/test/php/list-extensions/php.ini deleted file mode 100644 index 5848a0f2..00000000 --- a/test/php/list-extensions/php.ini +++ /dev/null @@ -1 +0,0 @@ -extension=json.so diff --git a/test/php/mirror/index.php b/test/php/mirror/index.php deleted file mode 100644 index ffd2291d..00000000 --- a/test/php/mirror/index.php +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/test/php/opcache/index.php b/test/php/opcache/index.php deleted file mode 100644 index cf67c4c2..00000000 --- a/test/php/opcache/index.php +++ /dev/null @@ -1,18 +0,0 @@ - diff --git a/test/php/opcache/preload/chdir.php b/test/php/opcache/preload/chdir.php deleted file mode 100644 index ad75e6ad..00000000 --- a/test/php/opcache/preload/chdir.php +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/test/php/opcache/preload/fastcgi_finish_request.php b/test/php/opcache/preload/fastcgi_finish_request.php deleted file mode 100644 index 31630cfa..00000000 --- a/test/php/opcache/preload/fastcgi_finish_request.php +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/test/php/opcache/test.php b/test/php/opcache/test.php deleted file mode 100644 index 147cebcd..00000000 --- a/test/php/opcache/test.php +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/php/open/index.php b/test/php/open/index.php deleted file mode 100644 index a5bebc54..00000000 --- a/test/php/open/index.php +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/test/php/open/test.txt b/test/php/open/test.txt deleted file mode 100644 index 30d74d25..00000000 --- a/test/php/open/test.txt +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file diff --git a/test/php/phpinfo/index.php b/test/php/phpinfo/index.php deleted file mode 100644 index cf608608..00000000 --- a/test/php/phpinfo/index.php +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/test/php/phpinfo/index.wrong b/test/php/phpinfo/index.wrong deleted file mode 100644 index 6c9e0678..00000000 --- a/test/php/phpinfo/index.wrong +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/test/php/post_variables/index.php b/test/php/post_variables/index.php deleted file mode 100644 index 8981d54d..00000000 --- a/test/php/post_variables/index.php +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/test/php/query_string/index.php b/test/php/query_string/index.php deleted file mode 100644 index 5691324d..00000000 --- a/test/php/query_string/index.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/test/php/script/phpinfo.php b/test/php/script/phpinfo.php deleted file mode 100644 index cf608608..00000000 --- a/test/php/script/phpinfo.php +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/test/php/targets/1.php b/test/php/targets/1.php deleted file mode 100644 index 09f7ae2c..00000000 --- a/test/php/targets/1.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/test/php/targets/2/2.php b/test/php/targets/2/2.php deleted file mode 100644 index 0c5d27c6..00000000 --- a/test/php/targets/2/2.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/test/php/targets/index.php b/test/php/targets/index.php deleted file mode 100644 index 88239d5f..00000000 --- a/test/php/targets/index.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/test/php/time_exec/index.php b/test/php/time_exec/index.php deleted file mode 100644 index 05d59d28..00000000 --- a/test/php/time_exec/index.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/test/php/variables/index.php b/test/php/variables/index.php deleted file mode 100644 index 279efc79..00000000 --- a/test/php/variables/index.php +++ /dev/null @@ -1,14 +0,0 @@ - diff --git a/test/pytest.ini b/test/pytest.ini deleted file mode 100644 index 8952e8c6..00000000 --- a/test/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -addopts = -vvv -s --print-log -python_functions = test_* diff --git a/test/python/204_no_content/asgi.py b/test/python/204_no_content/asgi.py deleted file mode 100644 index 5dbb67d0..00000000 --- a/test/python/204_no_content/asgi.py +++ /dev/null @@ -1,10 +0,0 @@ -async def application(scope, receive, send): - assert scope['type'] == 'http' - - await send( - { - 'type': 'http.response.start', - 'status': 204, - 'headers': [], - } - ) diff --git a/test/python/204_no_content/wsgi.py b/test/python/204_no_content/wsgi.py deleted file mode 100644 index 2184ffeb..00000000 --- a/test/python/204_no_content/wsgi.py +++ /dev/null @@ -1,4 +0,0 @@ -def application(environ, start_response): - - start_response('204 No Content', []) - return [] diff --git a/test/python/atexit/wsgi.py b/test/python/atexit/wsgi.py deleted file mode 100644 index b64b8477..00000000 --- a/test/python/atexit/wsgi.py +++ /dev/null @@ -1,12 +0,0 @@ -import atexit - - -def application(environ, start_response): - def at_exit(): - environ['wsgi.errors'].write('At exit called.\n') - environ['wsgi.errors'].flush() - - atexit.register(at_exit) - - start_response('200', [('Content-Length', '0')]) - return [] diff --git a/test/python/body_array/wsgi.py b/test/python/body_array/wsgi.py deleted file mode 100644 index 2390f222..00000000 --- a/test/python/body_array/wsgi.py +++ /dev/null @@ -1,3 +0,0 @@ -def application(env, start_response): - start_response('200', [('Content-Length', '10')]) - return [b'0123', b'4567', b'89'] diff --git a/test/python/body_bytearray/asgi.py b/test/python/body_bytearray/asgi.py deleted file mode 100644 index 6d2f402f..00000000 --- a/test/python/body_bytearray/asgi.py +++ /dev/null @@ -1,20 +0,0 @@ -async def application(scope, receive, send): - assert scope['type'] == 'http' - - body = b'' - while True: - m = await receive() - body += m.get('body', b'') - if not m.get('more_body', False): - body = bytearray(body) - break - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [(b'content-length', str(len(body)).encode())], - } - ) - - await send({'type': 'http.response.body', 'body': body}) diff --git a/test/python/body_generate/wsgi.py b/test/python/body_generate/wsgi.py deleted file mode 100644 index 3d12ac60..00000000 --- a/test/python/body_generate/wsgi.py +++ /dev/null @@ -1,6 +0,0 @@ -def application(env, start_response): - length = env.get('HTTP_X_LENGTH', '10') - body = b'X' * int(length) - - start_response('200', [('Content-Length', length)]) - return [body] diff --git a/test/python/body_io/wsgi.py b/test/python/body_io/wsgi.py deleted file mode 100644 index 58ce76a4..00000000 --- a/test/python/body_io/wsgi.py +++ /dev/null @@ -1,7 +0,0 @@ -import io - - -def application(env, start_response): - start_response('200', [('Content-Length', '10')]) - f = io.BytesIO(b'0123456789') - return f diff --git a/test/python/body_io_file/file b/test/python/body_io_file/file deleted file mode 100644 index 273a402f..00000000 --- a/test/python/body_io_file/file +++ /dev/null @@ -1 +0,0 @@ -body diff --git a/test/python/body_io_file/wsgi.py b/test/python/body_io_file/wsgi.py deleted file mode 100644 index 713e341b..00000000 --- a/test/python/body_io_file/wsgi.py +++ /dev/null @@ -1,4 +0,0 @@ -def application(env, start_response): - start_response('200', [('Content-Length', '5')]) - f = open('file', 'rb') - return f diff --git a/test/python/callable/wsgi.py b/test/python/callable/wsgi.py deleted file mode 100644 index 374ecb28..00000000 --- a/test/python/callable/wsgi.py +++ /dev/null @@ -1,8 +0,0 @@ -def application(env, start_response): - start_response('204', [('Content-Length', '0')]) - return [] - - -def app(env, start_response): - start_response('200', [('Content-Length', '0')]) - return [] diff --git a/test/python/chunked/wsgi.py b/test/python/chunked/wsgi.py deleted file mode 100644 index 23ee81fc..00000000 --- a/test/python/chunked/wsgi.py +++ /dev/null @@ -1,18 +0,0 @@ -def application(environ, start_response): - - content_length = int(environ.get('CONTENT_LENGTH', 0)) - body = bytes(environ['wsgi.input'].read(content_length)) - - header_transfer = environ.get('HTTP_X_TRANSFER') - header_length = environ.get('HTTP_X_LENGTH') - - headers = [] - - if header_length: - headers.append(('Content-Length', '0')) - - if header_transfer: - headers.append(('Transfer-Encoding', header_transfer)) - - start_response('200', headers) - return [body] diff --git a/test/python/client_ip/wsgi.py b/test/python/client_ip/wsgi.py deleted file mode 100644 index 0e12db0a..00000000 --- a/test/python/client_ip/wsgi.py +++ /dev/null @@ -1,4 +0,0 @@ -def application(env, start_response): - ip = env['REMOTE_ADDR'].encode() - start_response('200', [('Content-Length', str(len(ip)))]) - return ip diff --git a/test/python/close/wsgi.py b/test/python/close/wsgi.py deleted file mode 100644 index 71a5a06c..00000000 --- a/test/python/close/wsgi.py +++ /dev/null @@ -1,12 +0,0 @@ -class application: - def __init__(self, environ, start_response): - self.environ = environ - self.start = start_response - - def __iter__(self): - self.start('200', [(('Content-Length', '0'))]) - yield b'' - - def close(self): - self.environ['wsgi.errors'].write('Close called.\n') - self.environ['wsgi.errors'].flush() diff --git a/test/python/close_error/wsgi.py b/test/python/close_error/wsgi.py deleted file mode 100644 index dae12c2b..00000000 --- a/test/python/close_error/wsgi.py +++ /dev/null @@ -1,12 +0,0 @@ -class application: - def __init__(self, environ, start_response): - self.environ = environ - self.start = start_response - - def __iter__(self): - self.start('200', [(('!', '0'))]) - yield b'' - - def close(self): - self.environ['wsgi.errors'].write('Close called.\n') - self.environ['wsgi.errors'].flush() diff --git a/test/python/ctx_iter_atexit/wsgi.py b/test/python/ctx_iter_atexit/wsgi.py deleted file mode 100644 index 75d40895..00000000 --- a/test/python/ctx_iter_atexit/wsgi.py +++ /dev/null @@ -1,24 +0,0 @@ -import atexit - - -class application: - def __init__(self, environ, start_response): - self.environ = environ - self.start = start_response - - def __iter__(self): - atexit.register(self._atexit) - - content_length = int(self.environ.get('CONTENT_LENGTH', 0)) - body = bytes(self.environ['wsgi.input'].read(content_length)) - - self.start( - '200', - [ - ('Content-Length', str(len(body))), - ], - ) - yield body - - def _atexit(self): - self.start('200', [('Content-Length', '0')]) diff --git a/test/python/custom_header/wsgi.py b/test/python/custom_header/wsgi.py deleted file mode 100644 index 44fc2af5..00000000 --- a/test/python/custom_header/wsgi.py +++ /dev/null @@ -1,10 +0,0 @@ -def application(environ, start_response): - - start_response( - '200', - [ - ('Content-Length', '0'), - ('Custom-Header', environ.get('HTTP_CUSTOM_HEADER')), - ], - ) - return [] diff --git a/test/python/delayed/asgi.py b/test/python/delayed/asgi.py deleted file mode 100644 index 3c25e49a..00000000 --- a/test/python/delayed/asgi.py +++ /dev/null @@ -1,56 +0,0 @@ -import asyncio - - -async def application(scope, receive, send): - assert scope['type'] == 'http' - - body = b'' - while True: - m = await receive() - body += m.get('body', b'') - if not m.get('more_body', False): - break - - headers = scope.get('headers', []) - - def get_header(n, v=None): - for h in headers: - if h[0] == n: - return h[1] - return v - - parts = int(get_header(b'x-parts', 1)) - delay = int(get_header(b'x-delay', 0)) - - loop = asyncio.get_event_loop() - - async def sleep(n): - future = loop.create_future() - loop.call_later(n, future.set_result, None) - await future - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', str(len(body)).encode()), - ], - } - ) - - if not body: - await sleep(delay) - return - - step = int(len(body) / parts) - for i in range(0, len(body), step): - await send( - { - 'type': 'http.response.body', - 'body': body[i : i + step], - 'more_body': True, - } - ) - - await sleep(delay) diff --git a/test/python/delayed/wsgi.py b/test/python/delayed/wsgi.py deleted file mode 100644 index 3eb5a6f8..00000000 --- a/test/python/delayed/wsgi.py +++ /dev/null @@ -1,26 +0,0 @@ -import time - - -def application(environ, start_response): - parts = int(environ.get('HTTP_X_PARTS', 1)) - delay = int(environ.get('HTTP_X_DELAY', 0)) - - content_length = int(environ.get('CONTENT_LENGTH', 0)) - body = bytes(environ['wsgi.input'].read(content_length)) - - write = start_response('200', [('Content-Length', str(len(body)))]) - - if not body: - time.sleep(delay) - return [] - - step = int(len(body) / parts) - for i in range(0, len(body), step): - try: - write(body[i : i + step]) - except: - break - - time.sleep(delay) - - return [] diff --git a/test/python/empty/asgi.py b/test/python/empty/asgi.py deleted file mode 100644 index 14a40629..00000000 --- a/test/python/empty/asgi.py +++ /dev/null @@ -1,10 +0,0 @@ -async def application(scope, receive, send): - assert scope['type'] == 'http' - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [(b'content-length', b'0')], - } - ) diff --git a/test/python/empty/wsgi.py b/test/python/empty/wsgi.py deleted file mode 100644 index ce03850a..00000000 --- a/test/python/empty/wsgi.py +++ /dev/null @@ -1,3 +0,0 @@ -def application(env, start_response): - start_response('200', [('Content-Length', '0')]) - return [] diff --git a/test/python/encoding/wsgi.py b/test/python/encoding/wsgi.py deleted file mode 100644 index 0a916a9b..00000000 --- a/test/python/encoding/wsgi.py +++ /dev/null @@ -1,12 +0,0 @@ -import sys - - -def application(environ, start_response): - start_response( - '200', - [ - ('Content-Length', '0'), - ('X-Encoding', sys.getfilesystemencoding()), - ], - ) - return [] diff --git a/test/python/environment/wsgi.py b/test/python/environment/wsgi.py deleted file mode 100644 index 622b8bc0..00000000 --- a/test/python/environment/wsgi.py +++ /dev/null @@ -1,13 +0,0 @@ -import os - - -def application(env, start_response): - variables = env.get('HTTP_X_VARIABLES').split(',') - - body = ','.join( - [str(os.environ[var]) for var in variables if var in os.environ] - ) - body = body.encode() - - start_response('200', [('Content-Length', str(len(body)))]) - return body diff --git a/test/python/errors_write/wsgi.py b/test/python/errors_write/wsgi.py deleted file mode 100644 index 148bce9e..00000000 --- a/test/python/errors_write/wsgi.py +++ /dev/null @@ -1,6 +0,0 @@ -def application(environ, start_response): - environ['wsgi.errors'].write('Error in application.') - environ['wsgi.errors'].flush() - - start_response('200', [('Content-Length', '0')]) - return [] diff --git a/test/python/forwarded_header/wsgi.py b/test/python/forwarded_header/wsgi.py deleted file mode 100644 index 44d370ab..00000000 --- a/test/python/forwarded_header/wsgi.py +++ /dev/null @@ -1,10 +0,0 @@ -def application(env, start_response): - start_response( - '200', - [ - ('Content-Length', '0'), - ('Remote-Addr', env.get('REMOTE_ADDR')), - ('Url-Scheme', env.get('wsgi.url_scheme')), - ], - ) - return [] diff --git a/test/python/header_fields/wsgi.py b/test/python/header_fields/wsgi.py deleted file mode 100644 index 41144528..00000000 --- a/test/python/header_fields/wsgi.py +++ /dev/null @@ -1,8 +0,0 @@ -def application(environ, start_response): - - h = (k for k, v in environ.items() if k.startswith('HTTP_')) - - start_response( - '200', [('Content-Length', '0'), ('All-Headers', ','.join(h))] - ) - return [] diff --git a/test/python/host/wsgi.py b/test/python/host/wsgi.py deleted file mode 100644 index 0a08bc36..00000000 --- a/test/python/host/wsgi.py +++ /dev/null @@ -1,10 +0,0 @@ -def application(env, start_response): - start_response( - '200', - [ - ('Content-Length', '0'), - ('X-Server-Name', env.get('SERVER_NAME')), - ('X-Http-Host', str(env.get('HTTP_HOST'))), - ], - ) - return [] diff --git a/test/python/input_iter/wsgi.py b/test/python/input_iter/wsgi.py deleted file mode 100644 index 04a6a06c..00000000 --- a/test/python/input_iter/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -def application(environ, start_response): - body = [] - content_length = 0 - - for l in environ['wsgi.input'].__iter__(): - body.append(l) - content_length += len(l) - - start_response( - '200', - [ - ('Content-Length', str(content_length)), - ('X-Lines-Count', str(len(body))), - ], - ) - return body diff --git a/test/python/input_read_length/wsgi.py b/test/python/input_read_length/wsgi.py deleted file mode 100644 index 9d209556..00000000 --- a/test/python/input_read_length/wsgi.py +++ /dev/null @@ -1,7 +0,0 @@ -def application(environ, start_response): - - input_length = int(environ.get('HTTP_INPUT_LENGTH')) - body = bytes(environ['wsgi.input'].read(input_length)) - - start_response('200', [('Content-Length', str(len(body)))]) - return [body] diff --git a/test/python/input_readline/wsgi.py b/test/python/input_readline/wsgi.py deleted file mode 100644 index ec42e0c8..00000000 --- a/test/python/input_readline/wsgi.py +++ /dev/null @@ -1,20 +0,0 @@ -def application(environ, start_response): - body = [] - content_length = 0 - - while True: - l = environ['wsgi.input'].readline() - if not l: - break - - body.append(l) - content_length += len(l) - - start_response( - '200', - [ - ('Content-Length', str(content_length)), - ('X-Lines-Count', str(len(body))), - ], - ) - return body diff --git a/test/python/input_readline_size/wsgi.py b/test/python/input_readline_size/wsgi.py deleted file mode 100644 index bde8c0d4..00000000 --- a/test/python/input_readline_size/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -def application(environ, start_response): - body = [] - - while True: - l = environ['wsgi.input'].readline(9) - if not l: - break - - body.append(l) - - if len(l) > 9: - body.append(f'len(l) > 9: {l}'.encode()) - break - - start_response('200', [('X-Lines-Count', str(len(body)))]) - return body diff --git a/test/python/input_readlines/wsgi.py b/test/python/input_readlines/wsgi.py deleted file mode 100644 index 64b03d79..00000000 --- a/test/python/input_readlines/wsgi.py +++ /dev/null @@ -1,5 +0,0 @@ -def application(environ, start_response): - body = environ['wsgi.input'].readlines() - - start_response('200', [('X-Lines-Count', str(len(body)))]) - return body diff --git a/test/python/iter_exception/wsgi.py b/test/python/iter_exception/wsgi.py deleted file mode 100644 index 66a09af7..00000000 --- a/test/python/iter_exception/wsgi.py +++ /dev/null @@ -1,45 +0,0 @@ -class application: - def __init__(self, environ, start_response): - self.environ = environ - self.start = start_response - - self.next = self.__next__ - - def __iter__(self): - self.__i = 0 - self._skip_level = int(self.environ.get('HTTP_X_SKIP', 0)) - self._not_skip_close = int(self.environ.get('HTTP_X_NOT_SKIP_CLOSE', 0)) - self._is_chunked = self.environ.get('HTTP_X_CHUNKED') - - headers = [(('Content-Length', '10'))] - if self._is_chunked is not None: - headers = [] - - if self._skip_level < 1: - raise Exception('first exception') - - write = self.start('200', headers) - - if self._skip_level < 2: - raise Exception('second exception') - - write(b'XXXXX') - - if self._skip_level < 3: - raise Exception('third exception') - - return self - - def __next__(self): - if self._skip_level < 4: - raise Exception('next exception') - - self.__i += 1 - if self.__i > 2: - raise StopIteration - - return b'X' - - def close(self): - if self._not_skip_close == 1: - raise Exception('close exception') diff --git a/test/python/legacy/asgi.py b/test/python/legacy/asgi.py deleted file mode 100644 index 8be8932e..00000000 --- a/test/python/legacy/asgi.py +++ /dev/null @@ -1,16 +0,0 @@ -def application(scope): - assert scope['type'] == 'http' - - return app_http - - -async def app_http(receive, send): - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - ], - } - ) diff --git a/test/python/legacy_force/asgi.py b/test/python/legacy_force/asgi.py deleted file mode 100644 index 56c7061d..00000000 --- a/test/python/legacy_force/asgi.py +++ /dev/null @@ -1,19 +0,0 @@ -def application(scope, receive=None, send=None): - assert scope['type'] == 'http' - - if receive is None and send is None: - return app_http - - return app_http(receive, send) - - -async def app_http(receive, send): - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - ], - } - ) diff --git a/test/python/lifespan/empty/asgi.py b/test/python/lifespan/empty/asgi.py deleted file mode 100644 index 2071e6e0..00000000 --- a/test/python/lifespan/empty/asgi.py +++ /dev/null @@ -1,37 +0,0 @@ -import os - - -async def handler(prefix, scope, receive, send): - if scope['type'] == 'lifespan': - with open(f'{prefix}version', 'w+', encoding='utf-8') as f: - f.write( - f"{scope['asgi']['version']} {scope['asgi']['spec_version']}" - ) - while True: - message = await receive() - if message['type'] == 'lifespan.startup': - os.remove(f'{prefix}startup') - await send({'type': 'lifespan.startup.complete'}) - elif message['type'] == 'lifespan.shutdown': - os.remove(f'{prefix}shutdown') - await send({'type': 'lifespan.shutdown.complete'}) - return - - if scope['type'] == 'http': - await send( - { - 'type': 'http.response.start', - 'status': 204, - 'headers': [ - (b'content-length', b'0'), - ], - } - ) - - -async def application(scope, receive, send): - return await handler('', scope, receive, send) - - -async def application2(scope, receive, send): - return await handler('app2_', scope, receive, send) diff --git a/test/python/lifespan/error/asgi.py b/test/python/lifespan/error/asgi.py deleted file mode 100644 index 509cb3ee..00000000 --- a/test/python/lifespan/error/asgi.py +++ /dev/null @@ -1,3 +0,0 @@ -async def application(scope, receive, send): - if scope['type'] != 'http': - raise Exception('Exception blah') diff --git a/test/python/lifespan/error_auto/asgi.py b/test/python/lifespan/error_auto/asgi.py deleted file mode 100644 index 90d506a1..00000000 --- a/test/python/lifespan/error_auto/asgi.py +++ /dev/null @@ -1,2 +0,0 @@ -async def application(scope, receive, send): - assert scope['type'] == 'http' diff --git a/test/python/lifespan/failed/asgi.py b/test/python/lifespan/failed/asgi.py deleted file mode 100644 index fbd006f9..00000000 --- a/test/python/lifespan/failed/asgi.py +++ /dev/null @@ -1,11 +0,0 @@ -async def application(scope, receive, send): - if scope['type'] == 'lifespan': - while True: - message = await receive() - if message['type'] == 'lifespan.startup': - await send({"type": "lifespan.startup.failed"}) - raise Exception('Exception blah') - - if message['type'] == 'lifespan.shutdown': - await send({'type': 'lifespan.shutdown.complete'}) - return diff --git a/test/python/log_body/wsgi.py b/test/python/log_body/wsgi.py deleted file mode 100644 index 0ec07a68..00000000 --- a/test/python/log_body/wsgi.py +++ /dev/null @@ -1,9 +0,0 @@ -def application(environ, start_response): - content_length = int(environ.get('CONTENT_LENGTH', 0)) - body = bytes(environ['wsgi.input'].read(content_length)) - - environ['wsgi.errors'].write(body.decode()) - environ['wsgi.errors'].flush() - - start_response('200', [('Content-Length', '0')]) - return [] diff --git a/test/python/mirror/asgi.py b/test/python/mirror/asgi.py deleted file mode 100644 index 18a66a4c..00000000 --- a/test/python/mirror/asgi.py +++ /dev/null @@ -1,19 +0,0 @@ -async def application(scope, receive, send): - assert scope['type'] == 'http' - - body = b'' - while True: - m = await receive() - body += m.get('body', b'') - if not m.get('more_body', False): - break - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [(b'content-length', str(len(body)).encode())], - } - ) - - await send({'type': 'http.response.body', 'body': body}) diff --git a/test/python/mirror/wsgi.py b/test/python/mirror/wsgi.py deleted file mode 100644 index 3cd95437..00000000 --- a/test/python/mirror/wsgi.py +++ /dev/null @@ -1,7 +0,0 @@ -def application(environ, start_response): - - content_length = int(environ.get('CONTENT_LENGTH', 0)) - body = bytes(environ['wsgi.input'].read(content_length)) - - start_response('200', [('Content-Length', str(len(body)))]) - return [body] diff --git a/test/python/not_iterable/wsgi.py b/test/python/not_iterable/wsgi.py deleted file mode 100644 index ad24cca9..00000000 --- a/test/python/not_iterable/wsgi.py +++ /dev/null @@ -1,7 +0,0 @@ -class application: - def __init__(self, environ, start_response): - self.environ = environ - self.start = start_response - - def __iter__(self): - self.start('200', [(('Content-Length', '0'))]) diff --git a/test/python/ns_inspect/wsgi.py b/test/python/ns_inspect/wsgi.py deleted file mode 100644 index fa1222e4..00000000 --- a/test/python/ns_inspect/wsgi.py +++ /dev/null @@ -1,31 +0,0 @@ -import json -import os - -try: - # Python 3 - from urllib.parse import parse_qs -except ImportError: - # Python 2 - from urlparse import parse_qs - - -def application(environ, start_response): - ret = { - 'FileExists': False, - } - - d = parse_qs(environ['QUERY_STRING']) - - ret['FileExists'] = os.path.exists(d.get('path')[0]) - - out = json.dumps(ret) - - start_response( - '200', - [ - ('Content-Type', 'application/json'), - ('Content-Length', str(len(out))), - ], - ) - - return out.encode('utf-8') diff --git a/test/python/path/wsgi.py b/test/python/path/wsgi.py deleted file mode 100644 index da7e1ff1..00000000 --- a/test/python/path/wsgi.py +++ /dev/null @@ -1,9 +0,0 @@ -import os -import sys - - -def application(environ, start_response): - body = os.pathsep.join(sys.path).encode() - - start_response('200', [('Content-Length', str(len(body)))]) - return [body] diff --git a/test/python/prefix/asgi.py b/test/python/prefix/asgi.py deleted file mode 100644 index 234f084f..00000000 --- a/test/python/prefix/asgi.py +++ /dev/null @@ -1,15 +0,0 @@ -async def application(scope, receive, send): - assert scope['type'] == 'http' - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - (b'prefix', scope.get('root_path', 'NULL').encode()), - ], - } - ) - - await send({'type': 'http.response.body', 'body': b''}) diff --git a/test/python/prefix/wsgi.py b/test/python/prefix/wsgi.py deleted file mode 100644 index 83b58c9a..00000000 --- a/test/python/prefix/wsgi.py +++ /dev/null @@ -1,10 +0,0 @@ -def application(environ, start_response): - start_response( - '200', - [ - ('Content-Length', '0'), - ('Script-Name', environ.get('SCRIPT_NAME', 'NULL')), - ('Path-Info', environ['PATH_INFO']), - ], - ) - return [] diff --git a/test/python/query_string/asgi.py b/test/python/query_string/asgi.py deleted file mode 100644 index 5b659f9c..00000000 --- a/test/python/query_string/asgi.py +++ /dev/null @@ -1,13 +0,0 @@ -async def application(scope, receive, send): - assert scope['type'] == 'http' - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - (b'query-string', scope['query_string']), - ], - } - ) diff --git a/test/python/query_string/wsgi.py b/test/python/query_string/wsgi.py deleted file mode 100644 index 54a67b03..00000000 --- a/test/python/query_string/wsgi.py +++ /dev/null @@ -1,10 +0,0 @@ -def application(environ, start_response): - - start_response( - '200', - [ - ('Content-Length', '0'), - ('Query-String', environ.get('QUERY_STRING')), - ], - ) - return [] diff --git a/test/python/restart/longstart.py b/test/python/restart/longstart.py deleted file mode 100644 index 3bc383b7..00000000 --- a/test/python/restart/longstart.py +++ /dev/null @@ -1,11 +0,0 @@ -import os -import time - -time.sleep(2) - - -def application(environ, start_response): - body = str(os.getpid()).encode() - - start_response('200', [('Content-Length', str(len(body)))]) - return [body] diff --git a/test/python/restart/v1.py b/test/python/restart/v1.py deleted file mode 100644 index 08f7dd64..00000000 --- a/test/python/restart/v1.py +++ /dev/null @@ -1,5 +0,0 @@ -def application(environ, start_response): - body = "v1".encode() - - start_response('200', [('Content-Length', str(len(body)))]) - return [body] diff --git a/test/python/restart/v2.py b/test/python/restart/v2.py deleted file mode 100644 index 163d0d17..00000000 --- a/test/python/restart/v2.py +++ /dev/null @@ -1,5 +0,0 @@ -def application(environ, start_response): - body = "v2".encode() - - start_response('200', [('Content-Length', str(len(body)))]) - return [body] diff --git a/test/python/server_port/asgi.py b/test/python/server_port/asgi.py deleted file mode 100644 index 810a182c..00000000 --- a/test/python/server_port/asgi.py +++ /dev/null @@ -1,13 +0,0 @@ -async def application(scope, receive, send): - assert scope['type'] == 'http' - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - (b'server-port', str(scope['server'][1]).encode()), - ], - } - ) diff --git a/test/python/server_port/wsgi.py b/test/python/server_port/wsgi.py deleted file mode 100644 index c796da95..00000000 --- a/test/python/server_port/wsgi.py +++ /dev/null @@ -1,7 +0,0 @@ -def application(environ, start_response): - - start_response( - '200', - [('Content-Length', '0'), ('Server-Port', environ.get('SERVER_PORT'))], - ) - return [] diff --git a/test/python/start_response_exit/wsgi.py b/test/python/start_response_exit/wsgi.py deleted file mode 100644 index 37c3acfe..00000000 --- a/test/python/start_response_exit/wsgi.py +++ /dev/null @@ -1,4 +0,0 @@ -def application(env, start_response): - start_response('200', [('Content-Length', '1')]) - exit() - return [b'X'] diff --git a/test/python/syntax_error/wsgi.py b/test/python/syntax_error/wsgi.py deleted file mode 100644 index 0ac759de..00000000 --- a/test/python/syntax_error/wsgi.py +++ /dev/null @@ -1,3 +0,0 @@ -def application(env, start_response) - start_response('200', [('Content-Length', '0')]) - return [] diff --git a/test/python/targets/asgi.py b/test/python/targets/asgi.py deleted file mode 100644 index 749ec5b1..00000000 --- a/test/python/targets/asgi.py +++ /dev/null @@ -1,71 +0,0 @@ -async def application_201(scope, receive, send): - assert scope['type'] == 'http' - - await send( - { - 'type': 'http.response.start', - 'status': 201, - 'headers': [(b'content-length', b'0')], - } - ) - - -async def application_200(scope, receive, send): - assert scope['type'] == 'http' - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [(b'content-length', b'0')], - } - ) - - -async def application_prefix(scope, receive, send): - assert scope['type'] == 'http' - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - (b'prefix', scope.get('root_path', 'NULL').encode()), - ], - } - ) - - await send({'type': 'http.response.body', 'body': b''}) - - -def legacy_application_200(scope): - assert scope['type'] == 'http' - - return legacy_app_http_200 - - -async def legacy_app_http_200(receive, send): - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [(b'content-length', b'0')], - } - ) - - -def legacy_application_201(scope, receive=None, send=None): - assert scope['type'] == 'http' - - return legacy_app_http_201 - - -async def legacy_app_http_201(receive, send): - await send( - { - 'type': 'http.response.start', - 'status': 201, - 'headers': [(b'content-length', b'0')], - } - ) diff --git a/test/python/targets/wsgi.py b/test/python/targets/wsgi.py deleted file mode 100644 index 30a50efd..00000000 --- a/test/python/targets/wsgi.py +++ /dev/null @@ -1,14 +0,0 @@ -def wsgi_target_a(env, start_response): - start_response('200', [('Content-Length', '1')]) - return [b'1'] - - -def wsgi_target_b(env, start_response): - start_response('200', [('Content-Length', '1')]) - return [b'2'] - - -def wsgi_target_prefix(env, start_response): - data = f"{env.get('SCRIPT_NAME', 'No Script Name')} {env['PATH_INFO']}" - start_response('200', [('Content-Length', f'{data}')]) - return [data.encode('utf-8')] diff --git a/test/python/threading/asgi.py b/test/python/threading/asgi.py deleted file mode 100644 index aa9b76cf..00000000 --- a/test/python/threading/asgi.py +++ /dev/null @@ -1,39 +0,0 @@ -import sys -import threading -import time - - -class Foo(threading.Thread): - num = 10 - - def __init__(self, x): - self.__x = x - threading.Thread.__init__(self) - - def log_index(self, index): - sys.stderr.write(f'({index}) Thread: {self.__x}\n') - sys.stderr.flush() - - def run(self): - i = 0 - for _ in range(3): - self.log_index(i) - i += 1 - time.sleep(1) - self.log_index(i) - i += 1 - - -async def application(scope, receive, send): - assert scope['type'] == 'http' - - Foo(Foo.num).start() - Foo.num += 10 - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [(b'content-length', b'0')], - } - ) diff --git a/test/python/threading/wsgi.py b/test/python/threading/wsgi.py deleted file mode 100644 index afba674b..00000000 --- a/test/python/threading/wsgi.py +++ /dev/null @@ -1,31 +0,0 @@ -import sys -import threading -import time - - -class Foo(threading.Thread): - num = 10 - - def __init__(self, x): - self.__x = x - threading.Thread.__init__(self) - - def log_index(self, index): - sys.stderr.write(f'({index}) Thread: {self.__x}\n') - sys.stderr.flush() - - def run(self): - i = 0 - for _ in range(3): - self.log_index(i) - i += 1 - time.sleep(1) - self.log_index(i) - i += 1 - - -def application(environ, start_response): - Foo(Foo.num).start() - Foo.num += 10 - start_response('200 OK', [('Content-Length', '0')]) - return [] diff --git a/test/python/threads/asgi.py b/test/python/threads/asgi.py deleted file mode 100644 index 0537f59b..00000000 --- a/test/python/threads/asgi.py +++ /dev/null @@ -1,29 +0,0 @@ -import threading -import time - - -async def application(scope, receive, send): - assert scope['type'] == 'http' - - headers = scope.get('headers', []) - - def get_header(n, v=None): - for h in headers: - if h[0] == n: - return h[1] - return v - - delay = float(get_header(b'x-delay', 0)) - - time.sleep(delay) - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-length', b'0'), - (b'x-thread', str(threading.currentThread().ident).encode()), - ], - } - ) diff --git a/test/python/threads/wsgi.py b/test/python/threads/wsgi.py deleted file mode 100644 index 35db2d07..00000000 --- a/test/python/threads/wsgi.py +++ /dev/null @@ -1,19 +0,0 @@ -import threading -import time - - -def application(environ, start_response): - delay = float(environ.get('HTTP_X_DELAY', 0)) - - time.sleep(delay) - - start_response( - '200', - [ - ('Content-Length', '0'), - ('Wsgi-Multithread', str(environ['wsgi.multithread'])), - ('X-Thread', str(threading.currentThread().ident)), - ], - ) - - return [] diff --git a/test/python/unicode/wsgi.py b/test/python/unicode/wsgi.py deleted file mode 100644 index 8c9a59dd..00000000 --- a/test/python/unicode/wsgi.py +++ /dev/null @@ -1,8 +0,0 @@ -def application(environ, start_response): - temp_dir = environ.get('HTTP_TEMP_DIR') - - with open(f'{temp_dir}/tempfile', 'w', encoding='utf-8') as f: - f.write('\u26a0\ufe0f') - - start_response('200', [('Content-Length', '0')]) - return [] diff --git a/test/python/upload/wsgi.py b/test/python/upload/wsgi.py deleted file mode 100644 index 2c820d06..00000000 --- a/test/python/upload/wsgi.py +++ /dev/null @@ -1,29 +0,0 @@ -import cgi -from tempfile import TemporaryFile - - -def read(environ): - length = int(environ.get('CONTENT_LENGTH', 0)) - - body = TemporaryFile(mode='w+b') - body.write(bytes(environ['wsgi.input'].read(length))) - body.seek(0) - - environ['wsgi.input'] = body - return body - - -def application(environ, start_response): - file = read(environ) - - form = cgi.FieldStorage(fp=file, environ=environ, keep_blank_values=True) - - filename = form['file'].filename - data = filename.encode() + form['file'].file.read() - - start_response( - '200 OK', - [('Content-Type', 'text/plain'), ('Content-Length', str(len(data)))], - ) - - return data diff --git a/test/python/user_group/wsgi.py b/test/python/user_group/wsgi.py deleted file mode 100644 index 8f3ba50d..00000000 --- a/test/python/user_group/wsgi.py +++ /dev/null @@ -1,24 +0,0 @@ -import json -import os - - -def application(environ, start_response): - uid = os.geteuid() - gid = os.getegid() - - out = json.dumps( - { - 'UID': uid, - 'GID': gid, - } - ).encode('utf-8') - - start_response( - '200 OK', - [ - ('Content-Length', str(len(out))), - ('Content-Type', 'application/json'), - ], - ) - - return [out] diff --git a/test/python/variables/asgi.py b/test/python/variables/asgi.py deleted file mode 100644 index 5a4f55e8..00000000 --- a/test/python/variables/asgi.py +++ /dev/null @@ -1,39 +0,0 @@ -async def application(scope, receive, send): - assert scope['type'] == 'http' - - body = b'' - while True: - m = await receive() - body += m.get('body', b'') - if not m.get('more_body', False): - break - - headers = scope.get('headers', []) - - def get_header(n): - res = [] - for h in headers: - if h[0] == n: - res.append(h[1]) - return b', '.join(res) - - await send( - { - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - (b'content-type', get_header(b'content-type')), - (b'content-length', str(len(body)).encode()), - (b'request-method', scope['method'].encode()), - (b'request-uri', scope['path'].encode()), - (b'http-host', get_header(b'host')), - (b'http-version', scope['http_version'].encode()), - (b'asgi-version', scope['asgi']['version'].encode()), - (b'asgi-spec-version', scope['asgi']['spec_version'].encode()), - (b'scheme', scope['scheme'].encode()), - (b'custom-header', get_header(b'custom-header')), - ], - } - ) - - await send({'type': 'http.response.body', 'body': body}) diff --git a/test/python/variables/wsgi.py b/test/python/variables/wsgi.py deleted file mode 100644 index 5d77902d..00000000 --- a/test/python/variables/wsgi.py +++ /dev/null @@ -1,24 +0,0 @@ -def application(environ, start_response): - - content_length = int(environ.get('CONTENT_LENGTH', 0)) - body = bytes(environ['wsgi.input'].read(content_length)) - - start_response( - '200', - [ - ('Content-Type', environ.get('CONTENT_TYPE')), - ('Content-Length', str(len(body))), - ('Request-Method', environ.get('REQUEST_METHOD')), - ('Request-Uri', environ.get('REQUEST_URI')), - ('Http-Host', environ.get('HTTP_HOST')), - ('Server-Protocol', environ.get('SERVER_PROTOCOL')), - ('Server-Software', environ.get('SERVER_SOFTWARE')), - ('Custom-Header', environ.get('HTTP_CUSTOM_HEADER')), - ('Wsgi-Version', str(environ['wsgi.version'])), - ('Wsgi-Url-Scheme', environ['wsgi.url_scheme']), - ('Wsgi-Multithread', str(environ['wsgi.multithread'])), - ('Wsgi-Multiprocess', str(environ['wsgi.multiprocess'])), - ('Wsgi-Run-Once', str(environ['wsgi.run_once'])), - ], - ) - return [body] diff --git a/test/python/websockets/mirror/asgi.py b/test/python/websockets/mirror/asgi.py deleted file mode 100644 index 72a32d67..00000000 --- a/test/python/websockets/mirror/asgi.py +++ /dev/null @@ -1,18 +0,0 @@ -async def application(scope, receive, send): - if scope['type'] == 'websocket': - while True: - m = await receive() - if m['type'] == 'websocket.connect': - await send({'type': 'websocket.accept'}) - - if m['type'] == 'websocket.receive': - await send( - { - 'type': 'websocket.send', - 'bytes': m.get('bytes', None), - 'text': m.get('text', None), - } - ) - - if m['type'] == 'websocket.disconnect': - break diff --git a/test/python/websockets/subprotocol/asgi.py b/test/python/websockets/subprotocol/asgi.py deleted file mode 100644 index 0385bb9d..00000000 --- a/test/python/websockets/subprotocol/asgi.py +++ /dev/null @@ -1,29 +0,0 @@ -async def application(scope, receive, send): - assert scope['type'] == 'websocket' - - while True: - m = await receive() - if m['type'] == 'websocket.connect': - subprotocols = scope['subprotocols'] - - await send( - { - 'type': 'websocket.accept', - 'headers': [ - (b'x-subprotocols', str(subprotocols).encode()), - ], - 'subprotocol': subprotocols[0], - } - ) - - if m['type'] == 'websocket.receive': - await send( - { - 'type': 'websocket.send', - 'bytes': m.get('bytes', None), - 'text': m.get('text', None), - } - ) - - if m['type'] == 'websocket.disconnect': - break diff --git a/test/python/write/wsgi.py b/test/python/write/wsgi.py deleted file mode 100644 index 6c90b014..00000000 --- a/test/python/write/wsgi.py +++ /dev/null @@ -1,5 +0,0 @@ -def application(env, start_response): - write = start_response('200', [('Content-Length', '10')]) - write(b'012') - write(b'345') - return b'6789' diff --git a/test/requirements.txt b/test/requirements.txt deleted file mode 100644 index 5f94fad2..00000000 --- a/test/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pyOpenSSL>=20.0.1 -pytest>=6.0.1 diff --git a/test/ruby/at_exit/config.ru b/test/ruby/at_exit/config.ru deleted file mode 100644 index 0e2c40c6..00000000 --- a/test/ruby/at_exit/config.ru +++ /dev/null @@ -1,8 +0,0 @@ -app = Proc.new do |env| - at_exit do - env['rack.errors'].puts('At exit called.') - end - ['200', {'Content-Length' => '0'}, ['']] -end - -run app diff --git a/test/ruby/body_array/config.ru b/test/ruby/body_array/config.ru deleted file mode 100644 index 05dcc760..00000000 --- a/test/ruby/body_array/config.ru +++ /dev/null @@ -1,5 +0,0 @@ -app = Proc.new do |env| - ['200', {'Content-Length' => '10'}, ['0123', '4567', '89']] -end - -run app diff --git a/test/ruby/body_each_error/config.ru b/test/ruby/body_each_error/config.ru deleted file mode 100644 index 0d34603d..00000000 --- a/test/ruby/body_each_error/config.ru +++ /dev/null @@ -1,6 +0,0 @@ -app = Proc.new do |env| - io = IO.new(0, 'r') - ['200', {'Content-Length' => '0'}, io] -end - -run app diff --git a/test/ruby/body_empty/config.ru b/test/ruby/body_empty/config.ru deleted file mode 100644 index a8684b9b..00000000 --- a/test/ruby/body_empty/config.ru +++ /dev/null @@ -1,5 +0,0 @@ -app = Proc.new do |env| - ['200', {}, []] -end - -run app diff --git a/test/ruby/body_file/config.ru b/test/ruby/body_file/config.ru deleted file mode 100644 index 2b229699..00000000 --- a/test/ruby/body_file/config.ru +++ /dev/null @@ -1,6 +0,0 @@ -app = Proc.new do |env| - file = File.open('file', 'r') - ['200', {'Content-Length' => '5'}, file] -end - -run app diff --git a/test/ruby/body_file/file b/test/ruby/body_file/file deleted file mode 100644 index 273a402f..00000000 --- a/test/ruby/body_file/file +++ /dev/null @@ -1 +0,0 @@ -body diff --git a/test/ruby/constants/config.ru b/test/ruby/constants/config.ru deleted file mode 100644 index e0951bf4..00000000 --- a/test/ruby/constants/config.ru +++ /dev/null @@ -1,15 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'X-Copyright' => RUBY_COPYRIGHT, - 'X-Description' => RUBY_DESCRIPTION, - 'X-Engine' => RUBY_ENGINE, - 'X-Engine-Version' => RUBY_ENGINE_VERSION, - 'X-Patchlevel' => RUBY_PATCHLEVEL.to_s, - 'X-Platform' => RUBY_PLATFORM, - 'X-Release-Date' => RUBY_RELEASE_DATE, - 'X-Revision' => RUBY_REVISION.to_s, - 'X-Version' => RUBY_VERSION, - }, []] -end - -run app diff --git a/test/ruby/empty/config.ru b/test/ruby/empty/config.ru deleted file mode 100644 index eeeab5d3..00000000 --- a/test/ruby/empty/config.ru +++ /dev/null @@ -1,9 +0,0 @@ -app = Proc.new do |env| - body = env['rack.input'].gets - #body += env['rack.input'].gets - ['200', { - 'Content-Length' => body.length.to_s - }, [body]] -end - -run app diff --git a/test/ruby/encoding/config.ru b/test/ruby/encoding/config.ru deleted file mode 100644 index 60bf0efa..00000000 --- a/test/ruby/encoding/config.ru +++ /dev/null @@ -1,8 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'Content-Length' => '0', - 'X-Enc' => Encoding.default_external.to_s, - }, ['']] -end - -run app diff --git a/test/ruby/errors_puts/config.ru b/test/ruby/errors_puts/config.ru deleted file mode 100644 index 75d0d87e..00000000 --- a/test/ruby/errors_puts/config.ru +++ /dev/null @@ -1,6 +0,0 @@ -app = Proc.new do |env| - env['rack.errors'].puts('Error in application') - ['200', {'Content-Length' => '0'}, ['']] -end - -run app diff --git a/test/ruby/errors_puts_int/config.ru b/test/ruby/errors_puts_int/config.ru deleted file mode 100644 index bc1e664a..00000000 --- a/test/ruby/errors_puts_int/config.ru +++ /dev/null @@ -1,6 +0,0 @@ -app = Proc.new do |env| - env['rack.errors'].puts(1234567890) - ['200', {'Content-Length' => '0'}, ['']] -end - -run app diff --git a/test/ruby/errors_write/config.ru b/test/ruby/errors_write/config.ru deleted file mode 100644 index 79ee4d1d..00000000 --- a/test/ruby/errors_write/config.ru +++ /dev/null @@ -1,8 +0,0 @@ -app = Proc.new do |env| - env['rack.errors'].write('Error in application') - env['rack.errors'].flush - env['rack.errors'].close - ['200', {'Content-Length' => '0'}, ['']] -end - -run app diff --git a/test/ruby/errors_write_int/config.ru b/test/ruby/errors_write_int/config.ru deleted file mode 100644 index 55d6c9d3..00000000 --- a/test/ruby/errors_write_int/config.ru +++ /dev/null @@ -1,6 +0,0 @@ -app = Proc.new do |env| - env['rack.errors'].write(1234567890) - ['200', {'Content-Length' => '0'}, ['']] -end - -run app diff --git a/test/ruby/errors_write_to_s_custom/config.ru b/test/ruby/errors_write_to_s_custom/config.ru deleted file mode 100644 index 9eb06d1a..00000000 --- a/test/ruby/errors_write_to_s_custom/config.ru +++ /dev/null @@ -1,15 +0,0 @@ -app = Proc.new do |env| - - class Custom - def to_s() - nil - end - end - - e = Custom.new() - - env['rack.errors'].write(e) - ['200', {'Content-Length' => '0'}, ['']] -end - -run app diff --git a/test/ruby/header_array/config.ru b/test/ruby/header_array/config.ru deleted file mode 100644 index 6401ab4b..00000000 --- a/test/ruby/header_array/config.ru +++ /dev/null @@ -1,7 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'x-array' => ['name=value', '', 'value', 'av'], - }, []] -end - -run app diff --git a/test/ruby/header_array_empty/config.ru b/test/ruby/header_array_empty/config.ru deleted file mode 100644 index df40ffdd..00000000 --- a/test/ruby/header_array_empty/config.ru +++ /dev/null @@ -1,7 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'x-array' => [], - }, []] -end - -run app diff --git a/test/ruby/header_array_nil/config.ru b/test/ruby/header_array_nil/config.ru deleted file mode 100644 index 04550c8d..00000000 --- a/test/ruby/header_array_nil/config.ru +++ /dev/null @@ -1,7 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'x-array' => [nil], - }, []] -end - -run app diff --git a/test/ruby/header_custom/config.ru b/test/ruby/header_custom/config.ru deleted file mode 100644 index 8570fd2b..00000000 --- a/test/ruby/header_custom/config.ru +++ /dev/null @@ -1,8 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'Content-Length' => '0', - 'Custom-Header' => env['rack.input'].read - }, []] -end - -run app diff --git a/test/ruby/header_rack/config.ru b/test/ruby/header_rack/config.ru deleted file mode 100644 index 40f53249..00000000 --- a/test/ruby/header_rack/config.ru +++ /dev/null @@ -1,8 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'Content-Length' => '0', - 'rack.header' => 'hello' - }, ['']] -end - -run app diff --git a/test/ruby/header_status/config.ru b/test/ruby/header_status/config.ru deleted file mode 100644 index 29f038c2..00000000 --- a/test/ruby/header_status/config.ru +++ /dev/null @@ -1,8 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'Content-Length' => '0', - 'Status' => '200' - }, []] -end - -run app diff --git a/test/ruby/hooks/config.ru b/test/ruby/hooks/config.ru deleted file mode 100644 index f3069558..00000000 --- a/test/ruby/hooks/config.ru +++ /dev/null @@ -1,7 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'Content-Length' => '0' - }, ['']] -end - -run app diff --git a/test/ruby/hooks/eval.rb b/test/ruby/hooks/eval.rb deleted file mode 100644 index ce7329c1..00000000 --- a/test/ruby/hooks/eval.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'securerandom' - -File.write("./cookie_eval.#{SecureRandom.hex}", "evaluated") diff --git a/test/ruby/hooks/multiple.rb b/test/ruby/hooks/multiple.rb deleted file mode 100644 index b1b659a5..00000000 --- a/test/ruby/hooks/multiple.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'securerandom' - -@mutex = Mutex.new - -on_worker_boot do - File.write("./cookie_worker_boot.#{SecureRandom.hex}", "worker booted") -end - -on_thread_boot do - @mutex.synchronize do - File.write("./cookie_thread_boot.#{SecureRandom.hex}", "thread booted") - end -end diff --git a/test/ruby/hooks/on_thread_boot.rb b/test/ruby/hooks/on_thread_boot.rb deleted file mode 100644 index 4f88424e..00000000 --- a/test/ruby/hooks/on_thread_boot.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'securerandom' - -@mutex = Mutex.new - -on_thread_boot do - @mutex.synchronize do - File.write("./cookie_thread_boot.#{SecureRandom.hex}", "booted") - end -end diff --git a/test/ruby/hooks/on_thread_shutdown.rb b/test/ruby/hooks/on_thread_shutdown.rb deleted file mode 100644 index d953b8b7..00000000 --- a/test/ruby/hooks/on_thread_shutdown.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'securerandom' - -@mutex = Mutex.new - -on_thread_shutdown do - @mutex.synchronize do - File.write("./cookie_thread_shutdown.#{SecureRandom.hex}", "shutdown") - end -end diff --git a/test/ruby/hooks/on_worker_boot.rb b/test/ruby/hooks/on_worker_boot.rb deleted file mode 100644 index b6529f60..00000000 --- a/test/ruby/hooks/on_worker_boot.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'securerandom' - -on_worker_boot do - File.write("./cookie_worker_boot.#{SecureRandom.hex}", "booted") -end diff --git a/test/ruby/hooks/on_worker_shutdown.rb b/test/ruby/hooks/on_worker_shutdown.rb deleted file mode 100644 index 9ffaad93..00000000 --- a/test/ruby/hooks/on_worker_shutdown.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'securerandom' - -on_worker_shutdown do - File.write("./cookie_worker_shutdown.#{SecureRandom.hex}", "shutdown") -end diff --git a/test/ruby/input_each/config.ru b/test/ruby/input_each/config.ru deleted file mode 100644 index 02446998..00000000 --- a/test/ruby/input_each/config.ru +++ /dev/null @@ -1,11 +0,0 @@ -app = Proc.new do |env| - body = '' - env['rack.input'].each do |value| - body += value - end - ['200', { - 'Content-Length' => body.length.to_s - }, [body]] -end - -run app diff --git a/test/ruby/input_gets/config.ru b/test/ruby/input_gets/config.ru deleted file mode 100644 index 151fe235..00000000 --- a/test/ruby/input_gets/config.ru +++ /dev/null @@ -1,9 +0,0 @@ -app = Proc.new do |env| - body = env['rack.input'].gets - env['rack.input'].close - ['200', { - 'Content-Length' => body.length.to_s - }, [body]] -end - -run app diff --git a/test/ruby/input_gets_all/config.ru b/test/ruby/input_gets_all/config.ru deleted file mode 100644 index 186b2418..00000000 --- a/test/ruby/input_gets_all/config.ru +++ /dev/null @@ -1,14 +0,0 @@ -app = Proc.new do |env| - body = '' - buf = '' - loop do - buf = env['rack.input'].gets - break if buf == nil - body += buf - end - ['200', { - 'Content-Length' => body.length.to_s - }, [body]] -end - -run app diff --git a/test/ruby/input_read_buffer/config.ru b/test/ruby/input_read_buffer/config.ru deleted file mode 100644 index 1e8bf7b4..00000000 --- a/test/ruby/input_read_buffer/config.ru +++ /dev/null @@ -1,9 +0,0 @@ -app = Proc.new do |env| - body = '' - env['rack.input'].read(nil, body) - ['200', { - 'Content-Length' => body.length.to_s - }, [body]] -end - -run app diff --git a/test/ruby/input_read_buffer_not_empty/config.ru b/test/ruby/input_read_buffer_not_empty/config.ru deleted file mode 100644 index 5f1f0434..00000000 --- a/test/ruby/input_read_buffer_not_empty/config.ru +++ /dev/null @@ -1,9 +0,0 @@ -app = Proc.new do |env| - body = 'blah' - env['rack.input'].read(nil, body) - ['200', { - 'Content-Length' => body.length.to_s - }, [body]] -end - -run app diff --git a/test/ruby/input_read_empty/config.ru b/test/ruby/input_read_empty/config.ru deleted file mode 100644 index 92e885c5..00000000 --- a/test/ruby/input_read_empty/config.ru +++ /dev/null @@ -1,6 +0,0 @@ -app = Proc.new do |env| - body = env['rack.input'].read - ['200', {'Content-Length' => body.length.to_s}, [body]] -end - -run app diff --git a/test/ruby/input_read_parts/config.ru b/test/ruby/input_read_parts/config.ru deleted file mode 100644 index 59016a7b..00000000 --- a/test/ruby/input_read_parts/config.ru +++ /dev/null @@ -1,10 +0,0 @@ -app = Proc.new do |env| - body = env['rack.input'].read(4) - body += env['rack.input'].read(4) - body += env['rack.input'].read(1) - ['200', { - 'Content-Length' => body.length.to_s - }, [body]] -end - -run app diff --git a/test/ruby/mirror/config.ru b/test/ruby/mirror/config.ru deleted file mode 100644 index a4bba0e6..00000000 --- a/test/ruby/mirror/config.ru +++ /dev/null @@ -1,8 +0,0 @@ -app = Proc.new do |env| - body = env['rack.input'].read - ['200', { - 'Content-Length' => body.length.to_s - }, [body]] -end - -run app diff --git a/test/ruby/multipart/config.ru b/test/ruby/multipart/config.ru deleted file mode 100644 index 9187997c..00000000 --- a/test/ruby/multipart/config.ru +++ /dev/null @@ -1,7 +0,0 @@ -app = Proc.new do |env| - [200, { - 'x-multipart-buffer' => env['rack.multipart.buffer_size'].to_s - }, []] -end - -run app diff --git a/test/ruby/query_string/config.ru b/test/ruby/query_string/config.ru deleted file mode 100644 index 57ad7758..00000000 --- a/test/ruby/query_string/config.ru +++ /dev/null @@ -1,8 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'Content-Length' => '0', - 'Query-String' => env['QUERY_STRING'] - }, ['']] -end - -run app diff --git a/test/ruby/server_port/config.ru b/test/ruby/server_port/config.ru deleted file mode 100644 index af308177..00000000 --- a/test/ruby/server_port/config.ru +++ /dev/null @@ -1,8 +0,0 @@ -app = Proc.new do |env| - ['200', { - 'Content-Length' => '0', - 'Server-Port' => env['SERVER_PORT'] - }, ['']] -end - -run app diff --git a/test/ruby/session/config.ru b/test/ruby/session/config.ru deleted file mode 100644 index 8cea0588..00000000 --- a/test/ruby/session/config.ru +++ /dev/null @@ -1,6 +0,0 @@ -app = Proc.new do |env| - env['rack.session'].clear - [200, {}, []] -end - -run app diff --git a/test/ruby/status_int/config.ru b/test/ruby/status_int/config.ru deleted file mode 100644 index 305be2d3..00000000 --- a/test/ruby/status_int/config.ru +++ /dev/null @@ -1,5 +0,0 @@ -app = Proc.new do |env| - [200, {'Content-Length' => '0'}, ['']] -end - -run app diff --git a/test/ruby/syntax_error/config.ru b/test/ruby/syntax_error/config.ru deleted file mode 100644 index 45c42dad..00000000 --- a/test/ruby/syntax_error/config.ru +++ /dev/null @@ -1,5 +0,0 @@ -app = Proc.new |env| - ['200', {'Content-Length' => '0'}, ['']] -end - -run app diff --git a/test/ruby/threads/config.ru b/test/ruby/threads/config.ru deleted file mode 100644 index 2a234d0d..00000000 --- a/test/ruby/threads/config.ru +++ /dev/null @@ -1,13 +0,0 @@ -app = Proc.new do |env| - delay = env['HTTP_X_DELAY'].to_f - - sleep(delay) - - ['200', { - 'Content-Length' => 0.to_s, - 'Rack-Multithread' => env['rack.multithread'].to_s, - 'X-Thread' => Thread.current.object_id.to_s - }, []] -end - -run app diff --git a/test/ruby/variables/config.ru b/test/ruby/variables/config.ru deleted file mode 100644 index e335e049..00000000 --- a/test/ruby/variables/config.ru +++ /dev/null @@ -1,26 +0,0 @@ -app = Proc.new do |env| - body = env['rack.input'].read - version = env['rack.version'].join('') - - ['200', { - 'Content-Type' => env['CONTENT_TYPE'], - 'Content-Length' => body.length.to_s, - 'Request-Method' => env['REQUEST_METHOD'], - 'Request-Uri' => env['REQUEST_URI'], - 'Http-Host' => env['HTTP_HOST'], - 'Script-Name' => env['SCRIPT_NAME'], - 'Server-Protocol' => env['SERVER_PROTOCOL'], - 'Server-Software' => env['SERVER_SOFTWARE'], - 'Custom-Header' => env['HTTP_CUSTOM_HEADER'], - 'Rack-Version' => version, - 'Rack-Url-Scheme' => env['rack.url_scheme'], - 'Rack-Multithread' => env['rack.multithread'].to_s, - 'Rack-Multiprocess' => env['rack.multiprocess'].to_s, - 'Rack-Run-Once' => env['rack.run_once'].to_s, - 'Rack-Hijack-Q' => env['rack.hijack?'].to_s, - 'Rack-Hijack' => env['rack.hijack'].to_s, - 'Rack-Hijack-IO' => env['rack.hijack_io'].to_s - }, [body]] -end - -run app diff --git a/test/test_access_log.py b/test/test_access_log.py deleted file mode 100644 index 1b0ec8ad..00000000 --- a/test/test_access_log.py +++ /dev/null @@ -1,387 +0,0 @@ -import time - -import pytest - -from unit.applications.lang.python import ApplicationPython -from unit.option import option - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -def load(script): - client.load(script) - - assert 'success' in client.conf( - f'"{option.temp_dir}/access.log"', 'access_log' - ), 'access_log configure' - - -def set_format(log_format): - assert 'success' in client.conf( - { - 'path': f'{option.temp_dir}/access.log', - 'format': log_format, - }, - 'access_log', - ), 'access_log format' - - -def set_if(condition): - assert 'success' in client.conf(f'"{condition}"', 'access_log/if') - - -def test_access_log_keepalive(wait_for_record): - load('mirror') - - assert client.get()['status'] == 200, 'init' - - (_, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body='01234', - read_timeout=1, - ) - - assert ( - wait_for_record(r'"POST / HTTP/1.1" 200 5', 'access.log') is not None - ), 'keepalive 1' - - _ = client.post(sock=sock, body='0123456789') - - assert ( - wait_for_record(r'"POST / HTTP/1.1" 200 10', 'access.log') is not None - ), 'keepalive 2' - - -def test_access_log_pipeline(wait_for_record): - load('empty') - - client.http( - b"""GET / HTTP/1.1 -Host: localhost -Referer: Referer-1 - -GET / HTTP/1.1 -Host: localhost -Referer: Referer-2 - -GET / HTTP/1.1 -Host: localhost -Referer: Referer-3 -Connection: close - -""", - raw_resp=True, - raw=True, - ) - - assert ( - wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"', 'access.log') - is not None - ), 'pipeline 1' - assert ( - wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-2" "-"', 'access.log') - is not None - ), 'pipeline 2' - assert ( - wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-3" "-"', 'access.log') - is not None - ), 'pipeline 3' - - -def test_access_log_ipv6(wait_for_record): - load('empty') - - assert 'success' in client.conf( - {"[::1]:8080": {"pass": "applications/empty"}}, 'listeners' - ) - - client.get(sock_type='ipv6') - - assert ( - wait_for_record( - r'::1 - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"', 'access.log' - ) - is not None - ), 'ipv6' - - -def test_access_log_unix(temp_dir, wait_for_record): - load('empty') - - addr = f'{temp_dir}/sock' - - assert 'success' in client.conf( - {f'unix:{addr}': {"pass": "applications/empty"}}, 'listeners' - ) - - client.get(sock_type='unix', addr=addr) - - assert ( - wait_for_record( - r'unix: - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"', 'access.log' - ) - is not None - ), 'unix' - - -def test_access_log_referer(wait_for_record): - load('empty') - - client.get( - headers={ - 'Host': 'localhost', - 'Referer': 'referer-value', - 'Connection': 'close', - } - ) - - assert ( - wait_for_record( - r'"GET / HTTP/1.1" 200 0 "referer-value" "-"', 'access.log' - ) - is not None - ), 'referer' - - -def test_access_log_user_agent(wait_for_record): - load('empty') - - client.get( - headers={ - 'Host': 'localhost', - 'User-Agent': 'user-agent-value', - 'Connection': 'close', - } - ) - - assert ( - wait_for_record( - r'"GET / HTTP/1.1" 200 0 "-" "user-agent-value"', 'access.log' - ) - is not None - ), 'user agent' - - -def test_access_log_http10(wait_for_record): - load('empty') - - client.get(http_10=True) - - assert ( - wait_for_record(r'"GET / HTTP/1.0" 200 0 "-" "-"', 'access.log') - is not None - ), 'http 1.0' - - -def test_access_log_partial(wait_for_record): - load('empty') - - assert client.post()['status'] == 200, 'init' - - _ = client.http(b"""GE""", raw=True, read_timeout=1) - - time.sleep(1) - - assert ( - wait_for_record(r'"-" 400 0 "-" "-"', 'access.log') is not None - ), 'partial' - - -def test_access_log_partial_2(wait_for_record): - load('empty') - - assert client.post()['status'] == 200, 'init' - - client.http(b"""GET /\n""", raw=True) - - assert ( - wait_for_record(r'"-" 400 \d+ "-" "-"', 'access.log') is not None - ), 'partial 2' - - -def test_access_log_partial_3(wait_for_record): - load('empty') - - assert client.post()['status'] == 200, 'init' - - _ = client.http(b"""GET / HTTP/1.1""", raw=True, read_timeout=1) - - time.sleep(1) - - assert ( - wait_for_record(r'"-" 400 0 "-" "-"', 'access.log') is not None - ), 'partial 3' - - -def test_access_log_partial_4(wait_for_record): - load('empty') - - assert client.post()['status'] == 200, 'init' - - _ = client.http(b"""GET / HTTP/1.1\n""", raw=True, read_timeout=1) - - time.sleep(1) - - assert ( - wait_for_record(r'"-" 400 0 "-" "-"', 'access.log') is not None - ), 'partial 4' - - -@pytest.mark.skip('not yet') -def test_access_log_partial_5(wait_for_record): - load('empty') - - assert client.post()['status'] == 200, 'init' - - client.get(headers={'Connection': 'close'}) - - assert ( - wait_for_record(r'"GET / HTTP/1.1" 400 \d+ "-" "-"', 'access.log') - is not None - ), 'partial 5' - - -def test_access_log_get_parameters(wait_for_record): - load('empty') - - client.get(url='/?blah&var=val') - - assert ( - wait_for_record( - r'"GET /\?blah&var=val HTTP/1.1" 200 0 "-" "-"', 'access.log' - ) - is not None - ), 'get parameters' - - -def test_access_log_delete(search_in_file): - load('empty') - - assert 'success' in client.conf_delete('access_log') - - client.get(url='/delete') - - assert search_in_file(r'/delete', 'access.log') is None, 'delete' - - -def test_access_log_change(temp_dir, wait_for_record): - load('empty') - - client.get() - - assert 'success' in client.conf(f'"{temp_dir}/new.log"', 'access_log') - - client.get() - - assert ( - wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log') - is not None - ), 'change' - - -def test_access_log_format(wait_for_record): - load('empty') - - def check_format(log_format, expect, url='/'): - set_format(log_format) - - assert client.get(url=url)['status'] == 200 - assert wait_for_record(expect, 'access.log') is not None, 'found' - - log_format = 'BLAH\t0123456789' - check_format(log_format, log_format) - check_format('$uri $status $uri $status', '/ 200 / 200') - - -def test_access_log_variables(wait_for_record): - load('mirror') - - # $body_bytes_sent - - set_format('$uri $body_bytes_sent') - body = '0123456789' * 50 - client.post(url='/bbs', body=body, read_timeout=1) - assert ( - wait_for_record(fr'^\/bbs {len(body)}$', 'access.log') is not None - ), '$body_bytes_sent' - - -def test_access_log_if(search_in_file, wait_for_record): - load('empty') - set_format('$uri') - - def try_if(condition): - set_if(condition) - assert client.get(url=f'/{condition}')['status'] == 200 - - # const - - try_if('') - try_if('0') - try_if('false') - try_if('undefined') - try_if('!') - try_if('!null') - try_if('1') - - # variable - - set_if('$arg_foo') - assert client.get(url='/bar?bar')['status'] == 200 - assert client.get(url='/foo_empty?foo')['status'] == 200 - assert client.get(url='/foo?foo=1')['status'] == 200 - - # check results - - assert wait_for_record(r'^/foo$', 'access.log') is not None - - assert search_in_file(r'^/$', 'access.log') is None - assert search_in_file(r'^/0$', 'access.log') is None - assert search_in_file(r'^/false$', 'access.log') is None - assert search_in_file(r'^/undefined$', 'access.log') is None - assert search_in_file(r'^/!$', 'access.log') is not None - assert search_in_file(r'^/!null$', 'access.log') is not None - assert search_in_file(r'^/1$', 'access.log') is not None - - assert search_in_file(r'^/bar$', 'access.log') is None - assert search_in_file(r'^/foo_empty$', 'access.log') is None - - -def test_access_log_if_njs(require, search_in_file, wait_for_record): - require({'modules': {'njs': 'any'}}) - - load('empty') - set_format('$uri') - - set_if('`${args.foo == \'1\'}`') - - assert client.get(url='/foo_2?foo=2')['status'] == 200 - assert client.get(url='/foo_1?foo=1')['status'] == 200 - - assert wait_for_record(r'^/foo_1$', 'access.log') is not None - assert search_in_file(r'^/foo_2$', 'access.log') is None - - -def test_access_log_incorrect(temp_dir, skip_alert): - skip_alert(r'failed to apply new conf') - - assert 'error' in client.conf( - f'{temp_dir}/blah/access.log', - 'access_log/path', - ), 'access_log path incorrect' - - assert 'error' in client.conf( - { - 'path': f'{temp_dir}/access.log', - 'format': '$remote_add', - }, - 'access_log', - ), 'access_log format incorrect' - - assert 'error' in client.conf('$arg_', 'access_log/if') diff --git a/test/test_asgi_application.py b/test/test_asgi_application.py deleted file mode 100644 index 226a1ed7..00000000 --- a/test/test_asgi_application.py +++ /dev/null @@ -1,485 +0,0 @@ -import re -import time - -import pytest -from packaging import version - -from unit.applications.lang.python import ApplicationPython - -prerequisites = { - 'modules': {'python': lambda v: version.parse(v) >= version.parse('3.5')} -} - -client = ApplicationPython(load_module='asgi') - - -def test_asgi_application_variables(date_to_sec_epoch, sec_epoch): - client.load('variables') - - body = 'Test body string.' - - resp = client.http( - f"""POST / HTTP/1.1 -Host: localhost -Content-Length: {len(body)} -Custom-Header: blah -Custom-hEader: Blah -Content-Type: text/html -Connection: close -custom-header: BLAH - -{body}""".encode(), - raw=True, - ) - - assert resp['status'] == 200, 'status' - headers = resp['headers'] - header_server = headers.pop('Server') - assert re.search(r'Unit/[\d\.]+', header_server), 'server header' - - date = headers.pop('Date') - assert date[-4:] == ' GMT', 'date header timezone' - assert abs(date_to_sec_epoch(date) - sec_epoch) < 5, 'date header' - - assert headers == { - 'Connection': 'close', - 'content-length': str(len(body)), - 'content-type': 'text/html', - 'request-method': 'POST', - 'request-uri': '/', - 'http-host': 'localhost', - 'http-version': '1.1', - 'custom-header': 'blah, Blah, BLAH', - 'asgi-version': '3.0', - 'asgi-spec-version': '2.1', - 'scheme': 'http', - }, 'headers' - assert resp['body'] == body, 'body' - - -def test_asgi_application_ipv6(): - client.load('empty') - - assert 'success' in client.conf( - {"[::1]:8080": {"pass": "applications/empty"}}, 'listeners' - ) - - assert client.get(sock_type='ipv6')['status'] == 200 - - -def test_asgi_application_unix(temp_dir): - client.load('empty') - - addr = f'{temp_dir}/sock' - assert 'success' in client.conf( - {f"unix:{addr}": {"pass": "applications/empty"}}, 'listeners' - ) - - assert client.get(sock_type='unix', addr=addr)['status'] == 200 - - -def test_asgi_application_query_string(): - client.load('query_string') - - resp = client.get(url='/?var1=val1&var2=val2') - - assert ( - resp['headers']['query-string'] == 'var1=val1&var2=val2' - ), 'query-string header' - - -def test_asgi_application_prefix(): - client.load('prefix', prefix='/api/rest') - - def set_prefix(prefix): - client.conf(f'"{prefix}"', 'applications/prefix/prefix') - - def check_prefix(url, prefix): - resp = client.get(url=url) - assert resp['status'] == 200 - assert resp['headers']['prefix'] == prefix - - check_prefix('/ap', 'NULL') - check_prefix('/api', 'NULL') - check_prefix('/api/', 'NULL') - check_prefix('/api/res', 'NULL') - check_prefix('/api/restful', 'NULL') - check_prefix('/api/rest', '/api/rest') - check_prefix('/api/rest/', '/api/rest') - check_prefix('/api/rest/get', '/api/rest') - check_prefix('/api/rest/get/blah', '/api/rest') - - set_prefix('/api/rest/') - check_prefix('/api/rest', '/api/rest') - check_prefix('/api/restful', 'NULL') - check_prefix('/api/rest/', '/api/rest') - check_prefix('/api/rest/blah', '/api/rest') - - set_prefix('/app') - check_prefix('/ap', 'NULL') - check_prefix('/app', '/app') - check_prefix('/app/', '/app') - check_prefix('/application/', 'NULL') - - set_prefix('/') - check_prefix('/', 'NULL') - check_prefix('/app', 'NULL') - - -def test_asgi_application_query_string_space(): - client.load('query_string') - - resp = client.get(url='/ ?var1=val1&var2=val2') - assert ( - resp['headers']['query-string'] == 'var1=val1&var2=val2' - ), 'query-string space' - - resp = client.get(url='/ %20?var1=val1&var2=val2') - assert ( - resp['headers']['query-string'] == 'var1=val1&var2=val2' - ), 'query-string space 2' - - resp = client.get(url='/ %20 ?var1=val1&var2=val2') - assert ( - resp['headers']['query-string'] == 'var1=val1&var2=val2' - ), 'query-string space 3' - - resp = client.get(url='/blah %20 blah? var1= val1 & var2=val2') - assert ( - resp['headers']['query-string'] == ' var1= val1 & var2=val2' - ), 'query-string space 4' - - -def test_asgi_application_query_string_empty(): - client.load('query_string') - - resp = client.get(url='/?') - - assert resp['status'] == 200, 'query string empty status' - assert resp['headers']['query-string'] == '', 'query string empty' - - -def test_asgi_application_query_string_absent(): - client.load('query_string') - - resp = client.get() - - assert resp['status'] == 200, 'query string absent status' - assert resp['headers']['query-string'] == '', 'query string absent' - - -@pytest.mark.skip('not yet') -def test_asgi_application_server_port(): - client.load('server_port') - - assert ( - client.get()['headers']['Server-Port'] == '8080' - ), 'Server-Port header' - - -@pytest.mark.skip('not yet') -def test_asgi_application_working_directory_invalid(): - client.load('empty') - - assert 'success' in client.conf( - '"/blah"', 'applications/empty/working_directory' - ), 'configure invalid working_directory' - - assert client.get()['status'] == 500, 'status' - - -def test_asgi_application_204_transfer_encoding(): - client.load('204_no_content') - - assert ( - 'Transfer-Encoding' not in client.get()['headers'] - ), '204 header transfer encoding' - - -def test_asgi_application_shm_ack_handle(): - # Minimum possible limit - shm_limit = 10 * 1024 * 1024 - - client.load('mirror', limits={"shm": shm_limit}) - - # Should exceed shm_limit - max_body_size = 12 * 1024 * 1024 - - assert 'success' in client.conf( - f'{{"http":{{"max_body_size": {max_body_size} }}}}', - 'settings', - ) - - assert client.get()['status'] == 200, 'init' - - body = '0123456789AB' * 1024 * 1024 # 12 Mb - resp = client.post(body=body, read_buffer_size=1024 * 1024) - - assert resp['body'] == body, 'keep-alive 1' - - -def test_asgi_application_body_bytearray(): - client.load('body_bytearray') - - body = '0123456789' - - assert client.post(body=body)['body'] == body - - -def test_asgi_keepalive_body(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' * 500 - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive 1' - - body = '0123456789' - resp = client.post(sock=sock, body=body) - - assert resp['body'] == body, 'keep-alive 2' - - -def test_asgi_keepalive_reconfigure(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' - conns = 3 - socks = [] - - for i in range(conns): - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive open' - - client.load('mirror', processes=i + 1) - - socks.append(sock) - - for i in range(conns): - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - sock=socks[i], - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive request' - - client.load('mirror', processes=i + 1) - - for i in range(conns): - resp = client.post(sock=socks[i], body=body) - - assert resp['body'] == body, 'keep-alive close' - - client.load('mirror', processes=i + 1) - - -def test_asgi_keepalive_reconfigure_2(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' - - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'reconfigure 2 keep-alive 1' - - client.load('empty') - - assert client.get()['status'] == 200, 'init' - - (resp, sock) = client.post(start=True, sock=sock, body=body) - - assert resp['status'] == 200, 'reconfigure 2 keep-alive 2' - assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body' - - assert 'success' in client.conf( - {"listeners": {}, "applications": {}} - ), 'reconfigure 2 clear configuration' - - resp = client.get(sock=sock) - - assert resp == {}, 'reconfigure 2 keep-alive 3' - - -def test_asgi_keepalive_reconfigure_3(): - client.load('empty') - - assert client.get()['status'] == 200, 'init' - - sock = client.http( - b"""GET / HTTP/1.1 -""", - raw=True, - no_recv=True, - ) - - assert client.get()['status'] == 200 - - assert 'success' in client.conf( - {"listeners": {}, "applications": {}} - ), 'reconfigure 3 clear configuration' - - resp = client.http( - b"""Host: localhost -Connection: close - -""", - sock=sock, - raw=True, - ) - - assert resp['status'] == 200, 'reconfigure 3' - - -def test_asgi_process_switch(): - client.load('delayed', processes=2) - - client.get( - headers={ - 'Host': 'localhost', - 'Content-Length': '0', - 'X-Delay': '5', - 'Connection': 'close', - }, - no_recv=True, - ) - - headers_delay_1 = { - 'Connection': 'close', - 'Host': 'localhost', - 'Content-Length': '0', - 'X-Delay': '1', - } - - client.get(headers=headers_delay_1, no_recv=True) - - time.sleep(0.5) - - for _ in range(10): - client.get(headers=headers_delay_1, no_recv=True) - - client.get(headers=headers_delay_1) - - -def test_asgi_application_loading_error(skip_alert): - skip_alert(r'Python failed to import module "blah"') - - client.load('empty', module="blah") - - assert client.get()['status'] == 503, 'loading error' - - -def test_asgi_application_threading(wait_for_record): - """wait_for_record() timeouts after 5s while every thread works at - least 3s. So without releasing GIL test should fail. - """ - - client.load('threading') - - for _ in range(10): - client.get(no_recv=True) - - assert ( - wait_for_record(r'\(5\) Thread: 100', wait=50) is not None - ), 'last thread finished' - - -def test_asgi_application_threads(): - client.load('threads', threads=2) - - socks = [] - - for _ in range(2): - sock = client.get( - headers={ - 'Host': 'localhost', - 'X-Delay': '3', - 'Connection': 'close', - }, - no_recv=True, - ) - - socks.append(sock) - - time.sleep(1.0) # required to avoid greedy request reading - - threads = set() - - for sock in socks: - resp = client.recvall(sock).decode('utf-8') - - client.log_in(resp) - - resp = client._resp_to_dict(resp) - - assert resp['status'] == 200, 'status' - - threads.add(resp['headers']['x-thread']) - - sock.close() - - assert len(socks) == len(threads), 'threads differs' - - -def test_asgi_application_legacy(): - client.load('legacy') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Content-Length': '0', - 'Connection': 'close', - }, - ) - - assert resp['status'] == 200, 'status' - - -def test_asgi_application_legacy_force(): - client.load('legacy_force', protocol='asgi') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Content-Length': '0', - 'Connection': 'close', - }, - ) - - assert resp['status'] == 200, 'status' diff --git a/test/test_asgi_application_unix_abstract.py b/test/test_asgi_application_unix_abstract.py deleted file mode 100644 index f35ce0d7..00000000 --- a/test/test_asgi_application_unix_abstract.py +++ /dev/null @@ -1,22 +0,0 @@ -from packaging import version - -from unit.applications.lang.python import ApplicationPython - -prerequisites = { - 'modules': {'python': lambda v: version.parse(v) >= version.parse('3.5')}, - 'features': {'unix_abstract': True}, -} - -client = ApplicationPython(load_module='asgi') - - -def test_asgi_application_unix_abstract(): - client.load('empty') - - addr = '\0sock' - assert 'success' in client.conf( - {f"unix:@{addr[1:]}": {"pass": "applications/empty"}}, - 'listeners', - ) - - assert client.get(sock_type='unix', addr=addr)['status'] == 200 diff --git a/test/test_asgi_lifespan.py b/test/test_asgi_lifespan.py deleted file mode 100644 index e09ea1cc..00000000 --- a/test/test_asgi_lifespan.py +++ /dev/null @@ -1,122 +0,0 @@ -from pathlib import Path - -from packaging import version - -from conftest import unit_stop -from unit.applications.lang.python import ApplicationPython -from unit.option import option - -prerequisites = { - 'modules': {'python': lambda v: version.parse(v) >= version.parse('3.5')} -} - -client = ApplicationPython(load_module='asgi') - - -def assert_cookies(prefix): - for name in ['startup', 'shutdown']: - path = Path(f'{option.test_dir}/python/lifespan/empty/{prefix}{name}') - exists = path.is_file() - path.unlink(missing_ok=True) - - assert not exists, name - - path = Path(f'{option.test_dir}/python/lifespan/empty/{prefix}version') - versions = path.read_text(encoding='utf-8') - path.unlink() - - assert versions == '3.0 2.0', 'versions' - - -def setup_cookies(prefix): - base_dir = Path(f'{option.test_dir}/python/lifespan/empty') - base_dir.chmod(0o777) - - for name in ['startup', 'shutdown', 'version']: - path = Path(f'{option.test_dir}/python/lifespan/empty/{prefix}{name}') - path.touch(0o777) - - -def test_asgi_lifespan(): - client.load('lifespan/empty') - - setup_cookies('') - - assert client.get()['status'] == 204 - - unit_stop() - - assert_cookies('') - - -def test_asgi_lifespan_targets(): - path = f'{option.test_dir}/python/lifespan/empty' - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": "/1"}, - "action": {"pass": "applications/targets/1"}, - }, - { - "match": {"uri": "/2"}, - "action": {"pass": "applications/targets/2"}, - }, - ], - "applications": { - "targets": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "working_directory": path, - "path": path, - "targets": { - "1": {"module": "asgi", "callable": "application"}, - "2": { - "module": "asgi", - "callable": "application2", - }, - }, - } - }, - } - ) - - setup_cookies('') - setup_cookies('app2_') - - assert client.get(url="/1")['status'] == 204 - assert client.get(url="/2")['status'] == 204 - - unit_stop() - - assert_cookies('') - assert_cookies('app2_') - - -def test_asgi_lifespan_failed(wait_for_record): - client.load('lifespan/failed') - - assert client.get()['status'] == 503 - - assert ( - wait_for_record(r'\[error\].*Application startup failed') is not None - ), 'error message' - assert wait_for_record(r'Exception blah') is not None, 'exception' - - -def test_asgi_lifespan_error(wait_for_record): - client.load('lifespan/error') - - client.get() - - assert wait_for_record(r'Exception blah') is not None, 'exception' - - -def test_asgi_lifespan_error_auto(wait_for_record): - client.load('lifespan/error_auto') - - client.get() - - assert wait_for_record(r'AssertionError') is not None, 'assertion' diff --git a/test/test_asgi_targets.py b/test/test_asgi_targets.py deleted file mode 100644 index 3d4e2e24..00000000 --- a/test/test_asgi_targets.py +++ /dev/null @@ -1,143 +0,0 @@ -import pytest -from packaging import version - -from unit.applications.lang.python import ApplicationPython -from unit.option import option - -prerequisites = { - 'modules': {'python': lambda v: version.parse(v) >= version.parse('3.5')} -} - -client = ApplicationPython(load_module='asgi') - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - path = f'{option.test_dir}/python/targets/' - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": "/1"}, - "action": {"pass": "applications/targets/1"}, - }, - { - "match": {"uri": "/2"}, - "action": {"pass": "applications/targets/2"}, - }, - ], - "applications": { - "targets": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "working_directory": path, - "path": path, - "protocol": "asgi", - "targets": { - "1": { - "module": "asgi", - "callable": "application_200", - }, - "2": { - "module": "asgi", - "callable": "application_201", - }, - }, - } - }, - } - ) - - -def conf_targets(targets): - assert 'success' in client.conf(targets, 'applications/targets/targets') - - -def test_asgi_targets(): - assert client.get(url='/1')['status'] == 200 - assert client.get(url='/2')['status'] == 201 - - -def test_asgi_targets_legacy(): - conf_targets( - { - "1": {"module": "asgi", "callable": "legacy_application_200"}, - "2": {"module": "asgi", "callable": "legacy_application_201"}, - } - ) - - assert client.get(url='/1')['status'] == 200 - assert client.get(url='/2')['status'] == 201 - - -def test_asgi_targets_mix(): - conf_targets( - { - "1": {"module": "asgi", "callable": "application_200"}, - "2": {"module": "asgi", "callable": "legacy_application_201"}, - } - ) - - assert client.get(url='/1')['status'] == 200 - assert client.get(url='/2')['status'] == 201 - - -def test_asgi_targets_broken(skip_alert): - skip_alert(r'Python failed to get "blah" from module') - - conf_targets( - { - "1": {"module": "asgi", "callable": "application_200"}, - "2": {"module": "asgi", "callable": "blah"}, - } - ) - - assert client.get(url='/1')['status'] != 200 - - -def test_asgi_targets_prefix(): - conf_targets( - { - "1": { - "module": "asgi", - "callable": "application_prefix", - "prefix": "/1/", - }, - "2": { - "module": "asgi", - "callable": "application_prefix", - "prefix": "/api", - }, - } - ) - client.conf( - [ - { - "match": {"uri": "/1*"}, - "action": {"pass": "applications/targets/1"}, - }, - { - "match": {"uri": "*"}, - "action": {"pass": "applications/targets/2"}, - }, - ], - "routes", - ) - - def check_prefix(url, prefix): - resp = client.get(url=url) - assert resp['status'] == 200 - assert resp['headers']['prefix'] == prefix - - check_prefix('/1', '/1') - check_prefix('/11', 'NULL') - check_prefix('/1/', '/1') - check_prefix('/', 'NULL') - check_prefix('/ap', 'NULL') - check_prefix('/api', '/api') - check_prefix('/api/', '/api') - check_prefix('/api/test/', '/api') - check_prefix('/apis', 'NULL') - check_prefix('/apis/', 'NULL') diff --git a/test/test_asgi_websockets.py b/test/test_asgi_websockets.py deleted file mode 100644 index f93c97ab..00000000 --- a/test/test_asgi_websockets.py +++ /dev/null @@ -1,1505 +0,0 @@ -import struct -import time - -import pytest -from packaging import version - -from unit.applications.lang.python import ApplicationPython -from unit.applications.websockets import ApplicationWebsocket - -prerequisites = { - 'modules': {'python': lambda v: version.parse(v) >= version.parse('3.5')} -} - -client = ApplicationPython(load_module='asgi') -ws = ApplicationWebsocket() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(skip_alert): - assert 'success' in client.conf( - {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings' - ), 'clear keepalive_interval' - - skip_alert(r'socket close\(\d+\) failed') - - -def close_connection(sock): - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - - check_close(sock) - - -def check_close(sock, code=1000, no_close=False, frame=None): - if frame is None: - frame = ws.frame_read(sock) - - assert frame['fin'], 'close fin' - assert frame['opcode'] == ws.OP_CLOSE, 'close opcode' - assert frame['code'] == code, 'close code' - - if not no_close: - sock.close() - - -def check_frame(frame, fin, opcode, payload, decode=True): - if opcode == ws.OP_BINARY or not decode: - data = frame['data'] - else: - data = frame['data'].decode('utf-8') - - assert frame['fin'] == fin, 'fin' - assert frame['opcode'] == opcode, 'opcode' - assert data == payload, 'payload' - - -def test_asgi_websockets_handshake(): - client.load('websockets/mirror') - - resp, sock, key = ws.upgrade() - sock.close() - - assert resp['status'] == 101, 'status' - assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' - assert resp['headers']['Connection'] == 'Upgrade', 'connection' - assert resp['headers']['Sec-WebSocket-Accept'] == ws.accept(key), 'key' - - # remove "mirror" application - client.load('websockets/subprotocol') - - -def test_asgi_websockets_subprotocol(): - client.load('websockets/subprotocol') - - resp, sock, _ = ws.upgrade() - sock.close() - - assert resp['status'] == 101, 'status' - assert ( - resp['headers']['x-subprotocols'] == "('chat', 'phone', 'video')" - ), 'subprotocols' - assert resp['headers']['sec-websocket-protocol'] == 'chat', 'key' - - -def test_asgi_websockets_mirror(): - client.load('websockets/mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message) - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'mirror' - - ws.frame_write(sock, ws.OP_TEXT, message) - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'mirror 2' - - sock.close() - - -def test_asgi_websockets_mirror_app_change(): - client.load('websockets/mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message) - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'mirror' - - client.load('websockets/subprotocol') - - ws.frame_write(sock, ws.OP_TEXT, message) - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'mirror 2' - - sock.close() - - -def test_asgi_websockets_no_mask(): - client.load('websockets/mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message, mask=False) - - frame = ws.frame_read(sock) - - assert frame['opcode'] == ws.OP_CLOSE, 'no mask opcode' - assert frame['code'] == 1002, 'no mask close code' - - sock.close() - - -def test_asgi_websockets_fragmentation(): - client.load('websockets/mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message, fin=False) - ws.frame_write(sock, ws.OP_CONT, ' ', fin=False) - ws.frame_write(sock, ws.OP_CONT, message) - - frame = ws.frame_read(sock) - - assert f'{message} {message}' == frame['data'].decode( - 'utf-8' - ), 'mirror framing' - - sock.close() - - -def test_asgi_websockets_length_long(): - client.load('websockets/mirror') - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', length=2**64 - 1) - - check_close(sock, 1009) # 1009 - CLOSE_TOO_LARGE - - -def test_asgi_websockets_frame_fragmentation_invalid(): - client.load('websockets/mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, message, fin=False) - - frame = ws.frame_read(sock) - - frame.pop('data') - assert frame == { - 'fin': True, - 'rsv1': False, - 'rsv2': False, - 'rsv3': False, - 'opcode': ws.OP_CLOSE, - 'mask': 0, - 'code': 1002, - 'reason': 'Fragmented control frame', - }, 'close frame' - - sock.close() - - -def test_asgi_websockets_large(): - client.load('websockets/mirror') - - message = '0123456789' * 300 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message) - - frame = ws.frame_read(sock) - data = frame['data'].decode('utf-8') - - frame = ws.frame_read(sock) - data += frame['data'].decode('utf-8') - - assert message == data, 'large' - - sock.close() - - -def test_asgi_websockets_two_clients(): - client.load('websockets/mirror') - - message1 = 'blah1' - message2 = 'blah2' - - _, sock1, _ = ws.upgrade() - _, sock2, _ = ws.upgrade() - - ws.frame_write(sock1, ws.OP_TEXT, message1) - ws.frame_write(sock2, ws.OP_TEXT, message2) - - frame1 = ws.frame_read(sock1) - frame2 = ws.frame_read(sock2) - - assert message1 == frame1['data'].decode('utf-8'), 'client 1' - assert message2 == frame2['data'].decode('utf-8'), 'client 2' - - sock1.close() - sock2.close() - - -# FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1 -@pytest.mark.skip('not yet') -def test_asgi_websockets_handshake_upgrade_absent(): - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'upgrade absent' - - -def test_asgi_websockets_handshake_case_insensitive(): - client.load('websockets/mirror') - - resp, sock, _ = ws.upgrade( - headers={ - 'Host': 'localhost', - 'Upgrade': 'WEBSOCKET', - 'Connection': 'UPGRADE', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - } - ) - sock.close() - - assert resp['status'] == 101, 'status' - - -@pytest.mark.skip('not yet') -def test_asgi_websockets_handshake_connection_absent(): # FAIL - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'status' - - -def test_asgi_websockets_handshake_version_absent(): - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - }, - ) - - assert resp['status'] == 426, 'status' - - -@pytest.mark.skip('not yet') -def test_asgi_websockets_handshake_key_invalid(): - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': '!', - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'key length' - - key = ws.key() - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': [key, key], - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert ( - resp['status'] == 400 - ), 'key double' # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1 - - -def test_asgi_websockets_handshake_method_invalid(): - client.load('websockets/mirror') - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'status' - - -def test_asgi_websockets_handshake_http_10(): - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - http_10=True, - ) - - assert resp['status'] == 400, 'status' - - -def test_asgi_websockets_handshake_uri_invalid(): - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - url='!', - ) - - assert resp['status'] == 400, 'status' - - -def test_asgi_websockets_protocol_absent(): - client.load('websockets/mirror') - - key = ws.key() - resp, sock, _ = ws.upgrade( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': key, - 'Sec-WebSocket-Version': 13, - } - ) - sock.close() - - assert resp['status'] == 101, 'status' - assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' - assert resp['headers']['Connection'] == 'Upgrade', 'connection' - assert resp['headers']['Sec-WebSocket-Accept'] == ws.accept(key), 'key' - - -# autobahn-testsuite -# -# Some following tests fail because of Unit does not support UTF-8 -# validation for websocket frames. It should be implemented -# by application, if necessary. - - -def test_asgi_websockets_1_1_1__1_1_8(): - client.load('websockets/mirror') - - opcode = ws.OP_TEXT - - _, sock, _ = ws.upgrade() - - def check_length(length, chopsize=None): - payload = '*' * length - - ws.frame_write(sock, opcode, payload, chopsize=chopsize) - - frame = ws.frame_read(sock) - check_frame(frame, True, opcode, payload) - - check_length(0) # 1_1_1 - check_length(125) # 1_1_2 - check_length(126) # 1_1_3 - check_length(127) # 1_1_4 - check_length(128) # 1_1_5 - check_length(65535) # 1_1_6 - check_length(65536) # 1_1_7 - check_length(65536, chopsize=997) # 1_1_8 - - close_connection(sock) - - -def test_asgi_websockets_1_2_1__1_2_8(): - client.load('websockets/mirror') - - opcode = ws.OP_BINARY - - _, sock, _ = ws.upgrade() - - def check_length(length, chopsize=None): - payload = b'\xfe' * length - - ws.frame_write(sock, opcode, payload, chopsize=chopsize) - frame = ws.frame_read(sock) - - check_frame(frame, True, opcode, payload) - - check_length(0) # 1_2_1 - check_length(125) # 1_2_2 - check_length(126) # 1_2_3 - check_length(127) # 1_2_4 - check_length(128) # 1_2_5 - check_length(65535) # 1_2_6 - check_length(65536) # 1_2_7 - check_length(65536, chopsize=997) # 1_2_8 - - close_connection(sock) - - -def test_asgi_websockets_2_1__2_6(): - client.load('websockets/mirror') - - op_ping = ws.OP_PING - op_pong = ws.OP_PONG - - _, sock, _ = ws.upgrade() - - def check_ping(payload, chopsize=None, decode=True): - ws.frame_write(sock, op_ping, payload, chopsize=chopsize) - frame = ws.frame_read(sock) - - check_frame(frame, True, op_pong, payload, decode=decode) - - check_ping('') # 2_1 - check_ping('Hello, world!') # 2_2 - check_ping(b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', decode=False) # 2_3 - check_ping(b'\xfe' * 125, decode=False) # 2_4 - check_ping(b'\xfe' * 125, chopsize=1, decode=False) # 2_6 - - close_connection(sock) - - # 2_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, b'\xfe' * 126) - check_close(sock, 1002) - - -def test_asgi_websockets_2_7__2_9(): - client.load('websockets/mirror') - - # 2_7 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PONG, '') - assert client.recvall(sock, read_timeout=0.1) == b'', '2_7' - - # 2_8 - - ws.frame_write(sock, ws.OP_PONG, 'unsolicited pong payload') - assert client.recvall(sock, read_timeout=0.1) == b'', '2_8' - - # 2_9 - - payload = 'ping payload' - - ws.frame_write(sock, ws.OP_PONG, 'unsolicited pong payload') - ws.frame_write(sock, ws.OP_PING, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, payload) - - close_connection(sock) - - -def test_asgi_websockets_2_10__2_11(): - client.load('websockets/mirror') - - # 2_10 - - _, sock, _ = ws.upgrade() - - for i in range(0, 10): - ws.frame_write(sock, ws.OP_PING, f'payload-{i}') - - for i in range(0, 10): - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, f'payload-{i}') - - # 2_11 - - for i in range(0, 10): - opcode = ws.OP_PING - ws.frame_write(sock, opcode, f'payload-{i}', chopsize=1) - - for i in range(0, 10): - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, f'payload-{i}') - - close_connection(sock) - - -@pytest.mark.skip('not yet') -def test_asgi_websockets_3_1__3_7(): - client.load('websockets/mirror') - - payload = 'Hello, world!' - - # 3_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, rsv1=True) - check_close(sock, 1002) - - # 3_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - ws.frame_write(sock, ws.OP_TEXT, payload, rsv2=True) - ws.frame_write(sock, ws.OP_PING, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - check_close(sock, 1002, no_close=True) - - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2' - sock.close() - - # 3_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, ws.OP_TEXT, payload, rsv1=True, rsv2=True) - - check_close(sock, 1002, no_close=True) - - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3' - sock.close() - - # 3_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) - ws.frame_write(sock, ws.OP_TEXT, payload, rsv3=True, chopsize=1) - ws.frame_write(sock, ws.OP_PING, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - check_close(sock, 1002, no_close=True) - - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4' - sock.close() - - # 3_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write( - sock, - ws.OP_BINARY, - b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', - rsv1=True, - rsv3=True, - ) - - check_close(sock, 1002) - - # 3_6 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, payload, rsv2=True, rsv3=True) - - check_close(sock, 1002) - - # 3_7 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, payload, rsv1=True, rsv2=True, rsv3=True) - - check_close(sock, 1002) - - -def test_asgi_websockets_4_1_1__4_2_5(): - client.load('websockets/mirror') - - payload = 'Hello, world!' - - # 4_1_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x03, '') - check_close(sock, 1002) - - # 4_1_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x04, 'reserved opcode payload') - check_close(sock, 1002) - - # 4_1_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x05, '') - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_1_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x06, payload) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_1_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x07, payload, chopsize=1) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_2_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x0B, '') - check_close(sock, 1002) - - # 4_2_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x0C, 'reserved opcode payload') - check_close(sock, 1002) - - # 4_2_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x0D, '') - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_2_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x0E, payload) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_2_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x0F, payload, chopsize=1) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - -def test_asgi_websockets_5_1__5_20(): - client.load('websockets/mirror') - - # 5_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - check_close(sock, 1002) - - # 5_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PONG, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - check_close(sock, 1002) - - # 5_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_4 - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - assert client.recvall(sock, read_timeout=0.1) == b'', '5_4' - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_5 - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False, chopsize=1) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_6 - - ping_payload = 'ping payload' - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_PING, ping_payload) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, ping_payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_7 - - ping_payload = 'ping payload' - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - assert client.recvall(sock, read_timeout=0.1) == b'', '5_7' - - ws.frame_write(sock, ws.OP_PING, ping_payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, ping_payload) - - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_8 - - ping_payload = 'ping payload' - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False, chopsize=1) - ws.frame_write(sock, ws.OP_PING, ping_payload, chopsize=1) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, ping_payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_9 - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=True) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_10 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=True) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_11 - - _, sock, _ = ws.upgrade() - - ws.frame_write( - sock, - ws.OP_CONT, - 'non-continuation payload', - fin=True, - chopsize=1, - ) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1) - check_close(sock, 1002) - - # 5_12 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_13 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_14 - - _, sock, _ = ws.upgrade() - - ws.frame_write( - sock, - ws.OP_CONT, - 'non-continuation payload', - fin=False, - chopsize=1, - ) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1) - check_close(sock, 1002) - - # 5_15 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'fragment4', fin=True) - - frame = ws.frame_read(sock) - - if frame['opcode'] == ws.OP_TEXT: - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - frame = None - - check_close(sock, 1002, frame=frame) - - # 5_16 - - _, sock, _ = ws.upgrade() - - for _ in range(0, 2): - ws.frame_write(sock, ws.OP_CONT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=True) - check_close(sock, 1002) - - # 5_17 - - _, sock, _ = ws.upgrade() - - for _ in range(0, 2): - ws.frame_write(sock, ws.OP_CONT, 'fragment1', fin=True) - ws.frame_write(sock, ws.OP_TEXT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=True) - check_close(sock, 1002) - - # 5_18 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'fragment2') - check_close(sock, 1002) - - # 5_19 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 1!') - - time.sleep(1) - - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment4', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 2!') - ws.frame_write(sock, ws.OP_CONT, 'fragment5') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 1!') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 2!') - - check_frame( - ws.frame_read(sock), - True, - ws.OP_TEXT, - 'fragment1fragment2fragment3fragment4fragment5', - ) - - # 5_20 - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 1!') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 1!') - - time.sleep(1) - - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment4', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 2!') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 2!') - - assert client.recvall(sock, read_timeout=0.1) == b'', '5_20' - ws.frame_write(sock, ws.OP_CONT, 'fragment5') - - check_frame( - ws.frame_read(sock), - True, - ws.OP_TEXT, - 'fragment1fragment2fragment3fragment4fragment5', - ) - - close_connection(sock) - - -def test_asgi_websockets_6_1_1__6_4_4(): - client.load('websockets/mirror') - - # 6_1_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, '') - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, '') - - # 6_1_2 - - ws.frame_write(sock, ws.OP_TEXT, '', fin=False) - ws.frame_write(sock, ws.OP_CONT, '', fin=False) - ws.frame_write(sock, ws.OP_CONT, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, '') - - # 6_1_3 - - payload = 'middle frame payload' - - ws.frame_write(sock, ws.OP_TEXT, '', fin=False) - ws.frame_write(sock, ws.OP_CONT, payload, fin=False) - ws.frame_write(sock, ws.OP_CONT, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_1 - - payload = 'Hello-µ@ßöäüàá-UTF-8!!' - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_2 - - ws.frame_write(sock, ws.OP_TEXT, payload[:12], fin=False) - ws.frame_write(sock, ws.OP_CONT, payload[12:]) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_3 - - ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_4 - - payload = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5' - - ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - close_connection(sock) - - -# Unit does not support UTF-8 validation -# -# # 6_3_1 FAIL -# -# payload_1 = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5' -# payload_2 = '\xed\xa0\x80' -# payload_3 = '\x65\x64\x69\x74\x65\x64' -# -# payload = payload_1 + payload_2 + payload_3 -# -# ws.message(sock, ws.OP_TEXT, payload) -# check_close(sock, 1007) -# -# # 6_3_2 FAIL -# -# _, sock, _ = ws.upgrade() -# -# ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) -# check_close(sock, 1007) -# -# # 6_4_1 ... 6_4_4 FAIL - - -def test_asgi_websockets_7_1_1__7_5_1(): - client.load('websockets/mirror') - - # 7_1_1 - - _, sock, _ = ws.upgrade() - - payload = "Hello World!" - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - close_connection(sock) - - # 7_1_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - - check_close(sock) - - # 7_1_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock, no_close=True) - - ws.frame_write(sock, ws.OP_PING, '') - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_1_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock, no_close=True) - - ws.frame_write(sock, ws.OP_TEXT, payload) - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_1_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock, no_close=True) - - ws.frame_write(sock, ws.OP_CONT, 'fragment2') - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_1_6 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2**10) - ws.frame_write(sock, ws.OP_TEXT, payload) - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - - client.recvall(sock, read_timeout=1) - - ws.frame_write(sock, ws.OP_PING, '') - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_3_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, '') - check_close(sock) - - # 7_3_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, 'a') - check_close(sock, 1002) - - # 7_3_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock) - - # 7_3_4 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(reason='Hello World!') - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock) - - # 7_3_5 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(reason='*' * 123) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock) - - # 7_3_6 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(reason='*' * 124) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - -# # 7_5_1 FAIL Unit does not support UTF-8 validation -# -# _, sock, _ = ws.upgrade() -# -# payload = ws.serialize_close(reason = '\xce\xba\xe1\xbd\xb9\xcf' \ -# '\x83\xce\xbc\xce\xb5\xed\xa0\x80\x65\x64\x69\x74\x65\x64') -# -# ws.frame_write(sock, ws.OP_CLOSE, payload) -# check_close(sock, 1007) - - -def test_asgi_websockets_7_7_X__7_9_X(): - client.load('websockets/mirror') - - valid_codes = [ - 1000, - 1001, - 1002, - 1003, - 1007, - 1008, - 1009, - 1010, - 1011, - 3000, - 3999, - 4000, - 4999, - ] - - invalid_codes = [0, 999, 1004, 1005, 1006, 1016, 1100, 2000, 2999] - - for code in valid_codes: - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(code=code) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock) - - for code in invalid_codes: - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(code=code) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - -def test_asgi_websockets_7_13_1__7_13_2(): - client.load('websockets/mirror') - - # 7_13_1 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(code=5000) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - # 7_13_2 - - _, sock, _ = ws.upgrade() - - payload = struct.pack('!I', 65536) + ''.encode('utf-8') - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - -def test_asgi_websockets_9_1_1__9_6_6(is_unsafe, system): - if not is_unsafe: - pytest.skip('unsafe, long run') - - client.load('websockets/mirror') - - assert 'success' in client.conf( - { - 'http': { - 'websocket': { - 'max_frame_size': 33554432, - 'keepalive_interval': 0, - } - } - }, - 'settings', - ), 'increase max_frame_size and keepalive_interval' - - _, sock, _ = ws.upgrade() - - op_text = ws.OP_TEXT - op_binary = ws.OP_BINARY - - def check_payload(opcode, length, chopsize=None): - if opcode == ws.OP_TEXT: - payload = '*' * length - else: - payload = b'*' * length - - ws.frame_write(sock, opcode, payload, chopsize=chopsize) - frame = ws.frame_read(sock, read_timeout=5) - check_frame(frame, True, opcode, payload) - - def check_message(opcode, f_size): - if opcode == ws.OP_TEXT: - payload = '*' * 4 * 2**20 - else: - payload = b'*' * 4 * 2**20 - - ws.message(sock, opcode, payload, fragmention_size=f_size) - frame = ws.frame_read(sock, read_timeout=5) - check_frame(frame, True, opcode, payload) - - check_payload(op_text, 64 * 2**10) # 9_1_1 - check_payload(op_text, 256 * 2**10) # 9_1_2 - check_payload(op_text, 2**20) # 9_1_3 - check_payload(op_text, 4 * 2**20) # 9_1_4 - check_payload(op_text, 8 * 2**20) # 9_1_5 - check_payload(op_text, 16 * 2**20) # 9_1_6 - - check_payload(op_binary, 64 * 2**10) # 9_2_1 - check_payload(op_binary, 256 * 2**10) # 9_2_2 - check_payload(op_binary, 2**20) # 9_2_3 - check_payload(op_binary, 4 * 2**20) # 9_2_4 - check_payload(op_binary, 8 * 2**20) # 9_2_5 - check_payload(op_binary, 16 * 2**20) # 9_2_6 - - if system not in ['Darwin', 'FreeBSD']: - check_message(op_text, 64) # 9_3_1 - check_message(op_text, 256) # 9_3_2 - check_message(op_text, 2**10) # 9_3_3 - check_message(op_text, 4 * 2**10) # 9_3_4 - check_message(op_text, 16 * 2**10) # 9_3_5 - check_message(op_text, 64 * 2**10) # 9_3_6 - check_message(op_text, 256 * 2**10) # 9_3_7 - check_message(op_text, 2**20) # 9_3_8 - check_message(op_text, 4 * 2**20) # 9_3_9 - - check_message(op_binary, 64) # 9_4_1 - check_message(op_binary, 256) # 9_4_2 - check_message(op_binary, 2**10) # 9_4_3 - check_message(op_binary, 4 * 2**10) # 9_4_4 - check_message(op_binary, 16 * 2**10) # 9_4_5 - check_message(op_binary, 64 * 2**10) # 9_4_6 - check_message(op_binary, 256 * 2**10) # 9_4_7 - check_message(op_binary, 2**20) # 9_4_8 - check_message(op_binary, 4 * 2**20) # 9_4_9 - - check_payload(op_text, 2**20, chopsize=64) # 9_5_1 - check_payload(op_text, 2**20, chopsize=128) # 9_5_2 - check_payload(op_text, 2**20, chopsize=256) # 9_5_3 - check_payload(op_text, 2**20, chopsize=512) # 9_5_4 - check_payload(op_text, 2**20, chopsize=1024) # 9_5_5 - check_payload(op_text, 2**20, chopsize=2048) # 9_5_6 - - check_payload(op_binary, 2**20, chopsize=64) # 9_6_1 - check_payload(op_binary, 2**20, chopsize=128) # 9_6_2 - check_payload(op_binary, 2**20, chopsize=256) # 9_6_3 - check_payload(op_binary, 2**20, chopsize=512) # 9_6_4 - check_payload(op_binary, 2**20, chopsize=1024) # 9_6_5 - check_payload(op_binary, 2**20, chopsize=2048) # 9_6_6 - - close_connection(sock) - - -def test_asgi_websockets_10_1_1(): - client.load('websockets/mirror') - - _, sock, _ = ws.upgrade() - - payload = '*' * 65536 - - ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1300) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - close_connection(sock) - - -# settings - - -def test_asgi_websockets_max_frame_size(): - client.load('websockets/mirror') - - assert 'success' in client.conf( - {'http': {'websocket': {'max_frame_size': 100}}}, 'settings' - ), 'configure max_frame_size' - - _, sock, _ = ws.upgrade() - - payload = '*' * 94 - opcode = ws.OP_TEXT - - ws.frame_write(sock, opcode, payload) # frame length is 100 - - frame = ws.frame_read(sock) - check_frame(frame, True, opcode, payload) - - payload = '*' * 95 - - ws.frame_write(sock, opcode, payload) # frame length is 101 - check_close(sock, 1009) # 1009 - CLOSE_TOO_LARGE - - -def test_asgi_websockets_read_timeout(): - client.load('websockets/mirror') - - assert 'success' in client.conf( - {'http': {'websocket': {'read_timeout': 5}}}, 'settings' - ), 'configure read_timeout' - - _, sock, _ = ws.upgrade() - - frame = ws.frame_to_send(ws.OP_TEXT, 'blah') - sock.sendall(frame[:2]) - - time.sleep(2) - - check_close(sock, 1001) # 1001 - CLOSE_GOING_AWAY - - -def test_asgi_websockets_keepalive_interval(): - client.load('websockets/mirror') - - assert 'success' in client.conf( - {'http': {'websocket': {'keepalive_interval': 5}}}, 'settings' - ), 'configure keepalive_interval' - - _, sock, _ = ws.upgrade() - - frame = ws.frame_to_send(ws.OP_TEXT, 'blah') - sock.sendall(frame[:2]) - - time.sleep(2) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PING, '') # PING frame - - sock.close() - - -def test_asgi_websockets_client_locks_app(): - client.load('websockets/mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - assert 'success' in client.conf({}), 'remove app' - - ws.frame_write(sock, ws.OP_TEXT, message) - - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'client' - - sock.close() diff --git a/test/test_client_ip.py b/test/test_client_ip.py deleted file mode 100644 index 538db18b..00000000 --- a/test/test_client_ip.py +++ /dev/null @@ -1,187 +0,0 @@ -import pytest - -from unit.applications.lang.python import ApplicationPython -from unit.option import option - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - client.load('client_ip') - - -def client_ip(options): - assert 'success' in client.conf( - { - "127.0.0.1:8081": { - "client_ip": options, - "pass": "applications/client_ip", - }, - "[::1]:8082": { - "client_ip": options, - "pass": "applications/client_ip", - }, - f"unix:{option.temp_dir}/sock": { - "client_ip": options, - "pass": "applications/client_ip", - }, - }, - 'listeners', - ), 'listeners configure' - - -def get_xff(xff, sock_type='ipv4'): - address = { - 'ipv4': ('127.0.0.1', 8081), - 'ipv6': ('::1', 8082), - 'unix': (f'{option.temp_dir}/sock', None), - } - (addr, port) = address[sock_type] - - return client.get( - sock_type=sock_type, - addr=addr, - port=port, - headers={'Connection': 'close', 'X-Forwarded-For': xff}, - )['body'] - - -def test_client_ip_single_ip(): - client_ip({'header': 'X-Forwarded-For', 'source': '123.123.123.123'}) - - assert client.get(port=8081)['body'] == '127.0.0.1', 'ipv4 default' - assert ( - client.get(sock_type='ipv6', port=8082)['body'] == '::1' - ), 'ipv6 default' - assert get_xff('1.1.1.1') == '127.0.0.1', 'bad source' - assert get_xff('blah') == '127.0.0.1', 'bad header' - assert get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6' - - client_ip({'header': 'X-Forwarded-For', 'source': '127.0.0.1'}) - - assert client.get(port=8081)['body'] == '127.0.0.1', 'ipv4 default 2' - assert ( - client.get(sock_type='ipv6', port=8082)['body'] == '::1' - ), 'ipv6 default 2' - assert get_xff('1.1.1.1') == '1.1.1.1', 'replace' - assert get_xff('blah') == '127.0.0.1', 'bad header 2' - assert get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6 2' - - client_ip({'header': 'X-Forwarded-For', 'source': '!127.0.0.1'}) - - assert get_xff('1.1.1.1') == '127.0.0.1', 'bad source 3' - assert get_xff('1.1.1.1', 'ipv6') == '1.1.1.1', 'replace 2' - - -def test_client_ip_ipv4(): - client_ip({'header': 'X-Forwarded-For', 'source': '127.0.0.1'}) - - assert get_xff('8.8.8.8, 84.23.23.11') == '84.23.23.11', 'xff replace' - assert ( - get_xff('8.8.8.8, 84.23.23.11, 127.0.0.1') == '127.0.0.1' - ), 'xff replace 2' - assert ( - get_xff(['8.8.8.8', '127.0.0.1, 10.0.1.1']) == '10.0.1.1' - ), 'xff replace multi' - - -def test_client_ip_ipv6(): - client_ip({'header': 'X-Forwarded-For', 'source': '::1'}) - - assert get_xff('1.1.1.1') == '127.0.0.1', 'bad source ipv4' - - for ip in [ - 'f607:7403:1e4b:6c66:33b2:843f:2517:da27', - '2001:db8:3c4d:15::1a2f:1a2b', - '2001::3c4d:15:1a2f:1a2b', - '::11.22.33.44', - ]: - assert get_xff(ip, 'ipv6') == ip, 'replace' - - -def test_client_ip_unix(): - client_ip({'header': 'X-Forwarded-For', 'source': 'unix'}) - - assert get_xff('1.1.1.1') == '127.0.0.1', 'bad source ipv4' - assert get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6' - - for ip in [ - '1.1.1.1', - '::11.22.33.44', - ]: - assert get_xff(ip, 'unix') == ip, 'replace' - - -def test_client_ip_recursive(): - client_ip( - { - 'header': 'X-Forwarded-For', - 'recursive': True, - 'source': ['127.0.0.1', '10.50.0.17', '10.5.2.1'], - } - ) - - assert get_xff('1.1.1.1') == '1.1.1.1', 'xff chain' - assert get_xff('1.1.1.1, 10.5.2.1') == '1.1.1.1', 'xff chain 2' - assert get_xff('8.8.8.8, 1.1.1.1, 10.5.2.1') == '1.1.1.1', 'xff chain 3' - assert ( - get_xff('10.50.0.17, 10.5.2.1, 10.5.2.1') == '10.50.0.17' - ), 'xff chain 4' - assert ( - get_xff(['8.8.8.8', '1.1.1.1, 127.0.0.1']) == '1.1.1.1' - ), 'xff replace multi' - assert ( - get_xff(['8.8.8.8', '1.1.1.1, 127.0.0.1', '10.5.2.1']) == '1.1.1.1' - ), 'xff replace multi 2' - assert ( - get_xff(['10.5.2.1', '10.50.0.17, 1.1.1.1', '10.5.2.1']) == '1.1.1.1' - ), 'xff replace multi 3' - assert ( - get_xff('8.8.8.8, 2001:db8:3c4d:15::1a2f:1a2b, 127.0.0.1') - == '2001:db8:3c4d:15::1a2f:1a2b' - ), 'xff chain ipv6' - - -def test_client_ip_case_insensitive(): - client_ip({'header': 'x-forwarded-for', 'source': '127.0.0.1'}) - - assert get_xff('1.1.1.1') == '1.1.1.1', 'case insensitive' - - -def test_client_ip_empty_source(): - client_ip({'header': 'X-Forwarded-For', 'source': []}) - - assert get_xff('1.1.1.1') == '127.0.0.1', 'empty source' - - -def test_client_ip_invalid(): - assert 'error' in client.conf( - { - "127.0.0.1:8081": { - "client_ip": {"source": '127.0.0.1'}, - "pass": "applications/client_ip", - } - }, - 'listeners', - ), 'invalid header' - - def check_invalid_source(source): - assert 'error' in client.conf( - { - "127.0.0.1:8081": { - "client_ip": { - "header": "X-Forwarded-For", - "source": source, - }, - "pass": "applications/client_ip", - } - }, - 'listeners', - ), 'invalid source' - - check_invalid_source(None) - check_invalid_source('a') - check_invalid_source(['a']) diff --git a/test/test_configuration.py b/test/test_configuration.py deleted file mode 100644 index a7d519e9..00000000 --- a/test/test_configuration.py +++ /dev/null @@ -1,466 +0,0 @@ -import socket - -import pytest - -from unit.control import Control - -prerequisites = {'modules': {'python': 'any'}} - -client = Control() - - -def try_addr(addr): - return client.conf( - { - "listeners": {addr: {"pass": "routes"}}, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ) - - -def test_json_empty(): - assert 'error' in client.conf(''), 'empty' - - -def test_json_leading_zero(): - assert 'error' in client.conf('00'), 'leading zero' - - -def test_json_unicode(): - assert 'success' in client.conf( - """ - { - "ap\u0070": { - "type": "\u0070ython", - "processes": { "spare": 0 }, - "path": "\u002Fapp", - "module": "wsgi" - } - } - """, - 'applications', - ), 'unicode' - - assert client.conf_get('applications') == { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, 'unicode get' - - -def test_json_unicode_2(): - assert 'success' in client.conf( - { - "приложение": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - 'applications', - ), 'unicode 2' - - assert 'приложение' in client.conf_get('applications') - - -def test_json_unicode_number(): - assert 'success' in client.conf( - """ - { - "app": { - "type": "python", - "processes": { "spare": \u0030 }, - "path": "/app", - "module": "wsgi" - } - } - """, - 'applications', - ), 'unicode number' - - -def test_json_utf8_bom(): - assert 'success' in client.conf( - b"""\xEF\xBB\xBF - { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi" - } - } - """, - 'applications', - ), 'UTF-8 BOM' - - -def test_json_comment_single_line(): - assert 'success' in client.conf( - b""" - // this is bridge - { - "//app": { - "type": "python", // end line - "processes": {"spare": 0}, - // inside of block - "path": "/app", - "module": "wsgi" - } - // double // - } - // end of json \xEF\t - """, - 'applications', - ), 'single line comments' - - -def test_json_comment_multi_line(): - assert 'success' in client.conf( - b""" - /* this is bridge */ - { - "/*app": { - /** - * multiple lines - **/ - "type": "python", - "processes": /* inline */ {"spare": 0}, - "path": "/app", - "module": "wsgi" - /* - // end of block */ - } - /* blah * / blah /* blah */ - } - /* end of json \xEF\t\b */ - """, - 'applications', - ), 'multi line comments' - - -def test_json_comment_invalid(): - assert 'error' in client.conf(b'/{}', 'applications'), 'slash' - assert 'error' in client.conf(b'//{}', 'applications'), 'comment' - assert 'error' in client.conf(b'{} /', 'applications'), 'slash end' - assert 'error' in client.conf(b'/*{}', 'applications'), 'slash star' - assert 'error' in client.conf(b'{} /*', 'applications'), 'slash star end' - - -def test_applications_open_brace(): - assert 'error' in client.conf('{', 'applications'), 'open brace' - - -def test_applications_string(): - assert 'error' in client.conf('"{}"', 'applications'), 'string' - - -@pytest.mark.skip('not yet, unsafe') -def test_applications_type_only(): - assert 'error' in client.conf( - {"app": {"type": "python"}}, 'applications' - ), 'type only' - - -def test_applications_miss_quote(): - assert 'error' in client.conf( - """ - { - app": { - "type": "python", - "processes": { "spare": 0 }, - "path": "/app", - "module": "wsgi" - } - } - """, - 'applications', - ), 'miss quote' - - -def test_applications_miss_colon(): - assert 'error' in client.conf( - """ - { - "app" { - "type": "python", - "processes": { "spare": 0 }, - "path": "/app", - "module": "wsgi" - } - } - """, - 'applications', - ), 'miss colon' - - -def test_applications_miss_comma(): - assert 'error' in client.conf( - """ - { - "app": { - "type": "python" - "processes": { "spare": 0 }, - "path": "/app", - "module": "wsgi" - } - } - """, - 'applications', - ), 'miss comma' - - -def test_applications_skip_spaces(): - assert 'success' in client.conf(b'{ \n\r\t}', 'applications'), 'skip spaces' - - -def test_applications_relative_path(): - assert 'success' in client.conf( - { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "../app", - "module": "wsgi", - } - }, - 'applications', - ), 'relative path' - - -@pytest.mark.skip('not yet, unsafe') -def test_listeners_empty(): - assert 'error' in client.conf({"*:8080": {}}, 'listeners'), 'listener empty' - - -def test_listeners_no_app(): - assert 'error' in client.conf( - {"*:8080": {"pass": "applications/app"}}, 'listeners' - ), 'listeners no app' - - -def test_listeners_unix_abstract(system): - if system != 'Linux': - assert 'error' in try_addr("unix:@sock"), 'abstract at' - - pytest.skip('not yet') - - assert 'error' in try_addr("unix:\0soc"), 'abstract \0' - assert 'error' in try_addr("unix:\u0000soc"), 'abstract \0 unicode' - - -def test_listeners_addr(): - assert 'success' in try_addr("*:8080"), 'wildcard' - assert 'success' in try_addr("127.0.0.1:8081"), 'explicit' - assert 'success' in try_addr("[::1]:8082"), 'explicit ipv6' - - -def test_listeners_addr_error(): - assert 'error' in try_addr("127.0.0.1"), 'no port' - - -def test_listeners_addr_error_2(skip_alert): - skip_alert(r'bind.*failed', r'failed to apply new conf') - - assert 'error' in try_addr("[f607:7403:1e4b:6c66:33b2:843f:2517:da27]:8080") - - -def test_listeners_port_release(): - for _ in range(10): - fail = False - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - client.conf( - { - "listeners": {"127.0.0.1:8080": {"pass": "routes"}}, - "routes": [], - } - ) - - resp = client.conf({"listeners": {}, "applications": {}}) - - try: - s.bind(('127.0.0.1', 8080)) - s.listen() - - except OSError: - fail = True - - if fail: - pytest.fail('cannot bind or listen to the address') - - assert 'success' in resp, 'port release' - - -def test_json_application_name_large(): - name = "X" * 1024 * 1024 - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": f"applications/{name}"}}, - "applications": { - name: { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - } - ) - - -@pytest.mark.skip('not yet') -def test_json_application_many(): - apps = 999 - - conf = { - "applications": { - f"app-{a}": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - for a in range(apps) - }, - "listeners": { - f"*:{(7000 + a)}": {"pass": f"applications/app-{a}"} - for a in range(apps) - }, - } - - assert 'success' in client.conf(conf) - - -def test_json_application_python_prefix(): - conf = { - "applications": { - "sub-app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - "prefix": "/app", - } - }, - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": "/app/*"}, - "action": {"pass": "applications/sub-app"}, - } - ], - } - - assert 'success' in client.conf(conf) - - -def test_json_application_prefix_target(): - conf = { - "applications": { - "sub-app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "targets": { - "foo": {"module": "foo.wsgi", "prefix": "/app"}, - "bar": { - "module": "bar.wsgi", - "callable": "bar", - "prefix": "/api", - }, - }, - } - }, - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": "/app/*"}, - "action": {"pass": "applications/sub-app/foo"}, - }, - { - "match": {"uri": "/api/*"}, - "action": {"pass": "applications/sub-app/bar"}, - }, - ], - } - - assert 'success' in client.conf(conf) - - -def test_json_application_invalid_python_prefix(): - conf = { - "applications": { - "sub-app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - "prefix": "app", - } - }, - "listeners": {"*:8080": {"pass": "applications/sub-app"}}, - } - - assert 'error' in client.conf(conf) - - -def test_json_application_empty_python_prefix(): - conf = { - "applications": { - "sub-app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - "prefix": "", - } - }, - "listeners": {"*:8080": {"pass": "applications/sub-app"}}, - } - - assert 'error' in client.conf(conf) - - -def test_json_application_many2(): - conf = { - "applications": { - f"app-{a}": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - # Larger number of applications can cause test fail with default - # open files limit due to the lack of file descriptors. - for a in range(100) - }, - "listeners": {"*:8080": {"pass": "applications/app-1"}}, - } - - assert 'success' in client.conf(conf) - - -def test_unprivileged_user_error(require, skip_alert): - require({'privileged_user': False}) - - skip_alert(r'cannot set user "root"', r'failed to apply new conf') - - assert 'error' in client.conf( - { - "app": { - "type": "external", - "processes": 1, - "executable": "/app", - "user": "root", - } - }, - 'applications', - ), 'setting user' diff --git a/test/test_forwarded_header.py b/test/test_forwarded_header.py deleted file mode 100644 index 4b2f9424..00000000 --- a/test/test_forwarded_header.py +++ /dev/null @@ -1,271 +0,0 @@ -import pytest - -from unit.applications.lang.python import ApplicationPython - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - client.load('forwarded_header') - - -def forwarded_header(forwarded): - assert 'success' in client.conf( - { - "127.0.0.1:8081": { - "forwarded": forwarded, - "pass": "applications/forwarded_header", - }, - "[::1]:8082": { - "forwarded": forwarded, - "pass": "applications/forwarded_header", - }, - }, - 'listeners', - ), 'listeners configure' - - -def get_fwd(sock_type='ipv4', xff=None, xfp=None): - port = 8081 if sock_type == 'ipv4' else 8082 - - headers = {'Connection': 'close'} - - if xff is not None: - headers['X-Forwarded-For'] = xff - - if xfp is not None: - headers['X-Forwarded-Proto'] = xfp - - return client.get(sock_type=sock_type, port=port, headers=headers)[ - 'headers' - ] - - -def get_addr(*args, **kwargs): - return get_fwd(*args, **kwargs)['Remote-Addr'] - - -def get_scheme(*args, **kwargs): - return get_fwd(*args, **kwargs)['Url-Scheme'] - - -def test_forwarded_header_single_ip(): - forwarded_header( - { - 'client_ip': 'X-Forwarded-For', - 'protocol': 'X-Forwarded-Proto', - 'source': '123.123.123.123', - } - ) - - resp = get_fwd(xff='1.1.1.1', xfp='https') - assert resp['Remote-Addr'] == '127.0.0.1', 'both headers addr' - assert resp['Url-Scheme'] == 'http', 'both headers proto' - - assert get_addr() == '127.0.0.1', 'ipv4 default addr' - assert get_addr('ipv6') == '::1', 'ipv6 default addr' - assert get_addr(xff='1.1.1.1') == '127.0.0.1', 'bad source' - assert get_addr(xff='blah') == '127.0.0.1', 'bad xff' - assert get_addr('ipv6', '1.1.1.1') == '::1', 'bad source ipv6' - - assert get_scheme() == 'http', 'ipv4 default proto' - assert get_scheme('ipv6') == 'http', 'ipv6 default proto' - assert get_scheme(xfp='https') == 'http', 'bad proto' - assert get_scheme(xfp='blah') == 'http', 'bad xfp' - assert get_scheme('ipv6', xfp='https') == 'http', 'bad proto ipv6' - - forwarded_header( - { - 'client_ip': 'X-Forwarded-For', - 'protocol': 'X-Forwarded-Proto', - 'source': '127.0.0.1', - } - ) - - resp = get_fwd(xff='1.1.1.1', xfp='https') - assert resp['Remote-Addr'] == '1.1.1.1', 'both headers addr 2' - assert resp['Url-Scheme'] == 'https', 'both headers proto 2' - - assert get_addr() == '127.0.0.1', 'ipv4 default addr 2' - assert get_addr('ipv6') == '::1', 'ipv6 default addr 2' - assert get_addr(xff='1.1.1.1') == '1.1.1.1', 'xff replace' - assert get_addr('ipv6', '1.1.1.1') == '::1', 'bad source ipv6 2' - - assert get_scheme() == 'http', 'ipv4 default proto 2' - assert get_scheme('ipv6') == 'http', 'ipv6 default proto 2' - assert get_scheme(xfp='https') == 'https', 'xfp replace' - assert get_scheme(xfp='on') == 'https', 'xfp replace 2' - assert get_scheme('ipv6', xfp='https') == 'http', 'bad proto ipv6 2' - - forwarded_header( - { - 'client_ip': 'X-Forwarded-For', - 'protocol': 'X-Forwarded-Proto', - 'source': '!127.0.0.1', - } - ) - - assert get_addr(xff='1.1.1.1') == '127.0.0.1', 'bad source 3' - assert get_addr('ipv6', '1.1.1.1') == '1.1.1.1', 'xff replace 2' - assert get_scheme(xfp='https') == 'http', 'bad proto 2' - assert get_scheme('ipv6', xfp='https') == 'https', 'xfp replace 3' - - -def test_forwarded_header_ipv4(): - forwarded_header( - { - 'client_ip': 'X-Forwarded-For', - 'protocol': 'X-Forwarded-Proto', - 'source': '127.0.0.1', - } - ) - - assert get_addr(xff='8.8.8.8, 84.23.23.11') == '84.23.23.11', 'xff replace' - assert ( - get_addr(xff='8.8.8.8, 84.23.23.11, 127.0.0.1') == '127.0.0.1' - ), 'xff replace 2' - assert ( - get_addr(xff=['8.8.8.8', '127.0.0.1, 10.0.1.1']) == '10.0.1.1' - ), 'xff replace multi' - - assert get_scheme(xfp='http, https') == 'http', 'xfp replace' - assert get_scheme(xfp='http, https, http') == 'http', 'xfp replace 2' - assert ( - get_scheme(xfp=['http, https', 'http', 'https']) == 'http' - ), 'xfp replace multi' - - -def test_forwarded_header_ipv6(): - forwarded_header( - { - 'client_ip': 'X-Forwarded-For', - 'protocol': 'X-Forwarded-Proto', - 'source': '::1', - } - ) - - assert get_addr(xff='1.1.1.1') == '127.0.0.1', 'bad source ipv4' - - for ip in [ - 'f607:7403:1e4b:6c66:33b2:843f:2517:da27', - '2001:db8:3c4d:15::1a2f:1a2b', - '2001::3c4d:15:1a2f:1a2b', - '::11.22.33.44', - ]: - assert get_addr('ipv6', ip) == ip, 'replace' - - assert get_scheme(xfp='https') == 'http', 'bad source ipv4' - - for proto in ['http', 'https']: - assert get_scheme('ipv6', xfp=proto) == proto, 'replace' - - -def test_forwarded_header_recursive(): - forwarded_header( - { - 'client_ip': 'X-Forwarded-For', - 'recursive': True, - 'source': ['127.0.0.1', '10.50.0.17', '10.5.2.1'], - } - ) - - assert get_addr(xff='1.1.1.1') == '1.1.1.1', 'xff chain' - assert get_addr(xff='1.1.1.1, 10.5.2.1') == '1.1.1.1', 'xff chain 2' - assert ( - get_addr(xff='8.8.8.8, 1.1.1.1, 10.5.2.1') == '1.1.1.1' - ), 'xff chain 3' - assert ( - get_addr(xff='10.50.0.17, 10.5.2.1, 10.5.2.1') == '10.50.0.17' - ), 'xff chain 4' - assert ( - get_addr(xff=['8.8.8.8', '1.1.1.1, 127.0.0.1']) == '1.1.1.1' - ), 'xff replace multi' - assert ( - get_addr(xff=['8.8.8.8', '1.1.1.1, 127.0.0.1', '10.5.2.1']) == '1.1.1.1' - ), 'xff replace multi 2' - assert ( - get_addr(xff=['10.5.2.1', '10.50.0.17, 1.1.1.1', '10.5.2.1']) - == '1.1.1.1' - ), 'xff replace multi 3' - assert ( - get_addr(xff='8.8.8.8, 2001:db8:3c4d:15::1a2f:1a2b, 127.0.0.1') - == '2001:db8:3c4d:15::1a2f:1a2b' - ), 'xff chain ipv6' - - -def test_forwarded_header_case_insensitive(): - forwarded_header( - { - 'client_ip': 'x-forwarded-for', - 'protocol': 'x-forwarded-proto', - 'source': '127.0.0.1', - } - ) - - assert get_addr() == '127.0.0.1', 'ipv4 default addr' - assert get_addr('ipv6') == '::1', 'ipv6 default addr' - assert get_addr(xff='1.1.1.1') == '1.1.1.1', 'replace' - - assert get_scheme() == 'http', 'ipv4 default proto' - assert get_scheme('ipv6') == 'http', 'ipv6 default proto' - assert get_scheme(xfp='https') == 'https', 'replace 1' - assert get_scheme(xfp='oN') == 'https', 'replace 2' - - -def test_forwarded_header_source_empty(): - forwarded_header( - { - 'client_ip': 'X-Forwarded-For', - 'protocol': 'X-Forwarded-Proto', - 'source': [], - } - ) - - assert get_addr(xff='1.1.1.1') == '127.0.0.1', 'empty source xff' - assert get_scheme(xfp='https') == 'http', 'empty source xfp' - - -def test_forwarded_header_source_range(): - forwarded_header( - { - 'client_ip': 'X-Forwarded-For', - 'protocol': 'X-Forwarded-Proto', - 'source': '127.0.0.0-127.0.0.1', - } - ) - - assert get_addr(xff='1.1.1.1') == '1.1.1.1', 'source range' - assert get_addr('ipv6', '1.1.1.1') == '::1', 'source range 2' - - -def test_forwarded_header_invalid(): - assert 'error' in client.conf( - { - "127.0.0.1:8081": { - "forwarded": {"source": '127.0.0.1'}, - "pass": "applications/forwarded_header", - } - }, - 'listeners', - ), 'invalid forward' - - def check_invalid_source(source): - assert 'error' in client.conf( - { - "127.0.0.1:8081": { - "forwarded": { - "client_ip": "X-Forwarded-For", - "source": source, - }, - "pass": "applications/forwarded_header", - } - }, - 'listeners', - ), 'invalid source' - - check_invalid_source(None) - check_invalid_source('a') - check_invalid_source(['a']) diff --git a/test/test_go_application.py b/test/test_go_application.py deleted file mode 100644 index 469d4346..00000000 --- a/test/test_go_application.py +++ /dev/null @@ -1,168 +0,0 @@ -import re - -from unit.applications.lang.go import ApplicationGo - -prerequisites = {'modules': {'go': 'all'}} - -client = ApplicationGo() - - -def test_go_application_variables(date_to_sec_epoch, sec_epoch): - client.load('variables') - - body = 'Test body string.' - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Custom-Header': 'blah', - 'Connection': 'close', - }, - body=body, - ) - - assert resp['status'] == 200, 'status' - headers = resp['headers'] - header_server = headers.pop('Server') - assert re.search(r'Unit/[\d\.]+', header_server), 'server header' - - date = headers.pop('Date') - assert date[-4:] == ' GMT', 'date header timezone' - assert abs(date_to_sec_epoch(date) - sec_epoch) < 5, 'date header' - - assert headers == { - 'Content-Length': str(len(body)), - 'Content-Type': 'text/html', - 'Request-Method': 'POST', - 'Request-Uri': '/', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Server-Protocol-Major': '1', - 'Server-Protocol-Minor': '1', - 'Custom-Header': 'blah', - 'Connection': 'close', - }, 'headers' - assert resp['body'] == body, 'body' - - -def test_go_application_get_variables(): - client.load('get_variables') - - resp = client.get(url='/?var1=val1&var2=&var3') - assert resp['headers']['X-Var-1'] == 'val1', 'GET variables' - assert resp['headers']['X-Var-2'] == '', 'GET variables 2' - assert resp['headers']['X-Var-3'] == '', 'GET variables 3' - - -def test_go_application_post_variables(): - client.load('post_variables') - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'application/x-www-form-urlencoded', - 'Connection': 'close', - }, - body='var1=val1&var2=&var3', - ) - - assert resp['headers']['X-Var-1'] == 'val1', 'POST variables' - assert resp['headers']['X-Var-2'] == '', 'POST variables 2' - assert resp['headers']['X-Var-3'] == '', 'POST variables 3' - - -def test_go_application_404(): - client.load('404') - - resp = client.get() - - assert resp['status'] == 404, '404 status' - assert re.search(r'404 Not Found', resp['body']), '404 body' - - -def test_go_keepalive_body(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' * 500 - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive 1' - - body = '0123456789' - resp = client.post(sock=sock, body=body) - assert resp['body'] == body, 'keep-alive 2' - - -def test_go_application_cookies(): - client.load('cookies') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'var1=val1; var2=val2', - 'Connection': 'close', - } - ) - - assert resp['headers']['X-Cookie-1'] == 'val1', 'cookie 1' - assert resp['headers']['X-Cookie-2'] == 'val2', 'cookie 2' - - -def test_go_application_command_line_arguments_type(): - client.load('command_line_arguments') - - assert 'error' in client.conf( - "a b c", 'applications/command_line_arguments/arguments' - ), 'arguments type' - - -def test_go_application_command_line_arguments_0(): - client.load('command_line_arguments') - - assert client.get()['headers']['X-Arg-0'] == client.conf_get( - 'applications/command_line_arguments/executable' - ), 'argument 0' - - -def test_go_application_command_line_arguments(): - client.load('command_line_arguments') - - arg1 = '--cc=gcc-7.2.0' - arg2 = "--cc-opt='-O0 -DNXT_DEBUG_MEMORY=1 -fsanitize=address'" - arg3 = '--debug' - - assert 'success' in client.conf( - f'["{arg1}", "{arg2}", "{arg3}"]', - 'applications/command_line_arguments/arguments', - ) - - assert client.get()['body'] == f'{arg1},{arg2},{arg3}', 'arguments' - - -def test_go_application_command_line_arguments_change(): - client.load('command_line_arguments') - - args_path = 'applications/command_line_arguments/arguments' - - assert 'success' in client.conf('["0", "a", "$", ""]', args_path) - - assert client.get()['body'] == '0,a,$,', 'arguments' - - assert 'success' in client.conf('["-1", "b", "%"]', args_path) - - assert client.get()['body'] == '-1,b,%', 'arguments change' - - assert 'success' in client.conf('[]', args_path) - - assert client.get()['headers']['Content-Length'] == '0', 'arguments empty' diff --git a/test/test_go_isolation.py b/test/test_go_isolation.py deleted file mode 100644 index a864e9f6..00000000 --- a/test/test_go_isolation.py +++ /dev/null @@ -1,368 +0,0 @@ -import grp -import os -import pwd - -import pytest - -from unit.applications.lang.go import ApplicationGo -from unit.option import option -from unit.utils import getns - -prerequisites = {'modules': {'go': 'any'}, 'features': {'isolation': True}} - -client = ApplicationGo() - - -def unpriv_creds(): - nobody_uid = pwd.getpwnam('nobody').pw_uid - - try: - nogroup_gid = grp.getgrnam('nogroup').gr_gid - nogroup = 'nogroup' - except KeyError: - nogroup_gid = grp.getgrnam('nobody').gr_gid - nogroup = 'nobody' - - return (nobody_uid, nogroup_gid, nogroup) - - -def test_isolation_values(): - client.load('ns_inspect') - - obj = client.getjson()['body'] - - for ns, ns_value in option.available['features']['isolation'].items(): - if ns.upper() in obj['NS']: - assert obj['NS'][ns.upper()] == ns_value, f'{ns} match' - - -def test_isolation_unpriv_user(require): - require( - { - 'privileged_user': False, - 'features': {'isolation': ['unprivileged_userns_clone']}, - } - ) - - client.load('ns_inspect') - obj = client.getjson()['body'] - - assert obj['UID'] == os.geteuid(), 'uid match' - assert obj['GID'] == os.getegid(), 'gid match' - - client.load('ns_inspect', isolation={'namespaces': {'credential': True}}) - - obj = client.getjson()['body'] - - nobody_uid, nogroup_gid, nogroup = unpriv_creds() - - # unprivileged unit map itself to nobody in the container by default - assert obj['UID'] == nobody_uid, 'uid of nobody' - assert obj['GID'] == nogroup_gid, f'gid of {nogroup}' - - client.load( - 'ns_inspect', - user='root', - isolation={'namespaces': {'credential': True}}, - ) - - obj = client.getjson()['body'] - - assert obj['UID'] == 0, 'uid match user=root' - assert obj['GID'] == 0, 'gid match user=root' - - client.load( - 'ns_inspect', - user='root', - group=nogroup, - isolation={'namespaces': {'credential': True}}, - ) - - obj = client.getjson()['body'] - - assert obj['UID'] == 0, 'uid match user=root group=nogroup' - assert obj['GID'] == nogroup_gid, 'gid match user=root group=nogroup' - - client.load( - 'ns_inspect', - user='root', - group='root', - isolation={ - 'namespaces': {'credential': True}, - 'uidmap': [{'container': 0, 'host': os.geteuid(), 'size': 1}], - 'gidmap': [{'container': 0, 'host': os.getegid(), 'size': 1}], - }, - ) - - obj = client.getjson()['body'] - - assert obj['UID'] == 0, 'uid match uidmap' - assert obj['GID'] == 0, 'gid match gidmap' - - -def test_isolation_priv_user(require): - require({'privileged_user': True}) - - client.load('ns_inspect') - - nobody_uid, nogroup_gid, nogroup = unpriv_creds() - - obj = client.getjson()['body'] - - assert obj['UID'] == nobody_uid, 'uid match' - assert obj['GID'] == nogroup_gid, 'gid match' - - client.load('ns_inspect', isolation={'namespaces': {'credential': True}}) - - obj = client.getjson()['body'] - - # privileged unit map app creds in the container by default - assert obj['UID'] == nobody_uid, 'uid nobody' - assert obj['GID'] == nogroup_gid, 'gid nobody' - - client.load( - 'ns_inspect', - user='root', - isolation={'namespaces': {'credential': True}}, - ) - - obj = client.getjson()['body'] - - assert obj['UID'] == 0, 'uid nobody user=root' - assert obj['GID'] == 0, 'gid nobody user=root' - - client.load( - 'ns_inspect', - user='root', - group=nogroup, - isolation={'namespaces': {'credential': True}}, - ) - - obj = client.getjson()['body'] - - assert obj['UID'] == 0, 'uid match user=root group=nogroup' - assert obj['GID'] == nogroup_gid, 'gid match user=root group=nogroup' - - client.load( - 'ns_inspect', - user='root', - group='root', - isolation={ - 'namespaces': {'credential': True}, - 'uidmap': [{'container': 0, 'host': 0, 'size': 1}], - 'gidmap': [{'container': 0, 'host': 0, 'size': 1}], - }, - ) - - obj = client.getjson()['body'] - - assert obj['UID'] == 0, 'uid match uidmap user=root' - assert obj['GID'] == 0, 'gid match gidmap user=root' - - # map 65535 uids - client.load( - 'ns_inspect', - user='nobody', - isolation={ - 'namespaces': {'credential': True}, - 'uidmap': [{'container': 0, 'host': 0, 'size': nobody_uid + 1}], - }, - ) - - obj = client.getjson()['body'] - - assert obj['UID'] == nobody_uid, 'uid match uidmap user=nobody' - assert obj['GID'] == nogroup_gid, 'gid match uidmap user=nobody' - - -def test_isolation_mnt(require): - require( - { - 'features': {'isolation': ['unprivileged_userns_clone', 'mnt']}, - } - ) - - client.load( - 'ns_inspect', - isolation={'namespaces': {'mount': True, 'credential': True}}, - ) - - obj = client.getjson()['body'] - - # all but user and mnt - allns = list(option.available['features']['isolation'].keys()) - allns.remove('user') - allns.remove('mnt') - - for ns in allns: - if ns.upper() in obj['NS']: - assert ( - obj['NS'][ns.upper()] - == option.available['features']['isolation'][ns] - ), f'{ns} match' - - assert obj['NS']['MNT'] != getns('mnt'), 'mnt set' - assert obj['NS']['USER'] != getns('user'), 'user set' - - -def test_isolation_pid(is_su, require): - require({'features': {'isolation': ['pid']}}) - - if not is_su: - require( - { - 'features': { - 'isolation': [ - 'unprivileged_userns_clone', - 'user', - 'mnt', - ] - } - } - ) - - isolation = {'namespaces': {'pid': True}} - - if not is_su: - isolation['namespaces']['mount'] = True - isolation['namespaces']['credential'] = True - - client.load('ns_inspect', isolation=isolation) - - obj = client.getjson()['body'] - - assert obj['PID'] == 2, 'pid of container is 2' - - -def test_isolation_namespace_false(): - client.load('ns_inspect') - allns = list(option.available['features']['isolation'].keys()) - - remove_list = ['unprivileged_userns_clone', 'ipc', 'cgroup'] - allns = [ns for ns in allns if ns not in remove_list] - - namespaces = {} - for ns in allns: - if ns == 'user': - namespaces['credential'] = False - elif ns == 'mnt': - namespaces['mount'] = False - elif ns == 'net': - namespaces['network'] = False - elif ns == 'uts': - namespaces['uname'] = False - else: - namespaces[ns] = False - - client.load('ns_inspect', isolation={'namespaces': namespaces}) - - obj = client.getjson()['body'] - - for ns in allns: - if ns.upper() in obj['NS']: - assert ( - obj['NS'][ns.upper()] - == option.available['features']['isolation'][ns] - ), f'{ns} match' - - -def test_go_isolation_rootfs_container(is_su, require, temp_dir): - if not is_su: - require( - { - 'features': { - 'isolation': [ - 'unprivileged_userns_clone', - 'user', - 'mnt', - 'pid', - ] - } - } - ) - - isolation = {'rootfs': temp_dir} - - if not is_su: - isolation['namespaces'] = { - 'mount': True, - 'credential': True, - 'pid': True, - } - - client.load('ns_inspect', isolation=isolation) - - obj = client.getjson(url='/?file=/go/app')['body'] - - assert obj['FileExists'], 'app relative to rootfs' - - obj = client.getjson(url='/?file=/bin/sh')['body'] - assert not obj['FileExists'], 'file should not exists' - - -def test_go_isolation_rootfs_container_priv(require, temp_dir): - require({'privileged_user': True, 'features': {'isolation': ['mnt']}}) - - isolation = { - 'namespaces': {'mount': True}, - 'rootfs': temp_dir, - } - - client.load('ns_inspect', isolation=isolation) - - obj = client.getjson(url='/?file=/go/app')['body'] - - assert obj['FileExists'], 'app relative to rootfs' - - obj = client.getjson(url='/?file=/bin/sh')['body'] - assert not obj['FileExists'], 'file should not exists' - - -def test_go_isolation_rootfs_automount_tmpfs(is_su, require, temp_dir): - try: - open("/proc/self/mountinfo", encoding='utf-8') - except: - pytest.skip('The system lacks /proc/self/mountinfo file') - - if not is_su: - require( - { - 'features': { - 'isolation': [ - 'unprivileged_userns_clone', - 'user', - 'mnt', - 'pid', - ] - } - } - ) - - isolation = {'rootfs': temp_dir} - - if not is_su: - isolation['namespaces'] = { - 'mount': True, - 'credential': True, - 'pid': True, - } - - isolation['automount'] = {'tmpfs': False} - - client.load('ns_inspect', isolation=isolation) - - obj = client.getjson(url='/?mounts=true')['body'] - - assert ( - "/ /tmp" not in obj['Mounts'] and "tmpfs" not in obj['Mounts'] - ), 'app has no /tmp mounted' - - isolation['automount'] = {'tmpfs': True} - - client.load('ns_inspect', isolation=isolation) - - obj = client.getjson(url='/?mounts=true')['body'] - - assert ( - "/ /tmp" in obj['Mounts'] and "tmpfs" in obj['Mounts'] - ), 'app has /tmp mounted on /' diff --git a/test/test_go_isolation_rootfs.py b/test/test_go_isolation_rootfs.py deleted file mode 100644 index b627b515..00000000 --- a/test/test_go_isolation_rootfs.py +++ /dev/null @@ -1,19 +0,0 @@ -from unit.applications.lang.go import ApplicationGo - -prerequisites = { - 'modules': {'go': 'all'}, - 'features': {'isolation': True}, - 'privileged_user': True, -} - -client = ApplicationGo() - - -def test_go_isolation_rootfs_chroot(temp_dir): - client.load('ns_inspect', isolation={'rootfs': temp_dir}) - - obj = client.getjson(url='/?file=/go/app')['body'] - assert obj['FileExists'], 'app relative to rootfs' - - obj = client.getjson(url='/?file=/bin/sh')['body'] - assert not obj['FileExists'], 'file should not exists' diff --git a/test/test_http_header.py b/test/test_http_header.py deleted file mode 100644 index f6579df5..00000000 --- a/test/test_http_header.py +++ /dev/null @@ -1,501 +0,0 @@ -import pytest - -from unit.applications.lang.python import ApplicationPython - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -def test_http_header_value_leading_sp(): - client.load('custom_header') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Custom-Header': ' ,', - 'Connection': 'close', - } - ) - - assert resp['status'] == 200, 'value leading sp status' - assert ( - resp['headers']['Custom-Header'] == ',' - ), 'value leading sp custom header' - - -def test_http_header_value_leading_htab(): - client.load('custom_header') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Custom-Header': '\t,', - 'Connection': 'close', - } - ) - - assert resp['status'] == 200, 'value leading htab status' - assert ( - resp['headers']['Custom-Header'] == ',' - ), 'value leading htab custom header' - - -def test_http_header_value_trailing_sp(): - client.load('custom_header') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Custom-Header': ', ', - 'Connection': 'close', - } - ) - - assert resp['status'] == 200, 'value trailing sp status' - assert ( - resp['headers']['Custom-Header'] == ',' - ), 'value trailing sp custom header' - - -def test_http_header_value_trailing_htab(): - client.load('custom_header') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Custom-Header': ',\t', - 'Connection': 'close', - } - ) - - assert resp['status'] == 200, 'value trailing htab status' - assert ( - resp['headers']['Custom-Header'] == ',' - ), 'value trailing htab custom header' - - -def test_http_header_value_both_sp(): - client.load('custom_header') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Custom-Header': ' , ', - 'Connection': 'close', - } - ) - - assert resp['status'] == 200, 'value both sp status' - assert ( - resp['headers']['Custom-Header'] == ',' - ), 'value both sp custom header' - - -def test_http_header_value_both_htab(): - client.load('custom_header') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Custom-Header': '\t,\t', - 'Connection': 'close', - } - ) - - assert resp['status'] == 200, 'value both htab status' - assert ( - resp['headers']['Custom-Header'] == ',' - ), 'value both htab custom header' - - -def test_http_header_value_chars(): - client.load('custom_header') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Custom-Header': r"(),/:;<=>?@[\]{}\t !#$%&'*+-.^_`|~", - 'Connection': 'close', - } - ) - - assert resp['status'] == 200, 'value chars status' - assert ( - resp['headers']['Custom-Header'] - == r"(),/:;<=>?@[\]{}\t !#$%&'*+-.^_`|~" - ), 'value chars custom header' - - -def test_http_header_value_chars_edge(): - client.load('custom_header') - - resp = client.http( - b"""GET / HTTP/1.1 -Host: localhost -Custom-Header: \x20\xFF -Connection: close - -""", - raw=True, - encoding='latin1', - ) - - assert resp['status'] == 200, 'value chars edge status' - assert resp['headers']['Custom-Header'] == '\xFF', 'value chars edge' - - -def test_http_header_value_chars_below(): - client.load('custom_header') - - resp = client.http( - b"""GET / HTTP/1.1 -Host: localhost -Custom-Header: \x1F -Connection: close - -""", - raw=True, - ) - - assert resp['status'] == 400, 'value chars below' - - -def test_http_header_field_leading_sp(): - client.load('empty') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - ' Custom-Header': 'blah', - 'Connection': 'close', - } - )['status'] - == 400 - ), 'field leading sp' - - -def test_http_header_field_leading_htab(): - client.load('empty') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - '\tCustom-Header': 'blah', - 'Connection': 'close', - } - )['status'] - == 400 - ), 'field leading htab' - - -def test_http_header_field_trailing_sp(): - client.load('empty') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Custom-Header ': 'blah', - 'Connection': 'close', - } - )['status'] - == 400 - ), 'field trailing sp' - - -def test_http_header_field_trailing_htab(): - client.load('empty') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Custom-Header\t': 'blah', - 'Connection': 'close', - } - )['status'] - == 400 - ), 'field trailing htab' - - -def test_http_header_content_length_big(): - client.load('empty') - - assert ( - client.post( - headers={ - 'Host': 'localhost', - 'Content-Length': str(2**64), - 'Connection': 'close', - }, - body='X' * 1000, - )['status'] - == 400 - ), 'Content-Length big' - - -def test_http_header_content_length_negative(): - client.load('empty') - - assert ( - client.post( - headers={ - 'Host': 'localhost', - 'Content-Length': '-100', - 'Connection': 'close', - }, - body='X' * 1000, - )['status'] - == 400 - ), 'Content-Length negative' - - -def test_http_header_content_length_text(): - client.load('empty') - - assert ( - client.post( - headers={ - 'Host': 'localhost', - 'Content-Length': 'blah', - 'Connection': 'close', - }, - body='X' * 1000, - )['status'] - == 400 - ), 'Content-Length text' - - -def test_http_header_content_length_multiple_values(): - client.load('empty') - - assert ( - client.post( - headers={ - 'Host': 'localhost', - 'Content-Length': '41, 42', - 'Connection': 'close', - }, - body='X' * 1000, - )['status'] - == 400 - ), 'Content-Length multiple value' - - -def test_http_header_content_length_multiple_fields(): - client.load('empty') - - assert ( - client.post( - headers={ - 'Host': 'localhost', - 'Content-Length': ['41', '42'], - 'Connection': 'close', - }, - body='X' * 1000, - )['status'] - == 400 - ), 'Content-Length multiple fields' - - -@pytest.mark.skip('not yet') -def test_http_header_host_absent(): - client.load('host') - - resp = client.get(headers={'Connection': 'close'}) - - assert resp['status'] == 400, 'Host absent status' - - -def test_http_header_host_empty(): - client.load('host') - - resp = client.get(headers={'Host': '', 'Connection': 'close'}) - - assert resp['status'] == 200, 'Host empty status' - assert resp['headers']['X-Server-Name'] != '', 'Host empty SERVER_NAME' - - -def test_http_header_host_big(): - client.load('empty') - - assert ( - client.get(headers={'Host': 'X' * 10000, 'Connection': 'close'})[ - 'status' - ] - == 431 - ), 'Host big' - - -def test_http_header_host_port(): - client.load('host') - - resp = client.get( - headers={'Host': 'exmaple.com:8080', 'Connection': 'close'} - ) - - assert resp['status'] == 200, 'Host port status' - assert ( - resp['headers']['X-Server-Name'] == 'exmaple.com' - ), 'Host port SERVER_NAME' - assert ( - resp['headers']['X-Http-Host'] == 'exmaple.com:8080' - ), 'Host port HTTP_HOST' - - -def test_http_header_host_port_empty(): - client.load('host') - - resp = client.get(headers={'Host': 'exmaple.com:', 'Connection': 'close'}) - - assert resp['status'] == 200, 'Host port empty status' - assert ( - resp['headers']['X-Server-Name'] == 'exmaple.com' - ), 'Host port empty SERVER_NAME' - assert ( - resp['headers']['X-Http-Host'] == 'exmaple.com:' - ), 'Host port empty HTTP_HOST' - - -def test_http_header_host_literal(): - client.load('host') - - resp = client.get(headers={'Host': '127.0.0.1', 'Connection': 'close'}) - - assert resp['status'] == 200, 'Host literal status' - assert ( - resp['headers']['X-Server-Name'] == '127.0.0.1' - ), 'Host literal SERVER_NAME' - - -def test_http_header_host_literal_ipv6(): - client.load('host') - - resp = client.get(headers={'Host': '[::1]:8080', 'Connection': 'close'}) - - assert resp['status'] == 200, 'Host literal ipv6 status' - assert ( - resp['headers']['X-Server-Name'] == '[::1]' - ), 'Host literal ipv6 SERVER_NAME' - assert ( - resp['headers']['X-Http-Host'] == '[::1]:8080' - ), 'Host literal ipv6 HTTP_HOST' - - -def test_http_header_host_trailing_period(): - client.load('host') - - resp = client.get(headers={'Host': '127.0.0.1.', 'Connection': 'close'}) - - assert resp['status'] == 200, 'Host trailing period status' - assert ( - resp['headers']['X-Server-Name'] == '127.0.0.1' - ), 'Host trailing period SERVER_NAME' - assert ( - resp['headers']['X-Http-Host'] == '127.0.0.1.' - ), 'Host trailing period HTTP_HOST' - - -def test_http_header_host_trailing_period_2(): - client.load('host') - - resp = client.get(headers={'Host': 'EXAMPLE.COM.', 'Connection': 'close'}) - - assert resp['status'] == 200, 'Host trailing period 2 status' - assert ( - resp['headers']['X-Server-Name'] == 'example.com' - ), 'Host trailing period 2 SERVER_NAME' - assert ( - resp['headers']['X-Http-Host'] == 'EXAMPLE.COM.' - ), 'Host trailing period 2 HTTP_HOST' - - -def test_http_header_host_case_insensitive(): - client.load('host') - - resp = client.get(headers={'Host': 'EXAMPLE.COM', 'Connection': 'close'}) - - assert resp['status'] == 200, 'Host case insensitive' - assert ( - resp['headers']['X-Server-Name'] == 'example.com' - ), 'Host case insensitive SERVER_NAME' - - -def test_http_header_host_double_dot(): - client.load('empty') - - assert ( - client.get(headers={'Host': '127.0.0..1', 'Connection': 'close'})[ - 'status' - ] - == 400 - ), 'Host double dot' - - -def test_http_header_host_slash(): - client.load('empty') - - assert ( - client.get(headers={'Host': '/localhost', 'Connection': 'close'})[ - 'status' - ] - == 400 - ), 'Host slash' - - -def test_http_header_host_multiple_fields(): - client.load('empty') - - assert ( - client.get( - headers={ - 'Host': ['localhost', 'example.com'], - 'Connection': 'close', - } - )['status'] - == 400 - ), 'Host multiple fields' - - -def test_http_discard_unsafe_fields(): - client.load('header_fields') - - def check_status(header): - resp = client.get( - headers={ - 'Host': 'localhost', - header: 'blah', - 'Connection': 'close', - } - ) - - assert resp['status'] == 200 - return resp - - resp = check_status("!Custom-Header") - assert 'CUSTOM' not in resp['headers']['All-Headers'] - - resp = check_status("Custom_Header") - assert 'CUSTOM' not in resp['headers']['All-Headers'] - - assert 'success' in client.conf( - {'http': {'discard_unsafe_fields': False}}, - 'settings', - ) - - resp = check_status("!#$%&'*+.^`|~Custom_Header") - assert 'CUSTOM' in resp['headers']['All-Headers'] - - assert 'success' in client.conf( - {'http': {'discard_unsafe_fields': True}}, - 'settings', - ) - - resp = check_status("!Custom-Header") - assert 'CUSTOM' not in resp['headers']['All-Headers'] - - resp = check_status("Custom_Header") - assert 'CUSTOM' not in resp['headers']['All-Headers'] diff --git a/test/test_java_application.py b/test/test_java_application.py deleted file mode 100644 index 33151182..00000000 --- a/test/test_java_application.py +++ /dev/null @@ -1,1034 +0,0 @@ -import io -import re -import time -from pathlib import Path - -from unit.applications.lang.java import ApplicationJava -from unit.option import option -from unit.utils import public_dir - -prerequisites = {'modules': {'java': 'all'}} - -client = ApplicationJava() - - -def test_java_conf_error(temp_dir, skip_alert): - skip_alert( - r'realpath.*failed', - r'failed to apply new conf', - r'application setup failed', - ) - assert 'error' in client.conf( - { - "listeners": {"*:8080": {"pass": "applications/app"}}, - "applications": { - "app": { - "type": client.get_application_type(), - "processes": 1, - "working_directory": f"{option.test_dir}/java/empty", - "webapp": f"{temp_dir}/java", - "unit_jars": f"{temp_dir}/no_such_dir", - } - }, - } - ), 'conf error' - - -def test_java_war(temp_dir): - client.load('empty_war') - - assert 'success' in client.conf( - f'"{temp_dir}/java/empty.war"', - '/config/applications/empty_war/webapp', - ), 'configure war' - - assert client.get()['status'] == 200, 'war' - - -def test_java_application_cookies(): - client.load('cookies') - - headers = client.get( - headers={ - 'Cookie': 'var1=val1; var2=val2', - 'Host': 'localhost', - 'Connection': 'close', - } - )['headers'] - - assert headers['X-Cookie-1'] == 'val1', 'cookie 1' - assert headers['X-Cookie-2'] == 'val2', 'cookie 2' - - -def test_java_application_filter(): - client.load('filter') - - headers = client.get()['headers'] - - assert headers['X-Filter-Before'] == '1', 'filter before' - assert headers['X-Filter-After'] == '1', 'filter after' - - assert ( - client.get(url='/test')['headers']['X-Filter-After'] == '0' - ), 'filter after 2' - - -def test_java_application_get_variables(): - client.load('get_params') - - def check_header(header, expect): - values = header.split(' ')[:-1] - assert len(values) == len(expect) - assert set(values) == set(expect) - - headers = client.get(url='/?var1=val1&var2=&var4=val4&var4=foo')['headers'] - - assert headers['X-Var-1'] == 'val1', 'GET variables' - assert headers['X-Var-2'] == 'true', 'GET variables 2' - assert headers['X-Var-3'] == 'false', 'GET variables 3' - - check_header(headers['X-Param-Names'], ['var4', 'var2', 'var1']) - check_header(headers['X-Param-Values'], ['val4', 'foo']) - check_header( - headers['X-Param-Map'], ['var2=', 'var1=val1', 'var4=val4,foo'] - ) - - -def test_java_application_post_variables(): - client.load('post_params') - - headers = client.post( - headers={ - 'Content-Type': 'application/x-www-form-urlencoded', - 'Host': 'localhost', - 'Connection': 'close', - }, - body='var1=val1&var2=', - )['headers'] - - assert headers['X-Var-1'] == 'val1', 'POST variables' - assert headers['X-Var-2'] == 'true', 'POST variables 2' - assert headers['X-Var-3'] == 'false', 'POST variables 3' - - -def test_java_application_session(): - client.load('session') - - headers = client.get(url='/?var1=val1')['headers'] - session_id = headers['X-Session-Id'] - - assert headers['X-Var-1'] == 'null', 'variable empty' - assert headers['X-Session-New'] == 'true', 'session create' - - headers = client.get( - headers={ - 'Host': 'localhost', - 'Cookie': f'JSESSIONID={session_id}', - 'Connection': 'close', - }, - url='/?var1=val2', - )['headers'] - - assert headers['X-Var-1'] == 'val1', 'variable' - assert headers['X-Session-New'] == 'false', 'session resume' - assert session_id == headers['X-Session-Id'], 'session same id' - - -def test_java_application_session_active(date_to_sec_epoch, sec_epoch): - client.load('session_inactive') - - resp = client.get( - headers={ - 'X-Interval': '4', - 'Host': 'localhost', - 'Connection': 'close', - } - ) - session_id = resp['headers']['X-Session-Id'] - - assert resp['status'] == 200, 'session init' - assert resp['headers']['X-Session-Interval'] == '4', 'session interval' - assert ( - abs( - date_to_sec_epoch(resp['headers']['X-Session-Last-Access-Time']) - - sec_epoch - ) - < 5 - ), 'session last access time' - - time.sleep(1) - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Cookie': f'JSESSIONID={session_id}', - 'Connection': 'close', - } - ) - - assert resp['headers']['X-Session-Id'] == session_id, 'session active' - - session_id = resp['headers']['X-Session-Id'] - - time.sleep(1) - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Cookie': f'JSESSIONID={session_id}', - 'Connection': 'close', - } - ) - - assert resp['headers']['X-Session-Id'] == session_id, 'session active 2' - - time.sleep(2) - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Cookie': f'JSESSIONID={session_id}', - 'Connection': 'close', - } - ) - - assert resp['headers']['X-Session-Id'] == session_id, 'session active 3' - - -def test_java_application_session_inactive(): - client.load('session_inactive') - - resp = client.get( - headers={ - 'X-Interval': '1', - 'Host': 'localhost', - 'Connection': 'close', - } - ) - session_id = resp['headers']['X-Session-Id'] - - time.sleep(3) - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Cookie': f'JSESSIONID={session_id}', - 'Connection': 'close', - } - ) - - assert resp['headers']['X-Session-Id'] != session_id, 'session inactive' - - -def test_java_application_session_invalidate(): - client.load('session_invalidate') - - resp = client.get() - session_id = resp['headers']['X-Session-Id'] - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Cookie': f'JSESSIONID={session_id}', - 'Connection': 'close', - } - ) - - assert resp['headers']['X-Session-Id'] != session_id, 'session invalidate' - - -def test_java_application_session_listeners(): - client.load('session_listeners') - - headers = client.get(url='/test?var1=val1')['headers'] - session_id = headers['X-Session-Id'] - - assert headers['X-Session-Created'] == session_id, 'session create' - assert headers['X-Attr-Added'] == 'var1=val1', 'attribute add' - - headers = client.get( - headers={ - 'Host': 'localhost', - 'Cookie': f'JSESSIONID={session_id}', - 'Connection': 'close', - }, - url='/?var1=val2', - )['headers'] - - assert session_id == headers['X-Session-Id'], 'session same id' - assert headers['X-Attr-Replaced'] == 'var1=val1', 'attribute replace' - - headers = client.get( - headers={ - 'Host': 'localhost', - 'Cookie': f'JSESSIONID={session_id}', - 'Connection': 'close', - }, - url='/', - )['headers'] - - assert session_id == headers['X-Session-Id'], 'session same id' - assert headers['X-Attr-Removed'] == 'var1=val2', 'attribute remove' - - -def test_java_application_jsp(): - client.load('jsp') - - headers = client.get(url='/index.jsp')['headers'] - - assert headers['X-Unit-JSP'] == 'ok', 'JSP Ok header' - - -def test_java_application_url_pattern(): - client.load('url_pattern') - - headers = client.get(url='/foo/bar/index.html')['headers'] - - assert headers['X-Id'] == 'servlet1', '#1 Servlet1 request' - assert headers['X-Request-URI'] == '/foo/bar/index.html', '#1 request URI' - assert headers['X-Servlet-Path'] == '/foo/bar', '#1 servlet path' - assert headers['X-Path-Info'] == '/index.html', '#1 path info' - - headers = client.get(url='/foo/bar/index.bop')['headers'] - - assert headers['X-Id'] == 'servlet1', '#2 Servlet1 request' - assert headers['X-Request-URI'] == '/foo/bar/index.bop', '#2 request URI' - assert headers['X-Servlet-Path'] == '/foo/bar', '#2 servlet path' - assert headers['X-Path-Info'] == '/index.bop', '#2 path info' - - headers = client.get(url='/baz')['headers'] - - assert headers['X-Id'] == 'servlet2', '#3 Servlet2 request' - assert headers['X-Request-URI'] == '/baz', '#3 request URI' - assert headers['X-Servlet-Path'] == '/baz', '#3 servlet path' - assert headers['X-Path-Info'] == 'null', '#3 path info' - - headers = client.get(url='/baz/index.html')['headers'] - - assert headers['X-Id'] == 'servlet2', '#4 Servlet2 request' - assert headers['X-Request-URI'] == '/baz/index.html', '#4 request URI' - assert headers['X-Servlet-Path'] == '/baz', '#4 servlet path' - assert headers['X-Path-Info'] == '/index.html', '#4 path info' - - headers = client.get(url='/catalog')['headers'] - - assert headers['X-Id'] == 'servlet3', '#5 Servlet3 request' - assert headers['X-Request-URI'] == '/catalog', '#5 request URI' - assert headers['X-Servlet-Path'] == '/catalog', '#5 servlet path' - assert headers['X-Path-Info'] == 'null', '#5 path info' - - headers = client.get(url='/catalog/index.html')['headers'] - - assert headers['X-Id'] == 'default', '#6 default request' - assert headers['X-Request-URI'] == '/catalog/index.html', '#6 request URI' - assert headers['X-Servlet-Path'] == '/catalog/index.html', '#6 servlet path' - assert headers['X-Path-Info'] == 'null', '#6 path info' - - headers = client.get(url='/catalog/racecar.bop')['headers'] - - assert headers['X-Id'] == 'servlet4', '#7 servlet4 request' - assert headers['X-Request-URI'] == '/catalog/racecar.bop', '#7 request URI' - assert ( - headers['X-Servlet-Path'] == '/catalog/racecar.bop' - ), '#7 servlet path' - assert headers['X-Path-Info'] == 'null', '#7 path info' - - headers = client.get(url='/index.bop')['headers'] - - assert headers['X-Id'] == 'servlet4', '#8 servlet4 request' - assert headers['X-Request-URI'] == '/index.bop', '#8 request URI' - assert headers['X-Servlet-Path'] == '/index.bop', '#8 servlet path' - assert headers['X-Path-Info'] == 'null', '#8 path info' - - headers = client.get(url='/foo/baz')['headers'] - - assert headers['X-Id'] == 'servlet0', '#9 servlet0 request' - assert headers['X-Request-URI'] == '/foo/baz', '#9 request URI' - assert headers['X-Servlet-Path'] == '/foo', '#9 servlet path' - assert headers['X-Path-Info'] == '/baz', '#9 path info' - - headers = client.get()['headers'] - - assert headers['X-Id'] == 'default', '#10 default request' - assert headers['X-Request-URI'] == '/', '#10 request URI' - assert headers['X-Servlet-Path'] == '/', '#10 servlet path' - assert headers['X-Path-Info'] == 'null', '#10 path info' - - headers = client.get(url='/index.bop/')['headers'] - - assert headers['X-Id'] == 'default', '#11 default request' - assert headers['X-Request-URI'] == '/index.bop/', '#11 request URI' - assert headers['X-Servlet-Path'] == '/index.bop/', '#11 servlet path' - assert headers['X-Path-Info'] == 'null', '#11 path info' - - -def test_java_application_header(): - client.load('header') - - headers = client.get()['headers'] - - assert headers['X-Set-Utf8-Value'] == '????', 'set Utf8 header value' - assert headers['X-Set-Utf8-Name-???'] == 'x', 'set Utf8 header name' - assert headers['X-Add-Utf8-Value'] == '????', 'add Utf8 header value' - assert headers['X-Add-Utf8-Name-???'] == 'y', 'add Utf8 header name' - assert headers['X-Add-Test'] == 'v1', 'add null header' - assert 'X-Set-Test1' not in headers, 'set null header' - assert headers['X-Set-Test2'] == '', 'set empty header' - - -def test_java_application_content_type(): - client.load('content_type') - - headers = client.get(url='/1')['headers'] - - assert ( - headers['Content-Type'] == 'text/plain;charset=utf-8' - ), '#1 Content-Type header' - assert ( - headers['X-Content-Type'] == 'text/plain;charset=utf-8' - ), '#1 response Content-Type' - assert headers['X-Character-Encoding'] == 'utf-8', '#1 response charset' - - headers = client.get(url='/2')['headers'] - - assert ( - headers['Content-Type'] == 'text/plain;charset=iso-8859-1' - ), '#2 Content-Type header' - assert ( - headers['X-Content-Type'] == 'text/plain;charset=iso-8859-1' - ), '#2 response Content-Type' - assert ( - headers['X-Character-Encoding'] == 'iso-8859-1' - ), '#2 response charset' - - headers = client.get(url='/3')['headers'] - - assert ( - headers['Content-Type'] == 'text/plain;charset=windows-1251' - ), '#3 Content-Type header' - assert ( - headers['X-Content-Type'] == 'text/plain;charset=windows-1251' - ), '#3 response Content-Type' - assert ( - headers['X-Character-Encoding'] == 'windows-1251' - ), '#3 response charset' - - headers = client.get(url='/4')['headers'] - - assert ( - headers['Content-Type'] == 'text/plain;charset=windows-1251' - ), '#4 Content-Type header' - assert ( - headers['X-Content-Type'] == 'text/plain;charset=windows-1251' - ), '#4 response Content-Type' - assert ( - headers['X-Character-Encoding'] == 'windows-1251' - ), '#4 response charset' - - headers = client.get(url='/5')['headers'] - - assert ( - headers['Content-Type'] == 'text/plain;charset=iso-8859-1' - ), '#5 Content-Type header' - assert ( - headers['X-Content-Type'] == 'text/plain;charset=iso-8859-1' - ), '#5 response Content-Type' - assert ( - headers['X-Character-Encoding'] == 'iso-8859-1' - ), '#5 response charset' - - headers = client.get(url='/6')['headers'] - - assert 'Content-Type' not in headers, '#6 no Content-Type header' - assert 'X-Content-Type' not in headers, '#6 no response Content-Type' - assert headers['X-Character-Encoding'] == 'utf-8', '#6 response charset' - - headers = client.get(url='/7')['headers'] - - assert ( - headers['Content-Type'] == 'text/plain;charset=utf-8' - ), '#7 Content-Type header' - assert ( - headers['X-Content-Type'] == 'text/plain;charset=utf-8' - ), '#7 response Content-Type' - assert headers['X-Character-Encoding'] == 'utf-8', '#7 response charset' - - headers = client.get(url='/8')['headers'] - - assert ( - headers['Content-Type'] == 'text/html;charset=utf-8' - ), '#8 Content-Type header' - assert ( - headers['X-Content-Type'] == 'text/html;charset=utf-8' - ), '#8 response Content-Type' - assert headers['X-Character-Encoding'] == 'utf-8', '#8 response charset' - - -def test_java_application_welcome_files(): - client.load('welcome_files') - - headers = client.get()['headers'] - - resp = client.get(url='/dir1') - - assert resp['status'] == 302, 'dir redirect expected' - - resp = client.get(url='/dir1/') - - assert 'This is index.txt.' in resp['body'], 'dir1 index body' - assert resp['headers']['X-TXT-Filter'] == '1', 'TXT Filter header' - - headers = client.get(url='/dir2/')['headers'] - - assert headers['X-Unit-JSP'] == 'ok', 'JSP Ok header' - assert headers['X-JSP-Filter'] == '1', 'JSP Filter header' - - headers = client.get(url='/dir3/')['headers'] - - assert headers['X-App-Servlet'] == '1', 'URL pattern overrides welcome file' - - headers = client.get(url='/dir4/')['headers'] - - assert 'X-App-Servlet' not in headers, 'Static welcome file served first' - - headers = client.get(url='/dir5/')['headers'] - - assert ( - headers['X-App-Servlet'] == '1' - ), 'Servlet for welcome file served when no static file found' - - -def test_java_application_request_listeners(): - client.load('request_listeners') - - headers = client.get(url='/test1')['headers'] - - assert ( - headers['X-Request-Initialized'] == '/test1' - ), 'request initialized event' - assert headers['X-Request-Destroyed'] == '', 'request destroyed event' - assert headers['X-Attr-Added'] == '', 'attribute added event' - assert headers['X-Attr-Removed'] == '', 'attribute removed event' - assert headers['X-Attr-Replaced'] == '', 'attribute replaced event' - - headers = client.get(url='/test2?var1=1')['headers'] - - assert ( - headers['X-Request-Initialized'] == '/test2' - ), 'request initialized event' - assert headers['X-Request-Destroyed'] == '/test1', 'request destroyed event' - assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event' - assert headers['X-Attr-Removed'] == 'var=1;', 'attribute removed event' - assert headers['X-Attr-Replaced'] == '', 'attribute replaced event' - - headers = client.get(url='/test3?var1=1&var2=2')['headers'] - - assert ( - headers['X-Request-Initialized'] == '/test3' - ), 'request initialized event' - assert headers['X-Request-Destroyed'] == '/test2', 'request destroyed event' - assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event' - assert headers['X-Attr-Removed'] == 'var=2;', 'attribute removed event' - assert headers['X-Attr-Replaced'] == 'var=1;', 'attribute replaced event' - - headers = client.get(url='/test4?var1=1&var2=2&var3=3')['headers'] - - assert ( - headers['X-Request-Initialized'] == '/test4' - ), 'request initialized event' - assert headers['X-Request-Destroyed'] == '/test3', 'request destroyed event' - assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event' - assert headers['X-Attr-Removed'] == '', 'attribute removed event' - assert ( - headers['X-Attr-Replaced'] == 'var=1;var=2;' - ), 'attribute replaced event' - - -def test_java_application_request_uri_forward(): - client.load('forward') - - resp = client.get( - url='/fwd?uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4' - ) - headers = resp['headers'] - - assert headers['X-REQUEST-Id'] == 'fwd', 'initial request servlet mapping' - assert ( - headers['X-Forward-To'] == '/data/test?uri=new_uri&a=2&b=3' - ), 'forwarding triggered' - assert ( - headers['X-REQUEST-Param-uri'] == '/data/test?uri=new_uri&a=2&b=3' - ), 'original uri parameter' - assert headers['X-REQUEST-Param-a'] == '1', 'original a parameter' - assert headers['X-REQUEST-Param-c'] == '4', 'original c parameter' - - assert headers['X-FORWARD-Id'] == 'data', 'forward request servlet mapping' - assert ( - headers['X-FORWARD-Request-URI'] == '/data/test' - ), 'forward request uri' - assert ( - headers['X-FORWARD-Servlet-Path'] == '/data' - ), 'forward request servlet path' - assert ( - headers['X-FORWARD-Path-Info'] == '/test' - ), 'forward request path info' - assert ( - headers['X-FORWARD-Query-String'] == 'uri=new_uri&a=2&b=3' - ), 'forward request query string' - assert ( - headers['X-FORWARD-Param-uri'] - == 'new_uri,/data/test?uri=new_uri&a=2&b=3' - ), 'forward uri parameter' - assert headers['X-FORWARD-Param-a'] == '2,1', 'forward a parameter' - assert headers['X-FORWARD-Param-b'] == '3', 'forward b parameter' - assert headers['X-FORWARD-Param-c'] == '4', 'forward c parameter' - - assert ( - headers['X-javax.servlet.forward.request_uri'] == '/fwd' - ), 'original request uri' - assert ( - headers['X-javax.servlet.forward.context_path'] == '' - ), 'original request context path' - assert ( - headers['X-javax.servlet.forward.servlet_path'] == '/fwd' - ), 'original request servlet path' - assert ( - headers['X-javax.servlet.forward.path_info'] == 'null' - ), 'original request path info' - assert ( - headers['X-javax.servlet.forward.query_string'] - == 'uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4' - ), 'original request query' - - assert ( - 'Before forwarding' not in resp['body'] - ), 'discarded data added before forward() call' - assert ( - 'X-After-Forwarding' not in headers - ), 'cannot add headers after forward() call' - assert ( - 'After forwarding' not in resp['body'] - ), 'cannot add data after forward() call' - - -def test_java_application_named_dispatcher_forward(): - client.load('forward') - - resp = client.get(url='/fwd?disp=name&uri=data') - headers = resp['headers'] - - assert headers['X-REQUEST-Id'] == 'fwd', 'initial request servlet mapping' - assert headers['X-Forward-To'] == 'data', 'forwarding triggered' - - assert headers['X-FORWARD-Id'] == 'data', 'forward request servlet mapping' - assert headers['X-FORWARD-Request-URI'] == '/fwd', 'forward request uri' - assert ( - headers['X-FORWARD-Servlet-Path'] == '/fwd' - ), 'forward request servlet path' - assert headers['X-FORWARD-Path-Info'] == 'null', 'forward request path info' - assert ( - headers['X-FORWARD-Query-String'] == 'disp=name&uri=data' - ), 'forward request query string' - - assert ( - headers['X-javax.servlet.forward.request_uri'] == 'null' - ), 'original request uri' - assert ( - headers['X-javax.servlet.forward.context_path'] == 'null' - ), 'original request context path' - assert ( - headers['X-javax.servlet.forward.servlet_path'] == 'null' - ), 'original request servlet path' - assert ( - headers['X-javax.servlet.forward.path_info'] == 'null' - ), 'original request path info' - assert ( - headers['X-javax.servlet.forward.query_string'] == 'null' - ), 'original request query' - - assert ( - 'Before forwarding' not in resp['body'] - ), 'discarded data added before forward() call' - assert ( - 'X-After-Forwarding' not in headers - ), 'cannot add headers after forward() call' - assert ( - 'After forwarding' not in resp['body'] - ), 'cannot add data after forward() call' - - -def test_java_application_request_uri_include(): - client.load('include') - - resp = client.get(url='/inc?uri=/data/test') - headers = resp['headers'] - body = resp['body'] - - assert headers['X-REQUEST-Id'] == 'inc', 'initial request servlet mapping' - assert headers['X-Include'] == '/data/test', 'including triggered' - - assert ( - 'X-INCLUDE-Id' not in headers - ), 'unable to add headers in include request' - - assert ( - 'javax.servlet.include.request_uri: /data/test' in body - ), 'include request uri' - # assert ( - # 'javax.servlet.include.context_path: ' in body - # ) == True, 'include request context path' - assert ( - 'javax.servlet.include.servlet_path: /data' in body - ), 'include request servlet path' - assert ( - 'javax.servlet.include.path_info: /test' in body - ), 'include request path info' - assert ( - 'javax.servlet.include.query_string: null' in body - ), 'include request query' - - assert 'Before include' in body, 'preserve data added before include() call' - assert ( - headers['X-After-Include'] == 'you-should-see-this' - ), 'add headers after include() call' - assert 'After include' in body, 'add data after include() call' - - -def test_java_application_named_dispatcher_include(): - client.load('include') - - resp = client.get(url='/inc?disp=name&uri=data') - headers = resp['headers'] - body = resp['body'] - - assert headers['X-REQUEST-Id'] == 'inc', 'initial request servlet mapping' - assert headers['X-Include'] == 'data', 'including triggered' - - assert ( - 'X-INCLUDE-Id' not in headers - ), 'unable to add headers in include request' - - assert ( - 'javax.servlet.include.request_uri: null' in body - ), 'include request uri' - # assert ( - # 'javax.servlet.include.context_path: null' in body - # ) == True, 'include request context path' - assert ( - 'javax.servlet.include.servlet_path: null' in body - ), 'include request servlet path' - assert ( - 'javax.servlet.include.path_info: null' in body - ), 'include request path info' - assert ( - 'javax.servlet.include.query_string: null' in body - ), 'include request query' - - assert 'Before include' in body, 'preserve data added before include() call' - assert ( - headers['X-After-Include'] == 'you-should-see-this' - ), 'add headers after include() call' - assert 'After include' in body, 'add data after include() call' - - -def test_java_application_path_translation(): - client.load('path_translation') - - headers = client.get(url='/pt/test?path=/')['headers'] - - assert headers['X-Servlet-Path'] == '/pt', 'matched servlet path' - assert headers['X-Path-Info'] == '/test', 'the rest of the path' - assert ( - headers['X-Path-Translated'] - == f"{headers['X-Real-Path']}{headers['X-Path-Info']}" - ), 'translated path is the app root + path info' - assert headers['X-Resource-Paths'].endswith( - '/WEB-INF/, /index.html]' - ), 'app root directory content' - assert ( - headers['X-Resource-As-Stream'] == 'null' - ), 'no resource stream for root path' - - headers = client.get(url='/test?path=/none')['headers'] - - assert headers['X-Servlet-Path'] == '/test', 'matched whole path' - assert ( - headers['X-Path-Info'] == 'null' - ), 'the rest of the path is null, whole path matched' - assert ( - headers['X-Path-Translated'] == 'null' - ), 'translated path is null because path info is null' - assert headers['X-Real-Path'].endswith('/none'), 'read path is not null' - assert headers['X-Resource-Paths'] == 'null', 'no resource found' - assert headers['X-Resource-As-Stream'] == 'null', 'no resource stream' - - -def test_java_application_query_string(): - client.load('query_string') - - assert ( - client.get(url='/?a=b')['headers']['X-Query-String'] == 'a=b' - ), 'query string' - - -def test_java_application_query_empty(): - client.load('query_string') - - assert ( - client.get(url='/?')['headers']['X-Query-String'] == '' - ), 'query string empty' - - -def test_java_application_query_absent(): - client.load('query_string') - - assert ( - client.get()['headers']['X-Query-String'] == 'null' - ), 'query string absent' - - -def test_java_application_empty(): - client.load('empty') - - assert client.get()['status'] == 200, 'empty' - - -def test_java_application_keepalive_body(): - client.load('mirror') - - assert client.post()['status'] == 200, 'init' - - body = '0123456789' * 500 - (resp, sock) = client.post( - headers={ - 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive 1' - - body = '0123456789' - resp = client.post( - headers={ - 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost', - }, - sock=sock, - body=body, - ) - - assert resp['body'] == body, 'keep-alive 2' - - -def test_java_application_http_10(): - client.load('empty') - - assert client.get(http_10=True)['status'] == 200, 'HTTP 1.0' - - -def test_java_application_no_method(): - client.load('empty') - - assert client.post()['status'] == 405, 'no method' - - -def test_java_application_get_header(): - client.load('get_header') - - assert ( - client.get( - headers={ - 'X-Header': 'blah', - 'Content-Type': 'text/html', - 'Host': 'localhost', - 'Connection': 'close', - } - )['headers']['X-Reply'] - == 'blah' - ), 'get header' - - -def test_java_application_get_header_empty(): - client.load('get_header') - - assert 'X-Reply' not in client.get()['headers'], 'get header empty' - - -def test_java_application_get_headers(): - client.load('get_headers') - - headers = client.get( - headers={ - 'X-Header': ['blah', 'blah'], - 'Content-Type': 'text/html', - 'Host': 'localhost', - 'Connection': 'close', - } - )['headers'] - - assert headers['X-Reply-0'] == 'blah', 'get headers' - assert headers['X-Reply-1'] == 'blah', 'get headers 2' - - -def test_java_application_many_headers(): - client.load('get_headers') - - value = '0123456789' * 10 - - headers = client.get( - headers={ - 'X-Header': [value] * 100, - 'Content-Type': 'text/html', - 'Host': 'localhost', - 'Connection': 'close', - } - )['headers'] - - for i in range(0, 99): - assert headers[f'X-Reply-{i}'] == value, 'many headers' - - -def test_java_application_get_headers_empty(): - client.load('get_headers') - - assert 'X-Reply-0' not in client.get()['headers'], 'get headers empty' - - -def test_java_application_get_header_names(): - client.load('get_header_names') - - headers = client.get()['headers'] - - assert re.search( - r'(?:Host|Connection)', headers['X-Reply-0'] - ), 'get header names' - assert re.search( - r'(?:Host|Connection)', headers['X-Reply-1'] - ), 'get header names 2' - assert ( - headers['X-Reply-0'] != headers['X-Reply-1'] - ), 'get header names not equal' - - -def test_java_application_header_int(): - client.load('header_int') - - headers = client.get( - headers={ - 'X-Header': '2', - 'Content-Type': 'text/html', - 'Host': 'localhost', - 'Connection': 'close', - } - )['headers'] - - assert headers['X-Set-Int'] == '1', 'set int header' - assert headers['X-Get-Int'] == '2', 'get int header' - - -def test_java_application_header_date(): - client.load('header_date') - - date = 'Fri, 15 Mar 2019 14:45:34 GMT' - - headers = client.get( - headers={ - 'X-Header': date, - 'Content-Type': 'text/html', - 'Host': 'localhost', - 'Connection': 'close', - } - )['headers'] - - assert ( - headers['X-Set-Date'] == 'Thu, 01 Jan 1970 00:00:01 GMT' - ), 'set date header' - assert headers['X-Get-Date'] == date, 'get date header' - - -def test_java_application_multipart(search_in_file, temp_dir): - client.load('multipart') - - reldst = '/uploads' - fulldst = f'{temp_dir}{reldst}' - Path(fulldst).mkdir(parents=True) - public_dir(fulldst) - - fields = { - 'file': { - 'filename': 'sample.txt', - 'type': 'text/plain', - 'data': io.StringIO('Data from sample file'), - }, - 'destination': fulldst, - 'upload': 'Upload', - } - - encoded, content_type = client.multipart_encode(fields) - - preamble = 'Preamble. Should be ignored.' - epilogue = 'Epilogue. Should be ignored.' - body = f'{preamble}\r\n{encoded.decode()}\r\n{epilogue}' - - resp = client.post( - headers={ - 'Content-Type': content_type, - 'Host': 'localhost', - 'Connection': 'close', - }, - body=body, - ) - - assert resp['status'] == 200, 'multipart status' - assert re.search(r'sample\.txt created', resp['body']), 'multipart body' - assert ( - search_in_file(r'^Data from sample file$', name=f'{reldst}/sample.txt') - is not None - ), 'file created' - - -def test_java_application_threads(): - client.load('threads') - - assert 'success' in client.conf( - '4', 'applications/threads/threads' - ), 'configure 4 threads' - - socks = [] - - for _ in range(4): - sock = client.get( - headers={ - 'Host': 'localhost', - 'X-Delay': '2', - 'Connection': 'close', - }, - no_recv=True, - ) - - socks.append(sock) - - time.sleep(0.25) # required to avoid greedy request reading - - threads = set() - - for sock in socks: - resp = client.recvall(sock).decode('utf-8') - - client.log_in(resp) - - resp = client._resp_to_dict(resp) - - assert resp['status'] == 200, 'status' - - threads.add(resp['headers']['X-Thread']) - - sock.close() - - assert len(socks) == len(threads), 'threads differs' diff --git a/test/test_java_isolation_rootfs.py b/test/test_java_isolation_rootfs.py deleted file mode 100644 index 0ed66133..00000000 --- a/test/test_java_isolation_rootfs.py +++ /dev/null @@ -1,69 +0,0 @@ -import os -import subprocess - -import pytest - -from unit.applications.lang.java import ApplicationJava -from unit.option import option - -prerequisites = {'modules': {'java': 'all'}, 'privileged_user': True} - -client = ApplicationJava() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - os.makedirs(f'{temp_dir}/jars') - os.makedirs(f'{temp_dir}/tmp') - os.chmod(f'{temp_dir}/tmp', 0o777) - - try: - subprocess.run( - [ - "mount", - "--bind", - f'{option.current_dir}/build', - f'{temp_dir}/jars', - ], - stderr=subprocess.STDOUT, - check=True, - ) - - except KeyboardInterrupt: - raise - - except subprocess.CalledProcessError: - pytest.fail("Can't run mount process.") - - yield - - try: - subprocess.run( - ["umount", "--lazy", f"{option.temp_dir}/jars"], - stderr=subprocess.STDOUT, - check=True, - ) - - except KeyboardInterrupt: - raise - - except subprocess.CalledProcessError: - pytest.fail("Can't run umount process.") - - -def test_java_isolation_rootfs_chroot_war(temp_dir): - client.load('empty_war', isolation={'rootfs': temp_dir}) - - assert 'success' in client.conf( - '"/"', - '/config/applications/empty_war/working_directory', - ) - - assert 'success' in client.conf( - '"/jars"', 'applications/empty_war/unit_jars' - ) - assert 'success' in client.conf( - '"/java/empty.war"', 'applications/empty_war/webapp' - ) - - assert client.get()['status'] == 200, 'war' diff --git a/test/test_java_websockets.py b/test/test_java_websockets.py deleted file mode 100644 index 94ac6f86..00000000 --- a/test/test_java_websockets.py +++ /dev/null @@ -1,1415 +0,0 @@ -import struct -import time - -import pytest - -from unit.applications.lang.java import ApplicationJava -from unit.applications.websockets import ApplicationWebsocket - -prerequisites = {'modules': {'java': 'any'}} - -client = ApplicationJava() -ws = ApplicationWebsocket() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(skip_alert): - assert 'success' in client.conf( - {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings' - ), 'clear keepalive_interval' - - skip_alert(r'socket close\(\d+\) failed') - - -def close_connection(sock): - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - - check_close(sock) - - -def check_close(sock, code=1000, no_close=False, frame=None): - if frame is None: - frame = ws.frame_read(sock) - - assert frame['fin'], 'close fin' - assert frame['opcode'] == ws.OP_CLOSE, 'close opcode' - assert frame['code'] == code, 'close code' - - if not no_close: - sock.close() - - -def check_frame(frame, fin, opcode, payload, decode=True): - if opcode == ws.OP_BINARY or not decode: - data = frame['data'] - else: - data = frame['data'].decode('utf-8') - - assert frame['fin'] == fin, 'fin' - assert frame['opcode'] == opcode, 'opcode' - assert data == payload, 'payload' - - -def test_java_websockets_handshake(): - client.load('websockets_mirror') - - resp, sock, key = ws.upgrade() - sock.close() - - assert resp['status'] == 101, 'status' - assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' - assert resp['headers']['Connection'] == 'Upgrade', 'connection' - assert resp['headers']['Sec-WebSocket-Accept'] == ws.accept(key), 'key' - - -def test_java_websockets_mirror(): - client.load('websockets_mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message) - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'mirror' - - ws.frame_write(sock, ws.OP_TEXT, message) - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'mirror 2' - - sock.close() - - -def test_java_websockets_no_mask(): - client.load('websockets_mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message, mask=False) - - frame = ws.frame_read(sock) - - assert frame['opcode'] == ws.OP_CLOSE, 'no mask opcode' - assert frame['code'] == 1002, 'no mask close code' - - sock.close() - - -def test_java_websockets_fragmentation(): - client.load('websockets_mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message, fin=False) - ws.frame_write(sock, ws.OP_CONT, ' ', fin=False) - ws.frame_write(sock, ws.OP_CONT, message) - - frame = ws.frame_read(sock) - - assert f'{message} {message}' == frame['data'].decode( - 'utf-8' - ), 'mirror framing' - - sock.close() - - -def test_java_websockets_frame_fragmentation_invalid(): - client.load('websockets_mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, message, fin=False) - - frame = ws.frame_read(sock) - - frame.pop('data') - assert frame == { - 'fin': True, - 'rsv1': False, - 'rsv2': False, - 'rsv3': False, - 'opcode': ws.OP_CLOSE, - 'mask': 0, - 'code': 1002, - 'reason': 'Fragmented control frame', - }, 'close frame' - - sock.close() - - -def test_java_websockets_two_clients(): - client.load('websockets_mirror') - - message1 = 'blah1' - message2 = 'blah2' - - _, sock1, _ = ws.upgrade() - _, sock2, _ = ws.upgrade() - - ws.frame_write(sock1, ws.OP_TEXT, message1) - ws.frame_write(sock2, ws.OP_TEXT, message2) - - frame1 = ws.frame_read(sock1) - frame2 = ws.frame_read(sock2) - - assert message1 == frame1['data'].decode('utf-8'), 'client 1' - assert message2 == frame2['data'].decode('utf-8'), 'client 2' - - sock1.close() - sock2.close() - - -# FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1 -@pytest.mark.skip('not yet') -def test_java_websockets_handshake_upgrade_absent(): - client.load('websockets_mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'upgrade absent' - - -def test_java_websockets_handshake_case_insensitive(): - client.load('websockets_mirror') - - resp, sock, _ = ws.upgrade( - headers={ - 'Host': 'localhost', - 'Upgrade': 'WEBSOCKET', - 'Connection': 'UPGRADE', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - } - ) - sock.close() - - assert resp['status'] == 101, 'status' - - -@pytest.mark.skip('not yet') -def test_java_websockets_handshake_connection_absent(): # FAIL - client.load('websockets_mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'status' - - -def test_java_websockets_handshake_version_absent(): - client.load('websockets_mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - }, - ) - - assert resp['status'] == 426, 'status' - - -@pytest.mark.skip('not yet') -def test_java_websockets_handshake_key_invalid(): - client.load('websockets_mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': '!', - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'key length' - - key = ws.key() - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': [key, key], - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert ( - resp['status'] == 400 - ), 'key double' # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1 - - -def test_java_websockets_handshake_method_invalid(): - client.load('websockets_mirror') - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'status' - - -def test_java_websockets_handshake_http_10(): - client.load('websockets_mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - http_10=True, - ) - - assert resp['status'] == 400, 'status' - - -def test_java_websockets_handshake_uri_invalid(): - client.load('websockets_mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - url='!', - ) - - assert resp['status'] == 400, 'status' - - -def test_java_websockets_protocol_absent(): - client.load('websockets_mirror') - - key = ws.key() - resp, sock, _ = ws.upgrade( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': key, - 'Sec-WebSocket-Version': 13, - } - ) - sock.close() - - assert resp['status'] == 101, 'status' - assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' - assert resp['headers']['Connection'] == 'Upgrade', 'connection' - assert resp['headers']['Sec-WebSocket-Accept'] == ws.accept(key), 'key' - - -# autobahn-testsuite -# -# Some following tests fail because of Unit does not support UTF-8 -# validation for websocket frames. It should be implemented -# by application, if necessary. - - -def test_java_websockets_1_1_1__1_1_8(): - client.load('websockets_mirror') - - opcode = ws.OP_TEXT - - _, sock, _ = ws.upgrade() - - def check_length(length, chopsize=None): - payload = '*' * length - - ws.frame_write(sock, opcode, payload, chopsize=chopsize) - - frame = ws.message_read(sock) - check_frame(frame, True, opcode, payload) - - check_length(0) # 1_1_1 - check_length(125) # 1_1_2 - check_length(126) # 1_1_3 - check_length(127) # 1_1_4 - check_length(128) # 1_1_5 - check_length(65535) # 1_1_6 - check_length(65536) # 1_1_7 - check_length(65536, chopsize=997) # 1_1_8 - - close_connection(sock) - - -def test_java_websockets_1_2_1__1_2_8(): - client.load('websockets_mirror') - - opcode = ws.OP_BINARY - - _, sock, _ = ws.upgrade() - - def check_length(length, chopsize=None): - payload = b'\xfe' * length - - ws.frame_write(sock, opcode, payload, chopsize=chopsize) - - frame = ws.message_read(sock) - check_frame(frame, True, opcode, payload) - - check_length(0) # 1_2_1 - check_length(125) # 1_2_2 - check_length(126) # 1_2_3 - check_length(127) # 1_2_4 - check_length(128) # 1_2_5 - check_length(65535) # 1_2_6 - check_length(65536) # 1_2_7 - check_length(65536, chopsize=997) # 1_2_8 - - close_connection(sock) - - -def test_java_websockets_2_1__2_6(): - client.load('websockets_mirror') - - op_ping = ws.OP_PING - op_pong = ws.OP_PONG - - _, sock, _ = ws.upgrade() - - def check_ping(payload, chopsize=None, decode=True): - ws.frame_write(sock, op_ping, payload, chopsize=chopsize) - frame = ws.frame_read(sock) - - check_frame(frame, True, op_pong, payload, decode=decode) - - check_ping('') # 2_1 - check_ping('Hello, world!') # 2_2 - check_ping(b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', decode=False) # 2_3 - check_ping(b'\xfe' * 125, decode=False) # 2_4 - check_ping(b'\xfe' * 125, chopsize=1, decode=False) # 2_6 - - close_connection(sock) - - # 2_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, b'\xfe' * 126) - check_close(sock, 1002) - - -def test_java_websockets_2_7__2_9(): - client.load('websockets_mirror') - - # 2_7 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PONG, '') - assert client.recvall(sock, read_timeout=0.1) == b'', '2_7' - - # 2_8 - - ws.frame_write(sock, ws.OP_PONG, 'unsolicited pong payload') - assert client.recvall(sock, read_timeout=0.1) == b'', '2_8' - - # 2_9 - - payload = 'ping payload' - - ws.frame_write(sock, ws.OP_PONG, 'unsolicited pong payload') - ws.frame_write(sock, ws.OP_PING, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, payload) - - close_connection(sock) - - -def test_java_websockets_2_10__2_11(): - client.load('websockets_mirror') - - # 2_10 - - _, sock, _ = ws.upgrade() - - for i in range(0, 10): - ws.frame_write(sock, ws.OP_PING, f'payload-{i}') - - for i in range(0, 10): - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, f'payload-{i}') - - # 2_11 - - for i in range(0, 10): - opcode = ws.OP_PING - ws.frame_write(sock, opcode, f'payload-{i}', chopsize=1) - - for i in range(0, 10): - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, f'payload-{i}') - - close_connection(sock) - - -@pytest.mark.skip('not yet') -def test_java_websockets_3_1__3_7(): - client.load('websockets_mirror') - - payload = 'Hello, world!' - - # 3_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, rsv1=True) - check_close(sock, 1002) - - # 3_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - ws.frame_write(sock, ws.OP_TEXT, payload, rsv2=True) - ws.frame_write(sock, ws.OP_PING, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - check_close(sock, 1002, no_close=True) - - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2' - sock.close() - - # 3_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, ws.OP_TEXT, payload, rsv1=True, rsv2=True) - - check_close(sock, 1002, no_close=True) - - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3' - sock.close() - - # 3_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) - ws.frame_write(sock, ws.OP_TEXT, payload, rsv3=True, chopsize=1) - ws.frame_write(sock, ws.OP_PING, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - check_close(sock, 1002, no_close=True) - - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4' - sock.close() - - # 3_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write( - sock, - ws.OP_BINARY, - b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', - rsv1=True, - rsv3=True, - ) - - check_close(sock, 1002) - - # 3_6 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, payload, rsv2=True, rsv3=True) - - check_close(sock, 1002) - - # 3_7 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, payload, rsv1=True, rsv2=True, rsv3=True) - - check_close(sock, 1002) - - -def test_java_websockets_4_1_1__4_2_5(): - client.load('websockets_mirror') - - payload = 'Hello, world!' - - # 4_1_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x03, '') - check_close(sock, 1002) - - # 4_1_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x04, 'reserved opcode payload') - check_close(sock, 1002) - - # 4_1_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x05, '') - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_1_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x06, payload) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_1_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x07, payload, chopsize=1) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_2_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x0B, '') - check_close(sock, 1002) - - # 4_2_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x0C, 'reserved opcode payload') - check_close(sock, 1002) - - # 4_2_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x0D, '') - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_2_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x0E, payload) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_2_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x0F, payload, chopsize=1) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - -def test_java_websockets_5_1__5_20(): - client.load('websockets_mirror') - - # 5_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - check_close(sock, 1002) - - # 5_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PONG, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - check_close(sock, 1002) - - # 5_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_4 - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - assert client.recvall(sock, read_timeout=0.1) == b'', '5_4' - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_5 - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False, chopsize=1) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_6 - - ping_payload = 'ping payload' - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_PING, ping_payload) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, ping_payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_7 - - ping_payload = 'ping payload' - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - assert client.recvall(sock, read_timeout=0.1) == b'', '5_7' - - ws.frame_write(sock, ws.OP_PING, ping_payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, ping_payload) - - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_8 - - ping_payload = 'ping payload' - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False, chopsize=1) - ws.frame_write(sock, ws.OP_PING, ping_payload, chopsize=1) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, ping_payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_9 - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=True) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_10 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=True) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_11 - - _, sock, _ = ws.upgrade() - - ws.frame_write( - sock, - ws.OP_CONT, - 'non-continuation payload', - fin=True, - chopsize=1, - ) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1) - check_close(sock, 1002) - - # 5_12 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_13 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_14 - - _, sock, _ = ws.upgrade() - - ws.frame_write( - sock, - ws.OP_CONT, - 'non-continuation payload', - fin=False, - chopsize=1, - ) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1) - check_close(sock, 1002) - - # 5_15 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'fragment4', fin=True) - - frame = ws.frame_read(sock) - - if frame['opcode'] == ws.OP_TEXT: - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - frame = None - - check_close(sock, 1002, frame=frame) - - # 5_16 - - _, sock, _ = ws.upgrade() - - for _ in range(0, 2): - ws.frame_write(sock, ws.OP_CONT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=True) - check_close(sock, 1002) - - # 5_17 - - _, sock, _ = ws.upgrade() - - for _ in range(0, 2): - ws.frame_write(sock, ws.OP_CONT, 'fragment1', fin=True) - ws.frame_write(sock, ws.OP_TEXT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=True) - check_close(sock, 1002) - - # 5_18 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'fragment2') - check_close(sock, 1002) - - # 5_19 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 1!') - - time.sleep(1) - - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment4', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 2!') - ws.frame_write(sock, ws.OP_CONT, 'fragment5') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 1!') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 2!') - - check_frame( - ws.frame_read(sock), - True, - ws.OP_TEXT, - 'fragment1fragment2fragment3fragment4fragment5', - ) - - # 5_20 - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 1!') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 1!') - - time.sleep(1) - - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment4', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 2!') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 2!') - - assert client.recvall(sock, read_timeout=0.1) == b'', '5_20' - ws.frame_write(sock, ws.OP_CONT, 'fragment5') - - check_frame( - ws.frame_read(sock), - True, - ws.OP_TEXT, - 'fragment1fragment2fragment3fragment4fragment5', - ) - - close_connection(sock) - - -def test_java_websockets_6_1_1__6_4_4(): - client.load('websockets_mirror') - - # 6_1_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, '') - frame = ws.frame_read(sock, read_timeout=3) - check_frame(frame, True, ws.OP_TEXT, '') - - # 6_1_2 - - ws.frame_write(sock, ws.OP_TEXT, '', fin=False) - ws.frame_write(sock, ws.OP_CONT, '', fin=False) - ws.frame_write(sock, ws.OP_CONT, '') - - frame = ws.frame_read(sock, read_timeout=3) - check_frame(frame, True, ws.OP_TEXT, '') - - # 6_1_3 - - payload = 'middle frame payload' - - ws.frame_write(sock, ws.OP_TEXT, '', fin=False) - ws.frame_write(sock, ws.OP_CONT, payload, fin=False) - ws.frame_write(sock, ws.OP_CONT, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_1 - - payload = 'Hello-µ@ßöäüàá-UTF-8!!' - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_2 - - ws.frame_write(sock, ws.OP_TEXT, payload[:12], fin=False) - ws.frame_write(sock, ws.OP_CONT, payload[12:]) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_3 - - ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_4 - - payload = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5' - - ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - close_connection(sock) - - -# Unit does not support UTF-8 validation -# -# # 6_3_1 FAIL -# -# payload_1 = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5' -# payload_2 = '\xed\xa0\x80' -# payload_3 = '\x65\x64\x69\x74\x65\x64' -# -# payload = payload_1 + payload_2 + payload_3 -# -# ws.message(sock, ws.OP_TEXT, payload) -# check_close(sock, 1007) -# -# # 6_3_2 FAIL -# -# _, sock, _ = ws.upgrade() -# -# ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) -# check_close(sock, 1007) -# -# # 6_4_1 ... 6_4_4 FAIL - - -def test_java_websockets_7_1_1__7_5_1(): - client.load('websockets_mirror') - - # 7_1_1 - - _, sock, _ = ws.upgrade() - - payload = "Hello World!" - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - close_connection(sock) - - # 7_1_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - - check_close(sock) - - # 7_1_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock, no_close=True) - - ws.frame_write(sock, ws.OP_PING, '') - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_1_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock, no_close=True) - - ws.frame_write(sock, ws.OP_TEXT, payload) - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_1_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock, no_close=True) - - ws.frame_write(sock, ws.OP_CONT, 'fragment2') - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_1_6 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2**10) - ws.frame_write(sock, ws.OP_TEXT, payload) - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - - client.recvall(sock, read_timeout=1) - - ws.frame_write(sock, ws.OP_PING, '') - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_3_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, '') - check_close(sock) - - # 7_3_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, 'a') - check_close(sock, 1002) - - # 7_3_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock) - - # 7_3_4 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(reason='Hello World!') - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock) - - # 7_3_5 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(reason='*' * 123) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock) - - # 7_3_6 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(reason='*' * 124) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - -# # 7_5_1 FAIL Unit does not support UTF-8 validation -# -# _, sock, _ = ws.upgrade() -# -# payload = ws.serialize_close(reason = '\xce\xba\xe1\xbd\xb9\xcf' \ -# '\x83\xce\xbc\xce\xb5\xed\xa0\x80\x65\x64\x69\x74\x65\x64') -# -# ws.frame_write(sock, ws.OP_CLOSE, payload) -# check_close(sock, 1007) - - -def test_java_websockets_7_7_X__7_9_X(): - client.load('websockets_mirror') - - valid_codes = [ - 1000, - 1001, - 1002, - 1003, - 1007, - 1008, - 1009, - 1010, - 1011, - 3000, - 3999, - 4000, - 4999, - ] - - invalid_codes = [0, 999, 1004, 1005, 1006, 1016, 1100, 2000, 2999] - - for code in valid_codes: - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(code=code) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, code=code) - - for code in invalid_codes: - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(code=code) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - -def test_java_websockets_7_13_1__7_13_2(): - client.load('websockets_mirror') - - # 7_13_1 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(code=5000) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - # 7_13_2 - - _, sock, _ = ws.upgrade() - - payload = struct.pack('!I', 65536) + ''.encode('utf-8') - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - -def test_java_websockets_9_1_1__9_6_6(is_unsafe, system): - if not is_unsafe: - pytest.skip('unsafe, long run') - - client.load('websockets_mirror') - - assert 'success' in client.conf( - { - 'http': { - 'websocket': { - 'max_frame_size': 33554432, - 'keepalive_interval': 0, - } - } - }, - 'settings', - ), 'increase max_frame_size and keepalive_interval' - - _, sock, _ = ws.upgrade() - - op_text = ws.OP_TEXT - op_binary = ws.OP_BINARY - - def check_payload(opcode, length, chopsize=None): - if opcode == ws.OP_TEXT: - payload = '*' * length - else: - payload = b'*' * length - - ws.frame_write(sock, opcode, payload, chopsize=chopsize) - frame = ws.frame_read(sock) - check_frame(frame, True, opcode, payload) - - def check_message(opcode, f_size): - if opcode == ws.OP_TEXT: - payload = '*' * 4 * 2**20 - else: - payload = b'*' * 4 * 2**20 - - ws.message(sock, opcode, payload, fragmention_size=f_size) - frame = ws.frame_read(sock, read_timeout=5) - check_frame(frame, True, opcode, payload) - - check_payload(op_text, 64 * 2**10) # 9_1_1 - check_payload(op_text, 256 * 2**10) # 9_1_2 - check_payload(op_text, 2**20) # 9_1_3 - check_payload(op_text, 4 * 2**20) # 9_1_4 - check_payload(op_text, 8 * 2**20) # 9_1_5 - check_payload(op_text, 16 * 2**20) # 9_1_6 - - check_payload(op_binary, 64 * 2**10) # 9_2_1 - check_payload(op_binary, 256 * 2**10) # 9_2_2 - check_payload(op_binary, 2**20) # 9_2_3 - check_payload(op_binary, 4 * 2**20) # 9_2_4 - check_payload(op_binary, 8 * 2**20) # 9_2_5 - check_payload(op_binary, 16 * 2**20) # 9_2_6 - - if system not in ['Darwin', 'FreeBSD']: - check_message(op_text, 64) # 9_3_1 - check_message(op_text, 256) # 9_3_2 - check_message(op_text, 2**10) # 9_3_3 - check_message(op_text, 4 * 2**10) # 9_3_4 - check_message(op_text, 16 * 2**10) # 9_3_5 - check_message(op_text, 64 * 2**10) # 9_3_6 - check_message(op_text, 256 * 2**10) # 9_3_7 - check_message(op_text, 2**20) # 9_3_8 - check_message(op_text, 4 * 2**20) # 9_3_9 - - check_message(op_binary, 64) # 9_4_1 - check_message(op_binary, 256) # 9_4_2 - check_message(op_binary, 2**10) # 9_4_3 - check_message(op_binary, 4 * 2**10) # 9_4_4 - check_message(op_binary, 16 * 2**10) # 9_4_5 - check_message(op_binary, 64 * 2**10) # 9_4_6 - check_message(op_binary, 256 * 2**10) # 9_4_7 - check_message(op_binary, 2**20) # 9_4_8 - check_message(op_binary, 4 * 2**20) # 9_4_9 - - check_payload(op_text, 2**20, chopsize=64) # 9_5_1 - check_payload(op_text, 2**20, chopsize=128) # 9_5_2 - check_payload(op_text, 2**20, chopsize=256) # 9_5_3 - check_payload(op_text, 2**20, chopsize=512) # 9_5_4 - check_payload(op_text, 2**20, chopsize=1024) # 9_5_5 - check_payload(op_text, 2**20, chopsize=2048) # 9_5_6 - - check_payload(op_binary, 2**20, chopsize=64) # 9_6_1 - check_payload(op_binary, 2**20, chopsize=128) # 9_6_2 - check_payload(op_binary, 2**20, chopsize=256) # 9_6_3 - check_payload(op_binary, 2**20, chopsize=512) # 9_6_4 - check_payload(op_binary, 2**20, chopsize=1024) # 9_6_5 - check_payload(op_binary, 2**20, chopsize=2048) # 9_6_6 - - close_connection(sock) - - -def test_java_websockets_10_1_1(): - client.load('websockets_mirror') - - _, sock, _ = ws.upgrade() - - payload = '*' * 65536 - - ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1300) - - frame = ws.message_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - close_connection(sock) - - -# settings - - -def test_java_websockets_max_frame_size(): - client.load('websockets_mirror') - - assert 'success' in client.conf( - {'http': {'websocket': {'max_frame_size': 100}}}, 'settings' - ), 'configure max_frame_size' - - _, sock, _ = ws.upgrade() - - payload = '*' * 94 - opcode = ws.OP_TEXT - - ws.frame_write(sock, opcode, payload) # frame length is 100 - - frame = ws.frame_read(sock) - check_frame(frame, True, opcode, payload) - - payload = '*' * 95 - - ws.frame_write(sock, opcode, payload) # frame length is 101 - check_close(sock, 1009) # 1009 - CLOSE_TOO_LARGE - - -def test_java_websockets_read_timeout(): - client.load('websockets_mirror') - - assert 'success' in client.conf( - {'http': {'websocket': {'read_timeout': 5}}}, 'settings' - ), 'configure read_timeout' - - _, sock, _ = ws.upgrade() - - frame = ws.frame_to_send(ws.OP_TEXT, 'blah') - sock.sendall(frame[:2]) - - time.sleep(2) - - check_close(sock, 1001) # 1001 - CLOSE_GOING_AWAY - - -def test_java_websockets_keepalive_interval(): - client.load('websockets_mirror') - - assert 'success' in client.conf( - {'http': {'websocket': {'keepalive_interval': 5}}}, 'settings' - ), 'configure keepalive_interval' - - _, sock, _ = ws.upgrade() - - frame = ws.frame_to_send(ws.OP_TEXT, 'blah') - sock.sendall(frame[:2]) - - time.sleep(2) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PING, '') # PING frame - - sock.close() diff --git a/test/test_njs.py b/test/test_njs.py deleted file mode 100644 index 23d1df1b..00000000 --- a/test/test_njs.py +++ /dev/null @@ -1,154 +0,0 @@ -from pathlib import Path - -import pytest - -from unit.applications.proto import ApplicationProto -from unit.option import option -from unit.utils import waitforfiles - -prerequisites = {'modules': {'njs': 'any'}} - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"share": f"{temp_dir}/assets$uri"}}], - } - ) - - -def create_files(*files): - assets_dir = f'{option.temp_dir}/assets/' - Path(assets_dir).mkdir(exist_ok=True) - - _ = [Path(assets_dir + f).touch() for f in files] - waitforfiles(*[assets_dir + f for f in files]) - - -def set_share(share): - assert 'success' in client.conf(share, 'routes/0/action/share') - - -def check_expression(expression, url='/'): - set_share(f'"`{option.temp_dir}/assets{expression}`"') - assert client.get(url=url)['status'] == 200 - - -def test_njs_template_string(temp_dir): - create_files('str', '`string`', '`backtick', 'l1\nl2') - - check_expression('/str') - check_expression('/\\\\`backtick') - check_expression('/l1\\nl2') - - set_share(f'"{temp_dir}/assets/`string`"') - assert client.get()['status'] == 200 - - -def test_njs_template_expression(): - create_files('str', 'localhost') - - check_expression('${uri}', '/str') - check_expression('${uri}${host}') - check_expression('${uri + host}') - check_expression('${uri + `${host}`}') - - -def test_njs_iteration(): - create_files('Connection,Host', 'close,localhost') - - check_expression('/${Object.keys(headers).sort().join()}') - check_expression('/${Object.values(headers).sort().join()}') - - -def test_njs_variables(temp_dir): - create_files('str', 'localhost', '127.0.0.1') - - check_expression('/${host}') - check_expression('/${remoteAddr}') - check_expression('/${headers.Host}') - - set_share(f'"`{temp_dir}/assets/${{cookies.foo}}`"') - assert ( - client.get(headers={'Cookie': 'foo=str', 'Connection': 'close'})[ - 'status' - ] - == 200 - ), 'cookies' - - set_share(f'"`{temp_dir}/assets/${{args.foo}}`"') - assert client.get(url='/?foo=str')['status'] == 200, 'args' - - check_expression('/${vars.header_host}') - - set_share(f'"`{temp_dir}/assets/${{vars[\\"arg_foo\\"]}}`"') - assert client.get(url='/?foo=str')['status'] == 200, 'vars' - - set_share(f'"`{temp_dir}/assets/${{vars.non_exist}}`"') - assert client.get()['status'] == 404, 'undefined' - - create_files('undefined') - assert client.get()['status'] == 200, 'undefined 2' - - -def test_njs_variables_cacheable(temp_dir): - create_files('str') - - def check_rewrite(rewrite, uri): - assert 'success' in client.conf( - [ - { - "action": { - "rewrite": rewrite, - "share": f"`{temp_dir}/assets{uri}`", - }, - }, - ], - 'routes', - ) - assert client.get()['status'] == 200 - - check_rewrite('/str', '${uri}') - check_rewrite('/str', '${vars.uri}') - - -def test_njs_variables_cacheable_access_log(findall, temp_dir): - assert 'success' in client.conf({"return": 200}, 'routes/0/action') - - assert 'success' in client.conf( - { - 'path': f'{temp_dir}/access.log', - 'format': '`${vars.host}, ${vars.status}\n`', - }, - 'access_log' - ), 'access_log configure' - - reqs = 50 - for _ in range(reqs): - client.get() - - assert len(findall(r'localhost, 200', 'access.log')) == reqs - - -def test_njs_invalid(skip_alert): - skip_alert(r'js exception:') - - def check_invalid(template): - assert 'error' in client.conf(template, 'routes/0/action/share') - - check_invalid('"`a"') - check_invalid('"`a``"') - check_invalid('"`a`/"') - check_invalid('"`${vars.}`"') - - def check_invalid_resolve(template): - assert 'success' in client.conf(template, 'routes/0/action/share') - assert client.get()['status'] == 500 - - check_invalid_resolve('"`${a}`"') - check_invalid_resolve('"`${uri.a.a}`"') - check_invalid_resolve('"`${vars.a.a}`"') diff --git a/test/test_njs_modules.py b/test/test_njs_modules.py deleted file mode 100644 index a639fabd..00000000 --- a/test/test_njs_modules.py +++ /dev/null @@ -1,104 +0,0 @@ -from unit.applications.proto import ApplicationProto -from unit.option import option - -prerequisites = {'modules': {'njs': 'any'}} - -client = ApplicationProto() - - -def njs_script_load(module, name=None, expect='success'): - if name is None: - name = module - - with open(f'{option.test_dir}/njs/{module}/script.js', 'rb') as script: - assert expect in client.conf(script.read(), f'/js_modules/{name}') - - -def test_njs_modules(): - njs_script_load('next') - - assert 'export' in client.conf_get('/js_modules/next') - assert 'error' in client.conf_post('"blah"', '/js_modules/next') - - assert 'success' in client.conf( - { - "settings": {"js_module": "next"}, - "listeners": {"*:8080": {"pass": "routes/first"}}, - "routes": { - "first": [{"action": {"pass": "`routes/${next.route()}`"}}], - "next": [{"action": {"return": 200}}], - }, - } - ) - assert client.get()['status'] == 200, 'string' - - assert 'success' in client.conf({"js_module": ["next"]}, 'settings') - assert client.get()['status'] == 200, 'array' - - # add one more value to array - - assert len(client.conf_get('/js_modules').keys()) == 1 - - njs_script_load('next', 'next_2') - - assert len(client.conf_get('/js_modules').keys()) == 2 - - assert 'success' in client.conf_post('"next_2"', 'settings/js_module') - assert client.get()['status'] == 200, 'array len 2' - - assert 'success' in client.conf( - '"`routes/${next_2.route()}`"', 'routes/first/0/action/pass' - ) - assert client.get()['status'] == 200, 'array new' - - # can't update exsisting script - - njs_script_load('global_this', 'next', expect='error') - - # delete modules - - assert 'error' in client.conf_delete('/js_modules/next_2') - assert 'success' in client.conf_delete('settings/js_module') - assert 'success' in client.conf_delete('/js_modules/next_2') - - -def test_njs_modules_import(): - njs_script_load('import_from') - - assert 'success' in client.conf( - { - "settings": {"js_module": "import_from"}, - "listeners": {"*:8080": {"pass": "routes/first"}}, - "routes": { - "first": [ - {"action": {"pass": "`routes/${import_from.num()}`"}} - ], - "number": [{"action": {"return": 200}}], - }, - } - ) - assert client.get()['status'] == 200 - - -def test_njs_modules_this(): - njs_script_load('global_this') - - assert 'success' in client.conf( - { - "settings": {"js_module": "global_this"}, - "listeners": {"*:8080": {"pass": "routes/first"}}, - "routes": { - "first": [ - {"action": {"pass": "`routes/${global_this.str()}`"}} - ], - "string": [{"action": {"return": 200}}], - }, - } - ) - assert client.get()['status'] == 200 - - -def test_njs_modules_invalid(skip_alert): - skip_alert(r'.*JS compile module.*failed.*') - - njs_script_load('invalid', expect='error') diff --git a/test/test_node_application.py b/test/test_node_application.py deleted file mode 100644 index 88ae3136..00000000 --- a/test/test_node_application.py +++ /dev/null @@ -1,351 +0,0 @@ -import re - -import pytest - -from unit.applications.lang.node import ApplicationNode -from unit.utils import waitforfiles - -prerequisites = {'modules': {'node': 'all'}} - -client = ApplicationNode() - - -def assert_basic_application(): - resp = client.get() - assert resp['headers']['Content-Type'] == 'text/plain', 'basic header' - assert resp['body'] == 'Hello World\n', 'basic body' - - -def test_node_application_basic(): - client.load('basic') - - assert_basic_application() - -def test_node_application_options(wait_for_record): - client.load('options') - - assert_basic_application() - assert wait_for_record(r'constructor was called with unsupported') is not None - - -def test_node_application_loader_unit_http(): - client.load('loader/unit_http') - - assert_basic_application() - - -def test_node_application_loader_transitive_dependency(): - client.load('loader/transitive_dependency') - - assert_basic_application() - - -def test_node_application_seq(): - client.load('basic') - - assert client.get()['status'] == 200, 'seq' - assert client.get()['status'] == 200, 'seq 2' - - -def test_node_application_variables(date_to_sec_epoch, sec_epoch): - client.load('variables') - - body = 'Test body string.' - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Custom-Header': 'blah', - 'Connection': 'close', - }, - body=body, - ) - - assert resp['status'] == 200, 'status' - headers = resp['headers'] - header_server = headers.pop('Server') - assert re.search(r'Unit/[\d\.]+', header_server), 'server header' - - date = headers.pop('Date') - assert date[-4:] == ' GMT', 'date header timezone' - assert abs(date_to_sec_epoch(date) - sec_epoch) < 5, 'date header' - - raw_headers = headers.pop('Request-Raw-Headers') - assert re.search( - r'^(?:Host|localhost|Content-Type|' - r'text\/html|Custom-Header|blah|Content-Length|17|Connection|' - r'close|,)+$', - raw_headers, - ), 'raw headers' - - assert headers == { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Content-Type': 'text/html', - 'Request-Method': 'POST', - 'Request-Uri': '/', - 'Http-Host': 'localhost', - 'Server-Protocol': '1.1', - 'Custom-Header': 'blah', - }, 'headers' - assert resp['body'] == body, 'body' - - -def test_node_application_get_variables(): - client.load('get_variables') - - resp = client.get(url='/?var1=val1&var2=&var3') - assert resp['headers']['X-Var-1'] == 'val1', 'GET variables' - assert resp['headers']['X-Var-2'] == '', 'GET variables 2' - assert resp['headers']['X-Var-3'] == '', 'GET variables 3' - - -def test_node_application_post_variables(): - client.load('post_variables') - - resp = client.post( - headers={ - 'Content-Type': 'application/x-www-form-urlencoded', - 'Host': 'localhost', - 'Connection': 'close', - }, - body='var1=val1&var2=&var3', - ) - - assert resp['headers']['X-Var-1'] == 'val1', 'POST variables' - assert resp['headers']['X-Var-2'] == '', 'POST variables 2' - assert resp['headers']['X-Var-3'] == '', 'POST variables 3' - - -def test_node_application_404(): - client.load('404') - - resp = client.get() - - assert resp['status'] == 404, '404 status' - assert re.search(r'404 Not Found', resp['body']), '404 body' - - -def test_node_keepalive_body(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' * 500 - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == '0123456789' * 500, 'keep-alive 1' - - body = '0123456789' - resp = client.post(sock=sock, body=body) - - assert resp['body'] == body, 'keep-alive 2' - - -def test_node_application_write_buffer(): - client.load('write_buffer') - - assert client.get()['body'] == 'buffer', 'write buffer' - - -def test_node_application_write_array(): - client.load('write_array') - - assert client.get()['body'] == 'array', 'write array' - - -def test_node_application_write_callback(temp_dir): - client.load('write_callback') - - assert client.get()['body'] == 'helloworld', 'write callback order' - assert waitforfiles(f'{temp_dir}/node/callback'), 'write callback' - - -def test_node_application_write_before_write_head(): - client.load('write_before_write_head') - - assert client.get()['status'] == 200, 'write before writeHead' - - -def test_node_application_double_end(): - client.load('double_end') - - assert client.get()['status'] == 200, 'double end' - assert client.get()['status'] == 200, 'double end 2' - - -def test_node_application_write_return(): - client.load('write_return') - - assert client.get()['body'] == 'bodytrue', 'write return' - - -def test_node_application_remove_header(): - client.load('remove_header') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'X-Remove': 'X-Header', - 'Connection': 'close', - } - ) - assert resp['headers']['Was-Header'] == 'true', 'was header' - assert resp['headers']['Has-Header'] == 'false', 'has header' - assert not ('X-Header' in resp['headers']), 'remove header' - - -def test_node_application_remove_header_nonexisting(): - client.load('remove_header') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Remove': 'blah', - 'Connection': 'close', - } - )['headers']['Has-Header'] - == 'true' - ), 'remove header nonexisting' - - -def test_node_application_update_header(): - client.load('update_header') - - assert client.get()['headers']['X-Header'] == 'new', 'update header' - - -def test_node_application_set_header_array(): - client.load('set_header_array') - - assert client.get()['headers']['Set-Cookie'] == [ - 'tc=one,two,three', - 'tc=four,five,six', - ], 'set header array' - - -@pytest.mark.skip('not yet') -def test_node_application_status_message(): - client.load('status_message') - - assert re.search(r'200 blah', client.get(raw_resp=True)), 'status message' - - -def test_node_application_get_header_type(): - client.load('get_header_type') - - assert client.get()['headers']['X-Type'] == 'number', 'get header type' - - -def test_node_application_header_name_case(): - client.load('header_name_case') - - headers = client.get()['headers'] - - assert headers['X-HEADER'] == '3', 'header value' - assert 'X-Header' not in headers, 'insensitive' - assert 'X-header' not in headers, 'insensitive 2' - - -def test_node_application_promise_handler_write_after_end(): - client.load('promise_handler') - - assert ( - client.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'X-Write-Call': '1', - 'Connection': 'close', - }, - body='callback', - )['status'] - == 200 - ), 'promise handler request write after end' - - -def test_node_application_promise_end(temp_dir): - client.load('promise_end') - - assert ( - client.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Connection': 'close', - }, - body='end', - )['status'] - == 200 - ), 'promise end request' - assert waitforfiles(f'{temp_dir}/node/callback'), 'promise end' - - -@pytest.mark.skip('not yet') -def test_node_application_header_name_valid(): - client.load('header_name_valid') - - assert 'status' not in client.get(), 'header name valid' - - -def test_node_application_header_value_object(): - client.load('header_value_object') - - assert 'X-Header' in client.get()['headers'], 'header value object' - - -def test_node_application_get_header_names(): - client.load('get_header_names') - - assert client.get()['headers']['X-Names'] == [ - 'date', - 'x-header', - ], 'get header names' - - -def test_node_application_flush_headers(): - client.load('flush_headers') - - assert client.get()['headers']['X-Header'] == 'blah' - - -def test_node_application_has_header(): - client.load('has_header') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Header': 'length', - 'Connection': 'close', - } - )['headers']['X-Has-Header'] - == 'false' - ), 'has header length' - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Header': 'Date', - 'Connection': 'close', - } - )['headers']['X-Has-Header'] - == 'false' - ), 'has header date' - - -def test_node_application_write_multiple(): - client.load('write_multiple') - - assert client.get()['body'] == 'writewrite2end', 'write multiple' diff --git a/test/test_node_es_modules.py b/test/test_node_es_modules.py deleted file mode 100644 index 4effafea..00000000 --- a/test/test_node_es_modules.py +++ /dev/null @@ -1,49 +0,0 @@ -from packaging import version - -from unit.applications.lang.node import ApplicationNode -from unit.applications.websockets import ApplicationWebsocket - -prerequisites = { - 'modules': {'node': lambda v: version.parse(v) >= version.parse('14.16.0')} -} - -client = ApplicationNode(es_modules=True) -ws = ApplicationWebsocket() - - -def assert_basic_application(): - resp = client.get() - assert resp['headers']['Content-Type'] == 'text/plain', 'basic header' - assert resp['body'] == 'Hello World\n', 'basic body' - - -def test_node_es_modules_loader_http(): - client.load('loader/es_modules_http', name="app.mjs") - - assert_basic_application() - - -def test_node_es_modules_loader_http_indirect(): - client.load('loader/es_modules_http_indirect', name="app.js") - - assert_basic_application() - - -def test_node_es_modules_loader_websockets(): - client.load('loader/es_modules_websocket', name="app.mjs") - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message) - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'mirror' - - ws.frame_write(sock, ws.OP_TEXT, message) - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'mirror 2' - - sock.close() diff --git a/test/test_node_websockets.py b/test/test_node_websockets.py deleted file mode 100644 index 68bdd578..00000000 --- a/test/test_node_websockets.py +++ /dev/null @@ -1,1435 +0,0 @@ -import struct -import time - -import pytest - -from unit.applications.lang.node import ApplicationNode -from unit.applications.websockets import ApplicationWebsocket - -prerequisites = {'modules': {'node': 'any'}} - -client = ApplicationNode() -ws = ApplicationWebsocket() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(skip_alert): - assert 'success' in client.conf( - {'http': {'websocket': {'keepalive_interval': 0}}}, 'settings' - ), 'clear keepalive_interval' - - skip_alert(r'socket close\(\d+\) failed') - - -def close_connection(sock): - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - - check_close(sock) - - -def check_close(sock, code=1000, no_close=False, frame=None): - if frame is None: - frame = ws.frame_read(sock) - - assert frame['fin'], 'close fin' - assert frame['opcode'] == ws.OP_CLOSE, 'close opcode' - assert frame['code'] == code, 'close code' - - if not no_close: - sock.close() - - -def check_frame(frame, fin, opcode, payload, decode=True): - if opcode == ws.OP_BINARY or not decode: - data = frame['data'] - else: - data = frame['data'].decode('utf-8') - - assert frame['fin'] == fin, 'fin' - assert frame['opcode'] == opcode, 'opcode' - assert data == payload, 'payload' - - -def test_node_websockets_handshake(): - client.load('websockets/mirror') - - resp, sock, key = ws.upgrade() - sock.close() - - assert resp['status'] == 101, 'status' - assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' - assert resp['headers']['Connection'] == 'Upgrade', 'connection' - assert resp['headers']['Sec-WebSocket-Accept'] == ws.accept(key), 'key' - - -def test_node_websockets_mirror(): - client.load('websockets/mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message) - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'mirror' - - ws.frame_write(sock, ws.OP_TEXT, message) - frame = ws.frame_read(sock) - - assert message == frame['data'].decode('utf-8'), 'mirror 2' - - sock.close() - - -def test_node_websockets_no_mask(): - client.load('websockets/mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message, mask=False) - - frame = ws.frame_read(sock) - - assert frame['opcode'] == ws.OP_CLOSE, 'no mask opcode' - assert frame['code'] == 1002, 'no mask close code' - - sock.close() - - -def test_node_websockets_fragmentation(): - client.load('websockets/mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message, fin=False) - ws.frame_write(sock, ws.OP_CONT, ' ', fin=False) - ws.frame_write(sock, ws.OP_CONT, message) - - frame = ws.frame_read(sock) - - assert f'{message} {message}' == frame['data'].decode( - 'utf-8' - ), 'mirror framing' - - sock.close() - - -def test_node_websockets_frame_fragmentation_invalid(): - client.load('websockets/mirror') - - message = 'blah' - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, message, fin=False) - - frame = ws.frame_read(sock) - - frame.pop('data') - assert frame == { - 'fin': True, - 'rsv1': False, - 'rsv2': False, - 'rsv3': False, - 'opcode': ws.OP_CLOSE, - 'mask': 0, - 'code': 1002, - 'reason': 'Fragmented control frame', - }, 'close frame' - - sock.close() - - -def test_node_websockets_large(): - client.load('websockets/mirror_fragmentation') - - message = '0123456789' * 3000 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, message) - - frame = ws.frame_read(sock) - data = frame['data'].decode('utf-8') - - frame = ws.frame_read(sock) - data += frame['data'].decode('utf-8') - - assert message == data, 'large' - - sock.close() - - -def test_node_websockets_two_clients(): - client.load('websockets/mirror') - - message1 = 'blah1' - message2 = 'blah2' - - _, sock1, _ = ws.upgrade() - _, sock2, _ = ws.upgrade() - - ws.frame_write(sock1, ws.OP_TEXT, message1) - ws.frame_write(sock2, ws.OP_TEXT, message2) - - frame1 = ws.frame_read(sock1) - frame2 = ws.frame_read(sock2) - - assert message1 == frame1['data'].decode('utf-8'), 'client 1' - assert message2 == frame2['data'].decode('utf-8'), 'client 2' - - sock1.close() - sock2.close() - - -# FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1 -@pytest.mark.skip('not yet') -def test_node_websockets_handshake_upgrade_absent(): - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'upgrade absent' - - -def test_node_websockets_handshake_case_insensitive(): - client.load('websockets/mirror') - - resp, sock, _ = ws.upgrade( - headers={ - 'Host': 'localhost', - 'Upgrade': 'WEBSOCKET', - 'Connection': 'UPGRADE', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - } - ) - sock.close() - - assert resp['status'] == 101, 'status' - - -@pytest.mark.skip('not yet') -def test_node_websockets_handshake_connection_absent(): # FAIL - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'status' - - -def test_node_websockets_handshake_version_absent(): - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - }, - ) - - assert resp['status'] == 426, 'status' - - -@pytest.mark.skip('not yet') -def test_node_websockets_handshake_key_invalid(): - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': '!', - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'key length' - - key = ws.key() - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': [key, key], - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert ( - resp['status'] == 400 - ), 'key double' # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1 - - -def test_node_websockets_handshake_method_invalid(): - client.load('websockets/mirror') - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - ) - - assert resp['status'] == 400, 'status' - - -def test_node_websockets_handshake_http_10(): - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - http_10=True, - ) - - assert resp['status'] == 400, 'status' - - -def test_node_websockets_handshake_uri_invalid(): - client.load('websockets/mirror') - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': ws.key(), - 'Sec-WebSocket-Protocol': 'chat', - 'Sec-WebSocket-Version': 13, - }, - url='!', - ) - - assert resp['status'] == 400, 'status' - - -def test_node_websockets_protocol_absent(): - client.load('websockets/mirror') - - key = ws.key() - resp, sock, _ = ws.upgrade( - headers={ - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': key, - 'Sec-WebSocket-Version': 13, - } - ) - sock.close() - - assert resp['status'] == 101, 'status' - assert resp['headers']['Upgrade'] == 'websocket', 'upgrade' - assert resp['headers']['Connection'] == 'Upgrade', 'connection' - assert resp['headers']['Sec-WebSocket-Accept'] == ws.accept(key), 'key' - - -# autobahn-testsuite -# -# Some following tests fail because of Unit does not support UTF-8 -# validation for websocket frames. It should be implemented -# by application, if necessary. - - -def test_node_websockets_1_1_1__1_1_8(): - client.load('websockets/mirror') - - opcode = ws.OP_TEXT - - _, sock, _ = ws.upgrade() - - def check_length(length, chopsize=None): - payload = '*' * length - - ws.frame_write(sock, opcode, payload, chopsize=chopsize) - - frame = ws.frame_read(sock) - check_frame(frame, True, opcode, payload) - - check_length(0) # 1_1_1 - check_length(125) # 1_1_2 - check_length(126) # 1_1_3 - check_length(127) # 1_1_4 - check_length(128) # 1_1_5 - check_length(65535) # 1_1_6 - check_length(65536) # 1_1_7 - check_length(65536, chopsize=997) # 1_1_8 - - close_connection(sock) - - -def test_node_websockets_1_2_1__1_2_8(): - client.load('websockets/mirror') - - opcode = ws.OP_BINARY - - _, sock, _ = ws.upgrade() - - def check_length(length, chopsize=None): - payload = b'\xfe' * length - - ws.frame_write(sock, opcode, payload, chopsize=chopsize) - frame = ws.frame_read(sock) - - check_frame(frame, True, opcode, payload) - - check_length(0) # 1_2_1 - check_length(125) # 1_2_2 - check_length(126) # 1_2_3 - check_length(127) # 1_2_4 - check_length(128) # 1_2_5 - check_length(65535) # 1_2_6 - check_length(65536) # 1_2_7 - check_length(65536, chopsize=997) # 1_2_8 - - close_connection(sock) - - -def test_node_websockets_2_1__2_6(): - client.load('websockets/mirror') - - op_ping = ws.OP_PING - op_pong = ws.OP_PONG - - _, sock, _ = ws.upgrade() - - def check_ping(payload, chopsize=None, decode=True): - ws.frame_write(sock, op_ping, payload, chopsize=chopsize) - frame = ws.frame_read(sock) - - check_frame(frame, True, op_pong, payload, decode=decode) - - check_ping('') # 2_1 - check_ping('Hello, world!') # 2_2 - check_ping(b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', decode=False) # 2_3 - check_ping(b'\xfe' * 125, decode=False) # 2_4 - check_ping(b'\xfe' * 125, chopsize=1, decode=False) # 2_6 - - close_connection(sock) - - # 2_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, b'\xfe' * 126) - check_close(sock, 1002) - - -def test_node_websockets_2_7__2_9(): - client.load('websockets/mirror') - - # 2_7 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PONG, '') - assert client.recvall(sock, read_timeout=0.1) == b'', '2_7' - - # 2_8 - - ws.frame_write(sock, ws.OP_PONG, 'unsolicited pong payload') - assert client.recvall(sock, read_timeout=0.1) == b'', '2_8' - - # 2_9 - - payload = 'ping payload' - - ws.frame_write(sock, ws.OP_PONG, 'unsolicited pong payload') - ws.frame_write(sock, ws.OP_PING, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, payload) - - close_connection(sock) - - -def test_node_websockets_2_10__2_11(): - client.load('websockets/mirror') - - # 2_10 - - _, sock, _ = ws.upgrade() - - for i in range(0, 10): - ws.frame_write(sock, ws.OP_PING, f'payload-{i}') - - for i in range(0, 10): - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, f'payload-{i}') - - # 2_11 - - for i in range(0, 10): - opcode = ws.OP_PING - ws.frame_write(sock, opcode, f'payload-{i}', chopsize=1) - - for i in range(0, 10): - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, f'payload-{i}') - - close_connection(sock) - - -@pytest.mark.skip('not yet') -def test_node_websockets_3_1__3_7(): - client.load('websockets/mirror') - - payload = 'Hello, world!' - - # 3_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, rsv1=True) - check_close(sock, 1002) - - # 3_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - ws.frame_write(sock, ws.OP_TEXT, payload, rsv2=True) - ws.frame_write(sock, ws.OP_PING, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - check_close(sock, 1002, no_close=True) - - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2' - sock.close() - - # 3_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, ws.OP_TEXT, payload, rsv1=True, rsv2=True) - - check_close(sock, 1002, no_close=True) - - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3' - sock.close() - - # 3_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) - ws.frame_write(sock, ws.OP_TEXT, payload, rsv3=True, chopsize=1) - ws.frame_write(sock, ws.OP_PING, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - check_close(sock, 1002, no_close=True) - - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4' - sock.close() - - # 3_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write( - sock, - ws.OP_BINARY, - b'\x00\xff\xfe\xfd\xfc\xfb\x00\xff', - rsv1=True, - rsv3=True, - ) - - check_close(sock, 1002) - - # 3_6 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, payload, rsv2=True, rsv3=True) - - check_close(sock, 1002) - - # 3_7 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, payload, rsv1=True, rsv2=True, rsv3=True) - - check_close(sock, 1002) - - -def test_node_websockets_4_1_1__4_2_5(): - client.load('websockets/mirror') - - payload = 'Hello, world!' - - # 4_1_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x03, '') - check_close(sock, 1002) - - # 4_1_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x04, 'reserved opcode payload') - check_close(sock, 1002) - - # 4_1_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x05, '') - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_1_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x06, payload) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_1_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x07, payload, chopsize=1) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_2_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x0B, '') - check_close(sock, 1002) - - # 4_2_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, 0x0C, 'reserved opcode payload') - check_close(sock, 1002) - - # 4_2_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x0D, '') - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_2_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x0E, payload) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - # 4_2_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, payload, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - ws.frame_write(sock, 0x0F, payload, chopsize=1) - ws.frame_write(sock, ws.OP_PING, '') - - check_close(sock, 1002) - - -def test_node_websockets_5_1__5_20(): - client.load('websockets/mirror') - - # 5_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PING, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - check_close(sock, 1002) - - # 5_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_PONG, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - check_close(sock, 1002) - - # 5_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_4 - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - assert client.recvall(sock, read_timeout=0.1) == b'', '5_4' - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_5 - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False, chopsize=1) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_6 - - ping_payload = 'ping payload' - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_PING, ping_payload) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, ping_payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_7 - - ping_payload = 'ping payload' - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - assert client.recvall(sock, read_timeout=0.1) == b'', '5_7' - - ws.frame_write(sock, ws.OP_PING, ping_payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, ping_payload) - - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_8 - - ping_payload = 'ping payload' - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False, chopsize=1) - ws.frame_write(sock, ws.OP_PING, ping_payload, chopsize=1) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True, chopsize=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, ping_payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - - # 5_9 - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=True) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_10 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=True) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_11 - - _, sock, _ = ws.upgrade() - - ws.frame_write( - sock, - ws.OP_CONT, - 'non-continuation payload', - fin=True, - chopsize=1, - ) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1) - check_close(sock, 1002) - - # 5_12 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_13 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CONT, 'non-continuation payload', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True) - check_close(sock, 1002) - - # 5_14 - - _, sock, _ = ws.upgrade() - - ws.frame_write( - sock, - ws.OP_CONT, - 'non-continuation payload', - fin=False, - chopsize=1, - ) - ws.frame_write(sock, ws.OP_TEXT, 'Hello, world!', fin=True, chopsize=1) - check_close(sock, 1002) - - # 5_15 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=True) - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'fragment4', fin=True) - - frame = ws.frame_read(sock) - - if frame['opcode'] == ws.OP_TEXT: - check_frame(frame, True, ws.OP_TEXT, 'fragment1fragment2') - frame = None - - check_close(sock, 1002, frame=frame) - - # 5_16 - - _, sock, _ = ws.upgrade() - - for _ in range(0, 2): - ws.frame_write(sock, ws.OP_CONT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=True) - check_close(sock, 1002) - - # 5_17 - - _, sock, _ = ws.upgrade() - - for _ in range(0, 2): - ws.frame_write(sock, ws.OP_CONT, 'fragment1', fin=True) - ws.frame_write(sock, ws.OP_TEXT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=True) - check_close(sock, 1002) - - # 5_18 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_TEXT, 'fragment2') - check_close(sock, 1002) - - # 5_19 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 1!') - - time.sleep(1) - - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment4', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 2!') - ws.frame_write(sock, ws.OP_CONT, 'fragment5') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 1!') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 2!') - - check_frame( - ws.frame_read(sock), - True, - ws.OP_TEXT, - 'fragment1fragment2fragment3fragment4fragment5', - ) - - # 5_20 - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment2', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 1!') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 1!') - - time.sleep(1) - - ws.frame_write(sock, ws.OP_CONT, 'fragment3', fin=False) - ws.frame_write(sock, ws.OP_CONT, 'fragment4', fin=False) - ws.frame_write(sock, ws.OP_PING, 'pongme 2!') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PONG, 'pongme 2!') - - assert client.recvall(sock, read_timeout=0.1) == b'', '5_20' - ws.frame_write(sock, ws.OP_CONT, 'fragment5') - - check_frame( - ws.frame_read(sock), - True, - ws.OP_TEXT, - 'fragment1fragment2fragment3fragment4fragment5', - ) - - close_connection(sock) - - -def test_node_websockets_6_1_1__6_4_4(): - client.load('websockets/mirror') - - # 6_1_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, '') - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, '') - - # 6_1_2 - - ws.frame_write(sock, ws.OP_TEXT, '', fin=False) - ws.frame_write(sock, ws.OP_CONT, '', fin=False) - ws.frame_write(sock, ws.OP_CONT, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, '') - - # 6_1_3 - - payload = 'middle frame payload' - - ws.frame_write(sock, ws.OP_TEXT, '', fin=False) - ws.frame_write(sock, ws.OP_CONT, payload, fin=False) - ws.frame_write(sock, ws.OP_CONT, '') - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_1 - - payload = 'Hello-µ@ßöäüàá-UTF-8!!' - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_2 - - ws.frame_write(sock, ws.OP_TEXT, payload[:12], fin=False) - ws.frame_write(sock, ws.OP_CONT, payload[12:]) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_3 - - ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - # 6_2_4 - - payload = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5' - - ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - close_connection(sock) - - -# Unit does not support UTF-8 validation -# -# # 6_3_1 FAIL -# -# payload_1 = '\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5' -# payload_2 = '\xed\xa0\x80' -# payload_3 = '\x65\x64\x69\x74\x65\x64' -# -# payload = payload_1 + payload_2 + payload_3 -# -# ws.message(sock, ws.OP_TEXT, payload) -# check_close(sock, 1007) -# -# # 6_3_2 FAIL -# -# _, sock, _ = ws.upgrade() -# -# ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1) -# check_close(sock, 1007) -# -# # 6_4_1 ... 6_4_4 FAIL - - -def test_node_websockets_7_1_1__7_5_1(): - client.load('websockets/mirror') - - # 7_1_1 - - _, sock, _ = ws.upgrade() - - payload = "Hello World!" - - ws.frame_write(sock, ws.OP_TEXT, payload) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - close_connection(sock) - - # 7_1_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - - check_close(sock) - - # 7_1_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock, no_close=True) - - ws.frame_write(sock, ws.OP_PING, '') - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_1_4 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock, no_close=True) - - ws.frame_write(sock, ws.OP_TEXT, payload) - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_1_5 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'fragment1', fin=False) - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock, no_close=True) - - ws.frame_write(sock, ws.OP_CONT, 'fragment2') - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_1_6 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_TEXT, 'BAsd7&jh23' * 26 * 2**10) - ws.frame_write(sock, ws.OP_TEXT, payload) - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - - client.recvall(sock, read_timeout=1) - - ws.frame_write(sock, ws.OP_PING, '') - assert client.recvall(sock, read_timeout=0.1) == b'', 'empty soc' - - sock.close() - - # 7_3_1 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, '') - check_close(sock) - - # 7_3_2 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, 'a') - check_close(sock, 1002) - - # 7_3_3 - - _, sock, _ = ws.upgrade() - - ws.frame_write(sock, ws.OP_CLOSE, ws.serialize_close()) - check_close(sock) - - # 7_3_4 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(reason='Hello World!') - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock) - - # 7_3_5 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(reason='*' * 123) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock) - - # 7_3_6 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(reason='*' * 124) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - -# # 7_5_1 FAIL Unit does not support UTF-8 validation -# -# _, sock, _ = ws.upgrade() -# -# payload = ws.serialize_close(reason = '\xce\xba\xe1\xbd\xb9\xcf' \ -# '\x83\xce\xbc\xce\xb5\xed\xa0\x80\x65\x64\x69\x74\x65\x64') -# -# ws.frame_write(sock, ws.OP_CLOSE, payload) -# check_close(sock, 1007) - - -def test_node_websockets_7_7_X__7_9_X(): - client.load('websockets/mirror') - - valid_codes = [ - 1000, - 1001, - 1002, - 1003, - 1007, - 1008, - 1009, - 1010, - 1011, - 3000, - 3999, - 4000, - 4999, - ] - - invalid_codes = [0, 999, 1004, 1005, 1006, 1016, 1100, 2000, 2999] - - for code in valid_codes: - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(code=code) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock) - - for code in invalid_codes: - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(code=code) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - -def test_node_websockets_7_13_1__7_13_2(): - client.load('websockets/mirror') - - # 7_13_1 - - _, sock, _ = ws.upgrade() - - payload = ws.serialize_close(code=5000) - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - # 7_13_2 - - _, sock, _ = ws.upgrade() - - payload = struct.pack('!I', 65536) + ''.encode('utf-8') - - ws.frame_write(sock, ws.OP_CLOSE, payload) - check_close(sock, 1002) - - -def test_node_websockets_9_1_1__9_6_6(is_unsafe, system): - if not is_unsafe: - pytest.skip('unsafe, long run') - - client.load('websockets/mirror') - - assert 'success' in client.conf( - { - 'http': { - 'websocket': { - 'max_frame_size': 33554432, - 'keepalive_interval': 0, - } - } - }, - 'settings', - ), 'increase max_frame_size and keepalive_interval' - - _, sock, _ = ws.upgrade() - - op_text = ws.OP_TEXT - op_binary = ws.OP_BINARY - - def check_payload(opcode, length, chopsize=None): - if opcode == ws.OP_TEXT: - payload = '*' * length - else: - payload = b'*' * length - - ws.frame_write(sock, opcode, payload, chopsize=chopsize) - frame = ws.frame_read(sock, read_timeout=5) - check_frame(frame, True, opcode, payload) - - def check_message(opcode, f_size): - if opcode == ws.OP_TEXT: - payload = '*' * 4 * 2**20 - else: - payload = b'*' * 4 * 2**20 - - ws.message(sock, opcode, payload, fragmention_size=f_size) - frame = ws.frame_read(sock, read_timeout=5) - check_frame(frame, True, opcode, payload) - - check_payload(op_text, 64 * 2**10) # 9_1_1 - check_payload(op_text, 256 * 2**10) # 9_1_2 - check_payload(op_text, 2**20) # 9_1_3 - check_payload(op_text, 4 * 2**20) # 9_1_4 - check_payload(op_text, 8 * 2**20) # 9_1_5 - check_payload(op_text, 16 * 2**20) # 9_1_6 - - check_payload(op_binary, 64 * 2**10) # 9_2_1 - check_payload(op_binary, 256 * 2**10) # 9_2_2 - check_payload(op_binary, 2**20) # 9_2_3 - check_payload(op_binary, 4 * 2**20) # 9_2_4 - check_payload(op_binary, 8 * 2**20) # 9_2_5 - check_payload(op_binary, 16 * 2**20) # 9_2_6 - - if system not in ['Darwin', 'FreeBSD']: - check_message(op_text, 64) # 9_3_1 - check_message(op_text, 256) # 9_3_2 - check_message(op_text, 2**10) # 9_3_3 - check_message(op_text, 4 * 2**10) # 9_3_4 - check_message(op_text, 16 * 2**10) # 9_3_5 - check_message(op_text, 64 * 2**10) # 9_3_6 - check_message(op_text, 256 * 2**10) # 9_3_7 - check_message(op_text, 2**20) # 9_3_8 - check_message(op_text, 4 * 2**20) # 9_3_9 - - check_message(op_binary, 64) # 9_4_1 - check_message(op_binary, 256) # 9_4_2 - check_message(op_binary, 2**10) # 9_4_3 - check_message(op_binary, 4 * 2**10) # 9_4_4 - check_message(op_binary, 16 * 2**10) # 9_4_5 - check_message(op_binary, 64 * 2**10) # 9_4_6 - check_message(op_binary, 256 * 2**10) # 9_4_7 - check_message(op_binary, 2**20) # 9_4_8 - check_message(op_binary, 4 * 2**20) # 9_4_9 - - check_payload(op_text, 2**20, chopsize=64) # 9_5_1 - check_payload(op_text, 2**20, chopsize=128) # 9_5_2 - check_payload(op_text, 2**20, chopsize=256) # 9_5_3 - check_payload(op_text, 2**20, chopsize=512) # 9_5_4 - check_payload(op_text, 2**20, chopsize=1024) # 9_5_5 - check_payload(op_text, 2**20, chopsize=2048) # 9_5_6 - - check_payload(op_binary, 2**20, chopsize=64) # 9_6_1 - check_payload(op_binary, 2**20, chopsize=128) # 9_6_2 - check_payload(op_binary, 2**20, chopsize=256) # 9_6_3 - check_payload(op_binary, 2**20, chopsize=512) # 9_6_4 - check_payload(op_binary, 2**20, chopsize=1024) # 9_6_5 - check_payload(op_binary, 2**20, chopsize=2048) # 9_6_6 - - close_connection(sock) - - -def test_node_websockets_10_1_1(): - client.load('websockets/mirror') - - _, sock, _ = ws.upgrade() - - payload = '*' * 65536 - - ws.message(sock, ws.OP_TEXT, payload, fragmention_size=1300) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_TEXT, payload) - - close_connection(sock) - - -# settings - - -def test_node_websockets_max_frame_size(): - client.load('websockets/mirror') - - assert 'success' in client.conf( - {'http': {'websocket': {'max_frame_size': 100}}}, 'settings' - ), 'configure max_frame_size' - - _, sock, _ = ws.upgrade() - - payload = '*' * 94 - opcode = ws.OP_TEXT - - ws.frame_write(sock, opcode, payload) # frame length is 100 - - frame = ws.frame_read(sock) - check_frame(frame, True, opcode, payload) - - payload = '*' * 95 - - ws.frame_write(sock, opcode, payload) # frame length is 101 - check_close(sock, 1009) # 1009 - CLOSE_TOO_LARGE - - -def test_node_websockets_read_timeout(): - client.load('websockets/mirror') - - assert 'success' in client.conf( - {'http': {'websocket': {'read_timeout': 5}}}, 'settings' - ), 'configure read_timeout' - - _, sock, _ = ws.upgrade() - - frame = ws.frame_to_send(ws.OP_TEXT, 'blah') - sock.sendall(frame[:2]) - - time.sleep(2) - - check_close(sock, 1001) # 1001 - CLOSE_GOING_AWAY - - -def test_node_websockets_keepalive_interval(): - client.load('websockets/mirror') - - assert 'success' in client.conf( - {'http': {'websocket': {'keepalive_interval': 5}}}, 'settings' - ), 'configure keepalive_interval' - - _, sock, _ = ws.upgrade() - - frame = ws.frame_to_send(ws.OP_TEXT, 'blah') - sock.sendall(frame[:2]) - - time.sleep(2) - - frame = ws.frame_read(sock) - check_frame(frame, True, ws.OP_PING, '') # PING frame - - sock.close() diff --git a/test/test_perl_application.py b/test/test_perl_application.py deleted file mode 100644 index ad355117..00000000 --- a/test/test_perl_application.py +++ /dev/null @@ -1,319 +0,0 @@ -import re - -import pytest - -from unit.applications.lang.perl import ApplicationPerl - -prerequisites = {'modules': {'perl': 'all'}} - -client = ApplicationPerl() - - -def test_perl_application(date_to_sec_epoch, sec_epoch): - client.load('variables') - - body = 'Test body string.' - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Custom-Header': 'blah', - 'Connection': 'close', - }, - body=body, - ) - - assert resp['status'] == 200, 'status' - headers = resp['headers'] - header_server = headers.pop('Server') - assert re.search(r'Unit/[\d\.]+', header_server), 'server header' - assert ( - headers.pop('Server-Software') == header_server - ), 'server software header' - - date = headers.pop('Date') - assert date[-4:] == ' GMT', 'date header timezone' - assert abs(date_to_sec_epoch(date) - sec_epoch) < 5, 'date header' - - assert headers == { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Content-Type': 'text/html', - 'Request-Method': 'POST', - 'Request-Uri': '/', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Custom-Header': 'blah', - 'Psgi-Version': '11', - 'Psgi-Url-Scheme': 'http', - 'Psgi-Multithread': '', - 'Psgi-Multiprocess': '1', - 'Psgi-Run-Once': '', - 'Psgi-Nonblocking': '', - 'Psgi-Streaming': '1', - }, 'headers' - assert resp['body'] == body, 'body' - - -def test_perl_application_query_string(): - client.load('query_string') - - resp = client.get(url='/?var1=val1&var2=val2') - - assert ( - resp['headers']['Query-String'] == 'var1=val1&var2=val2' - ), 'Query-String header' - - -def test_perl_application_query_string_empty(): - client.load('query_string') - - resp = client.get(url='/?') - - assert resp['status'] == 200, 'query string empty status' - assert resp['headers']['Query-String'] == '', 'query string empty' - - -def test_perl_application_query_string_absent(): - client.load('query_string') - - resp = client.get() - - assert resp['status'] == 200, 'query string absent status' - assert resp['headers']['Query-String'] == '', 'query string absent' - - -@pytest.mark.skip('not yet') -def test_perl_application_server_port(): - client.load('server_port') - - assert ( - client.get()['headers']['Server-Port'] == '8080' - ), 'Server-Port header' - - -def test_perl_application_input_read_empty(): - client.load('input_read_empty') - - assert client.get()['body'] == '', 'read empty' - - -def test_perl_application_input_read_parts(): - client.load('input_read_parts') - - assert ( - client.post(body='0123456789')['body'] == '0123456789' - ), 'input read parts' - - -def test_perl_application_input_buffered_read(): - client.load('input_buffered_read') - - assert client.post(body='012345')['body'] == '012345', 'buffered read #1' - assert ( - client.post(body='9876543210')['body'] == '9876543210' - ), 'buffered read #2' - - -def test_perl_application_input_close(): - client.load('input_close') - - assert client.post(body='012345')['body'] == '012345', 'input close #1' - assert ( - client.post(body='9876543210')['body'] == '9876543210' - ), 'input close #2' - - -@pytest.mark.skip('not yet') -def test_perl_application_input_read_offset(): - client.load('input_read_offset') - - assert client.post(body='0123456789')['body'] == '4567', 'read offset' - - -def test_perl_application_input_copy(): - client.load('input_copy') - - body = '0123456789' - assert client.post(body=body)['body'] == body, 'input copy' - - -def test_perl_application_errors_print(wait_for_record): - client.load('errors_print') - - assert client.get()['body'] == '1', 'errors result' - - assert ( - wait_for_record(r'\[error\].+Error in application') is not None - ), 'errors print' - - -def test_perl_application_header_equal_names(): - client.load('header_equal_names') - - assert client.get()['headers']['Set-Cookie'] == [ - 'tc=one,two,three', - 'tc=four,five,six', - ], 'header equal names' - - -def test_perl_application_header_pairs(): - client.load('header_pairs') - - assert client.get()['headers']['blah'] == 'blah', 'header pairs' - - -def test_perl_application_body_empty(): - client.load('body_empty') - - assert client.get()['body'] == '', 'body empty' - - -def test_perl_application_body_array(): - client.load('body_array') - - assert client.get()['body'] == '0123456789', 'body array' - - -def test_perl_application_body_large(): - client.load('variables') - - body = '0123456789' * 1000 - - resp = client.post(body=body)['body'] - - assert resp == body, 'body large' - - -def test_perl_application_body_io_empty(): - client.load('body_io_empty') - - assert client.get()['status'] == 200, 'body io empty' - - -def test_perl_application_body_io_file(): - client.load('body_io_file') - - assert client.get()['body'] == 'body\n', 'body io file' - - -def test_perl_streaming_body_multiple_responses(): - client.load('streaming_body_multiple_responses') - - assert client.get()['status'] == 200 - - -@pytest.mark.skip('not yet') -def test_perl_application_syntax_error(skip_alert): - skip_alert(r'PSGI: Failed to parse script') - client.load('syntax_error') - - assert client.get()['status'] == 500, 'syntax error' - - -def test_perl_keepalive_body(): - client.load('variables') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' * 500 - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive 1' - - body = '0123456789' - resp = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'close', - 'Content-Type': 'text/html', - }, - sock=sock, - body=body, - ) - - assert resp['body'] == body, 'keep-alive 2' - - -def test_perl_body_io_fake(wait_for_record): - client.load('body_io_fake') - - assert client.get()['body'] == '21', 'body io fake' - - assert ( - wait_for_record(r'\[error\].+IOFake getline\(\) \$\/ is \d+') - is not None - ), 'body io fake $/ value' - - assert ( - wait_for_record(r'\[error\].+IOFake close\(\) called') is not None - ), 'body io fake close' - - -def test_perl_delayed_response(): - client.load('delayed_response') - - resp = client.get() - - assert resp['status'] == 200, 'status' - assert resp['body'] == 'Hello World!', 'body' - - -def test_perl_streaming_body(): - client.load('streaming_body') - - resp = client.get() - - assert resp['status'] == 200, 'status' - assert resp['body'] == 'Hello World!', 'body' - - -def test_perl_application_threads(): - client.load('threads') - - assert 'success' in client.conf( - '4', 'applications/threads/threads' - ), 'configure 4 threads' - - socks = [] - - for _ in range(4): - sock = client.get( - headers={ - 'Host': 'localhost', - 'X-Delay': '2', - 'Connection': 'close', - }, - no_recv=True, - ) - - socks.append(sock) - - threads = set() - - for sock in socks: - resp = client.recvall(sock).decode('utf-8') - - client.log_in(resp) - - resp = client._resp_to_dict(resp) - - assert resp['status'] == 200, 'status' - - threads.add(resp['headers']['X-Thread']) - - assert resp['headers']['Psgi-Multithread'] == '1', 'multithread' - - sock.close() - - assert len(socks) == len(threads), 'threads differs' diff --git a/test/test_php_application.py b/test/test_php_application.py deleted file mode 100644 index 90db38fa..00000000 --- a/test/test_php_application.py +++ /dev/null @@ -1,890 +0,0 @@ -import getpass -import os -import re -import shutil -import signal -import time -from pathlib import Path - -import pytest - -from unit.applications.lang.php import ApplicationPHP -from unit.option import option - -prerequisites = {'modules': {'php': 'all'}} - -client = ApplicationPHP() - - -def before_disable_functions(): - body = client.get()['body'] - - assert re.search(r'time: \d+', body), 'disable_functions before time' - assert re.search(r'exec: \/\w+', body), 'disable_functions before exec' - - -def check_opcache(): - resp = client.get() - assert resp['status'] == 200, 'status' - - headers = resp['headers'] - if 'X-OPcache' in headers and headers['X-OPcache'] == '-1': - pytest.skip('opcache is not supported') - - return resp - - -def run_php_application_cwd_root_tests(): - assert 'success' in client.conf_delete('applications/cwd/working_directory') - - script_cwd = f'{option.test_dir}/php/cwd' - - resp = client.get() - assert resp['status'] == 200, 'status ok' - assert resp['body'] == script_cwd, 'default cwd' - - assert 'success' in client.conf( - f'"{option.test_dir}"', - 'applications/cwd/working_directory', - ) - - resp = client.get() - assert resp['status'] == 200, 'status ok' - assert resp['body'] == script_cwd, 'wdir cwd' - - resp = client.get(url='/?chdir=/') - assert resp['status'] == 200, 'status ok' - assert resp['body'] == '/', 'cwd after chdir' - - # cwd must be restored - - resp = client.get() - assert resp['status'] == 200, 'status ok' - assert resp['body'] == script_cwd, 'cwd restored' - - resp = client.get(url='/subdir/') - assert resp['body'] == f'{script_cwd}/subdir', 'cwd subdir' - - -def run_php_application_cwd_script_tests(): - client.load('cwd') - - script_cwd = f'{option.test_dir}/php/cwd' - - assert 'success' in client.conf_delete('applications/cwd/working_directory') - - assert 'success' in client.conf('"index.php"', 'applications/cwd/script') - - assert client.get()['body'] == script_cwd, 'default cwd' - - assert client.get(url='/?chdir=/')['body'] == '/', 'cwd after chdir' - - # cwd must be restored - assert client.get()['body'] == script_cwd, 'cwd restored' - - -def set_opcache(app, val): - assert 'success' in client.conf( - {"admin": {"opcache.enable": val, "opcache.enable_cli": val}}, - f'applications/{app}/options', - ) - - r = check_opcache() - assert r['headers']['X-OPcache'] == val, 'opcache value' - - -def set_preload(preload): - Path(f'{option.temp_dir}/php.ini').write_text( - f"""opcache.preload = {option.test_dir}/php/opcache/preload\ -/{preload} -opcache.preload_user = {option.user or getpass.getuser()} -""", - encoding='utf-8', - ) - - assert 'success' in client.conf( - {"file": f"{option.temp_dir}/php.ini"}, - 'applications/opcache/options', - ) - - -def test_php_application_variables(date_to_sec_epoch, sec_epoch): - client.load('variables') - - body = 'Test body string.' - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Custom-Header': 'blah', - 'Connection': 'close', - }, - body=body, - url='/index.php/blah?var=val', - ) - - assert resp['status'] == 200, 'status' - headers = resp['headers'] - header_server = headers.pop('Server') - assert re.search(r'Unit/[\d\.]+', header_server), 'server header' - assert ( - headers.pop('Server-Software') == header_server - ), 'server software header' - - date = headers.pop('Date') - assert date[-4:] == ' GMT', 'date header timezone' - assert abs(date_to_sec_epoch(date) - sec_epoch) < 5, 'date header' - - if 'X-Powered-By' in headers: - headers.pop('X-Powered-By') - - headers.pop('Content-type') - assert headers == { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Request-Method': 'POST', - 'Path-Info': '/blah', - 'Request-Uri': '/index.php/blah?var=val', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Custom-Header': 'blah', - }, 'headers' - assert resp['body'] == body, 'body' - - -def test_php_application_query_string(): - client.load('query_string') - - resp = client.get(url='/?var1=val1&var2=val2') - - assert ( - resp['headers']['Query-String'] == 'var1=val1&var2=val2' - ), 'query string' - - -def test_php_application_query_string_empty(): - client.load('query_string') - - resp = client.get(url='/?') - - assert resp['status'] == 200, 'query string empty status' - assert resp['headers']['Query-String'] == '', 'query string empty' - - -def test_php_application_query_string_rewrite(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "action": { - "rewrite": "/new", - "pass": "applications/query_string", - }, - }, - ], - "applications": { - "query_string": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "root": f"{option.test_dir}/php/query_string", - "script": "index.php", - } - }, - }, - ) - - assert client.get(url='/old')['status'] == 200 - - resp = client.get(url='/old?arg=val') - assert resp['status'] == 200 - assert resp['headers']['Query-String'] == 'arg=val' - - -def test_php_application_fastcgi_finish_request(findall, unit_pid): - client.load('fastcgi_finish_request') - - assert 'success' in client.conf( - {"admin": {"auto_globals_jit": "1"}}, - 'applications/fastcgi_finish_request/options', - ) - - assert client.get()['body'] == '0123' - - os.kill(unit_pid, signal.SIGUSR1) - - errs = findall(r'Error in fastcgi_finish_request') - - assert len(errs) == 0, 'no error' - - -def test_php_application_fastcgi_finish_request_2(findall, unit_pid): - client.load('fastcgi_finish_request') - - assert 'success' in client.conf( - {"admin": {"auto_globals_jit": "1"}}, - 'applications/fastcgi_finish_request/options', - ) - - resp = client.get(url='/?skip') - assert resp['status'] == 200 - assert resp['body'] == '' - - os.kill(unit_pid, signal.SIGUSR1) - - errs = findall(r'Error in fastcgi_finish_request') - - assert len(errs) == 0, 'no error' - - -def test_php_application_query_string_absent(): - client.load('query_string') - - resp = client.get() - - assert resp['status'] == 200, 'query string absent status' - assert resp['headers']['Query-String'] == '', 'query string absent' - - -def test_php_application_phpinfo(): - client.load('phpinfo') - - resp = client.get() - - assert resp['status'] == 200, 'status' - assert resp['body'] != '', 'body not empty' - - -def test_php_application_header_status(): - client.load('header') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Connection': 'close', - 'X-Header': 'HTTP/1.1 404 Not Found', - } - )['status'] - == 404 - ), 'status' - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Connection': 'close', - 'X-Header': 'http/1.1 404 Not Found', - } - )['status'] - == 404 - ), 'status case insensitive' - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Connection': 'close', - 'X-Header': 'HTTP/ 404 Not Found', - } - )['status'] - == 404 - ), 'status version empty' - - -def test_php_application_404(): - client.load('404') - - resp = client.get() - - assert resp['status'] == 404, '404 status' - assert re.search(r'404 Not Found', resp['body']), '404 body' - - -def test_php_application_keepalive_body(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' * 500 - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive 1' - - body = '0123456789' - resp = client.post(sock=sock, body=body) - - assert resp['body'] == body, 'keep-alive 2' - - -def test_php_application_conditional(): - client.load('conditional') - - assert re.search(r'True', client.get()['body']), 'conditional true' - assert re.search(r'False', client.post()['body']), 'conditional false' - - -def test_php_application_get_variables(): - client.load('get_variables') - - resp = client.get(url='/?var1=val1&var2=&var3') - assert resp['headers']['X-Var-1'] == 'val1', 'GET variables' - assert resp['headers']['X-Var-2'] == '', 'GET variables 2' - assert resp['headers']['X-Var-3'] == '', 'GET variables 3' - assert resp['headers']['X-Var-4'] == 'not set', 'GET variables 4' - - -def test_php_application_post_variables(): - client.load('post_variables') - - resp = client.post( - headers={ - 'Content-Type': 'application/x-www-form-urlencoded', - 'Host': 'localhost', - 'Connection': 'close', - }, - body='var1=val1&var2=', - ) - assert resp['headers']['X-Var-1'] == 'val1', 'POST variables' - assert resp['headers']['X-Var-2'] == '', 'POST variables 2' - assert resp['headers']['X-Var-3'] == 'not set', 'POST variables 3' - - -def test_php_application_cookies(): - client.load('cookies') - - resp = client.get( - headers={ - 'Cookie': 'var=val; var2=val2', - 'Host': 'localhost', - 'Connection': 'close', - } - ) - - assert resp['headers']['X-Cookie-1'] == 'val', 'cookie' - assert resp['headers']['X-Cookie-2'] == 'val2', 'cookie' - - -def test_php_application_ini_precision(): - client.load('ini_precision') - - assert client.get()['headers']['X-Precision'] != '4', 'ini value default' - - assert 'success' in client.conf( - {"file": "ini/php.ini"}, 'applications/ini_precision/options' - ) - - assert ( - client.get()['headers']['X-File'] - == f'{option.test_dir}/php/ini_precision/ini/php.ini' - ), 'ini file' - assert client.get()['headers']['X-Precision'] == '4', 'ini value' - - -@pytest.mark.skip('not yet') -def test_php_application_ini_admin_user(): - client.load('ini_precision') - - assert 'error' in client.conf( - {"user": {"precision": "4"}, "admin": {"precision": "5"}}, - 'applications/ini_precision/options', - ), 'ini admin user' - - -def test_php_application_ini_admin(): - client.load('ini_precision') - - assert 'success' in client.conf( - {"file": "ini/php.ini", "admin": {"precision": "5"}}, - 'applications/ini_precision/options', - ) - - assert ( - client.get()['headers']['X-File'] - == f'{option.test_dir}/php/ini_precision/ini/php.ini' - ), 'ini file' - assert client.get()['headers']['X-Precision'] == '5', 'ini value admin' - - -def test_php_application_ini_user(): - client.load('ini_precision') - - assert 'success' in client.conf( - {"file": "ini/php.ini", "user": {"precision": "5"}}, - 'applications/ini_precision/options', - ) - - assert ( - client.get()['headers']['X-File'] - == f'{option.test_dir}/php/ini_precision/ini/php.ini' - ), 'ini file' - assert client.get()['headers']['X-Precision'] == '5', 'ini value user' - - -def test_php_application_ini_user_2(): - client.load('ini_precision') - - assert 'success' in client.conf( - {"file": "ini/php.ini"}, 'applications/ini_precision/options' - ) - - assert client.get()['headers']['X-Precision'] == '4', 'ini user file' - - assert 'success' in client.conf( - {"precision": "5"}, 'applications/ini_precision/options/user' - ) - - assert client.get()['headers']['X-Precision'] == '5', 'ini value user' - - -def test_php_application_ini_set_admin(): - client.load('ini_precision') - - assert 'success' in client.conf( - {"admin": {"precision": "5"}}, 'applications/ini_precision/options' - ) - - assert ( - client.get(url='/?precision=6')['headers']['X-Precision'] == '5' - ), 'ini set admin' - - -def test_php_application_ini_set_user(): - client.load('ini_precision') - - assert 'success' in client.conf( - {"user": {"precision": "5"}}, 'applications/ini_precision/options' - ) - - assert ( - client.get(url='/?precision=6')['headers']['X-Precision'] == '6' - ), 'ini set user' - - -def test_php_application_ini_repeat(): - client.load('ini_precision') - - assert 'success' in client.conf( - {"user": {"precision": "5"}}, 'applications/ini_precision/options' - ) - - assert client.get()['headers']['X-Precision'] == '5', 'ini value' - - assert client.get()['headers']['X-Precision'] == '5', 'ini value repeat' - - -def test_php_application_disable_functions_exec(): - client.load('time_exec') - - before_disable_functions() - - assert 'success' in client.conf( - {"admin": {"disable_functions": "exec"}}, - 'applications/time_exec/options', - ) - - body = client.get()['body'] - - assert re.search(r'time: \d+', body), 'disable_functions time' - assert not re.search(r'exec: \/\w+', body), 'disable_functions exec' - - -def test_php_application_disable_functions_comma(): - client.load('time_exec') - - before_disable_functions() - - assert 'success' in client.conf( - {"admin": {"disable_functions": "exec,time"}}, - 'applications/time_exec/options', - ) - - body = client.get()['body'] - - assert not re.search(r'time: \d+', body), 'disable_functions comma time' - assert not re.search(r'exec: \/\w+', body), 'disable_functions comma exec' - - -def test_php_application_auth(): - client.load('auth') - - resp = client.get() - assert resp['status'] == 200, 'status' - assert resp['headers']['X-Digest'] == 'not set', 'digest' - assert resp['headers']['X-User'] == 'not set', 'user' - assert resp['headers']['X-Password'] == 'not set', 'password' - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Authorization': 'Basic dXNlcjpwYXNzd29yZA==', - 'Connection': 'close', - } - ) - assert resp['status'] == 200, 'basic status' - assert resp['headers']['X-Digest'] == 'not set', 'basic digest' - assert resp['headers']['X-User'] == 'user', 'basic user' - assert resp['headers']['X-Password'] == 'password', 'basic password' - - resp = client.get( - headers={ - 'Host': 'localhost', - 'Authorization': 'Digest username="blah", realm="", uri="/"', - 'Connection': 'close', - } - ) - assert resp['status'] == 200, 'digest status' - assert ( - resp['headers']['X-Digest'] == 'username="blah", realm="", uri="/"' - ), 'digest digest' - assert resp['headers']['X-User'] == 'not set', 'digest user' - assert resp['headers']['X-Password'] == 'not set', 'digest password' - - -def test_php_application_auth_invalid(): - client.load('auth') - - def check_auth(auth): - resp = client.get( - headers={ - 'Host': 'localhost', - 'Authorization': auth, - 'Connection': 'close', - } - ) - - assert resp['status'] == 200, 'status' - assert resp['headers']['X-Digest'] == 'not set', 'Digest' - assert resp['headers']['X-User'] == 'not set', 'User' - assert resp['headers']['X-Password'] == 'not set', 'Password' - - check_auth('Basic dXN%cjpwYXNzd29yZA==') - check_auth('Basic XNlcjpwYXNzd29yZA==') - check_auth('Basic DdXNlcjpwYXNzd29yZA==') - check_auth('Basic blah') - check_auth('Basic') - check_auth('Digest') - check_auth('blah') - - -def test_php_application_disable_functions_space(): - client.load('time_exec') - - before_disable_functions() - - assert 'success' in client.conf( - {"admin": {"disable_functions": "exec time"}}, - 'applications/time_exec/options', - ) - - body = client.get()['body'] - - assert not re.search(r'time: \d+', body), 'disable_functions space time' - assert not re.search(r'exec: \/\w+', body), 'disable_functions space exec' - - -def test_php_application_disable_functions_user(): - client.load('time_exec') - - before_disable_functions() - - assert 'success' in client.conf( - {"user": {"disable_functions": "exec"}}, - 'applications/time_exec/options', - ) - - body = client.get()['body'] - - assert re.search(r'time: \d+', body), 'disable_functions user time' - assert not re.search(r'exec: \/\w+', body), 'disable_functions user exec' - - -def test_php_application_disable_functions_nonexistent(): - client.load('time_exec') - - before_disable_functions() - - assert 'success' in client.conf( - {"admin": {"disable_functions": "blah"}}, - 'applications/time_exec/options', - ) - - body = client.get()['body'] - - assert re.search(r'time: \d+', body), 'disable_functions nonexistent time' - assert re.search(r'exec: \/\w+', body), 'disable_functions nonexistent exec' - - -def test_php_application_disable_classes(): - client.load('date_time') - - assert re.search(r'012345', client.get()['body']), 'disable_classes before' - - assert 'success' in client.conf( - {"admin": {"disable_classes": "DateTime"}}, - 'applications/date_time/options', - ) - - assert not re.search( - r'012345', client.get()['body'] - ), 'disable_classes before' - - -def test_php_application_disable_classes_user(): - client.load('date_time') - - assert re.search(r'012345', client.get()['body']), 'disable_classes before' - - assert 'success' in client.conf( - {"user": {"disable_classes": "DateTime"}}, - 'applications/date_time/options', - ) - - assert not re.search( - r'012345', client.get()['body'] - ), 'disable_classes before' - - -def test_php_application_error_log(findall, wait_for_record): - client.load('error_log') - - assert client.get()['status'] == 200, 'status' - - time.sleep(1) - - assert client.get()['status'] == 200, 'status 2' - - pattern = r'\d{4}\/\d\d\/\d\d\s\d\d:.+\[notice\].+Error in application' - - assert wait_for_record(pattern) is not None, 'errors print' - - errs = findall(pattern) - - assert len(errs) == 2, 'error_log count' - - date = errs[0].split('[')[0] - date2 = errs[1].split('[')[0] - assert date != date2, 'date diff' - - -def test_php_application_script(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "applications/script"}}, - "applications": { - "script": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "root": f"{option.test_dir}/php/script", - "script": "phpinfo.php", - } - }, - } - ), 'configure script' - - resp = client.get() - - assert resp['status'] == 200, 'status' - assert resp['body'] != '', 'body not empty' - - -def test_php_application_index_default(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "applications/phpinfo"}}, - "applications": { - "phpinfo": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "root": f"{option.test_dir}/php/phpinfo", - } - }, - } - ), 'configure index default' - - resp = client.get() - - assert resp['status'] == 200, 'status' - assert resp['body'] != '', 'body not empty' - - -def test_php_application_trailing_slash(temp_dir): - new_root = f'{temp_dir}/php-root' - - Path(f'{new_root}/path').mkdir(parents=True) - Path(f'{new_root}/path/index.php').write_text( - '', encoding='utf-8' - ) - - addr = f'{temp_dir}/sock' - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "applications/php-path"}, - f'unix:{addr}': {"pass": "applications/php-path"}, - }, - "applications": { - "php-path": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "root": new_root, - } - }, - } - ), 'configure trailing slash' - - assert client.get(url='/path/')['status'] == 200, 'uri with trailing /' - - resp = client.get(url='/path?q=a') - assert resp['status'] == 301, 'uri without trailing /' - assert ( - resp['headers']['Location'] == 'http://localhost:8080/path/?q=a' - ), 'Location with query string' - - resp = client.get( - sock_type='unix', - addr=addr, - url='/path', - headers={'Host': 'foo', 'Connection': 'close'}, - ) - assert resp['status'] == 301, 'uri without trailing /' - assert ( - resp['headers']['Location'] == 'http://foo/path/' - ), 'Location with custom Host over UDS' - - -def test_php_application_forbidden(temp_dir): - Path(f'{temp_dir}/php-root/path').mkdir(mode=0o000, parents=True) - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "applications/php-path"}}, - "applications": { - "php-path": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "root": f'{temp_dir}/php-root', - } - }, - } - ), 'forbidden directory' - - assert client.get(url='/path/')['status'] == 403, 'access forbidden' - - -def test_php_application_extension_check(temp_dir): - client.load('phpinfo') - - assert client.get(url='/index.wrong')['status'] != 200, 'status' - - new_root = f'{temp_dir}/php' - Path(new_root).mkdir(parents=True) - shutil.copy(f'{option.test_dir}/php/phpinfo/index.wrong', new_root) - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "applications/phpinfo"}}, - "applications": { - "phpinfo": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "root": new_root, - "working_directory": new_root, - } - }, - } - ), 'configure new root' - - resp = client.get() - assert f'{resp["status"]}{resp["body"]}' != '200', 'status new root' - - -def test_php_application_cwd_root(): - client.load('cwd') - run_php_application_cwd_root_tests() - - -def test_php_application_cwd_opcache_disabled(): - client.load('cwd') - set_opcache('cwd', '0') - run_php_application_cwd_root_tests() - - -def test_php_application_cwd_opcache_enabled(): - client.load('cwd') - set_opcache('cwd', '1') - run_php_application_cwd_root_tests() - - -def test_php_application_cwd_script(): - client.load('cwd') - run_php_application_cwd_script_tests() - - -def test_php_application_cwd_script_opcache_disabled(): - client.load('cwd') - set_opcache('cwd', '0') - run_php_application_cwd_script_tests() - - -def test_php_application_cwd_script_opcache_enabled(): - client.load('cwd') - set_opcache('cwd', '1') - run_php_application_cwd_script_tests() - - -def test_php_application_path_relative(): - client.load('open') - - assert client.get()['body'] == 'test', 'relative path' - - assert ( - client.get(url='/?chdir=/')['body'] != 'test' - ), 'relative path w/ chdir' - - assert client.get()['body'] == 'test', 'relative path 2' - - -def test_php_application_shared_opcache(): - client.load('opcache', limits={'requests': 1}) - - r = check_opcache() - pid = r['headers']['X-Pid'] - assert r['headers']['X-Cached'] == '0', 'not cached' - - r = client.get() - - assert r['headers']['X-Pid'] != pid, 'new instance' - assert r['headers']['X-Cached'] == '1', 'cached' - - -def test_php_application_opcache_preload_chdir(): - client.load('opcache') - - check_opcache() - - set_preload('chdir.php') - - assert client.get()['headers']['X-Cached'] == '0', 'not cached' - assert client.get()['headers']['X-Cached'] == '1', 'cached' - - -def test_php_application_opcache_preload_ffr(): - client.load('opcache') - - check_opcache() - - set_preload('fastcgi_finish_request.php') - - assert client.get()['headers']['X-Cached'] == '0', 'not cached' - assert client.get()['headers']['X-Cached'] == '1', 'cached' diff --git a/test/test_php_basic.py b/test/test_php_basic.py deleted file mode 100644 index 076b7498..00000000 --- a/test/test_php_basic.py +++ /dev/null @@ -1,130 +0,0 @@ -from unit.control import Control - -prerequisites = {'modules': {'php': 'any'}} - -client = Control() - -conf_app = { - "app": { - "type": "php", - "processes": {"spare": 0}, - "root": "/app", - "index": "index.php", - } -} - -conf_basic = { - "listeners": {"*:8080": {"pass": "applications/app"}}, - "applications": conf_app, -} - - -def test_php_get_applications(): - assert 'success' in client.conf(conf_app, 'applications') - - conf = client.conf_get() - - assert conf['listeners'] == {}, 'listeners' - assert conf['applications'] == { - "app": { - "type": "php", - "processes": {"spare": 0}, - "root": "/app", - "index": "index.php", - } - }, 'applications' - - assert client.conf_get('applications') == { - "app": { - "type": "php", - "processes": {"spare": 0}, - "root": "/app", - "index": "index.php", - } - }, 'applications prefix' - - assert client.conf_get('applications/app') == { - "type": "php", - "processes": {"spare": 0}, - "root": "/app", - "index": "index.php", - }, 'applications prefix 2' - - assert client.conf_get('applications/app/type') == 'php', 'type' - assert ( - client.conf_get('applications/app/processes/spare') == 0 - ), 'spare processes' - - -def test_php_get_listeners(): - assert 'success' in client.conf(conf_basic) - - assert client.conf_get()['listeners'] == { - "*:8080": {"pass": "applications/app"} - }, 'listeners' - - assert client.conf_get('listeners') == { - "*:8080": {"pass": "applications/app"} - }, 'listeners prefix' - - assert client.conf_get('listeners/*:8080') == { - "pass": "applications/app" - }, 'listeners prefix 2' - - -def test_php_change_listener(): - assert 'success' in client.conf(conf_basic) - assert 'success' in client.conf( - {"*:8081": {"pass": "applications/app"}}, 'listeners' - ) - - assert client.conf_get('listeners') == { - "*:8081": {"pass": "applications/app"} - }, 'change listener' - - -def test_php_add_listener(): - assert 'success' in client.conf(conf_basic) - assert 'success' in client.conf( - {"pass": "applications/app"}, 'listeners/*:8082' - ) - - assert client.conf_get('listeners') == { - "*:8080": {"pass": "applications/app"}, - "*:8082": {"pass": "applications/app"}, - }, 'add listener' - - -def test_php_change_application(): - assert 'success' in client.conf(conf_basic) - - assert 'success' in client.conf('30', 'applications/app/processes/max') - assert ( - client.conf_get('applications/app/processes/max') == 30 - ), 'change application max' - - assert 'success' in client.conf('"/www"', 'applications/app/root') - assert ( - client.conf_get('applications/app/root') == '/www' - ), 'change application root' - - -def test_php_delete(): - assert 'success' in client.conf(conf_basic) - - assert 'error' in client.conf_delete('applications/app') - assert 'success' in client.conf_delete('listeners/*:8080') - assert 'success' in client.conf_delete('applications/app') - assert 'error' in client.conf_delete('applications/app') - - -def test_php_delete_blocks(): - assert 'success' in client.conf(conf_basic) - - assert 'success' in client.conf_delete('listeners') - assert 'success' in client.conf_delete('applications') - - assert 'success' in client.conf(conf_app, 'applications') - assert 'success' in client.conf( - {"*:8081": {"pass": "applications/app"}}, 'listeners' - ), 'applications restore' diff --git a/test/test_php_isolation.py b/test/test_php_isolation.py deleted file mode 100644 index f248da41..00000000 --- a/test/test_php_isolation.py +++ /dev/null @@ -1,85 +0,0 @@ -from unit.applications.lang.php import ApplicationPHP - -prerequisites = {'modules': {'php': 'any'}, 'features': {'isolation': True}} - -client = ApplicationPHP() - - -def test_php_isolation_rootfs(is_su, require, temp_dir): - isolation = {'rootfs': temp_dir} - - if not is_su: - require( - { - 'features': { - 'isolation': [ - 'unprivileged_userns_clone', - 'user', - 'mnt', - 'pid', - ] - } - } - ) - - isolation['namespaces'] = { - 'mount': True, - 'credential': True, - 'pid': True, - } - - client.load('phpinfo', isolation=isolation) - - assert 'success' in client.conf( - '"/app/php/phpinfo"', 'applications/phpinfo/root' - ) - assert 'success' in client.conf( - '"/app/php/phpinfo"', 'applications/phpinfo/working_directory' - ) - - assert client.get()['status'] == 200, 'empty rootfs' - - -def test_php_isolation_rootfs_extensions(is_su, require, temp_dir): - isolation = {'rootfs': temp_dir} - - if not is_su: - require( - { - 'features': { - 'isolation': [ - 'unprivileged_userns_clone', - 'user', - 'mnt', - 'pid', - ] - } - } - ) - - isolation['namespaces'] = { - 'mount': True, - 'credential': True, - 'pid': True, - } - - client.load('list-extensions', isolation=isolation) - - assert 'success' in client.conf( - '"/app/php/list-extensions"', 'applications/list-extensions/root' - ) - - assert 'success' in client.conf( - {'file': '/php/list-extensions/php.ini'}, - 'applications/list-extensions/options', - ) - - assert 'success' in client.conf( - '"/app/php/list-extensions"', - 'applications/list-extensions/working_directory', - ) - - extensions = client.getjson()['body'] - - assert 'json' in extensions, 'json in extensions list' - assert 'unit' in extensions, 'unit in extensions list' diff --git a/test/test_php_targets.py b/test/test_php_targets.py deleted file mode 100644 index 6085db40..00000000 --- a/test/test_php_targets.py +++ /dev/null @@ -1,100 +0,0 @@ -from unit.applications.lang.php import ApplicationPHP -from unit.option import option - -prerequisites = {'modules': {'php': 'any'}} - -client = ApplicationPHP() - - -def test_php_application_targets(): - targets_dir = f"{option.test_dir}/php/targets" - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": "/1"}, - "action": {"pass": "applications/targets/1"}, - }, - { - "match": {"uri": "/2"}, - "action": {"pass": "applications/targets/2"}, - }, - {"action": {"pass": "applications/targets/default"}}, - ], - "applications": { - "targets": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "targets": { - "1": { - "script": "1.php", - "root": targets_dir, - }, - "2": { - "script": "2.php", - "root": f'{targets_dir}/2', - }, - "default": { - "index": "index.php", - "root": targets_dir, - }, - }, - } - }, - } - ) - - assert client.get(url='/1')['body'] == '1' - assert client.get(url='/2')['body'] == '2' - assert client.get(url='/blah')['status'] == 404 - assert client.get(url='/')['body'] == 'index' - assert client.get(url='/1.php?test=test.php/')['body'] == '1' - - assert 'success' in client.conf( - "\"1.php\"", 'applications/targets/targets/default/index' - ), 'change targets index' - assert client.get(url='/')['body'] == '1' - - assert 'success' in client.conf_delete( - 'applications/targets/targets/default/index' - ), 'remove targets index' - assert client.get(url='/')['body'] == 'index' - - -def test_php_application_targets_error(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "applications/targets/default"}}, - "applications": { - "targets": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "targets": { - "default": { - "index": "index.php", - "root": f"{option.test_dir}/php/targets", - }, - }, - } - }, - } - ), 'initial configuration' - assert client.get()['status'] == 200 - - assert 'error' in client.conf( - {"pass": "applications/targets/blah"}, 'listeners/*:8080' - ), 'invalid targets pass' - assert 'error' in client.conf( - f'"{option.test_dir}/php/targets"', - 'applications/targets/root', - ), 'invalid root' - assert 'error' in client.conf( - '"index.php"', 'applications/targets/index' - ), 'invalid index' - assert 'error' in client.conf( - '"index.php"', 'applications/targets/script' - ), 'invalid script' - assert 'error' in client.conf_delete( - 'applications/targets/default/root' - ), 'root remove' diff --git a/test/test_procman.py b/test/test_procman.py deleted file mode 100644 index b4378c4f..00000000 --- a/test/test_procman.py +++ /dev/null @@ -1,303 +0,0 @@ -import re -import shutil -import subprocess -import time - -import pytest - -from unit.applications.lang.python import ApplicationPython -from unit.option import option - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - client.app_name = f'app-{temp_dir.split("/")[-1]}' - client.app_proc = f'applications/{client.app_name}/processes' - client.load('empty', client.app_name) - - -def pids_for_process(): - time.sleep(0.2) - - output = subprocess.check_output(['ps', 'ax']) - - pids = set() - for m in re.findall( - fr'.*unit: "{client.app_name}" application', output.decode() - ): - pids.add(re.search(r'^\s*(\d+)', m).group(1)) - - return pids - - -def conf_proc(conf, path=None): - if path is None: - path = client.app_proc - - assert 'success' in client.conf(conf, path), 'configure processes' - - -def stop_all(): - assert 'success' in client.conf({"listeners": {}, "applications": {}}) - - assert len(pids_for_process()) == 0, 'stop all' - - -@pytest.mark.skip('not yet') -def test_python_processes_idle_timeout_zero(): - conf_proc({"spare": 0, "max": 2, "idle_timeout": 0}) - - client.get() - assert len(pids_for_process()) == 0, 'idle timeout 0' - - -def test_python_prefork(): - conf_proc('2') - - pids = pids_for_process() - assert len(pids) == 2, 'prefork 2' - - client.get() - assert pids_for_process() == pids, 'prefork still 2' - - conf_proc('4') - - pids = pids_for_process() - assert len(pids) == 4, 'prefork 4' - - client.get() - assert pids_for_process() == pids, 'prefork still 4' - - stop_all() - - -@pytest.mark.skip('not yet') -def test_python_prefork_same_processes(): - conf_proc('2') - pids = pids_for_process() - - conf_proc('4') - pids_new = pids_for_process() - - assert pids.issubset(pids_new), 'prefork same processes' - - -def test_python_ondemand(): - conf_proc({"spare": 0, "max": 8, "idle_timeout": 1}) - - assert len(pids_for_process()) == 0, 'on-demand 0' - - client.get() - pids = pids_for_process() - assert len(pids) == 1, 'on-demand 1' - - client.get() - assert pids_for_process() == pids, 'on-demand still 1' - - time.sleep(1) - - assert len(pids_for_process()) == 0, 'on-demand stop idle' - - stop_all() - - -def test_python_scale_updown(): - conf_proc({"spare": 2, "max": 8, "idle_timeout": 1}) - - pids = pids_for_process() - assert len(pids) == 2, 'updown 2' - - client.get() - pids_new = pids_for_process() - assert len(pids_new) == 3, 'updown 3' - assert pids.issubset(pids_new), 'updown 3 only 1 new' - - client.get() - assert pids_for_process() == pids_new, 'updown still 3' - - time.sleep(1) - - pids = pids_for_process() - assert len(pids) == 2, 'updown stop idle' - - client.get() - pids_new = pids_for_process() - assert len(pids_new) == 3, 'updown again 3' - assert pids.issubset(pids_new), 'updown again 3 only 1 new' - - stop_all() - - -def test_python_reconfigure(): - conf_proc({"spare": 2, "max": 6, "idle_timeout": 1}) - - pids = pids_for_process() - assert len(pids) == 2, 'reconf 2' - - client.get() - pids_new = pids_for_process() - assert len(pids_new) == 3, 'reconf 3' - assert pids.issubset(pids_new), 'reconf 3 only 1 new' - - conf_proc('6', f'{client.app_proc}/spare') - - pids = pids_for_process() - assert len(pids) == 6, 'reconf 6' - - client.get() - assert pids_for_process() == pids, 'reconf still 6' - - stop_all() - - -def test_python_idle_timeout(): - conf_proc({"spare": 0, "max": 6, "idle_timeout": 2}) - - client.get() - pids = pids_for_process() - assert len(pids) == 1, 'idle timeout 1' - - time.sleep(1) - - client.get() - - time.sleep(1) - - pids_new = pids_for_process() - assert len(pids_new) == 1, 'idle timeout still 1' - assert pids_for_process() == pids, 'idle timeout still 1 same pid' - - time.sleep(1) - - assert len(pids_for_process()) == 0, 'idle timed out' - - -def test_python_processes_connection_keepalive(): - conf_proc({"spare": 0, "max": 6, "idle_timeout": 2}) - - (_, sock) = client.get( - headers={'Host': 'localhost', 'Connection': 'keep-alive'}, - start=True, - read_timeout=1, - ) - assert len(pids_for_process()) == 1, 'keepalive connection 1' - - time.sleep(2) - - assert len(pids_for_process()) == 0, 'keepalive connection 0' - - sock.close() - - -def test_python_processes_access(): - conf_proc('1') - - path = f'/{client.app_proc}' - assert 'error' in client.conf_get(f'{path}/max') - assert 'error' in client.conf_get(f'{path}/spare') - assert 'error' in client.conf_get(f'{path}/idle_timeout') - - -def test_python_processes_invalid(): - assert 'error' in client.conf( - {"spare": -1}, client.app_proc - ), 'negative spare' - assert 'error' in client.conf({"max": -1}, client.app_proc), 'negative max' - assert 'error' in client.conf( - {"idle_timeout": -1}, client.app_proc - ), 'negative idle_timeout' - assert 'error' in client.conf( - {"spare": 2}, client.app_proc - ), 'spare gt max default' - assert 'error' in client.conf( - {"spare": 2, "max": 1}, client.app_proc - ), 'spare gt max' - assert 'error' in client.conf( - {"spare": 0, "max": 0}, client.app_proc - ), 'max zero' - - -def test_python_restart(temp_dir): - shutil.copyfile( - f'{option.test_dir}/python/restart/v1.py', f'{temp_dir}/wsgi.py' - ) - - client.load( - temp_dir, - name=client.app_name, - processes=1, - environment={'PYTHONDONTWRITEBYTECODE': '1'}, - ) - - b = client.get()['body'] - assert b == "v1", 'process started' - - shutil.copyfile( - f'{option.test_dir}/python/restart/v2.py', f'{temp_dir}/wsgi.py' - ) - - b = client.get()['body'] - assert b == "v1", 'still old process' - - assert 'success' in client.conf_get( - f'/control/applications/{client.app_name}/restart' - ), 'restart processes' - - b = client.get()['body'] - assert b == "v2", 'new process started' - - assert 'error' in client.conf_get( - '/control/applications/blah/restart' - ), 'application incorrect' - - assert 'error' in client.conf_delete( - f'/control/applications/{client.app_name}/restart' - ), 'method incorrect' - - -def test_python_restart_multi(): - conf_proc('2') - - pids = pids_for_process() - assert len(pids) == 2, 'restart 2 started' - - assert 'success' in client.conf_get( - f'/control/applications/{client.app_name}/restart' - ), 'restart processes' - - new_pids = pids_for_process() - assert len(new_pids) == 2, 'restart still 2' - - assert len(new_pids.intersection(pids)) == 0, 'restart all new' - - -def test_python_restart_longstart(): - client.load( - 'restart', - name=client.app_name, - module="longstart", - processes={"spare": 1, "max": 2, "idle_timeout": 5}, - ) - - assert len(pids_for_process()) == 1, 'longstarts == 1' - - client.get() - - pids = pids_for_process() - assert len(pids) == 2, 'longstarts == 2' - - assert 'success' in client.conf_get( - f'/control/applications/{client.app_name}/restart' - ), 'restart processes' - - # wait for longstarted app - time.sleep(2) - - new_pids = pids_for_process() - assert len(new_pids) == 1, 'restart 1' - - assert len(new_pids.intersection(pids)) == 0, 'restart all new' diff --git a/test/test_proxy.py b/test/test_proxy.py deleted file mode 100644 index cd16fe5e..00000000 --- a/test/test_proxy.py +++ /dev/null @@ -1,508 +0,0 @@ -import re -import socket -import time - -import pytest - -from conftest import run_process -from unit.applications.lang.python import ApplicationPython -from unit.option import option -from unit.utils import waitforsocket - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() -SERVER_PORT = 7999 - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - run_process(run_server, SERVER_PORT) - waitforsocket(SERVER_PORT) - - python_dir = f'{option.test_dir}/python' - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - "*:8081": {"pass": "applications/mirror"}, - }, - "routes": [{"action": {"proxy": "http://127.0.0.1:8081"}}], - "applications": { - "mirror": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": f'{python_dir}/mirror', - "working_directory": f'{python_dir}/mirror', - "module": "wsgi", - }, - "custom_header": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": f'{python_dir}/custom_header', - "working_directory": f'{python_dir}/custom_header', - "module": "wsgi", - }, - "delayed": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": f'{python_dir}/delayed', - "working_directory": f'{python_dir}/delayed', - "module": "wsgi", - }, - }, - } - ), 'proxy initial configuration' - - -def run_server(server_port): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - server_address = ('', server_port) - sock.bind(server_address) - sock.listen(5) - - def recvall(sock): - buff_size = 4096 - data = b'' - while True: - part = sock.recv(buff_size) - data += part - if len(part) < buff_size: - break - return data - - req = b"""HTTP/1.1 200 OK -Content-Length: 10 - -""" - - while True: - connection, _ = sock.accept() - - data = recvall(connection).decode() - - to_send = req - - m = re.search(r'X-Len: (\d+)', data) - if m: - to_send += b'X' * int(m.group(1)) - - connection.sendall(to_send) - - connection.close() - - -def get_http10(*args, **kwargs): - return client.get(*args, http_10=True, **kwargs) - - -def post_http10(*args, **kwargs): - return client.post(*args, http_10=True, **kwargs) - - -def test_proxy_http10(): - for _ in range(10): - assert get_http10()['status'] == 200, 'status' - - -def test_proxy_chain(): - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes/first"}, - "*:8081": {"pass": "routes/second"}, - "*:8082": {"pass": "routes/third"}, - "*:8083": {"pass": "routes/fourth"}, - "*:8084": {"pass": "routes/fifth"}, - "*:8085": {"pass": "applications/mirror"}, - }, - "routes": { - "first": [{"action": {"proxy": "http://127.0.0.1:8081"}}], - "second": [{"action": {"proxy": "http://127.0.0.1:8082"}}], - "third": [{"action": {"proxy": "http://127.0.0.1:8083"}}], - "fourth": [{"action": {"proxy": "http://127.0.0.1:8084"}}], - "fifth": [{"action": {"proxy": "http://127.0.0.1:8085"}}], - }, - "applications": { - "mirror": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": f'{option.test_dir}/python/mirror', - "working_directory": f'{option.test_dir}/python/mirror', - "module": "wsgi", - } - }, - } - ), 'proxy chain configuration' - - assert get_http10()['status'] == 200, 'status' - - -def test_proxy_body(): - payload = '0123456789' - for _ in range(10): - resp = post_http10(body=payload) - - assert resp['status'] == 200, 'status' - assert resp['body'] == payload, 'body' - - payload = 'X' * 4096 - for _ in range(10): - resp = post_http10(body=payload) - - assert resp['status'] == 200, 'status' - assert resp['body'] == payload, 'body' - - payload = 'X' * 4097 - for _ in range(10): - resp = post_http10(body=payload) - - assert resp['status'] == 200, 'status' - assert resp['body'] == payload, 'body' - - payload = 'X' * 4096 * 256 - for _ in range(10): - resp = post_http10(body=payload, read_buffer_size=4096 * 128) - - assert resp['status'] == 200, 'status' - assert resp['body'] == payload, 'body' - - payload = 'X' * 4096 * 257 - for _ in range(10): - resp = post_http10(body=payload, read_buffer_size=4096 * 128) - - assert resp['status'] == 200, 'status' - assert resp['body'] == payload, 'body' - - assert 'success' in client.conf( - {'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings' - ) - - payload = '0123456789abcdef' * 32 * 64 * 1024 - resp = post_http10(body=payload, read_buffer_size=1024 * 1024) - assert resp['status'] == 200, 'status' - assert resp['body'] == payload, 'body' - - -def test_proxy_parallel(): - payload = 'X' * 4096 * 257 - buff_size = 4096 * 258 - - socks = [] - for i in range(10): - sock = post_http10( - body=f'{payload}{i}', - no_recv=True, - read_buffer_size=buff_size, - ) - socks.append(sock) - - for i in range(10): - resp = client.recvall(socks[i], buff_size=buff_size).decode() - socks[i].close() - - resp = client._resp_to_dict(resp) - - assert resp['status'] == 200, 'status' - assert resp['body'] == f'{payload}{i}', 'body' - - -def test_proxy_header(): - assert 'success' in client.conf( - {"pass": "applications/custom_header"}, 'listeners/*:8081' - ), 'custom_header configure' - - header_value = 'blah' - assert ( - get_http10( - headers={'Host': 'localhost', 'Custom-Header': header_value} - )['headers']['Custom-Header'] - == header_value - ), 'custom header' - - header_value = r"(),/:;<=>?@[\]{}\t !#$%&'*+-.^_`|~" - assert ( - get_http10( - headers={'Host': 'localhost', 'Custom-Header': header_value} - )['headers']['Custom-Header'] - == header_value - ), 'custom header 2' - - header_value = 'X' * 4096 - assert ( - get_http10( - headers={'Host': 'localhost', 'Custom-Header': header_value} - )['headers']['Custom-Header'] - == header_value - ), 'custom header 3' - - header_value = 'X' * 8191 - assert ( - get_http10( - headers={'Host': 'localhost', 'Custom-Header': header_value} - )['headers']['Custom-Header'] - == header_value - ), 'custom header 4' - - header_value = 'X' * 8192 - assert ( - get_http10( - headers={'Host': 'localhost', 'Custom-Header': header_value} - )['status'] - == 431 - ), 'custom header 5' - - -def test_proxy_fragmented(): - sock = client.http(b"""GET / HTT""", raw=True, no_recv=True) - - time.sleep(1) - - sock.sendall("P/1.0\r\nHost: localhos".encode()) - - time.sleep(1) - - sock.sendall("t\r\n\r\n".encode()) - - assert re.search('200 OK', client.recvall(sock).decode()), 'fragmented send' - sock.close() - - -def test_proxy_fragmented_close(): - sock = client.http(b"""GET / HTT""", raw=True, no_recv=True) - - time.sleep(1) - - sock.sendall("P/1.0\r\nHo".encode()) - - sock.close() - - -def test_proxy_fragmented_body(): - sock = client.http(b"""GET / HTT""", raw=True, no_recv=True) - - time.sleep(1) - - sock.sendall("P/1.0\r\nHost: localhost\r\n".encode()) - sock.sendall("Content-Length: 30000\r\n".encode()) - - time.sleep(1) - - sock.sendall("\r\n".encode()) - sock.sendall(("X" * 10000).encode()) - - time.sleep(1) - - sock.sendall(("X" * 10000).encode()) - - time.sleep(1) - - sock.sendall(("X" * 10000).encode()) - - resp = client._resp_to_dict(client.recvall(sock).decode()) - sock.close() - - assert resp['status'] == 200, 'status' - assert resp['body'] == "X" * 30000, 'body' - - -def test_proxy_fragmented_body_close(): - sock = client.http(b"""GET / HTT""", raw=True, no_recv=True) - - time.sleep(1) - - sock.sendall("P/1.0\r\nHost: localhost\r\n".encode()) - sock.sendall("Content-Length: 30000\r\n".encode()) - - time.sleep(1) - - sock.sendall("\r\n".encode()) - sock.sendall(("X" * 10000).encode()) - - sock.close() - - -def test_proxy_nowhere(): - assert 'success' in client.conf( - [{"action": {"proxy": "http://127.0.0.1:8082"}}], 'routes' - ), 'proxy path changed' - - assert get_http10()['status'] == 502, 'status' - - -def test_proxy_ipv6(): - assert 'success' in client.conf( - { - "*:8080": {"pass": "routes"}, - "[::1]:8081": {'application': 'mirror'}, - }, - 'listeners', - ), 'add ipv6 listener configure' - - assert 'success' in client.conf( - [{"action": {"proxy": "http://[::1]:8081"}}], 'routes' - ), 'proxy ipv6 configure' - - assert get_http10()['status'] == 200, 'status' - - -def test_proxy_unix(temp_dir): - addr = f'{temp_dir}/sock' - - assert 'success' in client.conf( - { - "*:8080": {"pass": "routes"}, - f'unix:{addr}': {'application': 'mirror'}, - }, - 'listeners', - ), 'add unix listener configure' - - assert 'success' in client.conf( - [{"action": {"proxy": f'http://unix:{addr}'}}], 'routes' - ), 'proxy unix configure' - - assert get_http10()['status'] == 200, 'status' - - -def test_proxy_delayed(): - assert 'success' in client.conf( - {"pass": "applications/delayed"}, 'listeners/*:8081' - ), 'delayed configure' - - body = '0123456789' * 1000 - resp = post_http10( - headers={ - 'Host': 'localhost', - 'Content-Length': str(len(body)), - 'X-Parts': '2', - 'X-Delay': '1', - }, - body=body, - ) - - assert resp['status'] == 200, 'status' - assert resp['body'] == body, 'body' - - resp = post_http10( - headers={ - 'Host': 'localhost', - 'Content-Length': str(len(body)), - 'X-Parts': '2', - 'X-Delay': '1', - }, - body=body, - ) - - assert resp['status'] == 200, 'status' - assert resp['body'] == body, 'body' - - -def test_proxy_delayed_close(): - assert 'success' in client.conf( - {"pass": "applications/delayed"}, 'listeners/*:8081' - ), 'delayed configure' - - sock = post_http10( - headers={ - 'Host': 'localhost', - 'Content-Length': '10000', - 'X-Parts': '3', - 'X-Delay': '1', - }, - body='0123456789' * 1000, - no_recv=True, - ) - - assert re.search('200 OK', sock.recv(100).decode()), 'first' - sock.close() - - sock = post_http10( - headers={ - 'Host': 'localhost', - 'Content-Length': '10000', - 'X-Parts': '3', - 'X-Delay': '1', - }, - body='0123456789' * 1000, - no_recv=True, - ) - - assert re.search('200 OK', sock.recv(100).decode()), 'second' - sock.close() - - -@pytest.mark.skip('not yet') -def test_proxy_content_length(): - assert 'success' in client.conf( - [{"action": {"proxy": f'http://127.0.0.1:{SERVER_PORT}'}}], - 'routes', - ), 'proxy backend configure' - - resp = get_http10() - assert len(resp['body']) == 0, 'body lt Content-Length 0' - - resp = get_http10(headers={'Host': 'localhost', 'X-Len': '5'}) - assert len(resp['body']) == 5, 'body lt Content-Length 5' - - resp = get_http10(headers={'Host': 'localhost', 'X-Len': '9'}) - assert len(resp['body']) == 9, 'body lt Content-Length 9' - - resp = get_http10(headers={'Host': 'localhost', 'X-Len': '11'}) - assert len(resp['body']) == 10, 'body gt Content-Length 11' - - resp = get_http10(headers={'Host': 'localhost', 'X-Len': '15'}) - assert len(resp['body']) == 10, 'body gt Content-Length 15' - - -def test_proxy_invalid(): - def check_proxy(proxy): - assert 'error' in client.conf( - [{"action": {"proxy": proxy}}], 'routes' - ), 'proxy invalid' - - check_proxy('blah') - check_proxy('/blah') - check_proxy('unix:/blah') - check_proxy('http://blah') - check_proxy('http://127.0.0.1') - check_proxy('http://127.0.0.1:') - check_proxy('http://127.0.0.1:blah') - check_proxy('http://127.0.0.1:-1') - check_proxy('http://127.0.0.1:8080b') - check_proxy('http://[]') - check_proxy('http://[]:8080') - check_proxy('http://[:]:8080') - check_proxy('http://[::8080') - - -@pytest.mark.skip('not yet') -def test_proxy_loop(skip_alert): - skip_alert( - r'socket.*failed', - r'accept.*failed', - r'new connections are not accepted', - ) - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - "*:8081": {"pass": "applications/mirror"}, - "*:8082": {"pass": "routes"}, - }, - "routes": [{"action": {"proxy": "http://127.0.0.1:8082"}}], - "applications": { - "mirror": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": f'{option.test_dir}/python/mirror', - "working_directory": f'{option.test_dir}/python/mirror', - "module": "wsgi", - }, - }, - } - ) - - get_http10(no_recv=True) - get_http10(read_timeout=1) diff --git a/test/test_proxy_chunked.py b/test/test_proxy_chunked.py deleted file mode 100644 index 23476cd9..00000000 --- a/test/test_proxy_chunked.py +++ /dev/null @@ -1,229 +0,0 @@ -import re -import select -import socket -import time - -import pytest - -from conftest import run_process -from unit.applications.lang.python import ApplicationPython -from unit.utils import waitforsocket - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() -SERVER_PORT = 7999 - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - run_process(run_server, SERVER_PORT) - waitforsocket(SERVER_PORT) - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - }, - "routes": [ - {"action": {"proxy": f'http://127.0.0.1:{SERVER_PORT}'}} - ], - } - ), 'proxy initial configuration' - - -def run_server(server_port): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - - server_address = ('127.0.0.1', server_port) - sock.bind(server_address) - sock.listen(10) - - def recvall(sock): - buff_size = 4096 * 4096 - data = b'' - while True: - rlist = select.select([sock], [], [], 0.1) - - if not rlist[0]: - break - - part = sock.recv(buff_size) - data += part - - if not part: - break - - return data - - while True: - connection, _ = sock.accept() - - req = """HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked""" - - data = recvall(connection).decode() - - m = re.search('\x0d\x0a\x0d\x0a(.*)', data, re.M | re.S) - if m is not None: - body = m.group(1) - - for line in re.split('\r\n', body): - add = '' - m1 = re.search(r'(.*)\sX\s(\d+)', line) - - if m1 is not None: - add = m1.group(1) * int(m1.group(2)) - else: - add = line - - req = f'{req}{add}\r\n' - - for chunk in re.split(r'([@#])', req): - if chunk in ('@', '#'): - if chunk == '#': - time.sleep(0.1) - continue - - connection.sendall(chunk.encode()) - - connection.close() - - -def chunks(chunks_lst): - body = '\r\n\r\n' - - for l, c in chunks_lst: - body = f'{body}{l}\r\n{c}\r\n' - - return f'{body}0\r\n\r\n' - - -def get_http10(*args, **kwargs): - return client.get(*args, http_10=True, **kwargs) - - -def test_proxy_chunked(): - for _ in range(10): - assert get_http10(body='\r\n\r\n0\r\n\r\n')['status'] == 200 - - -def test_proxy_chunked_body(): - part = '0123456789abcdef' - - assert ( - get_http10(body=chunks([('1000', f'{part} X 256')]))['body'] - == part * 256 - ) - assert ( - get_http10(body=chunks([('100000', f'{part} X 65536')]))['body'] - == part * 65536 - ) - assert ( - get_http10( - body=chunks([('1000000', f'{part} X 1048576')]), - read_buffer_size=4096 * 4096, - )['body'] - == part * 1048576 - ) - - assert ( - get_http10( - body=chunks([('1000', f'{part} X 256'), ('1000', f'{part} X 256')]) - )['body'] - == part * 256 * 2 - ) - assert ( - get_http10( - body=chunks( - [ - ('100000', f'{part} X 65536'), - ('100000', f'{part} X 65536'), - ] - ) - )['body'] - == part * 65536 * 2 - ) - assert ( - get_http10( - body=chunks( - [ - ('1000000', f'{part} X 1048576'), - ('1000000', f'{part} X 1048576'), - ] - ), - read_buffer_size=4096 * 4096, - )['body'] - == part * 1048576 * 2 - ) - - -def test_proxy_chunked_fragmented(): - part = '0123456789abcdef' - - assert ( - get_http10( - body=chunks([('1', hex(i % 16)[2:]) for i in range(4096)]), - )['body'] - == part * 256 - ) - - -def test_proxy_chunked_send(): - assert get_http10(body='\r\n\r\n@0@\r\n\r\n')['status'] == 200 - assert ( - get_http10(body='\r@\n\r\n2\r@\na@b\r\n2\r\ncd@\r\n0\r@\n\r\n')['body'] - == 'abcd' - ) - assert ( - get_http10(body='\r\n\r\n2\r#\na#b\r\n##2\r\n#cd\r\n0\r\n#\r#\n')[ - 'body' - ] - == 'abcd' - ) - - -def test_proxy_chunked_invalid(): - def check_invalid(body): - assert get_http10(body=body)['status'] != 200 - - check_invalid('\r\n\r0') - check_invalid('\r\n\r\n\r0') - check_invalid('\r\n\r\n\r\n0') - check_invalid('\r\nContent-Length: 5\r\n\r\n0\r\n\r\n') - check_invalid('\r\n\r\n1\r\nXX\r\n0\r\n\r\n') - check_invalid('\r\n\r\n2\r\nX\r\n0\r\n\r\n') - check_invalid('\r\n\r\nH\r\nXX\r\n0\r\n\r\n') - check_invalid('\r\n\r\n0\r\nX') - - resp = get_http10(body='\r\n\r\n65#\r\nA X 100') - assert resp['status'] == 200, 'incomplete chunk status' - assert resp['body'][-5:] != '0\r\n\r\n', 'incomplete chunk' - - resp = get_http10(body='\r\n\r\n64#\r\nA X 100') - assert resp['status'] == 200, 'no zero chunk status' - assert resp['body'][-5:] != '0\r\n\r\n', 'no zero chunk' - - assert get_http10(body='\r\n\r\n80000000\r\nA X 100')['status'] == 200 - assert ( - get_http10(body='\r\n\r\n10000000000000000\r\nA X 100')['status'] == 502 - ) - assert ( - len( - get_http10( - body='\r\n\r\n1000000\r\nA X 1048576\r\n1000000\r\nA X 100', - read_buffer_size=4096 * 4096, - )['body'] - ) - >= 1048576 - ) - assert ( - len( - get_http10( - body='\r\n\r\n1000000\r\nA X 1048576\r\nXXX\r\nA X 100', - read_buffer_size=4096 * 4096, - )['body'] - ) - >= 1048576 - ) diff --git a/test/test_python_application.py b/test/test_python_application.py deleted file mode 100644 index 466a59a2..00000000 --- a/test/test_python_application.py +++ /dev/null @@ -1,934 +0,0 @@ -import grp -import os -import pwd -import re -import subprocess -import time -import venv - -import pytest -from packaging import version - -from unit.applications.lang.python import ApplicationPython - -prerequisites = {'modules': {'python': 'all'}} - -client = ApplicationPython() - - -def test_python_application_variables(date_to_sec_epoch, sec_epoch): - client.load('variables') - - body = 'Test body string.' - - resp = client.http( - f"""POST / HTTP/1.1 -Host: localhost -Content-Length: {len(body)} -Custom-Header: blah -Custom-hEader: Blah -Content-Type: text/html -Connection: close -custom-header: BLAH - -{body}""".encode(), - raw=True, - ) - - assert resp['status'] == 200, 'status' - headers = resp['headers'] - header_server = headers.pop('Server') - assert re.search(r'Unit/[\d\.]+', header_server), 'server header' - assert ( - headers.pop('Server-Software') == header_server - ), 'server software header' - - date = headers.pop('Date') - assert date[-4:] == ' GMT', 'date header timezone' - assert abs(date_to_sec_epoch(date) - sec_epoch) < 5, 'date header' - - assert headers == { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Content-Type': 'text/html', - 'Request-Method': 'POST', - 'Request-Uri': '/', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Custom-Header': 'blah, Blah, BLAH', - 'Wsgi-Version': '(1, 0)', - 'Wsgi-Url-Scheme': 'http', - 'Wsgi-Multithread': 'False', - 'Wsgi-Multiprocess': 'True', - 'Wsgi-Run-Once': 'False', - }, 'headers' - assert resp['body'] == body, 'body' - - -def test_python_application_query_string(): - client.load('query_string') - - resp = client.get(url='/?var1=val1&var2=val2') - - assert ( - resp['headers']['Query-String'] == 'var1=val1&var2=val2' - ), 'Query-String header' - - -def test_python_application_query_string_space(): - client.load('query_string') - - resp = client.get(url='/ ?var1=val1&var2=val2') - assert ( - resp['headers']['Query-String'] == 'var1=val1&var2=val2' - ), 'Query-String space' - - resp = client.get(url='/ %20?var1=val1&var2=val2') - assert ( - resp['headers']['Query-String'] == 'var1=val1&var2=val2' - ), 'Query-String space 2' - - resp = client.get(url='/ %20 ?var1=val1&var2=val2') - assert ( - resp['headers']['Query-String'] == 'var1=val1&var2=val2' - ), 'Query-String space 3' - - resp = client.get(url='/blah %20 blah? var1= val1 & var2=val2') - assert ( - resp['headers']['Query-String'] == ' var1= val1 & var2=val2' - ), 'Query-String space 4' - - -def test_python_application_prefix(): - client.load('prefix', prefix='/api/rest') - - def set_prefix(prefix): - client.conf(f'"{prefix}"', 'applications/prefix/prefix') - - def check_prefix(url, script_name, path_info): - resp = client.get(url=url) - assert resp['status'] == 200 - assert resp['headers']['Script-Name'] == script_name - assert resp['headers']['Path-Info'] == path_info - - check_prefix('/ap', 'NULL', '/ap') - check_prefix('/api', 'NULL', '/api') - check_prefix('/api/', 'NULL', '/api/') - check_prefix('/api/res', 'NULL', '/api/res') - check_prefix('/api/restful', 'NULL', '/api/restful') - check_prefix('/api/rest', '/api/rest', '') - check_prefix('/api/rest/', '/api/rest', '/') - check_prefix('/api/rest/get', '/api/rest', '/get') - check_prefix('/api/rest/get/blah', '/api/rest', '/get/blah') - - set_prefix('/api/rest/') - check_prefix('/api/rest', '/api/rest', '') - check_prefix('/api/restful', 'NULL', '/api/restful') - check_prefix('/api/rest/', '/api/rest', '/') - check_prefix('/api/rest/blah', '/api/rest', '/blah') - - set_prefix('/app') - check_prefix('/ap', 'NULL', '/ap') - check_prefix('/app', '/app', '') - check_prefix('/app/', '/app', '/') - check_prefix('/application/', 'NULL', '/application/') - - set_prefix('/') - check_prefix('/', 'NULL', '/') - check_prefix('/app', 'NULL', '/app') - - -def test_python_application_query_string_empty(): - client.load('query_string') - - resp = client.get(url='/?') - - assert resp['status'] == 200, 'query string empty status' - assert resp['headers']['Query-String'] == '', 'query string empty' - - -def test_python_application_query_string_absent(): - client.load('query_string') - - resp = client.get() - - assert resp['status'] == 200, 'query string absent status' - assert resp['headers']['Query-String'] == '', 'query string absent' - - -@pytest.mark.skip('not yet') -def test_python_application_server_port(): - client.load('server_port') - - assert ( - client.get()['headers']['Server-Port'] == '8080' - ), 'Server-Port header' - - -@pytest.mark.skip('not yet') -def test_python_application_working_directory_invalid(): - client.load('empty') - - assert 'success' in client.conf( - '"/blah"', 'applications/empty/working_directory' - ), 'configure invalid working_directory' - - assert client.get()['status'] == 500, 'status' - - -def test_python_application_204_transfer_encoding(): - client.load('204_no_content') - - assert ( - 'Transfer-Encoding' not in client.get()['headers'] - ), '204 header transfer encoding' - - -def test_python_application_ctx_iter_atexit(wait_for_record): - client.load('ctx_iter_atexit') - - resp = client.post(body='0123456789') - - assert resp['status'] == 200, 'ctx iter status' - assert resp['body'] == '0123456789', 'ctx iter body' - - assert 'success' in client.conf({"listeners": {}, "applications": {}}) - - assert wait_for_record(r'RuntimeError') is not None, 'ctx iter atexit' - - -def test_python_keepalive_body(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' * 500 - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive 1' - - body = '0123456789' - resp = client.post(sock=sock, body=body) - - assert resp['body'] == body, 'keep-alive 2' - - -def test_python_keepalive_reconfigure(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' - conns = 3 - socks = [] - - for i in range(conns): - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive open' - - client.load('mirror', processes=i + 1) - - socks.append(sock) - - for i in range(conns): - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - sock=socks[i], - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive request' - - client.load('mirror', processes=i + 1) - - for i in range(conns): - resp = client.post(sock=socks[i], body=body) - - assert resp['body'] == body, 'keep-alive close' - - client.load('mirror', processes=i + 1) - - -def test_python_keepalive_reconfigure_2(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' - - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'reconfigure 2 keep-alive 1' - - client.load('empty') - - assert client.get()['status'] == 200, 'init' - - (resp, sock) = client.post(start=True, sock=sock, body=body) - - assert resp['status'] == 200, 'reconfigure 2 keep-alive 2' - assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body' - - assert 'success' in client.conf( - {"listeners": {}, "applications": {}} - ), 'reconfigure 2 clear configuration' - - resp = client.get(sock=sock) - - assert resp == {}, 'reconfigure 2 keep-alive 3' - - -def test_python_atexit(wait_for_record): - client.load('atexit') - - client.get() - - assert 'success' in client.conf({"listeners": {}, "applications": {}}) - - assert wait_for_record(r'At exit called\.') is not None, 'atexit' - - -def test_python_process_switch(): - client.load('delayed', processes=2) - - client.get( - headers={ - 'Host': 'localhost', - 'Content-Length': '0', - 'X-Delay': '5', - 'Connection': 'close', - }, - no_recv=True, - ) - - headers_delay_1 = { - 'Connection': 'close', - 'Host': 'localhost', - 'Content-Length': '0', - 'X-Delay': '1', - } - - client.get(headers=headers_delay_1, no_recv=True) - - time.sleep(0.5) - - for _ in range(10): - client.get(headers=headers_delay_1, no_recv=True) - - client.get(headers=headers_delay_1) - - -@pytest.mark.skip('not yet') -def test_python_application_start_response_exit(): - client.load('start_response_exit') - - assert client.get()['status'] == 500, 'start response exit' - - -def test_python_application_input_iter(): - client.load('input_iter') - - body = '''0123456789 -next line - -last line''' - - resp = client.post(body=body) - assert resp['body'] == body, 'input iter' - assert resp['headers']['X-Lines-Count'] == '4', 'input iter lines' - - -def test_python_application_input_readline(): - client.load('input_readline') - - body = '''0123456789 -next line - -last line''' - - resp = client.post(body=body) - assert resp['body'] == body, 'input readline' - assert resp['headers']['X-Lines-Count'] == '4', 'input readline lines' - - -def test_python_application_input_readline_size(): - client.load('input_readline_size') - - body = '''0123456789 -next line - -last line''' - - assert client.post(body=body)['body'] == body, 'input readline size' - assert ( - client.post(body='0123')['body'] == '0123' - ), 'input readline size less' - - -def test_python_application_input_readlines(): - client.load('input_readlines') - - body = '''0123456789 -next line - -last line''' - - resp = client.post(body=body) - assert resp['body'] == body, 'input readlines' - assert resp['headers']['X-Lines-Count'] == '4', 'input readlines lines' - - -def test_python_application_input_readlines_huge(): - client.load('input_readlines') - - body = ( - '''0123456789 abcdefghi -next line: 0123456789 abcdefghi - -last line: 987654321 -''' - * 512 - ) - - assert ( - client.post(body=body, read_buffer_size=16384)['body'] == body - ), 'input readlines huge' - - -def test_python_application_input_read_length(): - client.load('input_read_length') - - body = '0123456789' - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Input-Length': '5', - 'Connection': 'close', - }, - body=body, - ) - - assert resp['body'] == body[:5], 'input read length lt body' - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Input-Length': '15', - 'Connection': 'close', - }, - body=body, - ) - - assert resp['body'] == body, 'input read length gt body' - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Input-Length': '0', - 'Connection': 'close', - }, - body=body, - ) - - assert resp['body'] == '', 'input read length zero' - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Input-Length': '-1', - 'Connection': 'close', - }, - body=body, - ) - - assert resp['body'] == body, 'input read length negative' - - -@pytest.mark.skip('not yet') -def test_python_application_errors_write(wait_for_record): - client.load('errors_write') - - client.get() - - assert ( - wait_for_record(r'\[error\].+Error in application\.') is not None - ), 'errors write' - - -def test_python_application_body_array(): - client.load('body_array') - - assert client.get()['body'] == '0123456789', 'body array' - - -def test_python_application_body_io(): - client.load('body_io') - - assert client.get()['body'] == '0123456789', 'body io' - - -def test_python_application_body_io_file(): - client.load('body_io_file') - - assert client.get()['body'] == 'body\n', 'body io file' - - -@pytest.mark.skip('not yet') -def test_python_application_syntax_error(skip_alert): - skip_alert(r'Python failed to import module "wsgi"') - client.load('syntax_error') - - assert client.get()['status'] == 500, 'syntax error' - - -def test_python_application_loading_error(skip_alert): - skip_alert(r'Python failed to import module "blah"') - - client.load('empty', module="blah") - - assert client.get()['status'] == 503, 'loading error' - - -def test_python_application_close(wait_for_record): - client.load('close') - - client.get() - - assert wait_for_record(r'Close called\.') is not None, 'close' - - -def test_python_application_close_error(wait_for_record): - client.load('close_error') - - client.get() - - assert wait_for_record(r'Close called\.') is not None, 'close error' - - -def test_python_application_not_iterable(wait_for_record): - client.load('not_iterable') - - client.get() - - assert ( - wait_for_record( - r'\[error\].+the application returned not an iterable object' - ) - is not None - ), 'not iterable' - - -def test_python_application_write(): - client.load('write') - - assert client.get()['body'] == '0123456789', 'write' - - -def test_python_application_encoding(): - client.load('encoding') - - try: - locales = ( - subprocess.check_output( - ['locale', '-a'], - stderr=subprocess.STDOUT, - ) - .decode() - .splitlines() - ) - except ( - FileNotFoundError, - UnicodeDecodeError, - subprocess.CalledProcessError, - ): - pytest.skip('require locale') - - to_check = [ - re.compile(r'.*UTF[-_]?8'), - re.compile(r'.*ISO[-_]?8859[-_]?1'), - ] - matches = [ - loc - for loc in locales - if any(pattern.match(loc.upper()) for pattern in to_check) - ] - - if not matches: - pytest.skip('no available locales') - - def unify(enc): - enc.upper().replace('-', '').replace('_', '') - - for loc in matches: - assert 'success' in client.conf( - {"LC_CTYPE": loc, "LC_ALL": ""}, - '/config/applications/encoding/environment', - ) - resp = client.get() - assert resp['status'] == 200, 'status' - assert unify(resp['headers']['X-Encoding']) == unify(loc.split('.')[-1]) - - -def test_python_application_unicode(temp_dir): - try: - app_type = client.get_application_type() - v = version.Version(app_type.split()[-1]) - if v.major != 3: - raise version.InvalidVersion - - except version.InvalidVersion: - pytest.skip('require python module version 3') - - venv_path = f'{temp_dir}/venv' - venv.create(venv_path) - - client.load('unicode') - assert 'success' in client.conf( - f'"{venv_path}"', - '/config/applications/unicode/home', - ) - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Temp-dir': temp_dir, - 'Connection': 'close', - } - )['status'] - == 200 - ) - - -def test_python_application_threading(wait_for_record): - """wait_for_record() timeouts after 5s while every thread works at - least 3s. So without releasing GIL test should fail. - """ - - client.load('threading') - - for _ in range(10): - client.get(no_recv=True) - - assert ( - wait_for_record(r'\(5\) Thread: 100', wait=50) is not None - ), 'last thread finished' - - -def test_python_application_iter_exception(findall, wait_for_record): - client.load('iter_exception') - - # Default request doesn't lead to the exception. - - resp = client.get( - headers={ - 'Host': 'localhost', - 'X-Skip': '9', - 'X-Chunked': '1', - 'Connection': 'close', - } - ) - assert resp['status'] == 200, 'status' - assert resp['body'] == 'XXXXXXX', 'body' - - # Exception before start_response(). - - assert client.get()['status'] == 503, 'error' - - assert wait_for_record(r'Traceback') is not None, 'traceback' - assert ( - wait_for_record(r"raise Exception\('first exception'\)") is not None - ), 'first exception raise' - assert len(findall(r'Traceback')) == 1, 'traceback count 1' - - # Exception after start_response(), before first write(). - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Skip': '1', - 'Connection': 'close', - } - )['status'] - == 503 - ), 'error 2' - - assert ( - wait_for_record(r"raise Exception\('second exception'\)") is not None - ), 'exception raise second' - assert len(findall(r'Traceback')) == 2, 'traceback count 2' - - # Exception after first write(), before first __next__(). - - _, sock = client.get( - headers={ - 'Host': 'localhost', - 'X-Skip': '2', - 'Connection': 'keep-alive', - }, - start=True, - ) - - assert ( - wait_for_record(r"raise Exception\('third exception'\)") is not None - ), 'exception raise third' - assert len(findall(r'Traceback')) == 3, 'traceback count 3' - - assert client.get(sock=sock) == {}, 'closed connection' - - # Exception after first write(), before first __next__(), - # chunked (incomplete body). - - resp = client.get( - headers={ - 'Host': 'localhost', - 'X-Skip': '2', - 'X-Chunked': '1', - 'Connection': 'close', - }, - raw_resp=True, - ) - if resp: - assert resp[-5:] != '0\r\n\r\n', 'incomplete body' - assert len(findall(r'Traceback')) == 4, 'traceback count 4' - - # Exception in __next__(). - - _, sock = client.get( - headers={ - 'Host': 'localhost', - 'X-Skip': '3', - 'Connection': 'keep-alive', - }, - start=True, - ) - - assert ( - wait_for_record(r"raise Exception\('next exception'\)") is not None - ), 'exception raise next' - assert len(findall(r'Traceback')) == 5, 'traceback count 5' - - assert client.get(sock=sock) == {}, 'closed connection 2' - - # Exception in __next__(), chunked (incomplete body). - - resp = client.get( - headers={ - 'Host': 'localhost', - 'X-Skip': '3', - 'X-Chunked': '1', - 'Connection': 'close', - }, - raw_resp=True, - ) - if resp: - assert resp[-5:] != '0\r\n\r\n', 'incomplete body 2' - assert len(findall(r'Traceback')) == 6, 'traceback count 6' - - # Exception before start_response() and in close(). - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Not-Skip-Close': '1', - 'Connection': 'close', - } - )['status'] - == 503 - ), 'error' - - assert ( - wait_for_record(r"raise Exception\('close exception'\)") is not None - ), 'exception raise close' - assert len(findall(r'Traceback')) == 8, 'traceback count 8' - - -def test_python_user_group(require): - require({'privileged_user': True}) - - nobody_uid = pwd.getpwnam('nobody').pw_uid - - group = 'nobody' - - try: - group_id = grp.getgrnam(group).gr_gid - except KeyError: - group = 'nogroup' - group_id = grp.getgrnam(group).gr_gid - - client.load('user_group') - - obj = client.getjson()['body'] - assert obj['UID'] == nobody_uid, 'nobody uid' - assert obj['GID'] == group_id, 'nobody gid' - - client.load('user_group', user='nobody') - - obj = client.getjson()['body'] - assert obj['UID'] == nobody_uid, 'nobody uid user=nobody' - assert obj['GID'] == group_id, 'nobody gid user=nobody' - - client.load('user_group', user='nobody', group=group) - - obj = client.getjson()['body'] - assert obj['UID'] == nobody_uid, f'nobody uid user=nobody group={group}' - assert obj['GID'] == group_id, f'nobody gid user=nobody group={group}' - - client.load('user_group', group=group) - - obj = client.getjson()['body'] - assert obj['UID'] == nobody_uid, f'nobody uid group={group}' - assert obj['GID'] == group_id, f'nobody gid group={group}' - - client.load('user_group', user='root') - - obj = client.getjson()['body'] - assert obj['UID'] == 0, 'root uid user=root' - assert obj['GID'] == 0, 'root gid user=root' - - group = 'root' - - try: - grp.getgrnam(group) - group = True - except KeyError: - group = False - - if group: - client.load('user_group', user='root', group='root') - - obj = client.getjson()['body'] - assert obj['UID'] == 0, 'root uid user=root group=root' - assert obj['GID'] == 0, 'root gid user=root group=root' - - client.load('user_group', group='root') - - obj = client.getjson()['body'] - assert obj['UID'] == nobody_uid, 'root uid group=root' - assert obj['GID'] == 0, 'root gid group=root' - - -def test_python_application_callable(skip_alert): - skip_alert(r'Python failed to get "blah" from module') - client.load('callable') - - assert client.get()['status'] == 204, 'default application response' - - client.load('callable', callable="app") - - assert client.get()['status'] == 200, 'callable response' - - client.load('callable', callable="blah") - - assert client.get()['status'] not in [200, 204], 'callable response inv' - - -def test_python_application_path(): - client.load('path') - - def set_path(path): - assert 'success' in client.conf(path, 'applications/path/path') - - def get_path(): - return client.get()['body'].split(os.pathsep) - - default_path = client.conf_get('/config/applications/path/path') - assert 'success' in client.conf( - {"PYTHONPATH": default_path}, - '/config/applications/path/environment', - ) - - client.conf_delete('/config/applications/path/path') - sys_path = get_path() - - set_path('"/blah"') - assert ['/blah', *sys_path] == get_path(), 'check path' - - set_path('"/new"') - assert ['/new', *sys_path] == get_path(), 'check path update' - - set_path('["/blah1", "/blah2"]') - assert [ - '/blah1', - '/blah2', - *sys_path, - ] == get_path(), 'check path array' - - -def test_python_application_path_invalid(): - client.load('path') - - def check_path(path): - assert 'error' in client.conf(path, 'applications/path/path') - - check_path('{}') - check_path('["/blah", []]') - - -def test_python_application_threads(): - client.load('threads', threads=4) - - socks = [] - - for _ in range(4): - sock = client.get( - headers={ - 'Host': 'localhost', - 'X-Delay': '2', - 'Connection': 'close', - }, - no_recv=True, - ) - - socks.append(sock) - - threads = set() - - for sock in socks: - resp = client.recvall(sock).decode('utf-8') - - client.log_in(resp) - - resp = client._resp_to_dict(resp) - - assert resp['status'] == 200, 'status' - - threads.add(resp['headers']['X-Thread']) - - assert resp['headers']['Wsgi-Multithread'] == 'True', 'multithread' - - sock.close() - - assert len(socks) == len(threads), 'threads differs' diff --git a/test/test_python_basic.py b/test/test_python_basic.py deleted file mode 100644 index 81c768aa..00000000 --- a/test/test_python_basic.py +++ /dev/null @@ -1,134 +0,0 @@ -from unit.control import Control - -prerequisites = {'modules': {'python': 'any'}} - -client = Control() - -conf_app = { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } -} - -conf_basic = { - "listeners": {"*:8080": {"pass": "applications/app"}}, - "applications": conf_app, -} - - -def test_python_get_empty(): - assert client.conf_get() == {'listeners': {}, 'applications': {}} - assert client.conf_get('listeners') == {} - assert client.conf_get('applications') == {} - - -def test_python_get_applications(): - client.conf(conf_app, 'applications') - - conf = client.conf_get() - - assert conf['listeners'] == {}, 'listeners' - assert conf['applications'] == { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, 'applications' - - assert client.conf_get('applications') == { - "app": { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, 'applications prefix' - - assert client.conf_get('applications/app') == { - "type": "python", - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - }, 'applications prefix 2' - - assert client.conf_get('applications/app/type') == 'python', 'type' - assert client.conf_get('applications/app/processes/spare') == 0, 'spare' - - -def test_python_get_listeners(): - assert 'success' in client.conf(conf_basic) - - assert client.conf_get()['listeners'] == { - "*:8080": {"pass": "applications/app"} - }, 'listeners' - - assert client.conf_get('listeners') == { - "*:8080": {"pass": "applications/app"} - }, 'listeners prefix' - - assert client.conf_get('listeners/*:8080') == { - "pass": "applications/app" - }, 'listeners prefix 2' - - -def test_python_change_listener(): - assert 'success' in client.conf(conf_basic) - assert 'success' in client.conf( - {"*:8081": {"pass": "applications/app"}}, 'listeners' - ) - - assert client.conf_get('listeners') == { - "*:8081": {"pass": "applications/app"} - }, 'change listener' - - -def test_python_add_listener(): - assert 'success' in client.conf(conf_basic) - assert 'success' in client.conf( - {"pass": "applications/app"}, 'listeners/*:8082' - ) - - assert client.conf_get('listeners') == { - "*:8080": {"pass": "applications/app"}, - "*:8082": {"pass": "applications/app"}, - }, 'add listener' - - -def test_python_change_application(): - assert 'success' in client.conf(conf_basic) - - assert 'success' in client.conf('30', 'applications/app/processes/max') - assert ( - client.conf_get('applications/app/processes/max') == 30 - ), 'change application max' - - assert 'success' in client.conf('"/www"', 'applications/app/path') - assert ( - client.conf_get('applications/app/path') == '/www' - ), 'change application path' - - -def test_python_delete(): - assert 'success' in client.conf(conf_basic) - - assert 'error' in client.conf_delete('applications/app') - assert 'success' in client.conf_delete('listeners/*:8080') - assert 'success' in client.conf_delete('applications/app') - assert 'error' in client.conf_delete('applications/app') - - -def test_python_delete_blocks(): - assert 'success' in client.conf(conf_basic) - - assert 'success' in client.conf_delete('listeners') - assert 'success' in client.conf_delete('applications') - - assert 'success' in client.conf(conf_app, 'applications') - assert 'success' in client.conf( - {"*:8081": {"pass": "applications/app"}}, 'listeners' - ), 'applications restore' diff --git a/test/test_python_environment.py b/test/test_python_environment.py deleted file mode 100644 index 6aa02c94..00000000 --- a/test/test_python_environment.py +++ /dev/null @@ -1,162 +0,0 @@ -from unit.applications.lang.python import ApplicationPython - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -def test_python_environment_name_null(): - client.load('environment') - - assert 'error' in client.conf( - {"va\0r": "val1"}, 'applications/environment/environment' - ), 'name null' - - -def test_python_environment_name_equals(): - client.load('environment') - - assert 'error' in client.conf( - {"var=": "val1"}, 'applications/environment/environment' - ), 'name equals' - - -def test_python_environment_value_null(): - client.load('environment') - - assert 'error' in client.conf( - {"var": "\0val"}, 'applications/environment/environment' - ), 'value null' - - -def test_python_environment_update(): - client.load('environment') - - client.conf({"var": "val1"}, 'applications/environment/environment') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Variables': 'var', - 'Connection': 'close', - } - )['body'] - == 'val1' - ), 'set' - - client.conf({"var": "val2"}, 'applications/environment/environment') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Variables': 'var', - 'Connection': 'close', - } - )['body'] - == 'val2' - ), 'update' - - -def test_python_environment_replace(): - client.load('environment') - - client.conf({"var1": "val1"}, 'applications/environment/environment') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Variables': 'var1', - 'Connection': 'close', - } - )['body'] - == 'val1' - ), 'set' - - client.conf({"var2": "val2"}, 'applications/environment/environment') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Variables': 'var1,var2', - 'Connection': 'close', - } - )['body'] - == 'val2' - ), 'replace' - - -def test_python_environment_clear(): - client.load('environment') - - client.conf( - {"var1": "val1", "var2": "val2"}, - 'applications/environment/environment', - ) - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Variables': 'var1,var2', - 'Connection': 'close', - } - )['body'] - == 'val1,val2' - ), 'set' - - client.conf({}, 'applications/environment/environment') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Variables': 'var1,var2', - 'Connection': 'close', - } - )['body'] - == '' - ), 'clear' - - -def test_python_environment_replace_default(): - client.load('environment') - - home_default = client.get( - headers={ - 'Host': 'localhost', - 'X-Variables': 'HOME', - 'Connection': 'close', - } - )['body'] - - assert len(home_default) > 1, 'get default' - - client.conf({"HOME": "/"}, 'applications/environment/environment') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Variables': 'HOME', - 'Connection': 'close', - } - )['body'] - == '/' - ), 'replace default' - - client.conf({}, 'applications/environment/environment') - - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'X-Variables': 'HOME', - 'Connection': 'close', - } - )['body'] - == home_default - ), 'restore default' diff --git a/test/test_python_isolation.py b/test/test_python_isolation.py deleted file mode 100644 index fd692cb6..00000000 --- a/test/test_python_isolation.py +++ /dev/null @@ -1,214 +0,0 @@ -import re -import subprocess -from pathlib import Path - -import pytest - -from unit.applications.lang.python import ApplicationPython -from unit.option import option -from unit.utils import findmnt -from unit.utils import waitformount -from unit.utils import waitforunmount - -prerequisites = {'modules': {'python': 'any'}, 'features': {'isolation': True}} - -client = ApplicationPython() - - -def get_cgroup(app_name): - output = subprocess.check_output( - ['ps', 'ax', '-o', 'pid', '-o', 'cmd'] - ).decode() - - pid = re.search(fr'(\d+)\s*unit: "{app_name}" application', output).group(1) - - cgroup = f'/proc/{pid}/cgroup' - - if not Path(cgroup).is_file(): - pytest.skip(f'no cgroup at {cgroup}') - - with open(cgroup, 'r', encoding='utf-8') as f: - return f.read().rstrip() - - -def test_python_isolation_rootfs(is_su, require, temp_dir): - isolation = {'rootfs': temp_dir} - - if not is_su: - require( - { - 'features': { - 'isolation': [ - 'unprivileged_userns_clone', - 'user', - 'mnt', - 'pid', - ] - } - } - ) - - isolation['namespaces'] = { - 'mount': True, - 'credential': True, - 'pid': True, - } - - client.load('ns_inspect', isolation=isolation) - - assert not ( - client.getjson(url=f'/?path={temp_dir}')['body']['FileExists'] - ), 'temp_dir does not exists in rootfs' - - assert client.getjson(url='/?path=/proc/self')['body'][ - 'FileExists' - ], 'no /proc/self' - - assert not ( - client.getjson(url='/?path=/dev/pts')['body']['FileExists'] - ), 'no /dev/pts' - - assert not ( - client.getjson(url='/?path=/sys/kernel')['body']['FileExists'] - ), 'no /sys/kernel' - - ret = client.getjson(url='/?path=/app/python/ns_inspect') - - assert ret['body']['FileExists'], 'application exists in rootfs' - - -def test_python_isolation_rootfs_no_language_deps(require, temp_dir): - require({'privileged_user': True}) - - isolation = {'rootfs': temp_dir, 'automount': {'language_deps': False}} - client.load('empty', isolation=isolation) - - python_path = f'{temp_dir}/usr' - - assert findmnt().find(python_path) == -1 - assert client.get()['status'] != 200, 'disabled language_deps' - assert findmnt().find(python_path) == -1 - - isolation['automount']['language_deps'] = True - - client.load('empty', isolation=isolation) - - assert findmnt().find(python_path) == -1 - assert client.get()['status'] == 200, 'enabled language_deps' - assert waitformount(python_path), 'language_deps mount' - - client.conf({"listeners": {}, "applications": {}}) - - assert waitforunmount(python_path), 'language_deps unmount' - - -def test_python_isolation_procfs(require, temp_dir): - require({'privileged_user': True}) - - isolation = {'rootfs': temp_dir, 'automount': {'procfs': False}} - - client.load('ns_inspect', isolation=isolation) - - assert not ( - client.getjson(url='/?path=/proc/self')['body']['FileExists'] - ), 'no /proc/self' - - isolation['automount']['procfs'] = True - - client.load('ns_inspect', isolation=isolation) - - assert client.getjson(url='/?path=/proc/self')['body'][ - 'FileExists' - ], '/proc/self' - - -def test_python_isolation_cgroup(require): - require({'privileged_user': True, 'features': {'isolation': ['cgroup']}}) - - def set_cgroup_path(path): - isolation = {'cgroup': {'path': path}} - client.load('empty', processes=1, isolation=isolation) - - set_cgroup_path('scope/python') - - cgroup_rel = Path(get_cgroup('empty')) - assert cgroup_rel.parts[-2:] == ('scope', 'python'), 'cgroup rel' - - set_cgroup_path('/scope2/python') - - cgroup_abs = Path(get_cgroup('empty')) - assert cgroup_abs.parts[-2:] == ('scope2', 'python'), 'cgroup abs' - - assert len(cgroup_rel.parts) >= len(cgroup_abs.parts) - - -def test_python_isolation_cgroup_two(require): - require({'privileged_user': True, 'features': {'isolation': ['cgroup']}}) - - def set_two_cgroup_path(path, path2): - script_path = f'{option.test_dir}/python/empty' - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "applications/one"}, - "*:8081": {"pass": "applications/two"}, - }, - "applications": { - "one": { - "type": "python", - "processes": 1, - "path": script_path, - "working_directory": script_path, - "module": "wsgi", - "isolation": { - 'cgroup': {'path': path}, - }, - }, - "two": { - "type": "python", - "processes": 1, - "path": script_path, - "working_directory": script_path, - "module": "wsgi", - "isolation": { - 'cgroup': {'path': path2}, - }, - }, - }, - } - ) - - set_two_cgroup_path('/scope/python', '/scope/python') - assert get_cgroup('one') == get_cgroup('two') - - set_two_cgroup_path('/scope/python', '/scope2/python') - assert get_cgroup('one') != get_cgroup('two') - - -def test_python_isolation_cgroup_invalid(require): - require({'privileged_user': True, 'features': {'isolation': ['cgroup']}}) - - def check_invalid(path): - script_path = f'{option.test_dir}/python/empty' - assert 'error' in client.conf( - { - "listeners": {"*:8080": {"pass": "applications/empty"}}, - "applications": { - "empty": { - "type": "python", - "processes": {"spare": 0}, - "path": script_path, - "working_directory": script_path, - "module": "wsgi", - "isolation": { - 'cgroup': {'path': path}, - }, - } - }, - } - ) - - check_invalid('') - check_invalid('../scope') - check_invalid('scope/../python') diff --git a/test/test_python_isolation_chroot.py b/test/test_python_isolation_chroot.py deleted file mode 100644 index 60fac5ef..00000000 --- a/test/test_python_isolation_chroot.py +++ /dev/null @@ -1,29 +0,0 @@ -from unit.applications.lang.python import ApplicationPython - -prerequisites = {'modules': {'python': 'any'}, 'privileged_user': True} - -client = ApplicationPython() - - -def test_python_isolation_chroot(temp_dir): - client.load('ns_inspect', isolation={'rootfs': temp_dir}) - - assert not ( - client.getjson(url=f'/?path={temp_dir}')['body']['FileExists'] - ), 'temp_dir does not exists in rootfs' - - assert client.getjson(url='/?path=/proc/self')['body'][ - 'FileExists' - ], 'no /proc/self' - - assert not ( - client.getjson(url='/?path=/dev/pts')['body']['FileExists'] - ), 'no /dev/pts' - - assert not ( - client.getjson(url='/?path=/sys/kernel')['body']['FileExists'] - ), 'no /sys/kernel' - - ret = client.getjson(url='/?path=/app/python/ns_inspect') - - assert ret['body']['FileExists'], 'application exists in rootfs' diff --git a/test/test_python_targets.py b/test/test_python_targets.py deleted file mode 100644 index 10f10b70..00000000 --- a/test/test_python_targets.py +++ /dev/null @@ -1,105 +0,0 @@ -from unit.applications.lang.python import ApplicationPython -from unit.option import option - -prerequisites = {'modules': {'python': 'all'}} - -client = ApplicationPython() - - -def test_python_targets(): - python_dir = f'{option.test_dir}/python' - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": "/1"}, - "action": {"pass": "applications/targets/1"}, - }, - { - "match": {"uri": "/2"}, - "action": {"pass": "applications/targets/2"}, - }, - ], - "applications": { - "targets": { - "type": client.get_application_type(), - "working_directory": f'{python_dir}/targets/', - "path": f'{python_dir}/targets/', - "targets": { - "1": { - "module": "wsgi", - "callable": "wsgi_target_a", - }, - "2": { - "module": "wsgi", - "callable": "wsgi_target_b", - }, - }, - } - }, - } - ) - - resp = client.get(url='/1') - assert resp['status'] == 200 - assert resp['body'] == '1' - - resp = client.get(url='/2') - assert resp['status'] == 200 - assert resp['body'] == '2' - - -def test_python_targets_prefix(): - python_dir = f'{option.test_dir}/python' - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": ["/app*"]}, - "action": {"pass": "applications/targets/app"}, - }, - { - "match": {"uri": "*"}, - "action": {"pass": "applications/targets/catchall"}, - }, - ], - "applications": { - "targets": { - "type": "python", - "working_directory": f'{python_dir}/targets/', - "path": f'{python_dir}/targets/', - "protocol": "wsgi", - "targets": { - "app": { - "module": "wsgi", - "callable": "wsgi_target_prefix", - "prefix": "/app/", - }, - "catchall": { - "module": "wsgi", - "callable": "wsgi_target_prefix", - "prefix": "/api", - }, - }, - } - }, - } - ) - - def check_prefix(url, body): - resp = client.get(url=url) - assert resp['status'] == 200 - assert resp['body'] == body - - check_prefix('/app', '/app ') - check_prefix('/app/', '/app /') - check_prefix('/app/rest/user/', '/app /rest/user/') - check_prefix('/catchall', 'No Script Name /catchall') - check_prefix('/api', '/api ') - check_prefix('/api/', '/api /') - check_prefix('/apis', 'No Script Name /apis') - check_prefix('/api/users/', '/api /users/') diff --git a/test/test_reconfigure.py b/test/test_reconfigure.py deleted file mode 100644 index 28d1b4c9..00000000 --- a/test/test_reconfigure.py +++ /dev/null @@ -1,55 +0,0 @@ -import time - -import pytest - -from unit.applications.proto import ApplicationProto - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ) - - -def clear_conf(): - assert 'success' in client.conf({"listeners": {}, "applications": {}}) - - -def test_reconfigure(): - sock = client.http( - b"""GET / HTTP/1.1 -""", - raw=True, - no_recv=True, - ) - - clear_conf() - - resp = client.http( - b"""Host: localhost -Connection: close - -""", - sock=sock, - raw=True, - ) - assert resp['status'] == 200, 'finish request' - - -def test_reconfigure_2(): - sock = client.http(b'', raw=True, no_recv=True) - - # Waiting for connection completion. - # Delay should be more than TCP_DEFER_ACCEPT. - time.sleep(1.5) - - clear_conf() - - assert client.get(sock=sock)['status'] == 408, 'request timeout' diff --git a/test/test_reconfigure_tls.py b/test/test_reconfigure_tls.py deleted file mode 100644 index 4f7d344a..00000000 --- a/test/test_reconfigure_tls.py +++ /dev/null @@ -1,122 +0,0 @@ -import socket -import ssl -import time - -import pytest - -from unit.applications.tls import ApplicationTLS -from unit.option import option - -prerequisites = {'modules': {'openssl': 'any'}} - -client = ApplicationTLS() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - if 'HAS_TLSv1_2' not in dir(ssl) or not ssl.HAS_TLSv1_2: - pytest.skip('OpenSSL too old') - - client.certificate() - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": { - "pass": "routes", - "tls": {"certificate": "default"}, - } - }, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ), 'load application configuration' - - -def create_socket(): - ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ssl_sock = ctx.wrap_socket( - s, server_hostname='localhost', do_handshake_on_connect=False - ) - ssl_sock.connect(('127.0.0.1', 8080)) - - return ssl_sock - - -def clear_conf(): - assert 'success' in client.conf({"listeners": {}, "applications": {}}) - - -@pytest.mark.skip('not yet') -def test_reconfigure_tls_switch(): - assert 'success' in client.conf_delete('listeners/*:8080/tls') - - (_, sock) = client.get( - headers={'Host': 'localhost', 'Connection': 'keep-alive'}, - start=True, - read_timeout=1, - ) - - assert 'success' in client.conf( - {"pass": "routes", "tls": {"certificate": "default"}}, - 'listeners/*:8080', - ) - - assert client.get(sock=sock)['status'] == 200, 'reconfigure' - assert client.get_ssl()['status'] == 200, 'reconfigure tls' - - -def test_reconfigure_tls(): - if option.configure_flag['asan']: - pytest.skip('not yet, router crash') - - ssl_sock = create_socket() - - ssl_sock.sendall("""GET / HTTP/1.1\r\n""".encode()) - - clear_conf() - - ssl_sock.sendall( - """Host: localhost\r\nConnection: close\r\n\r\n""".encode() - ) - - assert ( - client.recvall(ssl_sock).decode().startswith('HTTP/1.1 200 OK') - ), 'finish request' - - -def test_reconfigure_tls_2(): - ssl_sock = create_socket() - - # Waiting for connection completion. - # Delay should be more than TCP_DEFER_ACCEPT. - time.sleep(1.5) - - clear_conf() - - success = False - - try: - ssl_sock.do_handshake() - except ssl.SSLError: - ssl_sock.close() - success = True - - if not success: - pytest.fail('Connection is not closed.') - - -def test_reconfigure_tls_3(): - if option.configure_flag['asan']: - pytest.skip('not yet, router crash') - - ssl_sock = create_socket() - ssl_sock.do_handshake() - - clear_conf() - - assert client.get(sock=ssl_sock)['status'] == 408, 'request timeout' diff --git a/test/test_respawn.py b/test/test_respawn.py deleted file mode 100644 index 03254037..00000000 --- a/test/test_respawn.py +++ /dev/null @@ -1,109 +0,0 @@ -import re -import subprocess -import time - -import pytest - -from unit.applications.lang.python import ApplicationPython - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - -PATTERN_ROUTER = 'unit: router' -PATTERN_CONTROLLER = 'unit: controller' - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - client.app_name = f'app-{temp_dir.split("/")[-1]}' - - client.load('empty', client.app_name) - - assert 'success' in client.conf( - '1', f'applications/{client.app_name}/processes' - ) - - -def pid_by_name(name, ppid): - output = subprocess.check_output(['ps', 'ax', '-O', 'ppid']).decode() - m = re.search(fr'\s*(\d+)\s*{ppid}.*{name}', output) - return None if m is None else m.group(1) - - -def kill_pids(*pids): - subprocess.call(['kill', '-9', *pids]) - - -def wait_for_process(process, unit_pid): - for _ in range(50): - found = pid_by_name(process, unit_pid) - - if found is not None: - break - - time.sleep(0.1) - - return found - - -def find_proc(name, ppid, ps_output): - return re.findall(fr'{ppid}.*{name}', ps_output) - - -def smoke_test(unit_pid): - for _ in range(10): - r = client.conf('1', f'applications/{client.app_name}/processes') - - if 'success' in r: - break - - time.sleep(0.1) - - assert 'success' in r - assert client.get()['status'] == 200 - - # Check if the only one router, controller, - # and application processes running. - - out = subprocess.check_output(['ps', 'ax', '-O', 'ppid']).decode() - assert len(find_proc(PATTERN_ROUTER, unit_pid, out)) == 1 - assert len(find_proc(PATTERN_CONTROLLER, unit_pid, out)) == 1 - assert len(find_proc(client.app_name, unit_pid, out)) == 1 - - -def test_respawn_router(skip_alert, unit_pid, skip_fds_check): - skip_fds_check(router=True) - pid = pid_by_name(PATTERN_ROUTER, unit_pid) - - kill_pids(pid) - skip_alert(fr'process {pid} exited on signal 9') - - assert wait_for_process(PATTERN_ROUTER, unit_pid) is not None - - smoke_test(unit_pid) - - -def test_respawn_controller(skip_alert, unit_pid, skip_fds_check): - skip_fds_check(controller=True) - pid = pid_by_name(PATTERN_CONTROLLER, unit_pid) - - kill_pids(pid) - skip_alert(fr'process {pid} exited on signal 9') - - assert wait_for_process(PATTERN_CONTROLLER, unit_pid) is not None - - assert client.get()['status'] == 200 - - smoke_test(unit_pid) - - -def test_respawn_application(skip_alert, unit_pid): - pid = pid_by_name(client.app_name, unit_pid) - - kill_pids(pid) - skip_alert(fr'process {pid} exited on signal 9') - - assert wait_for_process(client.app_name, unit_pid) is not None - - smoke_test(unit_pid) diff --git a/test/test_response_headers.py b/test/test_response_headers.py deleted file mode 100644 index e62c1293..00000000 --- a/test/test_response_headers.py +++ /dev/null @@ -1,174 +0,0 @@ -from pathlib import Path - -import pytest - -from unit.applications.lang.python import ApplicationPython -from unit.applications.proto import ApplicationProto -from unit.option import option - -client = ApplicationProto() -client_python = ApplicationPython() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - path = Path(f'{temp_dir}/index.html') - path.write_text('0123456789', encoding='utf-8') - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - }, - "routes": [ - { - "action": { - "share": str(path), - "response_headers": { - "X-Foo": "foo", - }, - } - } - ], - } - ) - - -def action_update(conf): - assert 'success' in client.conf(conf, 'routes/0/action') - - -def test_response_headers(temp_dir): - resp = client.get() - assert resp['status'] == 200, 'status 200' - assert resp['headers']['X-Foo'] == 'foo', 'header 200' - - assert 'success' in client.conf(f'"{temp_dir}"', 'routes/0/action/share') - - resp = client.get() - assert resp['status'] == 301, 'status 301' - assert resp['headers']['X-Foo'] == 'foo', 'header 301' - - assert 'success' in client.conf('"/blah"', 'routes/0/action/share') - - resp = client.get() - assert resp['status'] == 404, 'status 404' - assert 'X-Foo' not in client.get()['headers'], 'header 404' - - -def test_response_last_action(): - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes/first"}, - }, - "routes": { - "first": [ - { - "action": { - "pass": "routes/second", - "response_headers": { - "X-Foo": "foo", - }, - } - } - ], - "second": [ - { - "action": {"return": 200}, - } - ], - }, - "applications": {}, - } - ) - - assert 'X-Foo' not in client.get()['headers'] - - -def test_response_pass(require): - require({'modules': {'python': 'any'}}) - - assert 'success' in client_python.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - }, - "routes": [ - { - "action": { - "pass": "applications/empty", - "response_headers": { - "X-Foo": "foo", - }, - } - }, - ], - "applications": { - "empty": { - "type": client_python.get_application_type(), - "processes": {"spare": 0}, - "path": f'{option.test_dir}/python/empty', - "working_directory": f'{option.test_dir}/python/empty', - "module": "wsgi", - } - }, - } - ) - - assert client.get()['headers']['X-Foo'] == 'foo' - - -def test_response_fallback(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "action": { - "share": "/blah", - "fallback": { - "return": 200, - "response_headers": { - "X-Foo": "foo", - }, - }, - } - } - ], - } - ) - - assert client.get()['headers']['X-Foo'] == 'foo' - - -def test_response_headers_var(): - assert 'success' in client.conf( - { - "X-Foo": "$uri", - }, - 'routes/0/action/response_headers', - ) - - assert client.get()['headers']['X-Foo'] == '/' - - -def test_response_headers_remove(): - assert 'success' in client.conf( - {"etag": None}, - 'routes/0/action/response_headers', - ) - - assert 'ETag' not in client.get()['headers'] - - -def test_response_headers_invalid(skip_alert): - skip_alert(r'failed to apply new conf') - - def check_invalid(conf): - assert 'error' in client.conf( - conf, - 'routes/0/action/response_headers', - ) - - check_invalid({"X-Foo": "$u"}) diff --git a/test/test_return.py b/test/test_return.py deleted file mode 100644 index af15b886..00000000 --- a/test/test_return.py +++ /dev/null @@ -1,221 +0,0 @@ -import re - -import pytest - -from unit.applications.proto import ApplicationProto - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ) - - -def get_resps_sc(req=10): - to_send = b"""GET / HTTP/1.1 -Host: localhost - -""" * ( - req - 1 - ) - - to_send += b"""GET / HTTP/1.1 -Host: localhost -Connection: close - -""" - - return client.http(to_send, raw_resp=True, raw=True) - - -def test_return(): - resp = client.get() - assert resp['status'] == 200 - assert 'Server' in resp['headers'] - assert 'Date' in resp['headers'] - assert resp['headers']['Content-Length'] == '0' - assert resp['headers']['Connection'] == 'close' - assert resp['body'] == '', 'body' - - resp = client.post(body='blah') - assert resp['status'] == 200 - assert resp['body'] == '', 'body' - - resp = get_resps_sc() - assert len(re.findall('200 OK', resp)) == 10 - assert len(re.findall('Connection:', resp)) == 1 - assert len(re.findall('Connection: close', resp)) == 1 - - resp = client.get(http_10=True) - assert resp['status'] == 200 - assert 'Server' in resp['headers'] - assert 'Date' in resp['headers'] - assert resp['headers']['Content-Length'] == '0' - assert 'Connection' not in resp['headers'] - assert resp['body'] == '', 'body' - - -def test_return_update(): - assert 'success' in client.conf('0', 'routes/0/action/return') - - resp = client.get() - assert resp['status'] == 0 - assert resp['body'] == '' - - assert 'success' in client.conf('404', 'routes/0/action/return') - - resp = client.get() - assert resp['status'] == 404 - assert resp['body'] != '' - - assert 'success' in client.conf('598', 'routes/0/action/return') - - resp = client.get() - assert resp['status'] == 598 - assert resp['body'] != '' - - assert 'success' in client.conf('999', 'routes/0/action/return') - - resp = client.get() - assert resp['status'] == 999 - assert resp['body'] == '' - - -def test_return_location(): - reserved = ":/?#[]@!&'()*+,;=" - unreserved = ( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~" - ) - unsafe = " \"%<>\\^`{|}" - unsafe_enc = "%20%22%25%3C%3E%5C%5E%60%7B%7C%7D" - - def check_location(location, expect=None): - if expect is None: - expect = location - - assert 'success' in client.conf( - {"return": 301, "location": location}, 'routes/0/action' - ), 'configure location' - - assert client.get()['headers']['Location'] == expect - - # FAIL: can't specify empty header value. - # check_location("") - - check_location(reserved) - - # After first "?" all other "?" encoded. - check_location(f'/?{reserved}', "/?:/%3F#[]@!&'()*+,;=") - check_location("???", "?%3F%3F") - - # After first "#" all other "?" or "#" encoded. - check_location(f'/#{reserved}', "/#:/%3F%23[]@!&'()*+,;=") - check_location("##?#?", "#%23%3F%23%3F") - - # After first "?" next "#" not encoded. - check_location(f'/?#{reserved}', "/?#:/%3F%23[]@!&'()*+,;=") - check_location("??##", "?%3F#%23") - check_location("/?##?", "/?#%23%3F") - - # Unreserved never encoded. - check_location(unreserved) - check_location(f'/{unreserved}?{unreserved}#{unreserved}') - - # Unsafe always encoded. - check_location(unsafe, unsafe_enc) - check_location(f'?{unsafe}', f'?{unsafe_enc}') - check_location(f'#{unsafe}', f'#{unsafe_enc}') - - # %00-%20 and %7F-%FF always encoded. - check_location("\u0000\u0018\u001F\u0020\u0021", "%00%18%1F%20!") - check_location("\u007F\u0080н\u20BD", "%7F%C2%80%D0%BD%E2%82%BD") - - # Encoded string detection. If at least one char need to be encoded - # then whole string will be encoded. - check_location("%20") - check_location("/%20?%20#%20") - check_location(" %20", "%20%2520") - check_location("%20 ", "%2520%20") - check_location("/%20?%20#%20 ", "/%2520?%2520#%2520%20") - - -def test_return_location_edit(): - assert 'success' in client.conf( - {"return": 302, "location": "blah"}, 'routes/0/action' - ), 'configure init location' - assert client.get()['headers']['Location'] == 'blah' - - assert 'success' in client.conf_delete( - 'routes/0/action/location' - ), 'location delete' - assert 'Location' not in client.get()['headers'] - - assert 'success' in client.conf( - '"blah"', 'routes/0/action/location' - ), 'location restore' - assert client.get()['headers']['Location'] == 'blah' - - assert 'error' in client.conf_post( - '"blah"', 'routes/0/action/location' - ), 'location method not allowed' - assert client.get()['headers']['Location'] == 'blah' - - assert 'success' in client.conf( - '"https://${host}${uri}"', 'routes/0/action/location' - ), 'location with variables' - assert client.get()['headers']['Location'] == 'https://localhost/' - - assert 'success' in client.conf( - '"/#$host"', 'routes/0/action/location' - ), 'location with encoding and a variable' - assert client.get()['headers']['Location'] == '/#localhost' - - assert ( - client.get(headers={"Host": "#foo?bar", "Connection": "close"})[ - 'headers' - ]['Location'] - == "/#%23foo%3Fbar" - ), 'location with a variable with encoding' - - assert 'success' in client.conf( - '""', 'routes/0/action/location' - ), 'location empty' - assert client.get()['headers']['Location'] == '' - - assert 'success' in client.conf( - '"${host}"', 'routes/0/action/location' - ), 'location empty with variable' - assert ( - client.get(headers={"Host": "", "Connection": "close"})['headers'][ - 'Location' - ] - == "" - ), 'location with empty variable' - - -def test_return_invalid(): - def check_error(conf): - assert 'error' in client.conf(conf, 'routes/0/action') - - check_error({"return": "200"}) - check_error({"return": []}) - check_error({"return": 80.1}) - check_error({"return": 1000}) - check_error({"return": -1}) - check_error({"return": 200, "share": "/blah"}) - check_error({"return": 200, "location": "$hos"}) - check_error({"return": 200, "location": "$hostblah"}) - - assert 'error' in client.conf( - '001', 'routes/0/action/return' - ), 'leading zero' - - check_error({"return": 301, "location": 0}) - check_error({"return": 301, "location": []}) diff --git a/test/test_rewrite.py b/test/test_rewrite.py deleted file mode 100644 index f94fb528..00000000 --- a/test/test_rewrite.py +++ /dev/null @@ -1,222 +0,0 @@ -from pathlib import Path - -import pytest - -from unit.applications.proto import ApplicationProto - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": "/"}, - "action": {"rewrite": "/new", "pass": "routes"}, - }, - {"match": {"uri": "/new"}, "action": {"return": 200}}, - ], - "applications": {}, - "settings": {"http": {"log_route": True}}, - }, - ), 'set initial configuration' - - -def set_rewrite(rewrite, uri): - assert 'success' in client.conf( - [ - { - "match": {"uri": "/"}, - "action": {"rewrite": rewrite, "pass": "routes"}, - }, - {"match": {"uri": uri}, "action": {"return": 200}}, - ], - 'routes', - ) - - -def test_rewrite(findall, wait_for_record): - assert client.get()['status'] == 200 - assert wait_for_record(r'\[notice\].*"routes/1" selected') is not None - assert len(findall(r'\[notice\].*URI rewritten to "/new"')) == 1 - assert len(findall(r'\[notice\].*URI rewritten')) == 1 - - set_rewrite("", "") - assert client.get()['status'] == 200 - - -def test_rewrite_variable(): - set_rewrite("/$host", "/localhost") - assert client.get()['status'] == 200 - - set_rewrite("${uri}a", "/a") - assert client.get()['status'] == 200 - - -def test_rewrite_encoded(): - assert 'success' in client.conf( - [ - { - "match": {"uri": "/f"}, - "action": {"rewrite": "${request_uri}oo", "pass": "routes"}, - }, - {"match": {"uri": "/foo"}, "action": {"return": 200}}, - ], - 'routes', - ) - assert client.get(url='/%66')['status'] == 200 - - assert 'success' in client.conf( - [ - { - "match": {"uri": "/f"}, - "action": { - "rewrite": "${request_uri}o%6F", - "pass": "routes", - }, - }, - {"match": {"uri": "/foo"}, "action": {"return": 200}}, - ], - 'routes', - ) - assert client.get(url='/%66')['status'] == 200 - - -def test_rewrite_arguments(): - assert 'success' in client.conf( - [ - { - "match": {"uri": "/foo", "arguments": {"arg": "val"}}, - "action": {"rewrite": "/new?some", "pass": "routes"}, - }, - { - "match": {"uri": "/new", "arguments": {"arg": "val"}}, - "action": {"return": 200}, - }, - ], - 'routes', - ) - assert client.get(url='/foo?arg=val')['status'] == 200 - - -def test_rewrite_njs(require): - require({'modules': {'njs': 'any'}}) - - set_rewrite("`/${host}`", "/localhost") - assert client.get()['status'] == 200 - - -def test_rewrite_location(): - def check_location(rewrite, expect): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "action": { - "return": 301, - "location": "$uri", - "rewrite": rewrite, - } - } - ], - } - ) - assert client.get()['headers']['Location'] == expect - - check_location('/new', '/new') - check_location('${request_uri}new', '/new') - - -def test_rewrite_share(temp_dir): - Path(f'{temp_dir}/dir').mkdir() - Path(f'{temp_dir}/foo/').mkdir() - Path(f'{temp_dir}/foo/index.html').write_text('fooindex', encoding='utf-8') - - # same action block - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "action": { - "rewrite": "${request_uri}dir", - "share": f'{temp_dir}$uri', - } - } - ], - } - ) - - resp = client.get() - assert resp['status'] == 301, 'redirect status' - assert resp['headers']['Location'] == '/dir/', 'redirect Location' - - # request_uri - - index_path = f'{temp_dir}${{request_uri}}/index.html' - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": "/foo"}, - "action": { - "rewrite": "${request_uri}dir", - "pass": "routes", - }, - }, - {"action": {"share": index_path}}, - ], - } - ) - - assert client.get(url='/foo')['body'] == 'fooindex' - - # different action block - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"uri": "/foo"}, - "action": { - "rewrite": "${request_uri}dir", - "pass": "routes", - }, - }, - { - "action": { - "share": f'{temp_dir}/dir', - } - }, - ], - } - ) - resp = client.get(url='/foo') - assert resp['status'] == 301, 'redirect status 2' - assert resp['headers']['Location'] == '/foodir/', 'redirect Location 2' - - -def test_rewrite_invalid(skip_alert): - skip_alert(r'failed to apply new conf') - - def check_rewrite(rewrite): - assert 'error' in client.conf( - [ - { - "match": {"uri": "/"}, - "action": {"rewrite": rewrite, "pass": "routes"}, - }, - {"action": {"return": 200}}, - ], - 'routes', - ) - - check_rewrite("/$blah") - check_rewrite(["/"]) diff --git a/test/test_routing.py b/test/test_routing.py deleted file mode 100644 index 0b6eced2..00000000 --- a/test/test_routing.py +++ /dev/null @@ -1,2011 +0,0 @@ -# -*- coding: utf-8 -*- -import pytest - -from unit.applications.lang.python import ApplicationPython -from unit.option import option - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": {"method": "GET"}, - "action": {"return": 200}, - } - ], - "applications": {}, - } - ), 'routing configure' - - -def route(conf_route): - return client.conf([conf_route], 'routes') - - -def route_match(match): - assert 'success' in route( - {"match": match, "action": {"return": 200}} - ), 'route match configure' - - -def route_match_invalid(match): - assert 'error' in route( - {"match": match, "action": {"return": 200}} - ), 'route match configure invalid' - - -def host(host_header, status): - assert ( - client.get(headers={'Host': host_header, 'Connection': 'close'})[ - 'status' - ] - == status - ), 'match host' - - -def cookie(cookie_header, status): - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Cookie': cookie_header, - 'Connection': 'close', - }, - )['status'] - == status - ), 'match cookie' - - -def test_routes_match_method_positive(): - assert client.get()['status'] == 200, 'GET' - assert client.post()['status'] == 404, 'POST' - - -def test_routes_match_method_positive_many(): - route_match({"method": ["GET", "POST"]}) - - assert client.get()['status'] == 200, 'GET' - assert client.post()['status'] == 200, 'POST' - assert client.delete()['status'] == 404, 'DELETE' - - -def test_routes_match_method_negative(): - route_match({"method": "!GET"}) - - assert client.get()['status'] == 404, 'GET' - assert client.post()['status'] == 200, 'POST' - - -def test_routes_match_method_negative_many(): - route_match({"method": ["!GET", "!POST"]}) - - assert client.get()['status'] == 404, 'GET' - assert client.post()['status'] == 404, 'POST' - assert client.delete()['status'] == 200, 'DELETE' - - -def test_routes_match_method_wildcard_left(): - route_match({"method": "*ET"}) - - assert client.get()['status'] == 200, 'GET' - assert client.post()['status'] == 404, 'POST' - - -def test_routes_match_method_wildcard_right(): - route_match({"method": "GE*"}) - - assert client.get()['status'] == 200, 'GET' - assert client.post()['status'] == 404, 'POST' - - -def test_routes_match_method_wildcard_left_right(): - route_match({"method": "*GET*"}) - - assert client.get()['status'] == 200, 'GET' - assert client.post()['status'] == 404, 'POST' - - -def test_routes_match_method_wildcard(): - route_match({"method": "*"}) - - assert client.get()['status'] == 200, 'GET' - - -def test_routes_match_invalid(): - route_match_invalid({"method": "**"}) - - -def test_routes_match_valid(): - route_match({"method": "blah*"}) - route_match({"host": "*blah*blah"}) - route_match({"host": "blah*blah*blah"}) - route_match({"host": "blah*blah*"}) - - -def test_routes_match_empty_exact(): - route_match({"uri": ""}) - assert client.get()['status'] == 404 - - route_match({"uri": "/"}) - assert client.get()['status'] == 200 - assert client.get(url='/blah')['status'] == 404 - - -def test_routes_match_negative(): - route_match({"uri": "!"}) - assert client.get()['status'] == 200 - - route_match({"uri": "!*"}) - assert client.get()['status'] == 404 - - route_match({"uri": "!/"}) - assert client.get()['status'] == 404 - assert client.get(url='/blah')['status'] == 200 - - route_match({"uri": "!*blah"}) - assert client.get()['status'] == 200 - assert client.get(url='/bla')['status'] == 200 - assert client.get(url='/blah')['status'] == 404 - assert client.get(url='/blah1')['status'] == 200 - - route_match({"uri": "!/blah*1*"}) - assert client.get()['status'] == 200 - assert client.get(url='/blah')['status'] == 200 - assert client.get(url='/blah1')['status'] == 404 - assert client.get(url='/blah12')['status'] == 404 - assert client.get(url='/blah2')['status'] == 200 - - -def test_routes_match_wildcard_middle(): - route_match({"host": "ex*le"}) - - host('example', 200) - host('www.example', 404) - host('example.com', 404) - host('exampl', 404) - - -def test_routes_match_method_case_insensitive(): - route_match({"method": "get"}) - - assert client.get()['status'] == 200, 'GET' - - -def test_routes_match_wildcard_left_case_insensitive(): - route_match({"method": "*get"}) - assert client.get()['status'] == 200, 'GET' - - route_match({"method": "*et"}) - assert client.get()['status'] == 200, 'GET' - - -def test_routes_match_wildcard_middle_case_insensitive(): - route_match({"method": "g*t"}) - - assert client.get()['status'] == 200, 'GET' - - -def test_routes_match_wildcard_right_case_insensitive(): - route_match({"method": "get*"}) - assert client.get()['status'] == 200, 'GET' - - route_match({"method": "ge*"}) - assert client.get()['status'] == 200, 'GET' - - -def test_routes_match_wildcard_substring_case_insensitive(): - route_match({"method": "*et*"}) - - assert client.get()['status'] == 200, 'GET' - - -def test_routes_match_wildcard_left_case_sensitive(): - route_match({"uri": "*blah"}) - - assert client.get(url='/blah')['status'] == 200, '/blah' - assert client.get(url='/BLAH')['status'] == 404, '/BLAH' - - -def test_routes_match_wildcard_middle_case_sensitive(): - route_match({"uri": "/b*h"}) - - assert client.get(url='/blah')['status'] == 200, '/blah' - assert client.get(url='/BLAH')['status'] == 404, '/BLAH' - - -def test_route_match_wildcards_ordered(): - route_match({"uri": "/a*x*y*"}) - - assert client.get(url='/axy')['status'] == 200, '/axy' - assert client.get(url='/ayx')['status'] == 404, '/ayx' - - -def test_route_match_wildcards_adjust_start(): - route_match({"uri": "/bla*bla*"}) - - assert client.get(url='/bla_foo')['status'] == 404, '/bla_foo' - - -def test_route_match_wildcards_adjust_start_substr(): - route_match({"uri": "*bla*bla*"}) - - assert client.get(url='/bla_foo')['status'] == 404, '/bla_foo' - - -def test_route_match_wildcards_adjust_end(): - route_match({"uri": "/bla*bla"}) - - assert client.get(url='/foo_bla')['status'] == 404, '/foo_bla' - - -def test_routes_match_wildcard_right_case_sensitive(): - route_match({"uri": "/bla*"}) - - assert client.get(url='/blah')['status'] == 200, '/blah' - assert client.get(url='/BLAH')['status'] == 404, '/BLAH' - - -def test_routes_match_wildcard_substring_case_sensitive(): - route_match({"uri": "*bla*"}) - - assert client.get(url='/blah')['status'] == 200, '/blah' - assert client.get(url='/BLAH')['status'] == 404, '/BLAH' - - -def test_routes_match_many_wildcard_substrings_case_sensitive(): - route_match({"uri": "*a*B*c*"}) - - assert client.get(url='/blah-a-B-c-blah')['status'] == 200 - assert client.get(url='/a-B-c')['status'] == 200 - assert client.get(url='/aBc')['status'] == 200 - assert client.get(url='/aBCaBbc')['status'] == 200 - assert client.get(url='/ABc')['status'] == 404 - - -def test_routes_empty_regex(require): - require({'modules': {'regex': True}}) - - route_match({"uri": "~"}) - assert client.get(url='/')['status'] == 200, 'empty regexp' - assert client.get(url='/anything')['status'] == 200, '/anything' - - route_match({"uri": "!~"}) - assert client.get(url='/')['status'] == 404, 'empty regexp 2' - assert client.get(url='/nothing')['status'] == 404, '/nothing' - - -def test_routes_bad_regex(require): - require({'modules': {'regex': True}}) - - assert 'error' in route( - {"match": {"uri": "~/bl[ah"}, "action": {"return": 200}} - ), 'bad regex' - - status = route({"match": {"uri": "~(?R)?z"}, "action": {"return": 200}}) - if 'error' not in status: - assert client.get(url='/nothing_z')['status'] == 500, '/nothing_z' - - status = route({"match": {"uri": "~((?1)?z)"}, "action": {"return": 200}}) - if 'error' not in status: - assert client.get(url='/nothing_z')['status'] == 500, '/nothing_z' - - -def test_routes_match_regex_case_sensitive(require): - require({'modules': {'regex': True}}) - - route_match({"uri": "~/bl[ah]"}) - - assert client.get(url='/rlah')['status'] == 404, '/rlah' - assert client.get(url='/blah')['status'] == 200, '/blah' - assert client.get(url='/blh')['status'] == 200, '/blh' - assert client.get(url='/BLAH')['status'] == 404, '/BLAH' - - -def test_routes_match_regex_negative_case_sensitive(require): - require({'modules': {'regex': True}}) - - route_match({"uri": "!~/bl[ah]"}) - - assert client.get(url='/rlah')['status'] == 200, '/rlah' - assert client.get(url='/blah')['status'] == 404, '/blah' - assert client.get(url='/blh')['status'] == 404, '/blh' - assert client.get(url='/BLAH')['status'] == 200, '/BLAH' - - -def test_routes_pass_encode(): - python_dir = f'{option.test_dir}/python' - - def check_pass(path, name): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": f'applications/{path}'}}, - "applications": { - name: { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": f'{python_dir}/empty', - "working_directory": f'{python_dir}/empty', - "module": "wsgi", - } - }, - } - ) - - assert client.get()['status'] == 200 - - check_pass("%25", "%") - check_pass("blah%2Fblah", "blah/blah") - check_pass("%2Fblah%2F%2Fblah%2F", "/blah//blah/") - check_pass("%20blah%252Fblah%7E", " blah%2Fblah~") - - def check_pass_error(path, name): - assert 'error' in client.conf( - { - "listeners": {"*:8080": {"pass": f'applications/{path}'}}, - "applications": { - name: { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": f'{python_dir}/empty', - "working_directory": f'{python_dir}/empty', - "module": "wsgi", - } - }, - } - ) - - check_pass_error("%", "%") - check_pass_error("%1", "%1") - - -def test_routes_absent(): - assert 'success' in client.conf( - { - "listeners": {"*:8081": {"pass": "applications/empty"}}, - "applications": { - "empty": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": f'{option.test_dir}/python/empty', - "working_directory": f'{option.test_dir}/python/empty', - "module": "wsgi", - } - }, - } - ) - - assert client.get(port=8081)['status'] == 200, 'routes absent' - - -def test_routes_pass_invalid(): - assert 'error' in client.conf( - {"pass": "routes/blah"}, 'listeners/*:8080' - ), 'routes invalid' - - -def test_route_empty(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes/main"}}, - "routes": {"main": []}, - "applications": {}, - } - ), 'route empty configure' - - assert client.get()['status'] == 404, 'route empty' - - -def test_routes_route_empty(): - assert 'success' in client.conf( - {}, 'listeners' - ), 'routes empty listeners configure' - - assert 'success' in client.conf({}, 'routes'), 'routes empty configure' - - -def test_routes_route_match_absent(): - assert 'success' in client.conf( - [{"action": {"return": 200}}], 'routes' - ), 'route match absent configure' - - assert client.get()['status'] == 200, 'route match absent' - - -def test_routes_route_action_absent(skip_alert): - skip_alert(r'failed to apply new conf') - - assert 'error' in client.conf( - [{"match": {"method": "GET"}}], 'routes' - ), 'route pass absent configure' - - -def test_routes_route_pass(): - assert 'success' in client.conf( - { - "applications": { - "app": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - "upstreams": { - "one": { - "servers": { - "127.0.0.1:8081": {}, - "127.0.0.1:8082": {}, - }, - }, - "two": { - "servers": { - "127.0.0.1:8081": {}, - "127.0.0.1:8082": {}, - }, - }, - }, - } - ) - - assert 'success' in client.conf([{"action": {"pass": "routes"}}], 'routes') - assert 'success' in client.conf( - [{"action": {"pass": "applications/app"}}], 'routes' - ) - assert 'success' in client.conf( - [{"action": {"pass": "upstreams/one"}}], 'routes' - ) - - -def test_routes_route_pass_absent(): - assert 'error' in client.conf( - [{"match": {"method": "GET"}, "action": {}}], 'routes' - ), 'route pass absent configure' - - -def test_routes_route_pass_invalid(): - assert 'success' in client.conf( - { - "applications": { - "app": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - "upstreams": { - "one": { - "servers": { - "127.0.0.1:8081": {}, - "127.0.0.1:8082": {}, - }, - }, - "two": { - "servers": { - "127.0.0.1:8081": {}, - "127.0.0.1:8082": {}, - }, - }, - }, - } - ) - - assert 'error' in client.conf( - [{"action": {"pass": "blah"}}], 'routes' - ), 'route pass invalid' - assert 'error' in client.conf( - [{"action": {"pass": "routes/blah"}}], 'routes' - ), 'route pass routes invalid' - assert 'error' in client.conf( - [{"action": {"pass": "applications/blah"}}], 'routes' - ), 'route pass applications invalid' - assert 'error' in client.conf( - [{"action": {"pass": "upstreams/blah"}}], 'routes' - ), 'route pass upstreams invalid' - - -def test_routes_action_unique(temp_dir): - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - "*:8081": {"pass": "applications/app"}, - }, - "routes": [{"action": {"proxy": "http://127.0.0.1:8081"}}], - "applications": { - "app": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": "/app", - "module": "wsgi", - } - }, - } - ) - - assert 'error' in client.conf( - {"proxy": "http://127.0.0.1:8081", "share": temp_dir}, - 'routes/0/action', - ), 'proxy share' - assert 'error' in client.conf( - { - "proxy": "http://127.0.0.1:8081", - "pass": "applications/app", - }, - 'routes/0/action', - ), 'proxy pass' - assert 'error' in client.conf( - {"share": temp_dir, "pass": "applications/app"}, - 'routes/0/action', - ), 'share pass' - - -def test_routes_rules_two(): - assert 'success' in client.conf( - [ - {"match": {"method": "GET"}, "action": {"return": 200}}, - {"match": {"method": "POST"}, "action": {"return": 201}}, - ], - 'routes', - ), 'rules two configure' - - assert client.get()['status'] == 200, 'rules two match first' - assert client.post()['status'] == 201, 'rules two match second' - - -def test_routes_two(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes/first"}}, - "routes": { - "first": [ - { - "match": {"method": "GET"}, - "action": {"pass": "routes/second"}, - } - ], - "second": [ - { - "match": {"host": "localhost"}, - "action": {"return": 200}, - } - ], - }, - "applications": {}, - } - ), 'routes two configure' - - assert client.get()['status'] == 200, 'routes two' - - -def test_routes_match_host_positive(): - route_match({"host": "localhost"}) - - assert client.get()['status'] == 200, 'localhost' - host('localhost.', 200) - host('localhost.', 200) - host('.localhost', 404) - host('www.localhost', 404) - host('localhost1', 404) - - -@pytest.mark.skip('not yet') -def test_routes_match_host_absent(): - route_match({"host": "localhost"}) - - assert ( - client.get(headers={'Connection': 'close'})['status'] == 400 - ), 'match host absent' - - -def test_routes_match_host_ipv4(): - route_match({"host": "127.0.0.1"}) - - host('127.0.0.1', 200) - host('127.0.0.1:8080', 200) - - -def test_routes_match_host_ipv6(): - route_match({"host": "[::1]"}) - - host('[::1]', 200) - host('[::1]:8080', 200) - - -def test_routes_match_host_positive_many(): - route_match({"host": ["localhost", "example.com"]}) - - assert client.get()['status'] == 200, 'localhost' - host('example.com', 200) - - -def test_routes_match_host_positive_and_negative(): - route_match({"host": ["*example.com", "!www.example.com"]}) - - assert client.get()['status'] == 404, 'localhost' - host('example.com', 200) - host('www.example.com', 404) - host('!www.example.com', 200) - - -def test_routes_match_host_positive_and_negative_wildcard(): - route_match({"host": ["*example*", "!www.example*"]}) - - host('example.com', 200) - host('www.example.com', 404) - - -def test_routes_match_host_case_insensitive(): - route_match({"host": "Example.com"}) - - host('example.com', 200) - host('EXAMPLE.COM', 200) - - -def test_routes_match_host_port(): - route_match({"host": "example.com"}) - - host('example.com:8080', 200) - - -def test_routes_match_host_empty(): - route_match({"host": ""}) - - host('', 200) - assert ( - client.get(http_10=True, headers={})['status'] == 200 - ), 'match host empty 2' - assert client.get()['status'] == 404, 'match host empty 3' - - -def test_routes_match_uri_positive(): - route_match({"uri": ["/blah", "/slash/"]}) - - assert client.get()['status'] == 404, '/' - assert client.get(url='/blah')['status'] == 200, '/blah' - assert client.get(url='/blah#foo')['status'] == 200, '/blah#foo' - assert client.get(url='/blah?var')['status'] == 200, '/blah?var' - assert client.get(url='//blah')['status'] == 200, '//blah' - assert client.get(url='/slash/foo/../')['status'] == 200, 'relative' - assert client.get(url='/slash/./')['status'] == 200, '/slash/./' - assert client.get(url='/slash//.//')['status'] == 200, 'adjacent slashes' - assert client.get(url='/%')['status'] == 400, 'percent' - assert client.get(url='/%1')['status'] == 400, 'percent digit' - assert client.get(url='/%A')['status'] == 400, 'percent letter' - assert client.get(url='/slash/.?args')['status'] == 200, 'dot args' - assert client.get(url='/slash/.#frag')['status'] == 200, 'dot frag' - assert client.get(url='/slash/foo/..?args')['status'] == 200, 'dot dot args' - assert client.get(url='/slash/foo/..#frag')['status'] == 200, 'dot dot frag' - assert client.get(url='/slash/.')['status'] == 200, 'trailing dot' - assert client.get(url='/slash/foo/..')['status'] == 200, 'trailing dot dot' - - -def test_routes_match_uri_case_sensitive(): - route_match({"uri": "/BLAH"}) - - assert client.get(url='/blah')['status'] == 404, '/blah' - assert client.get(url='/BlaH')['status'] == 404, '/BlaH' - assert client.get(url='/BLAH')['status'] == 200, '/BLAH' - - -def test_routes_match_uri_normalize(): - route_match({"uri": "/blah"}) - - assert client.get(url='/%62%6c%61%68')['status'] == 200, 'normalize' - - -def test_routes_match_empty_array(): - route_match({"uri": []}) - - assert client.get(url='/blah')['status'] == 200, 'empty array' - - -def test_routes_reconfigure(): - assert 'success' in client.conf([], 'routes'), 'redefine' - assert client.get()['status'] == 404, 'redefine request' - - assert 'success' in client.conf( - [{"action": {"return": 200}}], 'routes' - ), 'redefine 2' - assert client.get()['status'] == 200, 'redefine request 2' - - assert 'success' in client.conf([], 'routes'), 'redefine 3' - assert client.get()['status'] == 404, 'redefine request 3' - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes/main"}}, - "routes": {"main": [{"action": {"return": 200}}]}, - "applications": {}, - } - ), 'redefine 4' - assert client.get()['status'] == 200, 'redefine request 4' - - assert 'success' in client.conf_delete('routes/main/0'), 'redefine 5' - assert client.get()['status'] == 404, 'redefine request 5' - - assert 'success' in client.conf_post( - {"action": {"return": 200}}, 'routes/main' - ), 'redefine 6' - assert client.get()['status'] == 200, 'redefine request 6' - - assert 'error' in client.conf( - {"action": {"return": 200}}, 'routes/main/2' - ), 'redefine 7' - assert 'success' in client.conf( - {"action": {"return": 201}}, 'routes/main/1' - ), 'redefine 8' - - assert len(client.conf_get('routes/main')) == 2, 'redefine conf 8' - assert client.get()['status'] == 200, 'redefine request 8' - - -def test_routes_edit(): - route_match({"method": "GET"}) - - assert client.get()['status'] == 200, 'routes edit GET' - assert client.post()['status'] == 404, 'routes edit POST' - - assert 'success' in client.conf_post( - {"match": {"method": "POST"}, "action": {"return": 200}}, - 'routes', - ), 'routes edit configure 2' - assert 'GET' == client.conf_get( - 'routes/0/match/method' - ), 'routes edit configure 2 check' - assert 'POST' == client.conf_get( - 'routes/1/match/method' - ), 'routes edit configure 2 check 2' - - assert client.get()['status'] == 200, 'routes edit GET 2' - assert client.post()['status'] == 200, 'routes edit POST 2' - - assert 'success' in client.conf_delete( - 'routes/0' - ), 'routes edit configure 3' - - assert client.get()['status'] == 404, 'routes edit GET 3' - assert client.post()['status'] == 200, 'routes edit POST 3' - - assert 'error' in client.conf_delete( - 'routes/1' - ), 'routes edit configure invalid' - assert 'error' in client.conf_delete( - 'routes/-1' - ), 'routes edit configure invalid 2' - assert 'error' in client.conf_delete( - 'routes/blah' - ), 'routes edit configure invalid 3' - - assert client.get()['status'] == 404, 'routes edit GET 4' - assert client.post()['status'] == 200, 'routes edit POST 4' - - assert 'success' in client.conf_delete( - 'routes/0' - ), 'routes edit configure 5' - - assert client.get()['status'] == 404, 'routes edit GET 5' - assert client.post()['status'] == 404, 'routes edit POST 5' - - assert 'success' in client.conf_post( - {"match": {"method": "POST"}, "action": {"return": 200}}, - 'routes', - ), 'routes edit configure 6' - - assert client.get()['status'] == 404, 'routes edit GET 6' - assert client.post()['status'] == 200, 'routes edit POST 6' - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes/main"}}, - "routes": {"main": [{"action": {"return": 200}}]}, - "applications": {}, - } - ), 'route edit configure 7' - - assert 'error' in client.conf_delete( - 'routes/0' - ), 'routes edit configure invalid 4' - assert 'error' in client.conf_delete( - 'routes/main' - ), 'routes edit configure invalid 5' - - assert client.get()['status'] == 200, 'routes edit GET 7' - - assert 'success' in client.conf_delete( - 'listeners/*:8080' - ), 'route edit configure 8' - assert 'success' in client.conf_delete( - 'routes/main' - ), 'route edit configure 9' - - -def test_match_edit(skip_alert): - skip_alert(r'failed to apply new conf') - - route_match({"method": ["GET", "POST"]}) - - assert client.get()['status'] == 200, 'match edit GET' - assert client.post()['status'] == 200, 'match edit POST' - assert client.put()['status'] == 404, 'match edit PUT' - - assert 'success' in client.conf_post( - '\"PUT\"', 'routes/0/match/method' - ), 'match edit configure 2' - assert ['GET', 'POST', 'PUT'] == client.conf_get( - 'routes/0/match/method' - ), 'match edit configure 2 check' - - assert client.get()['status'] == 200, 'match edit GET 2' - assert client.post()['status'] == 200, 'match edit POST 2' - assert client.put()['status'] == 200, 'match edit PUT 2' - - assert 'success' in client.conf_delete( - 'routes/0/match/method/1' - ), 'match edit configure 3' - assert ['GET', 'PUT'] == client.conf_get( - 'routes/0/match/method' - ), 'match edit configure 3 check' - - assert client.get()['status'] == 200, 'match edit GET 3' - assert client.post()['status'] == 404, 'match edit POST 3' - assert client.put()['status'] == 200, 'match edit PUT 3' - - assert 'success' in client.conf_delete( - 'routes/0/match/method/1' - ), 'match edit configure 4' - assert ['GET'] == client.conf_get( - 'routes/0/match/method' - ), 'match edit configure 4 check' - - assert client.get()['status'] == 200, 'match edit GET 4' - assert client.post()['status'] == 404, 'match edit POST 4' - assert client.put()['status'] == 404, 'match edit PUT 4' - - assert 'error' in client.conf_delete( - 'routes/0/match/method/1' - ), 'match edit configure invalid' - assert 'error' in client.conf_delete( - 'routes/0/match/method/-1' - ), 'match edit configure invalid 2' - assert 'error' in client.conf_delete( - 'routes/0/match/method/blah' - ), 'match edit configure invalid 3' - assert ['GET'] == client.conf_get( - 'routes/0/match/method' - ), 'match edit configure 5 check' - - assert client.get()['status'] == 200, 'match edit GET 5' - assert client.post()['status'] == 404, 'match edit POST 5' - assert client.put()['status'] == 404, 'match edit PUT 5' - - assert 'success' in client.conf_delete( - 'routes/0/match/method/0' - ), 'match edit configure 6' - assert [] == client.conf_get( - 'routes/0/match/method' - ), 'match edit configure 6 check' - - assert client.get()['status'] == 200, 'match edit GET 6' - assert client.post()['status'] == 200, 'match edit POST 6' - assert client.put()['status'] == 200, 'match edit PUT 6' - - assert 'success' in client.conf( - '"GET"', 'routes/0/match/method' - ), 'match edit configure 7' - - assert client.get()['status'] == 200, 'match edit GET 7' - assert client.post()['status'] == 404, 'match edit POST 7' - assert client.put()['status'] == 404, 'match edit PUT 7' - - assert 'error' in client.conf_delete( - 'routes/0/match/method/0' - ), 'match edit configure invalid 5' - assert 'error' in client.conf( - {}, 'routes/0/action' - ), 'match edit configure invalid 6' - - assert 'success' in client.conf( - {}, 'routes/0/match' - ), 'match edit configure 8' - - assert client.get()['status'] == 200, 'match edit GET 8' - - -def test_routes_match_rules(): - route_match({"method": "GET", "host": "localhost", "uri": "/"}) - - assert client.get()['status'] == 200, 'routes match rules' - - -def test_routes_loop(): - assert 'success' in route( - {"match": {"uri": "/"}, "action": {"pass": "routes"}} - ), 'routes loop configure' - - assert client.get()['status'] == 500, 'routes loop' - - -def test_routes_match_headers(): - route_match({"headers": {"host": "localhost"}}) - - assert client.get()['status'] == 200, 'match headers' - host('Localhost', 200) - host('localhost.com', 404) - host('llocalhost', 404) - host('host', 404) - - -def test_routes_match_headers_multiple(): - route_match({"headers": {"host": "localhost", "x-blah": "test"}}) - - assert client.get()['status'] == 404, 'match headers multiple' - assert ( - client.get( - headers={ - "Host": "localhost", - "X-blah": "test", - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers multiple 2' - - assert ( - client.get( - headers={ - "Host": "localhost", - "X-blah": "", - "Connection": "close", - } - )['status'] - == 404 - ), 'match headers multiple 3' - - -def test_routes_match_headers_multiple_values(): - route_match({"headers": {"x-blah": "test"}}) - - assert ( - client.get( - headers={ - "Host": "localhost", - "X-blah": ["test", "test", "test"], - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers multiple values' - assert ( - client.get( - headers={ - "Host": "localhost", - "X-blah": ["test", "blah", "test"], - "Connection": "close", - } - )['status'] - == 404 - ), 'match headers multiple values 2' - assert ( - client.get( - headers={ - "Host": "localhost", - "X-blah": ["test", "", "test"], - "Connection": "close", - } - )['status'] - == 404 - ), 'match headers multiple values 3' - - -def test_routes_match_headers_multiple_rules(): - route_match({"headers": {"x-blah": ["test", "blah"]}}) - - assert client.get()['status'] == 404, 'match headers multiple rules' - assert ( - client.get( - headers={ - "Host": "localhost", - "X-blah": "test", - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers multiple rules 2' - assert ( - client.get( - headers={ - "Host": "localhost", - "X-blah": "blah", - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers multiple rules 3' - assert ( - client.get( - headers={ - "Host": "localhost", - "X-blah": ["test", "blah", "test"], - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers multiple rules 4' - - assert ( - client.get( - headers={ - "Host": "localhost", - "X-blah": ["blah", ""], - "Connection": "close", - } - )['status'] - == 404 - ), 'match headers multiple rules 5' - - -def test_routes_match_headers_case_insensitive(): - route_match({"headers": {"X-BLAH": "TEST"}}) - - assert ( - client.get( - headers={ - "Host": "localhost", - "x-blah": "test", - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers case insensitive' - - -def test_routes_match_headers_invalid(): - route_match_invalid({"headers": ["blah"]}) - route_match_invalid({"headers": {"foo": ["bar", {}]}}) - route_match_invalid({"headers": {"": "blah"}}) - - -def test_routes_match_headers_empty_rule(): - route_match({"headers": {"host": ""}}) - - assert client.get()['status'] == 404, 'localhost' - host('', 200) - - -def test_routes_match_headers_empty(): - route_match({"headers": {}}) - assert client.get()['status'] == 200, 'empty' - - route_match({"headers": []}) - assert client.get()['status'] == 200, 'empty 2' - - -def test_routes_match_headers_rule_array_empty(): - route_match({"headers": {"blah": []}}) - - assert client.get()['status'] == 404, 'array empty' - assert ( - client.get( - headers={ - "Host": "localhost", - "blah": "foo", - "Connection": "close", - } - )['status'] - == 200 - ), 'match headers rule array empty 2' - - -def test_routes_match_headers_array(): - route_match( - { - "headers": [ - {"x-header1": "foo*"}, - {"x-header2": "bar"}, - {"x-header3": ["foo", "bar"]}, - {"x-header1": "bar", "x-header4": "foo"}, - ] - } - ) - - def check_headers(hds): - hds = dict({"Host": "localhost", "Connection": "close"}, **hds) - assert client.get(headers=hds)['status'] == 200, 'headers array match' - - def check_headers_404(hds): - hds = dict({"Host": "localhost", "Connection": "close"}, **hds) - assert ( - client.get(headers=hds)['status'] == 404 - ), 'headers array no match' - - assert client.get()['status'] == 404, 'match headers array' - check_headers({"x-header1": "foo123"}) - check_headers({"x-header2": "bar"}) - check_headers({"x-header3": "bar"}) - check_headers_404({"x-header1": "bar"}) - check_headers({"x-header1": "bar", "x-header4": "foo"}) - - assert 'success' in client.conf_delete( - 'routes/0/match/headers/1' - ), 'match headers array configure 2' - - check_headers_404({"x-header2": "bar"}) - check_headers({"x-header3": "foo"}) - - -def test_routes_match_arguments(): - route_match({"arguments": {"foo": "bar"}}) - - assert client.get()['status'] == 404, 'args' - assert client.get(url='/?foo=bar')['status'] == 200, 'args 2' - assert client.get(url='/?foo=bar1')['status'] == 404, 'args 3' - assert client.get(url='/?1foo=bar')['status'] == 404, 'args 4' - assert client.get(url='/?Foo=bar')['status'] == 404, 'case' - assert client.get(url='/?foo=Bar')['status'] == 404, 'case 2' - - -def test_routes_match_arguments_chars(): - chars = ( - " !\"%23$%25%26'()*%2B,-./0123456789:;<%3D>?@" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" - ) - - chars_enc = "" - for h1 in ["2", "3", "4", "5", "6", "7"]: - for h2 in [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "A", - "B", - "C", - "D", - "E", - "F", - ]: - chars_enc += f'%{h1}{h2}' - chars_enc = chars_enc[:-3] - - def check_args(args, query): - route_match({"arguments": args}) - assert client.get(url=f'/?{query}')['status'] == 200 - - check_args({chars: chars}, f'{chars}={chars}') - check_args({chars: chars}, f'{chars}={chars_enc}') - check_args({chars: chars}, f'{chars_enc}={chars}') - check_args({chars: chars}, f'{chars_enc}={chars_enc}') - check_args({chars_enc: chars_enc}, f'{chars}={chars}') - check_args({chars_enc: chars_enc}, f'{chars}={chars_enc}') - check_args({chars_enc: chars_enc}, f'{chars_enc}={chars}') - check_args({chars_enc: chars_enc}, f'{chars_enc}={chars_enc}') - - -def test_routes_match_arguments_empty(): - route_match({"arguments": {}}) - assert client.get()['status'] == 200, 'arguments empty' - - route_match({"arguments": []}) - assert client.get()['status'] == 200, 'arguments empty 2' - - -def test_routes_match_arguments_space(): - route_match({"arguments": {"+fo o%20": "%20b+a r"}}) - assert client.get(url='/? fo o = b a r&')['status'] == 200 - assert client.get(url='/?+fo+o+=+b+a+r&')['status'] == 200 - assert client.get(url='/?%20fo%20o%20=%20b%20a%20r&')['status'] == 200 - - route_match({"arguments": {"%20foo": " bar"}}) - assert client.get(url='/? foo= bar')['status'] == 200 - assert client.get(url='/?+foo=+bar')['status'] == 200 - assert client.get(url='/?%20foo=%20bar')['status'] == 200 - assert client.get(url='/?+foo= bar')['status'] == 200 - assert client.get(url='/?%20foo=+bar')['status'] == 200 - - -def test_routes_match_arguments_equal(): - route_match({"arguments": {"=": "="}}) - assert client.get(url='/?%3D=%3D')['status'] == 200 - assert client.get(url='/?%3D==')['status'] == 200 - assert client.get(url='/?===')['status'] == 404 - assert client.get(url='/?%3D%3D%3D')['status'] == 404 - assert client.get(url='/?==%3D')['status'] == 404 - - -def test_routes_match_arguments_enc(): - route_match({"arguments": {"Ю": "н"}}) - assert client.get(url='/?%D0%AE=%D0%BD')['status'] == 200 - assert client.get(url='/?%d0%ae=%d0%Bd')['status'] == 200 - - -def test_routes_match_arguments_hash(): - route_match({"arguments": {"#": "#"}}) - assert client.get(url='/?%23=%23')['status'] == 200 - assert client.get(url='/?%23=%23#')['status'] == 200 - assert client.get(url='/?#=#')['status'] == 404 - assert client.get(url='/?%23=#')['status'] == 404 - - -def test_routes_match_arguments_wildcard(): - route_match({"arguments": {"foo": "*"}}) - assert client.get(url='/?foo')['status'] == 200 - assert client.get(url='/?foo=')['status'] == 200 - assert client.get(url='/?foo=blah')['status'] == 200 - assert client.get(url='/?blah=foo')['status'] == 404 - - route_match({"arguments": {"foo": "%25*"}}) - assert client.get(url='/?foo=%xx')['status'] == 200 - - route_match({"arguments": {"foo": "%2A*"}}) - assert client.get(url='/?foo=*xx')['status'] == 200 - assert client.get(url='/?foo=xx')['status'] == 404 - - route_match({"arguments": {"foo": "*%2A"}}) - assert client.get(url='/?foo=xx*')['status'] == 200 - assert client.get(url='/?foo=xx*x')['status'] == 404 - - route_match({"arguments": {"foo": "1*2"}}) - assert client.get(url='/?foo=12')['status'] == 200 - assert client.get(url='/?foo=1blah2')['status'] == 200 - assert client.get(url='/?foo=1%2A2')['status'] == 200 - assert client.get(url='/?foo=x12')['status'] == 404 - - route_match({"arguments": {"foo": "bar*", "%25": "%25"}}) - assert client.get(url='/?foo=barxx&%=%')['status'] == 200 - assert client.get(url='/?foo=barxx&x%=%')['status'] == 404 - - -def test_routes_match_arguments_negative(): - route_match({"arguments": {"foo": "!"}}) - assert client.get(url='/?bar')['status'] == 404 - assert client.get(url='/?foo')['status'] == 404 - assert client.get(url='/?foo=')['status'] == 404 - assert client.get(url='/?foo=%25')['status'] == 200 - - route_match({"arguments": {"foo": "!*"}}) - assert client.get(url='/?bar')['status'] == 404 - assert client.get(url='/?foo')['status'] == 404 - assert client.get(url='/?foo=')['status'] == 404 - assert client.get(url='/?foo=blah')['status'] == 404 - - route_match({"arguments": {"foo": "!%25"}}) - assert client.get(url='/?foo=blah')['status'] == 200 - assert client.get(url='/?foo=%')['status'] == 404 - - route_match({"arguments": {"foo": "%21blah"}}) - assert client.get(url='/?foo=%21blah')['status'] == 200 - assert client.get(url='/?foo=!blah')['status'] == 200 - assert client.get(url='/?foo=bar')['status'] == 404 - - route_match({"arguments": {"foo": "!!%21*a"}}) - assert client.get(url='/?foo=blah')['status'] == 200 - assert client.get(url='/?foo=!blah')['status'] == 200 - assert client.get(url='/?foo=!!a')['status'] == 404 - assert client.get(url='/?foo=!!bla')['status'] == 404 - - -def test_routes_match_arguments_percent(): - route_match({"arguments": {"%25": "%25"}}) - assert client.get(url='/?%=%')['status'] == 200 - assert client.get(url='/?%25=%25')['status'] == 200 - assert client.get(url='/?%25=%')['status'] == 200 - - route_match({"arguments": {"%251": "%252"}}) - assert client.get(url='/?%1=%2')['status'] == 200 - assert client.get(url='/?%251=%252')['status'] == 200 - assert client.get(url='/?%251=%2')['status'] == 200 - - route_match({"arguments": {"%25%21%251": "%25%24%252"}}) - assert client.get(url='/?%!%1=%$%2')['status'] == 200 - assert client.get(url='/?%25!%251=%25$%252')['status'] == 200 - assert client.get(url='/?%25!%1=%$%2')['status'] == 200 - - -def test_routes_match_arguments_ampersand(): - route_match({"arguments": {"foo": "&"}}) - assert client.get(url='/?foo=%26')['status'] == 200 - assert client.get(url='/?foo=%26&')['status'] == 200 - assert client.get(url='/?foo=%26%26')['status'] == 404 - assert client.get(url='/?foo=&')['status'] == 404 - - route_match({"arguments": {"&": ""}}) - assert client.get(url='/?%26=')['status'] == 200 - assert client.get(url='/?%26=&')['status'] == 200 - assert client.get(url='/?%26=%26')['status'] == 404 - assert client.get(url='/?&=')['status'] == 404 - - -def test_routes_match_arguments_complex(): - route_match({"arguments": {"foo": ""}}) - - assert client.get(url='/?foo')['status'] == 200, 'complex' - assert client.get(url='/?blah=blah&foo=')['status'] == 200, 'complex 2' - assert client.get(url='/?&&&foo&&&')['status'] == 200, 'complex 3' - assert client.get(url='/?foo&foo=bar&foo')['status'] == 404, 'complex 4' - assert client.get(url='/?foo=&foo')['status'] == 200, 'complex 5' - assert client.get(url='/?&=&foo&==&')['status'] == 200, 'complex 6' - assert client.get(url='/?&=&bar&==&')['status'] == 404, 'complex 7' - - -def test_routes_match_arguments_multiple(): - route_match({"arguments": {"foo": "bar", "blah": "test"}}) - - assert client.get()['status'] == 404, 'multiple' - assert client.get(url='/?foo=bar&blah=test')['status'] == 200, 'multiple 2' - assert client.get(url='/?foo=bar&blah')['status'] == 404, 'multiple 3' - assert client.get(url='/?foo=bar&blah=tes')['status'] == 404, 'multiple 4' - assert ( - client.get(url='/?foo=b%61r&bl%61h=t%65st')['status'] == 200 - ), 'multiple 5' - - -def test_routes_match_arguments_multiple_rules(): - route_match({"arguments": {"foo": ["bar", "blah"]}}) - - assert client.get()['status'] == 404, 'rules' - assert client.get(url='/?foo=bar')['status'] == 200, 'rules 2' - assert client.get(url='/?foo=blah')['status'] == 200, 'rules 3' - assert ( - client.get(url='/?foo=blah&foo=bar&foo=blah')['status'] == 200 - ), 'rules 4' - assert client.get(url='/?foo=blah&foo=bar&foo=')['status'] == 404, 'rules 5' - - -def test_routes_match_arguments_array(): - route_match( - { - "arguments": [ - {"var1": "val1*"}, - {"var2": "val2"}, - {"var3": ["foo", "bar"]}, - {"var1": "bar", "var4": "foo"}, - ] - } - ) - - assert client.get()['status'] == 404, 'arr' - assert client.get(url='/?var1=val123')['status'] == 200, 'arr 2' - assert client.get(url='/?var2=val2')['status'] == 200, 'arr 3' - assert client.get(url='/?var3=bar')['status'] == 200, 'arr 4' - assert client.get(url='/?var1=bar')['status'] == 404, 'arr 5' - assert client.get(url='/?var1=bar&var4=foo')['status'] == 200, 'arr 6' - - assert 'success' in client.conf_delete( - 'routes/0/match/arguments/1' - ), 'match arguments array configure 2' - - assert client.get(url='/?var2=val2')['status'] == 404, 'arr 7' - assert client.get(url='/?var3=foo')['status'] == 200, 'arr 8' - - -def test_routes_match_arguments_invalid(): - route_match_invalid({"arguments": ["var"]}) - route_match_invalid({"arguments": [{"var1": {}}]}) - route_match_invalid({"arguments": {"": "bar"}}) - route_match_invalid({"arguments": {"foo": "%"}}) - route_match_invalid({"arguments": {"foo": "%1G"}}) - route_match_invalid({"arguments": {"%": "bar"}}) - route_match_invalid({"arguments": {"foo": "%0"}}) - route_match_invalid({"arguments": {"foo": "%%1F"}}) - route_match_invalid({"arguments": {"%%1F": ""}}) - route_match_invalid({"arguments": {"%7%F": ""}}) - - -def test_routes_match_query(): - route_match({"query": "!"}) - assert client.get(url='/')['status'] == 404 - assert client.get(url='/?')['status'] == 404 - assert client.get(url='/?foo')['status'] == 200 - assert client.get(url='/?foo=')['status'] == 200 - assert client.get(url='/?foo=baz')['status'] == 200 - - route_match({"query": "foo=%26"}) - assert client.get(url='/?foo=&')['status'] == 200 - - route_match({"query": "a=b&c=d"}) - assert client.get(url='/?a=b&c=d')['status'] == 200 - - route_match({"query": "a=b%26c%3Dd"}) - assert client.get(url='/?a=b%26c%3Dd')['status'] == 200 - assert client.get(url='/?a=b&c=d')['status'] == 200 - - route_match({"query": "a=b%26c%3Dd+e"}) - assert client.get(url='/?a=b&c=d e')['status'] == 200 - - -def test_routes_match_query_array(): - route_match({"query": ["foo", "bar"]}) - - assert client.get()['status'] == 404, 'no args' - assert client.get(url='/?foo')['status'] == 200, 'arg first' - assert client.get(url='/?bar')['status'] == 200, 'arg second' - - assert 'success' in client.conf_delete( - 'routes/0/match/query/1' - ), 'query array remove second' - - assert client.get(url='/?foo')['status'] == 200, 'still arg first' - assert client.get(url='/?bar')['status'] == 404, 'no arg second' - - route_match({"query": ["!f", "foo"]}) - - assert client.get(url='/?f')['status'] == 404, 'negative arg' - assert client.get(url='/?fo')['status'] == 404, 'negative arg 2' - assert client.get(url='/?foo')['status'] == 200, 'negative arg 3' - - route_match({"query": []}) - assert client.get()['status'] == 200, 'empty array' - - -def test_routes_match_query_invalid(): - route_match_invalid({"query": [1]}) - route_match_invalid({"query": "%"}) - route_match_invalid({"query": "%1G"}) - route_match_invalid({"query": "%0"}) - route_match_invalid({"query": "%%1F"}) - route_match_invalid({"query": ["foo", "%3D", "%%1F"]}) - - -def test_routes_match_cookies(): - route_match({"cookies": {"foO": "bar"}}) - - assert client.get()['status'] == 404, 'cookie' - cookie('foO=bar', 200) - cookie('foO=bar;1', 200) - cookie(['foO=bar', 'blah=blah'], 200) - cookie('foO=bar; blah=blah', 200) - cookie('Foo=bar', 404) - cookie('foO=Bar', 404) - cookie('foO=bar1', 404) - cookie('1foO=bar;', 404) - - -def test_routes_match_cookies_empty(): - route_match({"cookies": {}}) - assert client.get()['status'] == 200, 'cookies empty' - - route_match({"cookies": []}) - assert client.get()['status'] == 200, 'cookies empty 2' - - -def test_routes_match_cookies_invalid(): - route_match_invalid({"cookies": ["var"]}) - route_match_invalid({"cookies": [{"foo": {}}]}) - - -def test_routes_match_cookies_complex(): - route_match({"cookies": {"foo": "bar=baz"}}) - cookie('foo=bar=baz', 200) - cookie(' foo=bar=baz ', 200) - cookie('=foo=bar=baz', 404) - - route_match({"cookies": {"foo": ""}}) - cookie('foo=', 200) - cookie('foo=;', 200) - cookie(' foo=;', 200) - cookie('foo', 404) - cookie('', 404) - cookie('=', 404) - - -def test_routes_match_cookies_multiple(): - route_match({"cookies": {"foo": "bar", "blah": "blah"}}) - - assert client.get()['status'] == 404, 'multiple' - cookie('foo=bar; blah=blah', 200) - cookie(['foo=bar', 'blah=blah'], 200) - cookie(['foo=bar; blah', 'blah'], 404) - cookie(['foo=bar; blah=test', 'blah=blah'], 404) - - -def test_routes_match_cookies_multiple_values(): - route_match({"cookies": {"blah": "blah"}}) - - cookie(['blah=blah', 'blah=blah', 'blah=blah'], 200) - cookie(['blah=blah', 'blah=test', 'blah=blah'], 404) - cookie(['blah=blah; blah=', 'blah=blah'], 404) - - -def test_routes_match_cookies_multiple_rules(): - route_match({"cookies": {"blah": ["test", "blah"]}}) - - assert client.get()['status'] == 404, 'multiple rules' - cookie('blah=test', 200) - cookie('blah=blah', 200) - cookie(['blah=blah', 'blah=test', 'blah=blah'], 200) - cookie(['blah=blah; blah=test', 'blah=blah'], 200) - cookie(['blah=blah', 'blah'], 200) # invalid cookie - - -def test_routes_match_cookies_array(): - route_match( - { - "cookies": [ - {"var1": "val1*"}, - {"var2": "val2"}, - {"var3": ["foo", "bar"]}, - {"var1": "bar", "var4": "foo"}, - ] - } - ) - - assert client.get()['status'] == 404, 'cookies array' - cookie('var1=val123', 200) - cookie('var2=val2', 200) - cookie(' var2=val2 ', 200) - cookie('var3=bar', 200) - cookie('var3=bar;', 200) - cookie('var1=bar', 404) - cookie('var1=bar; var4=foo;', 200) - cookie(['var1=bar', 'var4=foo'], 200) - - assert 'success' in client.conf_delete( - 'routes/0/match/cookies/1' - ), 'match cookies array configure 2' - - cookie('var2=val2', 404) - cookie('var3=foo', 200) - - -def test_routes_match_scheme(): - route_match({"scheme": "http"}) - route_match({"scheme": "https"}) - route_match({"scheme": "HtTp"}) - route_match({"scheme": "HtTpS"}) - - -def test_routes_match_scheme_invalid(): - route_match_invalid({"scheme": ["http"]}) - route_match_invalid({"scheme": "ftp"}) - route_match_invalid({"scheme": "ws"}) - route_match_invalid({"scheme": "*"}) - route_match_invalid({"scheme": ""}) - - -def test_routes_source_port(): - def sock_port(): - sock = client.http(b'', raw=True, no_recv=True) - port = sock.getsockname()[1] - return (sock, port) - - sock, port = sock_port() - sock2, _ = sock_port() - - route_match({"source": f'127.0.0.1:{port}'}) - assert client.get(sock=sock)['status'] == 200, 'exact' - assert client.get(sock=sock2)['status'] == 404, 'exact 2' - - sock, port = sock_port() - sock2, _ = sock_port() - - route_match({"source": f'!127.0.0.1:{port}'}) - assert client.get(sock=sock)['status'] == 404, 'negative' - assert client.get(sock=sock2)['status'] == 200, 'negative 2' - - sock, port = sock_port() - sock2, _ = sock_port() - - route_match({"source": [f'*:{port}', "!127.0.0.1"]}) - assert client.get(sock=sock)['status'] == 404, 'negative 3' - assert client.get(sock=sock2)['status'] == 404, 'negative 4' - - sock, port = sock_port() - sock2, _ = sock_port() - - route_match({"source": f'127.0.0.1:{port}-{port}'}) - assert client.get(sock=sock)['status'] == 200, 'range single' - assert client.get(sock=sock2)['status'] == 404, 'range single 2' - - socks = [ - sock_port(), - sock_port(), - sock_port(), - sock_port(), - sock_port(), - ] - socks.sort(key=lambda sock: sock[1]) - - route_match({"source": f'127.0.0.1:{socks[1][1]}-{socks[3][1]}'}) - assert client.get(sock=socks[0][0])['status'] == 404, 'range' - assert client.get(sock=socks[1][0])['status'] == 200, 'range 2' - assert client.get(sock=socks[2][0])['status'] == 200, 'range 3' - assert client.get(sock=socks[3][0])['status'] == 200, 'range 4' - assert client.get(sock=socks[4][0])['status'] == 404, 'range 5' - - socks = [ - sock_port(), - sock_port(), - sock_port(), - ] - socks.sort(key=lambda sock: sock[1]) - - route_match( - { - "source": [ - f'127.0.0.1:{socks[0][1]}', - f'127.0.0.1:{socks[2][1]}', - ] - } - ) - assert client.get(sock=socks[0][0])['status'] == 200, 'array' - assert client.get(sock=socks[1][0])['status'] == 404, 'array 2' - assert client.get(sock=socks[2][0])['status'] == 200, 'array 3' - - -def test_routes_source_addr(): - assert 'success' in client.conf( - { - "*:8080": {"pass": "routes"}, - "[::1]:8081": {"pass": "routes"}, - }, - 'listeners', - ), 'source listeners configure' - - def get_ipv6(): - return client.get(sock_type='ipv6', port=8081) - - route_match({"source": "127.0.0.1"}) - assert client.get()['status'] == 200, 'exact' - assert get_ipv6()['status'] == 404, 'exact ipv6' - - route_match({"source": ["127.0.0.1"]}) - assert client.get()['status'] == 200, 'exact 2' - assert get_ipv6()['status'] == 404, 'exact 2 ipv6' - - route_match({"source": "!127.0.0.1"}) - assert client.get()['status'] == 404, 'exact neg' - assert get_ipv6()['status'] == 200, 'exact neg ipv6' - - route_match({"source": "127.0.0.2"}) - assert client.get()['status'] == 404, 'exact 3' - assert get_ipv6()['status'] == 404, 'exact 3 ipv6' - - route_match({"source": "127.0.0.1-127.0.0.1"}) - assert client.get()['status'] == 200, 'range single' - assert get_ipv6()['status'] == 404, 'range single ipv6' - - route_match({"source": "127.0.0.2-127.0.0.2"}) - assert client.get()['status'] == 404, 'range single 2' - assert get_ipv6()['status'] == 404, 'range single 2 ipv6' - - route_match({"source": "127.0.0.2-127.0.0.3"}) - assert client.get()['status'] == 404, 'range' - assert get_ipv6()['status'] == 404, 'range ipv6' - - route_match({"source": "127.0.0.1-127.0.0.2"}) - assert client.get()['status'] == 200, 'range 2' - assert get_ipv6()['status'] == 404, 'range 2 ipv6' - - route_match({"source": "127.0.0.0-127.0.0.2"}) - assert client.get()['status'] == 200, 'range 3' - assert get_ipv6()['status'] == 404, 'range 3 ipv6' - - route_match({"source": "127.0.0.0-127.0.0.1"}) - assert client.get()['status'] == 200, 'range 4' - assert get_ipv6()['status'] == 404, 'range 4 ipv6' - - route_match({"source": "126.0.0.0-127.0.0.0"}) - assert client.get()['status'] == 404, 'range 5' - assert get_ipv6()['status'] == 404, 'range 5 ipv6' - - route_match({"source": "126.126.126.126-127.0.0.2"}) - assert client.get()['status'] == 200, 'range 6' - assert get_ipv6()['status'] == 404, 'range 6 ipv6' - - -def test_routes_source_ipv6(): - assert 'success' in client.conf( - { - "[::1]:8080": {"pass": "routes"}, - "127.0.0.1:8081": {"pass": "routes"}, - }, - 'listeners', - ), 'source listeners configure' - - route_match({"source": "::1"}) - assert client.get(sock_type='ipv6')['status'] == 200, 'exact' - assert client.get(port=8081)['status'] == 404, 'exact ipv4' - - route_match({"source": ["::1"]}) - assert client.get(sock_type='ipv6')['status'] == 200, 'exact 2' - assert client.get(port=8081)['status'] == 404, 'exact 2 ipv4' - - route_match({"source": "!::1"}) - assert client.get(sock_type='ipv6')['status'] == 404, 'exact neg' - assert client.get(port=8081)['status'] == 200, 'exact neg ipv4' - - route_match({"source": "::2"}) - assert client.get(sock_type='ipv6')['status'] == 404, 'exact 3' - assert client.get(port=8081)['status'] == 404, 'exact 3 ipv4' - - route_match({"source": "::1-::1"}) - assert client.get(sock_type='ipv6')['status'] == 200, 'range' - assert client.get(port=8081)['status'] == 404, 'range ipv4' - - route_match({"source": "::2-::2"}) - assert client.get(sock_type='ipv6')['status'] == 404, 'range 2' - assert client.get(port=8081)['status'] == 404, 'range 2 ipv4' - - route_match({"source": "::2-::3"}) - assert client.get(sock_type='ipv6')['status'] == 404, 'range 3' - assert client.get(port=8081)['status'] == 404, 'range 3 ipv4' - - route_match({"source": "::1-::2"}) - assert client.get(sock_type='ipv6')['status'] == 200, 'range 4' - assert client.get(port=8081)['status'] == 404, 'range 4 ipv4' - - route_match({"source": "::0-::2"}) - assert client.get(sock_type='ipv6')['status'] == 200, 'range 5' - assert client.get(port=8081)['status'] == 404, 'range 5 ipv4' - - route_match({"source": "::0-::1"}) - assert client.get(sock_type='ipv6')['status'] == 200, 'range 6' - assert client.get(port=8081)['status'] == 404, 'range 6 ipv4' - - -def test_routes_source_cidr(): - assert 'success' in client.conf( - { - "*:8080": {"pass": "routes"}, - "[::1]:8081": {"pass": "routes"}, - }, - 'listeners', - ), 'source listeners configure' - - def get_ipv6(): - return client.get(sock_type='ipv6', port=8081) - - route_match({"source": "127.0.0.1/32"}) - assert client.get()['status'] == 200, '32' - assert get_ipv6()['status'] == 404, '32 ipv6' - - route_match({"source": "127.0.0.0/32"}) - assert client.get()['status'] == 404, '32 2' - assert get_ipv6()['status'] == 404, '32 2 ipv6' - - route_match({"source": "127.0.0.0/31"}) - assert client.get()['status'] == 200, '31' - assert get_ipv6()['status'] == 404, '31 ipv6' - - route_match({"source": "0.0.0.0/1"}) - assert client.get()['status'] == 200, '1' - assert get_ipv6()['status'] == 404, '1 ipv6' - - route_match({"source": "0.0.0.0/0"}) - assert client.get()['status'] == 200, '0' - assert get_ipv6()['status'] == 404, '0 ipv6' - - -def test_routes_source_cidr_ipv6(): - assert 'success' in client.conf( - { - "[::1]:8080": {"pass": "routes"}, - "127.0.0.1:8081": {"pass": "routes"}, - }, - 'listeners', - ), 'source listeners configure' - - route_match({"source": "::1/128"}) - assert client.get(sock_type='ipv6')['status'] == 200, '128' - assert client.get(port=8081)['status'] == 404, '128 ipv4' - - route_match({"source": "::0/128"}) - assert client.get(sock_type='ipv6')['status'] == 404, '128 2' - assert client.get(port=8081)['status'] == 404, '128 ipv4' - - route_match({"source": "::0/127"}) - assert client.get(sock_type='ipv6')['status'] == 200, '127' - assert client.get(port=8081)['status'] == 404, '127 ipv4' - - route_match({"source": "::0/32"}) - assert client.get(sock_type='ipv6')['status'] == 200, '32' - assert client.get(port=8081)['status'] == 404, '32 ipv4' - - route_match({"source": "::0/1"}) - assert client.get(sock_type='ipv6')['status'] == 200, '1' - assert client.get(port=8081)['status'] == 404, '1 ipv4' - - route_match({"source": "::/0"}) - assert client.get(sock_type='ipv6')['status'] == 200, '0' - assert client.get(port=8081)['status'] == 404, '0 ipv4' - - -def test_routes_source_unix(temp_dir): - addr = f'{temp_dir}/sock' - - assert 'success' in client.conf( - { - "127.0.0.1:8081": {"pass": "routes"}, - f'unix:{addr}': {"pass": "routes"}, - }, - 'listeners', - ), 'source listeners configure' - - route_match({"source": "!0.0.0.0/0"}) - assert ( - client.get(sock_type='unix', addr=addr)['status'] == 200 - ), 'unix ipv4 neg' - - route_match({"source": "!::/0"}) - assert ( - client.get(sock_type='unix', addr=addr)['status'] == 200 - ), 'unix ipv6 neg' - - route_match({"source": "unix"}) - assert client.get(port=8081)['status'] == 404, 'unix ipv4' - assert client.get(sock_type='unix', addr=addr)['status'] == 200, 'unix' - - -def test_routes_match_source(): - route_match({"source": "::"}) - route_match( - { - "source": [ - "127.0.0.1", - "192.168.0.10:8080", - "192.168.0.11:8080-8090", - ] - } - ) - route_match( - { - "source": [ - "10.0.0.0/8", - "10.0.0.0/7:1000", - "10.0.0.0/32:8080-8090", - ] - } - ) - route_match( - { - "source": [ - "10.0.0.0-10.0.0.1", - "10.0.0.0-11.0.0.0:1000", - "127.0.0.0-127.0.0.255:8080-8090", - ] - } - ) - route_match({"source": ["2001::", "[2002::]:8000", "[2003::]:8080-8090"]}) - route_match( - { - "source": [ - "2001::-200f:ffff:ffff:ffff:ffff:ffff:ffff:ffff", - "[fe08::-feff::]:8000", - "[fff0::-fff0::10]:8080-8090", - ] - } - ) - route_match( - { - "source": [ - "2001::/16", - "[0ff::/64]:8000", - "[fff0:abcd:ffff:ffff:ffff::/128]:8080-8090", - ] - } - ) - route_match({"source": "*:0-65535"}) - assert client.get()['status'] == 200, 'source any' - - -def test_routes_match_source_invalid(): - route_match_invalid({"source": "127"}) - route_match_invalid({"source": "256.0.0.1"}) - route_match_invalid({"source": "127.0.0."}) - route_match_invalid({"source": " 127.0.0.1"}) - route_match_invalid({"source": "127.0.0.1:"}) - route_match_invalid({"source": "127.0.0.1/"}) - route_match_invalid({"source": "11.0.0.0/33"}) - route_match_invalid({"source": "11.0.0.0/65536"}) - route_match_invalid({"source": "11.0.0.0-10.0.0.0"}) - route_match_invalid({"source": "11.0.0.0:3000-2000"}) - route_match_invalid({"source": ["11.0.0.0:3000-2000"]}) - route_match_invalid({"source": "[2001::]:3000-2000"}) - route_match_invalid({"source": "2001::-2000::"}) - route_match_invalid({"source": "2001::/129"}) - route_match_invalid({"source": "::FFFFF"}) - route_match_invalid({"source": "[::1]:"}) - route_match_invalid({"source": "[:::]:8080"}) - route_match_invalid({"source": "*:"}) - route_match_invalid({"source": "*:1-a"}) - route_match_invalid({"source": "*:65536"}) - - -def test_routes_match_source_none(): - route_match({"source": []}) - assert client.get()['status'] == 404, 'source none' - - -def test_routes_match_destination(): - assert 'success' in client.conf( - {"*:8080": {"pass": "routes"}, "*:8081": {"pass": "routes"}}, - 'listeners', - ), 'listeners configure' - - route_match({"destination": "*:8080"}) - assert client.get()['status'] == 200, 'dest' - assert client.get(port=8081)['status'] == 404, 'dest 2' - - route_match({"destination": ["127.0.0.1:8080"]}) - assert client.get()['status'] == 200, 'dest 3' - assert client.get(port=8081)['status'] == 404, 'dest 4' - - route_match({"destination": "!*:8080"}) - assert client.get()['status'] == 404, 'dest neg' - assert client.get(port=8081)['status'] == 200, 'dest neg 2' - - route_match({"destination": ['!*:8080', '!*:8081']}) - assert client.get()['status'] == 404, 'dest neg 3' - assert client.get(port=8081)['status'] == 404, 'dest neg 4' - - route_match({"destination": ['!*:8081', '!*:8082']}) - assert client.get()['status'] == 200, 'dest neg 5' - - route_match({"destination": ['*:8080', '!*:8080']}) - assert client.get()['status'] == 404, 'dest neg 6' - - route_match({"destination": ['127.0.0.1:8080', '*:8081', '!*:8080']}) - assert client.get()['status'] == 404, 'dest neg 7' - assert client.get(port=8081)['status'] == 200, 'dest neg 8' - - route_match({"destination": ['!*:8081', '!*:8082', '*:8083']}) - assert client.get()['status'] == 404, 'dest neg 9' - - route_match({"destination": ['*:8081', '!127.0.0.1:8080', '*:8080']}) - assert client.get()['status'] == 404, 'dest neg 10' - assert client.get(port=8081)['status'] == 200, 'dest neg 11' - - assert 'success' in client.conf_delete( - 'routes/0/match/destination/0' - ), 'remove destination rule' - assert client.get()['status'] == 404, 'dest neg 12' - assert client.get(port=8081)['status'] == 404, 'dest neg 13' - - assert 'success' in client.conf_delete( - 'routes/0/match/destination/0' - ), 'remove destination rule 2' - assert client.get()['status'] == 200, 'dest neg 14' - assert client.get(port=8081)['status'] == 404, 'dest neg 15' - - assert 'success' in client.conf_post( - "\"!127.0.0.1\"", 'routes/0/match/destination' - ), 'add destination rule' - assert client.get()['status'] == 404, 'dest neg 16' - assert client.get(port=8081)['status'] == 404, 'dest neg 17' - - -def test_routes_match_destination_proxy(): - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes/first"}, - "*:8081": {"pass": "routes/second"}, - }, - "routes": { - "first": [{"action": {"proxy": "http://127.0.0.1:8081"}}], - "second": [ - { - "match": {"destination": ["127.0.0.1:8081"]}, - "action": {"return": 200}, - } - ], - }, - "applications": {}, - } - ), 'proxy configure' - - assert client.get()['status'] == 200, 'proxy' diff --git a/test/test_routing_tls.py b/test/test_routing_tls.py deleted file mode 100644 index f8cef546..00000000 --- a/test/test_routing_tls.py +++ /dev/null @@ -1,29 +0,0 @@ -from unit.applications.tls import ApplicationTLS - -prerequisites = {'modules': {'openssl': 'any'}} - -client = ApplicationTLS() - - -def test_routes_match_scheme_tls(): - client.certificate() - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - "*:8081": { - "pass": "routes", - "tls": {"certificate": 'default'}, - }, - }, - "routes": [ - {"match": {"scheme": "http"}, "action": {"return": 200}}, - {"match": {"scheme": "https"}, "action": {"return": 201}}, - ], - "applications": {}, - } - ), 'scheme configure' - - assert client.get()['status'] == 200, 'http' - assert client.get_ssl(port=8081)['status'] == 201, 'https' diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py deleted file mode 100644 index 127b75b7..00000000 --- a/test/test_ruby_application.py +++ /dev/null @@ -1,471 +0,0 @@ -import re -import subprocess - -import pytest - -from unit.applications.lang.ruby import ApplicationRuby - -prerequisites = {'modules': {'ruby': 'all'}} - -client = ApplicationRuby() - - -def test_ruby_application(date_to_sec_epoch, sec_epoch): - client.load('variables') - - body = 'Test body string.' - - resp = client.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Custom-Header': 'blah', - 'Connection': 'close', - }, - body=body, - ) - - assert resp['status'] == 200, 'status' - headers = resp['headers'] - header_server = headers.pop('Server') - assert re.search(r'Unit/[\d\.]+', header_server), 'server header' - assert ( - headers.pop('Server-Software') == header_server - ), 'server software header' - - date = headers.pop('Date') - assert date[-4:] == ' GMT', 'date header timezone' - assert abs(date_to_sec_epoch(date) - sec_epoch) < 5, 'date header' - - assert headers == { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Content-Type': 'text/html', - 'Request-Method': 'POST', - 'Request-Uri': '/', - 'Http-Host': 'localhost', - 'Script-Name': '', - 'Server-Protocol': 'HTTP/1.1', - 'Custom-Header': 'blah', - 'Rack-Version': '13', - 'Rack-Url-Scheme': 'http', - 'Rack-Multithread': 'false', - 'Rack-Multiprocess': 'true', - 'Rack-Run-Once': 'false', - 'Rack-Hijack-Q': 'false', - 'Rack-Hijack': '', - 'Rack-Hijack-IO': '', - }, 'headers' - assert resp['body'] == body, 'body' - - -def test_ruby_application_query_string(): - client.load('query_string') - - resp = client.get(url='/?var1=val1&var2=val2') - - assert ( - resp['headers']['Query-String'] == 'var1=val1&var2=val2' - ), 'Query-String header' - - -def test_ruby_application_query_string_empty(): - client.load('query_string') - - resp = client.get(url='/?') - - assert resp['status'] == 200, 'query string empty status' - assert resp['headers']['Query-String'] == '', 'query string empty' - - -def test_ruby_application_query_string_absent(): - client.load('query_string') - - resp = client.get() - - assert resp['status'] == 200, 'query string absent status' - assert resp['headers']['Query-String'] == '', 'query string absent' - - -@pytest.mark.skip('not yet') -def test_ruby_application_server_port(): - client.load('server_port') - - assert ( - client.get()['headers']['Server-Port'] == '8080' - ), 'Server-Port header' - - -def test_ruby_application_status_int(): - client.load('status_int') - - assert client.get()['status'] == 200, 'status int' - - -def test_ruby_application_input_read_empty(): - client.load('input_read_empty') - - assert client.get()['body'] == '', 'read empty' - - -def test_ruby_application_input_read_parts(): - client.load('input_read_parts') - - assert ( - client.post(body='0123456789')['body'] == '012345678' - ), 'input read parts' - - -def test_ruby_application_input_read_buffer(): - client.load('input_read_buffer') - - assert ( - client.post(body='0123456789')['body'] == '0123456789' - ), 'input read buffer' - - -def test_ruby_application_input_read_buffer_not_empty(): - client.load('input_read_buffer_not_empty') - - assert ( - client.post(body='0123456789')['body'] == '0123456789' - ), 'input read buffer not empty' - - -def test_ruby_application_input_gets(): - client.load('input_gets') - - body = '0123456789' - - assert client.post(body=body)['body'] == body, 'input gets' - - -def test_ruby_application_input_gets_2(): - client.load('input_gets') - - assert ( - client.post(body='01234\n56789\n')['body'] == '01234\n' - ), 'input gets 2' - - -def test_ruby_application_input_gets_all(): - client.load('input_gets_all') - - body = '\n01234\n56789\n\n' - - assert client.post(body=body)['body'] == body, 'input gets all' - - -def test_ruby_application_input_each(): - client.load('input_each') - - body = '\n01234\n56789\n\n' - - assert client.post(body=body)['body'] == body, 'input each' - - -@pytest.mark.skip('not yet') -def test_ruby_application_syntax_error(skip_alert): - skip_alert( - r'Failed to parse rack script', - r'syntax error', - r'new_from_string', - r'parse_file', - ) - client.load('syntax_error') - - assert client.get()['status'] == 500, 'syntax error' - - -def test_ruby_application_errors_puts(wait_for_record): - client.load('errors_puts') - - assert client.get()['status'] == 200 - - assert ( - wait_for_record(r'\[error\].+Error in application') is not None - ), 'errors puts' - - -def test_ruby_application_errors_puts_int(wait_for_record): - client.load('errors_puts_int') - - assert client.get()['status'] == 200 - - assert ( - wait_for_record(r'\[error\].+1234567890') is not None - ), 'errors puts int' - - -def test_ruby_application_errors_write(wait_for_record): - client.load('errors_write') - - assert client.get()['status'] == 200 - assert ( - wait_for_record(r'\[error\].+Error in application') is not None - ), 'errors write' - - -def test_ruby_application_errors_write_to_s_custom(): - client.load('errors_write_to_s_custom') - - assert client.get()['status'] == 200, 'errors write to_s custom' - - -def test_ruby_application_errors_write_int(wait_for_record): - client.load('errors_write_int') - - assert client.get()['status'] == 200 - assert ( - wait_for_record(r'\[error\].+1234567890') is not None - ), 'errors write int' - - -def test_ruby_application_at_exit(wait_for_record): - client.load('at_exit') - - assert client.get()['status'] == 200 - - assert 'success' in client.conf({"listeners": {}, "applications": {}}) - - assert ( - wait_for_record(r'\[error\].+At exit called\.') is not None - ), 'at exit' - - -def test_ruby_application_encoding(): - client.load('encoding') - - try: - locales = ( - subprocess.check_output( - ['locale', '-a'], - stderr=subprocess.STDOUT, - ) - .decode() - .split('\n') - ) - - except (FileNotFoundError, subprocess.CalledProcessError): - pytest.skip('require locale') - - def get_locale(pattern): - return next( - (l for l in locales if re.match(pattern, l.upper()) is not None), - None, - ) - - utf8 = get_locale(r'.*UTF[-_]?8') - iso88591 = get_locale(r'.*ISO[-_]?8859[-_]?1') - - def check_locale(enc): - assert 'success' in client.conf( - {"LC_CTYPE": enc, "LC_ALL": ""}, - '/config/applications/encoding/environment', - ) - - resp = client.get() - assert resp['status'] == 200, 'status' - - enc_default = re.sub(r'[-_]', '', resp['headers']['X-Enc']).upper() - assert enc_default == re.sub(r'[-_]', '', enc.split('.')[-1]).upper() - - if utf8: - check_locale(utf8) - - if iso88591: - check_locale(iso88591) - - if not utf8 and not iso88591: - pytest.skip('no available locales') - - -def test_ruby_application_header_custom(): - client.load('header_custom') - - resp = client.post(body="\ntc=one,two\ntc=three,four,\n\n") - - assert resp['headers']['Custom-Header'] == [ - '', - 'tc=one,two', - 'tc=three,four,', - '', - '', - ], 'header custom' - - -@pytest.mark.skip('not yet') -def test_ruby_application_header_custom_non_printable(): - client.load('header_custom') - - assert ( - client.post(body='\b')['status'] == 500 - ), 'header custom non printable' - - -def test_ruby_application_header_status(): - client.load('header_status') - - assert client.get()['status'] == 200, 'header status' - - -def test_ruby_application_header_array(): - client.load('header_array') - - assert client.get()['headers']['x-array'] == 'name=value; ; value; av' - - -def test_ruby_application_header_array_nil(): - client.load('header_array_nil') - - assert client.get()['status'] == 503 - - -def test_ruby_application_header_array_empty(): - client.load('header_array_empty') - - headers = client.get()['headers'] - assert 'x-array' in headers - assert headers['x-array'] == '' - - -@pytest.mark.skip('not yet') -def test_ruby_application_header_rack(): - client.load('header_rack') - - assert client.get()['status'] == 500, 'header rack' - - -@pytest.mark.skip('not yet') -def test_ruby_application_session(): - client.load('session') - - assert client.get()['status'] == 200 - - -@pytest.mark.skip('not yet') -def test_ruby_application_multipart(): - client.load('multipart') - - assert client.get()['status'] == 200 - - -def test_ruby_application_body_empty(): - client.load('body_empty') - - assert client.get()['body'] == '', 'body empty' - - -def test_ruby_application_body_array(): - client.load('body_array') - - assert client.get()['body'] == '0123456789', 'body array' - - -def test_ruby_application_body_large(): - client.load('mirror') - - body = '0123456789' * 1000 - - assert client.post(body=body)['body'] == body, 'body large' - - -@pytest.mark.skip('not yet') -def test_ruby_application_body_each_error(wait_for_record): - client.load('body_each_error') - - assert client.get()['status'] == 500, 'body each error status' - - assert ( - wait_for_record(r'\[error\].+Failed to run ruby script') is not None - ), 'body each error' - - -def test_ruby_application_body_file(): - client.load('body_file') - - assert client.get()['body'] == 'body\n', 'body file' - - -def test_ruby_keepalive_body(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - body = '0123456789' * 500 - (resp, sock) = client.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - - assert resp['body'] == body, 'keep-alive 1' - - body = '0123456789' - resp = client.post(sock=sock, body=body) - - assert resp['body'] == body, 'keep-alive 2' - - -def test_ruby_application_constants(): - client.load('constants') - - resp = client.get() - - assert resp['status'] == 200, 'status' - - headers = resp['headers'] - assert len(headers['X-Copyright']) > 0, 'RUBY_COPYRIGHT' - assert len(headers['X-Description']) > 0, 'RUBY_DESCRIPTION' - assert len(headers['X-Engine']) > 0, 'RUBY_ENGINE' - assert len(headers['X-Engine-Version']) > 0, 'RUBY_ENGINE_VERSION' - assert len(headers['X-Patchlevel']) > 0, 'RUBY_PATCHLEVEL' - assert len(headers['X-Platform']) > 0, 'RUBY_PLATFORM' - assert len(headers['X-Release-Date']) > 0, 'RUBY_RELEASE_DATE' - assert len(headers['X-Revision']) > 0, 'RUBY_REVISION' - assert len(headers['X-Version']) > 0, 'RUBY_VERSION' - - -def test_ruby_application_threads(): - client.load('threads') - - assert 'success' in client.conf( - '4', 'applications/threads/threads' - ), 'configure 4 threads' - - socks = [] - - for _ in range(4): - sock = client.get( - headers={ - 'Host': 'localhost', - 'X-Delay': '2', - 'Connection': 'close', - }, - no_recv=True, - ) - - socks.append(sock) - - threads = set() - - for sock in socks: - resp = client.recvall(sock).decode('utf-8') - - client.log_in(resp) - - resp = client._resp_to_dict(resp) - - assert resp['status'] == 200, 'status' - - threads.add(resp['headers']['X-Thread']) - - assert resp['headers']['Rack-Multithread'] == 'true', 'multithread' - - sock.close() - - assert len(socks) == len(threads), 'threads differs' diff --git a/test/test_ruby_hooks.py b/test/test_ruby_hooks.py deleted file mode 100644 index dd9e0fca..00000000 --- a/test/test_ruby_hooks.py +++ /dev/null @@ -1,102 +0,0 @@ -from unit.applications.lang.ruby import ApplicationRuby -from unit.option import option -from unit.utils import waitforglob -from packaging import version - -prerequisites = { - 'modules': {'ruby': lambda v: version.parse(v) >= version.parse('3.0')} -} - -client = ApplicationRuby() - - -def wait_cookie(pattern, count): - return waitforglob(f'{option.temp_dir}/ruby/hooks/cookie_{pattern}', count) - - -def test_ruby_hooks_eval(): - processes = 2 - - client.load('hooks', processes=processes, hooks='eval.rb') - - hooked = wait_cookie('eval.*', processes) - - assert hooked, 'hooks evaluated' - - -def test_ruby_hooks_on_worker_boot(): - processes = 2 - - client.load('hooks', processes=processes, hooks='on_worker_boot.rb') - - hooked = wait_cookie('worker_boot.*', processes) - - assert hooked, 'on_worker_boot called' - - -def test_ruby_hooks_on_worker_shutdown(): - processes = 2 - - client.load('hooks', processes=processes, hooks='on_worker_shutdown.rb') - - assert client.get()['status'] == 200, 'app response' - - client.load('empty') - - hooked = wait_cookie('worker_shutdown.*', processes) - - assert hooked, 'on_worker_shutdown called' - - -def test_ruby_hooks_on_thread_boot(): - processes = 1 - threads = 2 - - client.load( - 'hooks', - processes=processes, - threads=threads, - hooks='on_thread_boot.rb', - ) - - hooked = wait_cookie('thread_boot.*', processes * threads) - - assert hooked, 'on_thread_boot called' - - -def test_ruby_hooks_on_thread_shutdown(): - processes = 1 - threads = 2 - - client.load( - 'hooks', - processes=processes, - threads=threads, - hooks='on_thread_shutdown.rb', - ) - - assert client.get()['status'] == 200, 'app response' - - client.load('empty') - - hooked = wait_cookie('thread_shutdown.*', processes * threads) - - assert hooked, 'on_thread_shutdown called' - - -def test_ruby_hooks_multiple(): - processes = 1 - threads = 1 - - client.load( - 'hooks', - processes=processes, - threads=threads, - hooks='multiple.rb', - ) - - hooked = wait_cookie('worker_boot.*', processes) - assert hooked, 'on_worker_boot called' - - hooked = wait_cookie('thread_boot.*', threads) - assert hooked, 'on_thread_boot called' diff --git a/test/test_ruby_isolation.py b/test/test_ruby_isolation.py deleted file mode 100644 index 59c0e5f6..00000000 --- a/test/test_ruby_isolation.py +++ /dev/null @@ -1,43 +0,0 @@ -from unit.applications.lang.ruby import ApplicationRuby - -prerequisites = {'modules': {'ruby': 'any'}, 'features': {'isolation': True}} - -client = ApplicationRuby() - - -def test_ruby_isolation_rootfs(is_su, require, temp_dir): - isolation = {'rootfs': temp_dir} - - if not is_su: - require( - { - 'features': { - 'isolation': [ - 'unprivileged_userns_clone', - 'user', - 'mnt', - 'pid', - ] - } - } - ) - - isolation['namespaces'] = { - 'mount': True, - 'credential': True, - 'pid': True, - } - - client.load('status_int', isolation=isolation) - - assert 'success' in client.conf( - '"/ruby/status_int/config.ru"', - 'applications/status_int/script', - ) - - assert 'success' in client.conf( - '"/ruby/status_int"', - 'applications/status_int/working_directory', - ) - - assert client.get()['status'] == 200, 'status int' diff --git a/test/test_settings.py b/test/test_settings.py deleted file mode 100644 index 9d37d6ca..00000000 --- a/test/test_settings.py +++ /dev/null @@ -1,588 +0,0 @@ -import re -import socket -import subprocess -import time - -import pytest - -from unit.applications.lang.python import ApplicationPython - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -def sysctl(): - try: - out = subprocess.check_output( - ['sysctl', '-a'], stderr=subprocess.STDOUT - ).decode() - except FileNotFoundError: - pytest.skip('requires sysctl') - - return out - - -def test_settings_large_header_buffer_size(): - client.load('empty') - - def set_buffer_size(size): - assert 'success' in client.conf( - {'http': {'large_header_buffer_size': size}}, - 'settings', - ) - - def header_value(size, expect=200): - headers = {'Host': 'a' * (size - 1), 'Connection': 'close'} - assert client.get(headers=headers)['status'] == expect - - set_buffer_size(4096) - header_value(4096) - header_value(4097, 431) - - set_buffer_size(16384) - header_value(16384) - header_value(16385, 431) - - -def test_settings_large_header_buffers(): - client.load('empty') - - def set_buffers(buffers): - assert 'success' in client.conf( - {'http': {'large_header_buffers': buffers}}, - 'settings', - ) - - def big_headers(headers_num, expect=200): - headers = {'Host': 'localhost', 'Connection': 'close'} - - for i in range(headers_num): - headers[f'Custom-header-{i}'] = 'a' * 8000 - - assert client.get(headers=headers)['status'] == expect - - set_buffers(1) - big_headers(1) - big_headers(2, 431) - - set_buffers(2) - big_headers(2) - big_headers(3, 431) - - set_buffers(8) - big_headers(8) - big_headers(9, 431) - - -@pytest.mark.skip('not yet') -def test_settings_large_header_buffer_invalid(): - def check_error(conf): - assert 'error' in client.conf({'http': conf}, 'settings') - - check_error({'large_header_buffer_size': -1}) - check_error({'large_header_buffer_size': 0}) - check_error({'large_header_buffers': -1}) - check_error({'large_header_buffers': 0}) - - -def test_settings_server_version(): - client.load('empty') - - assert client.get()['headers']['Server'].startswith('Unit/') - - assert 'success' in client.conf( - {"http": {"server_version": False}}, 'settings' - ), 'remove version' - assert client.get()['headers']['Server'] == 'Unit' - - assert 'success' in client.conf( - {"http": {"server_version": True}}, 'settings' - ), 'add version' - assert client.get()['headers']['Server'].startswith('Unit/') - - -def test_settings_header_read_timeout(): - client.load('empty') - - def req(): - (_, sock) = client.http( - b"""GET / HTTP/1.1 -""", - start=True, - read_timeout=1, - raw=True, - ) - - time.sleep(3) - - return client.http( - b"""Host: localhost -Connection: close - -""", - sock=sock, - raw=True, - ) - - assert 'success' in client.conf( - {'http': {'header_read_timeout': 2}}, 'settings' - ) - assert req()['status'] == 408, 'status header read timeout' - - assert 'success' in client.conf( - {'http': {'header_read_timeout': 7}}, 'settings' - ) - assert req()['status'] == 200, 'status header read timeout 2' - - -def test_settings_header_read_timeout_update(): - client.load('empty') - - assert 'success' in client.conf( - {'http': {'header_read_timeout': 4}}, 'settings' - ) - - sock = client.http( - b"""GET / HTTP/1.1 -""", - raw=True, - no_recv=True, - ) - - time.sleep(2) - - sock = client.http( - b"""Host: localhost -""", - sock=sock, - raw=True, - no_recv=True, - ) - - time.sleep(2) - - (resp, sock) = client.http( - b"""X-Blah: blah -""", - start=True, - sock=sock, - read_timeout=1, - raw=True, - ) - - if len(resp) != 0: - sock.close() - - else: - time.sleep(2) - - resp = client.http( - b"""Connection: close - -""", - sock=sock, - raw=True, - ) - - assert resp['status'] == 408, 'status header read timeout update' - - -def test_settings_body_read_timeout(): - client.load('empty') - - def req(): - (_, sock) = client.http( - b"""POST / HTTP/1.1 -Host: localhost -Content-Length: 10 -Connection: close - -""", - start=True, - raw_resp=True, - read_timeout=1, - raw=True, - ) - - time.sleep(3) - - return client.http(b"""0123456789""", sock=sock, raw=True) - - assert 'success' in client.conf( - {'http': {'body_read_timeout': 2}}, 'settings' - ) - assert req()['status'] == 408, 'status body read timeout' - - assert 'success' in client.conf( - {'http': {'body_read_timeout': 7}}, 'settings' - ) - assert req()['status'] == 200, 'status body read timeout 2' - - -def test_settings_body_read_timeout_update(): - client.load('empty') - - assert 'success' in client.conf( - {'http': {'body_read_timeout': 4}}, 'settings' - ) - - (resp, sock) = client.http( - b"""POST / HTTP/1.1 -Host: localhost -Content-Length: 10 -Connection: close - -""", - start=True, - read_timeout=1, - raw=True, - ) - - time.sleep(2) - - (resp, sock) = client.http( - b"""012""", start=True, sock=sock, read_timeout=1, raw=True - ) - - time.sleep(2) - - (resp, sock) = client.http( - b"""345""", start=True, sock=sock, read_timeout=1, raw=True - ) - - time.sleep(2) - - resp = client.http(b"""6789""", sock=sock, raw=True) - - assert resp['status'] == 200, 'status body read timeout update' - - -def test_settings_send_timeout(temp_dir): - client.load('body_generate') - - def req(addr, data_len): - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect(addr) - - req = f"""GET / HTTP/1.1 -Host: localhost -X-Length: {data_len} -Connection: close - -""" - - sock.sendall(req.encode()) - - data = sock.recv(16).decode() - - time.sleep(3) - - data += client.recvall(sock).decode() - - sock.close() - - return data - - sysctl_out = sysctl() - values = re.findall(r'net.core.[rw]mem_(?:max|default).*?(\d+)', sysctl_out) - values = [int(v) for v in values] - - data_len = 1048576 if len(values) == 0 else 10 * max(values) - - addr = f'{temp_dir}/sock' - - assert 'success' in client.conf( - {f'unix:{addr}': {'application': 'body_generate'}}, 'listeners' - ) - - assert 'success' in client.conf({'http': {'send_timeout': 1}}, 'settings') - - data = req(addr, data_len) - assert re.search(r'200 OK', data), 'send timeout status' - assert len(data) < data_len, 'send timeout data ' - - client.conf({'http': {'send_timeout': 7}}, 'settings') - - data = req(addr, data_len) - assert re.search(r'200 OK', data), 'send timeout status 2' - assert len(data) > data_len, 'send timeout data 2' - - -def test_settings_idle_timeout(): - client.load('empty') - - def req(): - (_, sock) = client.get( - headers={'Host': 'localhost', 'Connection': 'keep-alive'}, - start=True, - read_timeout=1, - ) - - time.sleep(3) - - return client.get(sock=sock) - - assert client.get()['status'] == 200, 'init' - - assert 'success' in client.conf({'http': {'idle_timeout': 2}}, 'settings') - assert req()['status'] == 408, 'status idle timeout' - - assert 'success' in client.conf({'http': {'idle_timeout': 7}}, 'settings') - assert req()['status'] == 200, 'status idle timeout 2' - - -def test_settings_idle_timeout_2(): - client.load('empty') - - def req(): - sock = client.http(b'', raw=True, no_recv=True) - - time.sleep(3) - - return client.get(sock=sock) - - assert client.get()['status'] == 200, 'init' - - assert 'success' in client.conf({'http': {'idle_timeout': 1}}, 'settings') - assert req()['status'] == 408, 'status idle timeout' - - assert 'success' in client.conf({'http': {'idle_timeout': 7}}, 'settings') - assert req()['status'] == 200, 'status idle timeout 2' - - -def test_settings_max_body_size(): - client.load('empty') - - assert 'success' in client.conf({'http': {'max_body_size': 5}}, 'settings') - - assert client.post(body='01234')['status'] == 200, 'status size' - assert client.post(body='012345')['status'] == 413, 'status size max' - - -def test_settings_max_body_size_large(): - client.load('mirror') - - assert 'success' in client.conf( - {'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings' - ) - - body = '0123456789abcdef' * 4 * 64 * 1024 - resp = client.post(body=body, read_buffer_size=1024 * 1024) - assert resp['status'] == 200, 'status size 4' - assert resp['body'] == body, 'status body 4' - - body = '0123456789abcdef' * 8 * 64 * 1024 - resp = client.post(body=body, read_buffer_size=1024 * 1024) - assert resp['status'] == 200, 'status size 8' - assert resp['body'] == body, 'status body 8' - - body = '0123456789abcdef' * 16 * 64 * 1024 - resp = client.post(body=body, read_buffer_size=1024 * 1024) - assert resp['status'] == 200, 'status size 16' - assert resp['body'] == body, 'status body 16' - - body = '0123456789abcdef' * 32 * 64 * 1024 - resp = client.post(body=body, read_buffer_size=1024 * 1024) - assert resp['status'] == 200, 'status size 32' - assert resp['body'] == body, 'status body 32' - - -@pytest.mark.skip('not yet') -def test_settings_negative_value(): - assert 'error' in client.conf( - {'http': {'max_body_size': -1}}, 'settings' - ), 'settings negative value' - - -def test_settings_body_buffer_size(): - client.load('mirror') - - assert 'success' in client.conf( - { - 'http': { - 'max_body_size': 64 * 1024 * 1024, - 'body_buffer_size': 32 * 1024 * 1024, - } - }, - 'settings', - ) - - body = '0123456789abcdef' - resp = client.post(body=body) - assert bool(resp), 'response from application' - assert resp['status'] == 200, 'status' - assert resp['body'] == body, 'body' - - body = '0123456789abcdef' * 1024 * 1024 - resp = client.post(body=body, read_buffer_size=1024 * 1024) - assert bool(resp), 'response from application 2' - assert resp['status'] == 200, 'status 2' - assert resp['body'] == body, 'body 2' - - body = '0123456789abcdef' * 2 * 1024 * 1024 - resp = client.post(body=body, read_buffer_size=1024 * 1024) - assert bool(resp), 'response from application 3' - assert resp['status'] == 200, 'status 3' - assert resp['body'] == body, 'body 3' - - body = '0123456789abcdef' * 3 * 1024 * 1024 - resp = client.post(body=body, read_buffer_size=1024 * 1024) - assert bool(resp), 'response from application 4' - assert resp['status'] == 200, 'status 4' - assert resp['body'] == body, 'body 4' - - -def test_settings_log_route(findall, search_in_file, wait_for_record): - def count_fallbacks(): - return len(findall(r'"fallback" taken')) - - def check_record(template): - assert search_in_file(template) is not None - - def check_no_record(template): - assert search_in_file(template) is None - - def template_req_line(url): - return rf'\[notice\].*http request line "GET {url} HTTP/1\.1"' - - def template_selected(route): - return rf'\[notice\].*"{route}" selected' - - def template_discarded(route): - return rf'\[info\].*"{route}" discarded' - - def wait_for_request_log(status, uri, route): - assert client.get(url=uri)['status'] == status - assert wait_for_record(template_req_line(uri)) is not None - assert wait_for_record(template_selected(route)) is not None - - # routes array - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "match": { - "uri": "/zero", - }, - "action": {"return": 200}, - }, - { - "action": {"return": 201}, - }, - ], - "applications": {}, - "settings": {"http": {"log_route": True}}, - } - ) - - wait_for_request_log(200, '/zero', 'routes/0') - check_no_record(r'discarded') - - wait_for_request_log(201, '/one', 'routes/1') - check_record(template_discarded('routes/0')) - - # routes object - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes/main"}}, - "routes": { - "main": [ - { - "match": { - "uri": "/named_route", - }, - "action": {"return": 200}, - }, - { - "action": {"return": 201}, - }, - ] - }, - "applications": {}, - "settings": {"http": {"log_route": True}}, - } - ) - - wait_for_request_log(200, '/named_route', 'routes/main/0') - check_no_record(template_discarded('routes/main')) - - wait_for_request_log(201, '/unnamed_route', 'routes/main/1') - check_record(template_discarded('routes/main/0')) - - # routes sequence - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes/first"}}, - "routes": { - "first": [ - { - "action": {"pass": "routes/second"}, - }, - ], - "second": [ - { - "action": {"return": 200}, - }, - ], - }, - "applications": {}, - "settings": {"http": {"log_route": True}}, - } - ) - - wait_for_request_log(200, '/sequence', 'routes/second/0') - check_record(template_selected('routes/first/0')) - - # fallback - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes/fall"}}, - "routes": { - "fall": [ - { - "action": { - "share": "/blah", - "fallback": {"pass": "routes/fall2"}, - }, - }, - ], - "fall2": [ - { - "action": {"return": 200}, - }, - ], - }, - "applications": {}, - "settings": {"http": {"log_route": True}}, - } - ) - - wait_for_request_log(200, '/', 'routes/fall2/0') - assert count_fallbacks() == 1 - check_record(template_selected('routes/fall/0')) - - assert client.head()['status'] == 200 - assert count_fallbacks() == 2 - - # disable log - - assert 'success' in client.conf({"log_route": False}, 'settings/http') - - url = '/disable_logging' - assert client.get(url=url)['status'] == 200 - - time.sleep(1) - - check_no_record(template_req_line(url)) - - # total - - assert len(findall(r'\[notice\].*http request line')) == 7 - assert len(findall(r'\[notice\].*selected')) == 10 - assert len(findall(r'\[info\].*discarded')) == 2 diff --git a/test/test_static.py b/test/test_static.py deleted file mode 100644 index e2fc2283..00000000 --- a/test/test_static.py +++ /dev/null @@ -1,350 +0,0 @@ -import os -import socket -from pathlib import Path - -import pytest - -from unit.applications.proto import ApplicationProto -from unit.utils import waitforfiles - - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - assets_dir = f'{temp_dir}/assets' - - Path(f'{assets_dir}/dir').mkdir(parents=True) - Path(f'{assets_dir}/index.html').write_text('0123456789', encoding='utf-8') - Path(f'{assets_dir}/README').write_text('readme', encoding='utf-8') - Path(f'{assets_dir}/log.log').write_text('[debug]', encoding='utf-8') - Path(f'{assets_dir}/dir/file').write_text('blah', encoding='utf-8') - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"share": f'{assets_dir}$uri'}}], - "settings": { - "http": { - "static": {"mime_types": {"text/plain": [".log", "README"]}} - } - }, - } - ) - - -def test_static_index(temp_dir): - def set_index(index): - assert 'success' in client.conf( - {"share": f'{temp_dir}/assets$uri', "index": index}, - 'routes/0/action', - ), 'configure index' - - set_index('README') - assert client.get()['body'] == 'readme', 'index' - - client.conf_delete('routes/0/action/index') - assert client.get()['body'] == '0123456789', 'delete index' - - set_index('') - assert client.get()['status'] == 404, 'index empty' - - -def test_static_index_default(): - assert client.get(url='/index.html')['body'] == '0123456789', 'index' - assert client.get(url='/')['body'] == '0123456789', 'index 2' - assert client.get(url='//')['body'] == '0123456789', 'index 3' - assert client.get(url='/.')['body'] == '0123456789', 'index 4' - assert client.get(url='/./')['body'] == '0123456789', 'index 5' - assert client.get(url='/?blah')['body'] == '0123456789', 'index vars' - assert client.get(url='/#blah')['body'] == '0123456789', 'index anchor' - assert client.get(url='/dir/')['status'] == 404, 'index not found' - - resp = client.get(url='/index.html/') - assert resp['status'] == 404, 'index not found 2 status' - assert ( - resp['headers']['Content-Type'] == 'text/html' - ), 'index not found 2 Content-Type' - - -def test_static_index_invalid(skip_alert, temp_dir): - skip_alert(r'failed to apply new conf') - - def check_index(index): - assert 'error' in client.conf( - {"share": f'{temp_dir}/assets$uri', "index": index}, - 'routes/0/action', - ) - - check_index({}) - check_index(['index.html', '$blah']) - - -def test_static_large_file(temp_dir): - file_size = 32 * 1024 * 1024 - with open(f'{temp_dir}/assets/large', 'wb') as f: - f.seek(file_size - 1) - f.write(b'\0') - - assert ( - len(client.get(url='/large', read_buffer_size=1024 * 1024)['body']) - == file_size - ), 'large file' - - -def test_static_etag(temp_dir): - etag = client.get(url='/')['headers']['ETag'] - etag_2 = client.get(url='/README')['headers']['ETag'] - - assert etag != etag_2, 'different ETag' - assert etag == client.get(url='/')['headers']['ETag'], 'same ETag' - - with open(f'{temp_dir}/assets/index.html', 'w', encoding='utf-8') as f: - f.write('blah') - - assert etag != client.get(url='/')['headers']['ETag'], 'new ETag' - - -def test_static_redirect(): - resp = client.get(url='/dir') - assert resp['status'] == 301, 'redirect status' - assert resp['headers']['Location'] == '/dir/', 'redirect Location' - assert 'Content-Type' not in resp['headers'], 'redirect Content-Type' - - -def test_static_space_in_name(temp_dir): - assets_dir = f'{temp_dir}/assets' - - Path(f'{assets_dir}/dir/file').rename(f'{assets_dir}/dir/fi le') - - assert waitforfiles(f'{assets_dir}/dir/fi le') - assert client.get(url='/dir/fi le')['body'] == 'blah', 'file name' - - Path(f'{assets_dir}/dir').rename(f'{assets_dir}/di r') - assert waitforfiles(f'{assets_dir}/di r/fi le') - assert client.get(url='/di r/fi le')['body'] == 'blah', 'dir name' - - Path(f'{assets_dir}/di r').rename(f'{assets_dir}/ di r ') - assert waitforfiles(f'{assets_dir}/ di r /fi le') - assert ( - client.get(url='/ di r /fi le')['body'] == 'blah' - ), 'dir name enclosing' - - assert ( - client.get(url='/%20di%20r%20/fi le')['body'] == 'blah' - ), 'dir encoded' - assert client.get(url='/ di r %2Ffi le')['body'] == 'blah', 'slash encoded' - assert client.get(url='/ di r /fi%20le')['body'] == 'blah', 'file encoded' - assert ( - client.get(url='/%20di%20r%20%2Ffi%20le')['body'] == 'blah' - ), 'encoded' - assert ( - client.get(url='/%20%64%69%20%72%20%2F%66%69%20%6C%65')['body'] - == 'blah' - ), 'encoded 2' - - Path(f'{assets_dir}/ di r /fi le').rename(f'{assets_dir}/ di r / fi le ') - assert waitforfiles(f'{assets_dir}/ di r / fi le ') - assert ( - client.get(url='/%20di%20r%20/%20fi%20le%20')['body'] == 'blah' - ), 'file name enclosing' - - try: - Path(f'{temp_dir}/ф а').touch() - utf8 = True - - except KeyboardInterrupt: - raise - - except: - utf8 = False - - if utf8: - Path(f'{assets_dir}/ di r / fi le ').rename( - f'{assets_dir}/ di r /фа йл' - ) - assert waitforfiles(f'{assets_dir}/ di r /фа йл') - assert client.get(url='/ di r /фа йл')['body'] == 'blah' - - Path(f'{assets_dir}/ di r ').rename(f'{assets_dir}/ди ректория') - assert waitforfiles(f'{assets_dir}/ди ректория/фа йл') - assert ( - client.get(url='/ди ректория/фа йл')['body'] == 'blah' - ), 'dir name 2' - - -def test_static_unix_socket(temp_dir): - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.bind(f'{temp_dir}/assets/unix_socket') - - assert client.get(url='/unix_socket')['status'] == 404, 'socket' - - sock.close() - - -def test_static_unix_fifo(temp_dir): - os.mkfifo(f'{temp_dir}/assets/fifo') - - assert client.get(url='/fifo')['status'] == 404, 'fifo' - - -def test_static_method(): - resp = client.head() - assert resp['status'] == 200, 'HEAD status' - assert resp['body'] == '', 'HEAD empty body' - - assert client.delete()['status'] == 405, 'DELETE' - assert client.post()['status'] == 405, 'POST' - assert client.put()['status'] == 405, 'PUT' - - -def test_static_path(): - assert client.get(url='/dir/../dir/file')['status'] == 200, 'relative' - - assert client.get(url='./')['status'] == 400, 'path invalid' - assert client.get(url='../')['status'] == 400, 'path invalid 2' - assert client.get(url='/..')['status'] == 400, 'path invalid 3' - assert client.get(url='../assets/')['status'] == 400, 'path invalid 4' - assert client.get(url='/../assets/')['status'] == 400, 'path invalid 5' - - -def test_static_two_clients(): - sock = client.get(no_recv=True) - sock2 = client.get(no_recv=True) - - assert sock.recv(1) == b'H', 'client 1' - assert sock2.recv(1) == b'H', 'client 2' - assert sock.recv(1) == b'T', 'client 1 again' - assert sock2.recv(1) == b'T', 'client 2 again' - - sock.close() - sock2.close() - - -def test_static_mime_types(): - assert 'success' in client.conf( - { - "text/x-code/x-blah/x-blah": "readme", - "text/plain": [".html", ".log", "file"], - }, - 'settings/http/static/mime_types', - ), 'configure mime_types' - - assert ( - client.get(url='/README')['headers']['Content-Type'] - == 'text/x-code/x-blah/x-blah' - ), 'mime_types string case insensitive' - assert ( - client.get(url='/index.html')['headers']['Content-Type'] == 'text/plain' - ), 'mime_types html' - assert ( - client.get(url='/')['headers']['Content-Type'] == 'text/plain' - ), 'mime_types index default' - assert ( - client.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain' - ), 'mime_types file in dir' - - -def test_static_mime_types_partial_match(): - assert 'success' in client.conf( - { - "text/x-blah": ["ile", "fil", "f", "e", ".file"], - }, - 'settings/http/static/mime_types', - ), 'configure mime_types' - assert 'Content-Type' not in client.get(url='/dir/file'), 'partial match' - - -def test_static_mime_types_reconfigure(): - assert 'success' in client.conf( - { - "text/x-code": "readme", - "text/plain": [".html", ".log", "file"], - }, - 'settings/http/static/mime_types', - ), 'configure mime_types' - - assert client.conf_get('settings/http/static/mime_types') == { - 'text/x-code': 'readme', - 'text/plain': ['.html', '.log', 'file'], - }, 'mime_types get' - assert ( - client.conf_get('settings/http/static/mime_types/text%2Fx-code') - == 'readme' - ), 'mime_types get string' - assert client.conf_get('settings/http/static/mime_types/text%2Fplain') == [ - '.html', - '.log', - 'file', - ], 'mime_types get array' - assert ( - client.conf_get('settings/http/static/mime_types/text%2Fplain/1') - == '.log' - ), 'mime_types get array element' - - assert 'success' in client.conf_delete( - 'settings/http/static/mime_types/text%2Fplain/2' - ), 'mime_types remove array element' - assert ( - 'Content-Type' not in client.get(url='/dir/file')['headers'] - ), 'mime_types removed' - - assert 'success' in client.conf_post( - '"file"', 'settings/http/static/mime_types/text%2Fplain' - ), 'mime_types add array element' - assert ( - client.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain' - ), 'mime_types reverted' - - assert 'success' in client.conf( - '"file"', 'settings/http/static/mime_types/text%2Fplain' - ), 'configure mime_types update' - assert ( - client.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain' - ), 'mime_types updated' - assert ( - 'Content-Type' not in client.get(url='/log.log')['headers'] - ), 'mime_types updated 2' - - assert 'success' in client.conf( - '".log"', 'settings/http/static/mime_types/text%2Fblahblahblah' - ), 'configure mime_types create' - assert ( - client.get(url='/log.log')['headers']['Content-Type'] - == 'text/blahblahblah' - ), 'mime_types create' - - -def test_static_mime_types_correct(): - assert 'error' in client.conf( - {"text/x-code": "readme", "text/plain": "readme"}, - 'settings/http/static/mime_types', - ), 'mime_types same extensions' - assert 'error' in client.conf( - {"text/x-code": [".h", ".c"], "text/plain": ".c"}, - 'settings/http/static/mime_types', - ), 'mime_types same extensions array' - assert 'error' in client.conf( - { - "text/x-code": [".h", ".c", "readme"], - "text/plain": "README", - }, - 'settings/http/static/mime_types', - ), 'mime_types same extensions case insensitive' - - -@pytest.mark.skip('not yet') -def test_static_mime_types_invalid(temp_dir): - assert 'error' in client.http( - b"""PUT /config/settings/http/static/mime_types/%0%00% HTTP/1.1\r -Host: localhost\r -Connection: close\r -Content-Length: 6\r -\r -\"blah\"""", - raw_resp=True, - raw=True, - sock_type='unix', - addr=f'{temp_dir}/control.unit.sock', - ), 'mime_types invalid' diff --git a/test/test_static_chroot.py b/test/test_static_chroot.py deleted file mode 100644 index 31e10b4e..00000000 --- a/test/test_static_chroot.py +++ /dev/null @@ -1,165 +0,0 @@ -import os -from pathlib import Path - -import pytest - -from unit.applications.proto import ApplicationProto -from unit.option import option - -prerequisites = {'features': {'chroot': True}} - -client = ApplicationProto() -test_path = f'/{os.path.relpath(Path(__file__))}' - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - Path(f'{temp_dir}/assets/dir').mkdir(parents=True) - Path(f'{temp_dir}/assets/index.html').write_text( - '0123456789', encoding='utf-8' - ) - Path(f'{temp_dir}/assets/dir/file').write_text('blah', encoding='utf-8') - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}], - } - ) - - -def update_action(chroot, share=f'{option.temp_dir}/assets$uri'): - return client.conf( - {'chroot': chroot, 'share': share}, - 'routes/0/action', - ) - - -def get_custom(uri, host): - return client.get(url=uri, headers={'Host': host, 'Connection': 'close'})[ - 'status' - ] - - -def test_static_chroot(temp_dir): - assert client.get(url='/dir/file')['status'] == 200, 'default chroot' - assert client.get(url='/index.html')['status'] == 200, 'default chroot 2' - - assert 'success' in update_action(f'{temp_dir}/assets/dir') - - assert client.get(url='/dir/file')['status'] == 200, 'chroot' - assert client.get(url='/index.html')['status'] == 403, 'chroot 403 2' - assert client.get(url='/file')['status'] == 403, 'chroot 403' - - -def test_share_chroot_array(temp_dir): - assert 'success' in update_action( - f'{temp_dir}/assets/dir', ["/blah", f'{temp_dir}/assets$uri'] - ) - assert client.get(url='/dir/file')['status'] == 200, 'share array' - - assert 'success' in update_action( - f'{temp_dir}/assets/$host', - ['/blah', f'{temp_dir}/assets$uri'], - ) - assert get_custom('/dir/file', 'dir') == 200, 'array variable' - - assert 'success' in update_action( - f'{temp_dir}/assets/dir', ['/blah', '/blah2'] - ) - assert client.get()['status'] != 200, 'share array bad' - - -def test_static_chroot_permission(require, temp_dir): - require({'privileged_user': False}) - - os.chmod(f'{temp_dir}/assets/dir', 0o100) - - assert 'success' in update_action( - f'{temp_dir}/assets/dir' - ), 'configure chroot' - - assert client.get(url='/dir/file')['status'] == 200, 'chroot' - - -def test_static_chroot_empty(): - assert 'success' in update_action('') - assert client.get(url='/dir/file')['status'] == 200, 'empty absolute' - - assert 'success' in update_action("", ".$uri") - assert client.get(url=test_path)['status'] == 200, 'empty relative' - - -def test_static_chroot_relative(require): - require({'privileged_user': False}) - - assert 'success' in update_action('.') - assert client.get(url='/dir/file')['status'] == 403, 'relative chroot' - - assert 'success' in client.conf({"share": ".$uri"}, 'routes/0/action') - assert client.get(url=test_path)['status'] == 200, 'relative share' - - assert 'success' in update_action(".", ".$uri") - assert client.get(url=test_path)['status'] == 200, 'relative' - - -def test_static_chroot_variables(temp_dir): - assert 'success' in update_action(f'{temp_dir}/assets/$host') - assert get_custom('/dir/file', 'dir') == 200 - - assert 'success' in update_action(f'{temp_dir}/assets/${{host}}') - assert get_custom('/dir/file', 'dir') == 200 - - -def test_static_chroot_variables_buildin_start(temp_dir): - assert 'success' in update_action( - '$uri/assets/dir', - f'{temp_dir}/assets/dir/$host', - ) - assert get_custom(temp_dir, 'file') == 200 - - -def test_static_chroot_variables_buildin_mid(temp_dir): - assert 'success' in update_action(f'{temp_dir}/$host/dir') - assert get_custom('/dir/file', 'assets') == 200 - - -def test_static_chroot_variables_buildin_end(temp_dir): - assert 'success' in update_action(f'{temp_dir}/assets/$host') - assert get_custom('/dir/file', 'dir') == 200 - - -def test_static_chroot_slash(temp_dir): - assert 'success' in update_action(f'{temp_dir}/assets/dir/') - assert client.get(url='/dir/file')['status'] == 200, 'slash end' - assert client.get(url='/dirxfile')['status'] == 403, 'slash end bad' - - assert 'success' in update_action(f'{temp_dir}/assets/dir') - assert client.get(url='/dir/file')['status'] == 200, 'no slash end' - - assert 'success' in update_action(f'{temp_dir}/assets/dir/') - assert client.get(url='/dir/file')['status'] == 200, 'slash end 2' - assert client.get(url='/dirxfile')['status'] == 403, 'slash end 2 bad' - - assert 'success' in update_action( - f'{temp_dir}//assets////dir///', f'{temp_dir}///assets/////$uri' - ) - assert client.get(url='/dir/file')['status'] == 200, 'multiple slashes' - - -def test_static_chroot_invalid(temp_dir): - assert 'error' in client.conf( - {"share": temp_dir, "chroot": True}, - 'routes/0/action', - ), 'configure chroot error' - assert 'error' in client.conf( - {"share": temp_dir, "symlinks": "True"}, - 'routes/0/action', - ), 'configure symlink error' - assert 'error' in client.conf( - {"share": temp_dir, "mount": "True"}, - 'routes/0/action', - ), 'configure mount error' - - assert 'error' in update_action(f'{temp_dir}/assets/d$r$uri') - assert 'error' in update_action(f'{temp_dir}/assets/$$uri') diff --git a/test/test_static_fallback.py b/test/test_static_fallback.py deleted file mode 100644 index 9b5fcb53..00000000 --- a/test/test_static_fallback.py +++ /dev/null @@ -1,158 +0,0 @@ -import os -from pathlib import Path - -import pytest - -from unit.applications.proto import ApplicationProto - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - assets_dir = f'{temp_dir}/assets' - os.makedirs(f'{assets_dir}/dir') - Path(f'{assets_dir}/index.html').write_text('0123456789', encoding='utf-8') - - os.makedirs(f'{assets_dir}/403') - os.chmod(f'{assets_dir}/403', 0o000) - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - "*:8081": {"pass": "routes"}, - }, - "routes": [{"action": {"share": f'{assets_dir}$uri'}}], - "applications": {}, - } - ) - - yield - - try: - os.chmod(f'{assets_dir}/403', 0o777) - except FileNotFoundError: - pass - - -def action_update(conf): - assert 'success' in client.conf(conf, 'routes/0/action') - - -def test_static_fallback(): - action_update({"share": "/blah"}) - assert client.get()['status'] == 404, 'bad path no fallback' - - action_update({"share": "/blah", "fallback": {"return": 200}}) - - resp = client.get() - assert resp['status'] == 200, 'bad path fallback status' - assert resp['body'] == '', 'bad path fallback' - - -def test_static_fallback_valid_path(temp_dir): - action_update( - {"share": f"{temp_dir}/assets$uri", "fallback": {"return": 200}} - ) - resp = client.get() - assert resp['status'] == 200, 'fallback status' - assert resp['body'] == '0123456789', 'fallback' - - resp = client.get(url='/403/') - assert resp['status'] == 200, 'fallback status 403' - assert resp['body'] == '', 'fallback 403' - - resp = client.post() - assert resp['status'] == 200, 'fallback status 405' - assert resp['body'] == '', 'fallback 405' - - assert client.get(url='/dir')['status'] == 301, 'fallback status 301' - - -def test_static_fallback_nested(): - action_update( - { - "share": "/blah", - "fallback": { - "share": "/blah/blah", - "fallback": {"return": 200}, - }, - } - ) - - resp = client.get() - assert resp['status'] == 200, 'fallback nested status' - assert resp['body'] == '', 'fallback nested' - - -def test_static_fallback_share(temp_dir): - action_update( - { - "share": "/blah", - "fallback": {"share": f"{temp_dir}/assets$uri"}, - } - ) - - resp = client.get() - assert resp['status'] == 200, 'fallback share status' - assert resp['body'] == '0123456789', 'fallback share' - - resp = client.head() - assert resp['status'] == 200, 'fallback share status HEAD' - assert resp['body'] == '', 'fallback share HEAD' - - assert client.get(url='/dir')['status'] == 301, 'fallback share status 301' - - -def test_static_fallback_proxy(): - assert 'success' in client.conf( - [ - { - "match": {"destination": "*:8081"}, - "action": {"return": 200}, - }, - { - "action": { - "share": "/blah", - "fallback": {"proxy": "http://127.0.0.1:8081"}, - } - }, - ], - 'routes', - ), 'configure fallback proxy route' - - resp = client.get() - assert resp['status'] == 200, 'fallback proxy status' - assert resp['body'] == '', 'fallback proxy' - - -@pytest.mark.skip('not yet') -def test_static_fallback_proxy_loop(skip_alert): - skip_alert( - r'open.*/blah/index.html.*failed', - r'accept.*failed', - r'socket.*failed', - r'new connections are not accepted', - ) - - action_update( - {"share": "/blah", "fallback": {"proxy": "http://127.0.0.1:8080"}} - ) - client.get(no_recv=True) - - assert 'success' in client.conf_delete('listeners/*:8081') - client.get(read_timeout=1) - - -def test_static_fallback_invalid(): - def check_error(conf): - assert 'error' in client.conf(conf, 'routes/0/action') - - check_error({"share": "/blah", "fallback": {}}) - check_error({"share": "/blah", "fallback": ""}) - check_error({"return": 200, "fallback": {"share": "/blah"}}) - check_error( - {"proxy": "http://127.0.0.1:8081", "fallback": {"share": "/blah"}} - ) - check_error({"fallback": {"share": "/blah"}}) diff --git a/test/test_static_mount.py b/test/test_static_mount.py deleted file mode 100644 index 41b436e2..00000000 --- a/test/test_static_mount.py +++ /dev/null @@ -1,139 +0,0 @@ -import os -import subprocess -from pathlib import Path - -import pytest - -from unit.applications.proto import ApplicationProto - -prerequisites = {'features': {'chroot': True}, 'privileged_user': True} - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - os.makedirs(f'{temp_dir}/assets/dir/mount') - os.makedirs(f'{temp_dir}/assets/dir/dir') - os.makedirs(f'{temp_dir}/assets/mount') - Path(f'{temp_dir}/assets/index.html').write_text('index', encoding='utf-8') - Path(f'{temp_dir}/assets/dir/dir/file').write_text('file', encoding='utf-8') - Path(f'{temp_dir}/assets/mount/index.html').write_text( - 'mount', encoding='utf-8' - ) - - try: - subprocess.check_output( - [ - "mount", - "--bind", - f'{temp_dir}/assets/mount', - f'{temp_dir}/assets/dir/mount', - ], - stderr=subprocess.STDOUT, - ) - - except KeyboardInterrupt: - raise - - except subprocess.CalledProcessError: - pytest.fail("Can't run mount process.") - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"share": f'{temp_dir}/assets/dir$uri'}}], - } - ) - - yield - - try: - subprocess.check_output( - ["umount", "--lazy", f'{temp_dir}/assets/dir/mount'], - stderr=subprocess.STDOUT, - ) - - except KeyboardInterrupt: - raise - - except subprocess.CalledProcessError: - pytest.fail("Can't run umount process.") - - -def test_static_mount(temp_dir, skip_alert): - skip_alert(r'opening.*failed') - - resp = client.get(url='/mount/') - assert resp['status'] == 200 - assert resp['body'] == 'mount' - - assert 'success' in client.conf( - {"share": f'{temp_dir}/assets/dir$uri', "traverse_mounts": False}, - 'routes/0/action', - ), 'configure mount disable' - - assert client.get(url='/mount/')['status'] == 403 - - assert 'success' in client.conf( - {"share": f'{temp_dir}/assets/dir$uri', "traverse_mounts": True}, - 'routes/0/action', - ), 'configure mount enable' - - resp = client.get(url='/mount/') - assert resp['status'] == 200 - assert resp['body'] == 'mount' - - -def test_static_mount_two_blocks(temp_dir, skip_alert): - skip_alert(r'opening.*failed') - - os.symlink(f'{temp_dir}/assets/dir', f'{temp_dir}/assets/link') - - assert 'success' in client.conf( - [ - { - "match": {"method": "HEAD"}, - "action": { - "share": f'{temp_dir}/assets/dir$uri', - "traverse_mounts": False, - }, - }, - { - "match": {"method": "GET"}, - "action": { - "share": f'{temp_dir}/assets/dir$uri', - "traverse_mounts": True, - }, - }, - ], - 'routes', - ), 'configure two options' - - assert client.get(url='/mount/')['status'] == 200, 'block enabled' - assert client.head(url='/mount/')['status'] == 403, 'block disabled' - - -def test_static_mount_chroot(temp_dir, skip_alert): - skip_alert(r'opening.*failed') - - assert 'success' in client.conf( - { - "share": f'{temp_dir}/assets/dir$uri', - "chroot": f'{temp_dir}/assets', - }, - 'routes/0/action', - ), 'configure chroot mount default' - - assert client.get(url='/mount/')['status'] == 200, 'chroot' - - assert 'success' in client.conf( - { - "share": f'{temp_dir}/assets/dir$uri', - "chroot": f'{temp_dir}/assets', - "traverse_mounts": False, - }, - 'routes/0/action', - ), 'configure chroot mount disable' - - assert client.get(url='/mount/')['status'] == 403, 'chroot mount' diff --git a/test/test_static_share.py b/test/test_static_share.py deleted file mode 100644 index ee53fe9b..00000000 --- a/test/test_static_share.py +++ /dev/null @@ -1,74 +0,0 @@ -import os -from pathlib import Path - -import pytest - -from unit.applications.proto import ApplicationProto - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - os.makedirs(f'{temp_dir}/assets/dir') - os.makedirs(f'{temp_dir}/assets/dir2') - - Path(f'{temp_dir}/assets/dir/file').write_text('1', encoding='utf-8') - Path(f'{temp_dir}/assets/dir2/file2').write_text('2', encoding='utf-8') - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}], - "applications": {}, - } - ) - - -def action_update(conf): - assert 'success' in client.conf(conf, 'routes/0/action') - - -def test_share_array(temp_dir): - assert client.get(url='/dir/file')['body'] == '1' - assert client.get(url='/dir2/file2')['body'] == '2' - - action_update({"share": [f'{temp_dir}/assets/dir$uri']}) - - assert client.get(url='/file')['body'] == '1' - assert client.get(url='/file2')['status'] == 404 - - action_update( - { - "share": [ - f'{temp_dir}/assets/dir$uri', - f'{temp_dir}/assets/dir2$uri', - ] - } - ) - - assert client.get(url='/file')['body'] == '1' - assert client.get(url='/file2')['body'] == '2' - - action_update( - { - "share": [ - f'{temp_dir}/assets/dir2$uri', - f'{temp_dir}/assets/dir3$uri', - ] - } - ) - - assert client.get(url='/file')['status'] == 404 - assert client.get(url='/file2')['body'] == '2' - - -def test_share_array_fallback(): - action_update({"share": ["/blah", "/blah2"], "fallback": {"return": 201}}) - - assert client.get()['status'] == 201 - - -def test_share_array_invalid(): - assert 'error' in client.conf({"share": []}, 'routes/0/action') - assert 'error' in client.conf({"share": {}}, 'routes/0/action') diff --git a/test/test_static_symlink.py b/test/test_static_symlink.py deleted file mode 100644 index 2d402d48..00000000 --- a/test/test_static_symlink.py +++ /dev/null @@ -1,98 +0,0 @@ -import os -from pathlib import Path - -import pytest - -from unit.applications.proto import ApplicationProto - -prerequisites = {'features': {'chroot': True}} - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - os.makedirs(f'{temp_dir}/assets/dir/dir') - Path(f'{temp_dir}/assets/index.html').write_text( - '0123456789', encoding='utf-8' - ) - Path(f'{temp_dir}/assets/dir/file').write_text('blah', encoding='utf-8') - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}], - } - ) - - -def test_static_symlink(temp_dir, skip_alert): - skip_alert(r'opening.*failed') - - os.symlink(f'{temp_dir}/assets/dir', f'{temp_dir}/assets/link') - - assert client.get(url='/dir')['status'] == 301, 'dir' - assert client.get(url='/dir/file')['status'] == 200, 'file' - assert client.get(url='/link')['status'] == 301, 'symlink dir' - assert client.get(url='/link/file')['status'] == 200, 'symlink file' - - assert 'success' in client.conf( - {"share": f'{temp_dir}/assets$uri', "follow_symlinks": False}, - 'routes/0/action', - ), 'configure symlink disable' - - assert client.get(url='/link/file')['status'] == 403, 'symlink disabled' - - assert 'success' in client.conf( - {"share": f'{temp_dir}/assets$uri', "follow_symlinks": True}, - 'routes/0/action', - ), 'configure symlink enable' - - assert client.get(url='/link/file')['status'] == 200, 'symlink enabled' - - -def test_static_symlink_two_blocks(temp_dir, skip_alert): - skip_alert(r'opening.*failed') - - os.symlink(f'{temp_dir}/assets/dir', f'{temp_dir}/assets/link') - - assert 'success' in client.conf( - [ - { - "match": {"method": "HEAD"}, - "action": { - "share": f'{temp_dir}/assets$uri', - "follow_symlinks": False, - }, - }, - { - "match": {"method": "GET"}, - "action": { - "share": f'{temp_dir}/assets$uri', - "follow_symlinks": True, - }, - }, - ], - 'routes', - ), 'configure two options' - - assert client.get(url='/link/file')['status'] == 200, 'block enabled' - assert client.head(url='/link/file')['status'] == 403, 'block disabled' - - -def test_static_symlink_chroot(temp_dir, skip_alert): - skip_alert(r'opening.*failed') - - os.symlink(f'{temp_dir}/assets/dir/file', f'{temp_dir}/assets/dir/dir/link') - - assert client.get(url='/dir/dir/link')['status'] == 200, 'default chroot' - - assert 'success' in client.conf( - { - "share": f'{temp_dir}/assets$uri', - "chroot": f'{temp_dir}/assets/dir/dir', - }, - 'routes/0/action', - ), 'configure chroot' - - assert client.get(url='/dir/dir/link')['status'] == 404, 'chroot' diff --git a/test/test_static_types.py b/test/test_static_types.py deleted file mode 100644 index e931d949..00000000 --- a/test/test_static_types.py +++ /dev/null @@ -1,174 +0,0 @@ -from pathlib import Path - -import pytest - -from unit.applications.proto import ApplicationProto - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - Path(f'{temp_dir}/assets').mkdir() - for ext in ['.xml', '.mp4', '.php', '', '.txt', '.html', '.png']: - Path(f'{temp_dir}/assets/file{ext}').write_text(ext, encoding='utf-8') - - Path(f'{temp_dir}/assets/index.html').write_text('index', encoding='utf-8') - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - "*:8081": {"pass": "routes"}, - }, - "routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}], - "applications": {}, - } - ) - - -def action_update(conf): - assert 'success' in client.conf(conf, 'routes/0/action') - - -def check_body(http_url, body): - resp = client.get(url=http_url) - assert resp['status'] == 200, 'status' - assert resp['body'] == body, 'body' - - -def test_static_types_basic(temp_dir): - action_update({"share": f'{temp_dir}/assets$uri'}) - check_body('/index.html', 'index') - check_body('/file.xml', '.xml') - - action_update( - {"share": f'{temp_dir}/assets$uri', "types": "application/xml"} - ) - check_body('/file.xml', '.xml') - - action_update( - {"share": f'{temp_dir}/assets$uri', "types": ["application/xml"]} - ) - check_body('/file.xml', '.xml') - - action_update({"share": f'{temp_dir}/assets$uri', "types": [""]}) - assert client.get(url='/file.xml')['status'] == 403, 'no mtype' - - -def test_static_types_wildcard(temp_dir): - action_update( - {"share": f'{temp_dir}/assets$uri', "types": ["application/*"]} - ) - check_body('/file.xml', '.xml') - assert client.get(url='/file.mp4')['status'] == 403, 'app * mtype mp4' - - action_update({"share": f'{temp_dir}/assets$uri', "types": ["video/*"]}) - assert client.get(url='/file.xml')['status'] == 403, 'video * mtype xml' - check_body('/file.mp4', '.mp4') - - -def test_static_types_negation(temp_dir): - action_update( - {"share": f'{temp_dir}/assets$uri', "types": ["!application/xml"]} - ) - assert client.get(url='/file.xml')['status'] == 403, 'forbidden negation' - check_body('/file.mp4', '.mp4') - - # sorting negation - action_update( - { - "share": f'{temp_dir}/assets$uri', - "types": ["!video/*", "image/png", "!image/jpg"], - } - ) - assert client.get(url='/file.mp4')['status'] == 403, 'negation sort mp4' - check_body('/file.png', '.png') - assert client.get(url='/file.jpg')['status'] == 403, 'negation sort jpg' - - -def test_static_types_regex(temp_dir): - action_update( - { - "share": f'{temp_dir}/assets$uri', - "types": ["~text/(html|plain)"], - } - ) - assert client.get(url='/file.php')['status'] == 403, 'regex fail' - check_body('/file.html', '.html') - check_body('/file.txt', '.txt') - - -def test_static_types_case(temp_dir): - action_update( - {"share": f'{temp_dir}/assets$uri', "types": ["!APpliCaTiOn/xMl"]} - ) - check_body('/file.mp4', '.mp4') - assert ( - client.get(url='/file.xml')['status'] == 403 - ), 'mixed case xml negation' - - action_update({"share": f'{temp_dir}/assets$uri', "types": ["vIdEo/mp4"]}) - assert client.get(url='/file.mp4')['status'] == 200, 'mixed case' - assert ( - client.get(url='/file.xml')['status'] == 403 - ), 'mixed case video negation' - - action_update({"share": f'{temp_dir}/assets$uri', "types": ["vIdEo/*"]}) - check_body('/file.mp4', '.mp4') - assert ( - client.get(url='/file.xml')['status'] == 403 - ), 'mixed case video * negation' - - -def test_static_types_fallback(temp_dir): - assert 'success' in client.conf( - [ - { - "match": {"destination": "*:8081"}, - "action": {"return": 200}, - }, - { - "action": { - "share": f'{temp_dir}/assets$uri', - "types": ["!application/x-httpd-php"], - "fallback": {"proxy": "http://127.0.0.1:8081"}, - } - }, - ], - 'routes', - ), 'configure fallback proxy route' - - check_body('/file.php', '') - check_body('/file.mp4', '.mp4') - - -def test_static_types_index(temp_dir): - action_update( - {"share": f'{temp_dir}/assets$uri', "types": "application/xml"} - ) - check_body('/', 'index') - check_body('/file.xml', '.xml') - assert client.get(url='/index.html')['status'] == 403, 'forbidden mtype' - assert client.get(url='/file.mp4')['status'] == 403, 'forbidden mtype' - - -def test_static_types_custom_mime(temp_dir): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}], - "applications": {}, - "settings": { - "http": {"static": {"mime_types": {"test/mime-type": ["file"]}}} - }, - } - ) - - action_update({"share": f'{temp_dir}/assets$uri', "types": [""]}) - assert client.get(url='/file')['status'] == 403, 'forbidden custom mime' - - action_update( - {"share": f'{temp_dir}/assets$uri', "types": ["test/mime-type"]} - ) - check_body('/file', '') diff --git a/test/test_static_variables.py b/test/test_static_variables.py deleted file mode 100644 index 62753750..00000000 --- a/test/test_static_variables.py +++ /dev/null @@ -1,86 +0,0 @@ -import os -from pathlib import Path - -import pytest - -from unit.applications.proto import ApplicationProto - -client = ApplicationProto() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(temp_dir): - os.makedirs(f'{temp_dir}/assets/dir') - os.makedirs(f'{temp_dir}/assets/d$r') - Path(f'{temp_dir}/assets/index.html').write_text( - '0123456789', encoding='utf-8' - ) - Path(f'{temp_dir}/assets/dir/file').write_text('file', encoding='utf-8') - Path(f'{temp_dir}/assets/d$r/file').write_text('d$r', encoding='utf-8') - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}], - } - ) - - -def update_share(share): - if isinstance(share, list): - return client.conf(share, 'routes/0/action/share') - - return client.conf(f'"{share}"', 'routes/0/action/share') - - -def test_static_variables(temp_dir): - assert client.get(url='/index.html')['status'] == 200 - assert client.get(url='/d$r/file')['status'] == 200 - - assert 'success' in update_share('$uri') - assert client.get(url=f'{temp_dir}/assets/index.html')['status'] == 200 - - assert 'success' in update_share(f'{temp_dir}/assets${{uri}}') - assert client.get(url='/index.html')['status'] == 200 - - -def test_static_variables_array(temp_dir): - assert 'success' in update_share([f'{temp_dir}/assets$uri', '$uri']) - - assert client.get(url='/dir/file')['status'] == 200 - assert client.get(url=f'{temp_dir}/assets/index.html')['status'] == 200 - assert client.get(url='/blah')['status'] == 404 - - assert 'success' in client.conf( - { - "share": [f'{temp_dir}/assets$uri', '$uri'], - "fallback": {"return": 201}, - }, - 'routes/0/action', - ) - - assert client.get(url='/dir/file')['status'] == 200 - assert client.get(url=f'{temp_dir}/assets/index.html')['status'] == 200 - assert client.get(url='/dir/blah')['status'] == 201 - - -def test_static_variables_buildin_start(temp_dir): - assert 'success' in update_share('$uri/assets/index.html') - assert client.get(url=temp_dir)['status'] == 200 - - -def test_static_variables_buildin_mid(temp_dir): - assert 'success' in update_share(f'{temp_dir}$uri/index.html') - assert client.get(url='/assets')['status'] == 200 - - -def test_static_variables_buildin_end(): - assert client.get(url='/index.html')['status'] == 200 - - -def test_static_variables_invalid(temp_dir): - assert 'error' in update_share(f'{temp_dir}/assets/d$r$uri') - assert 'error' in update_share(f'{temp_dir}/assets/$$uri') - assert 'error' in update_share( - [f'{temp_dir}/assets$uri', f'{temp_dir}/assets/dir', '$$uri'] - ) diff --git a/test/test_status.py b/test/test_status.py deleted file mode 100644 index a52f7486..00000000 --- a/test/test_status.py +++ /dev/null @@ -1,242 +0,0 @@ -import time - -from unit.applications.lang.python import ApplicationPython -from unit.option import option -from unit.status import Status - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -def check_connections(accepted, active, idle, closed): - assert Status.get('/connections') == { - 'accepted': accepted, - 'active': active, - 'idle': idle, - 'closed': closed, - } - - -def app_default(name="empty", module="wsgi"): - name_dir = f'{option.test_dir}/python/{name}' - return { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": name_dir, - "working_directory": name_dir, - "module": module, - } - - -def test_status(): - assert 'error' in client.conf_delete('/status'), 'DELETE method' - - -def test_status_requests(skip_alert): - skip_alert(r'Python failed to import module "blah"') - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - "*:8081": {"pass": "applications/empty"}, - "*:8082": {"pass": "applications/blah"}, - }, - "routes": [{"action": {"return": 200}}], - "applications": { - "empty": app_default(), - "blah": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "module": "blah", - }, - }, - }, - ) - - Status.init() - - assert client.get()['status'] == 200 - assert Status.get('/requests/total') == 1, '2xx' - - assert client.get(port=8081)['status'] == 200 - assert Status.get('/requests/total') == 2, '2xx app' - - assert ( - client.get(headers={'Host': '/', 'Connection': 'close'})['status'] - == 400 - ) - assert Status.get('/requests/total') == 3, '4xx' - - assert client.get(port=8082)['status'] == 503 - assert Status.get('/requests/total') == 4, '5xx' - - client.http( - b"""GET / HTTP/1.1 -Host: localhost - -GET / HTTP/1.1 -Host: localhost -Connection: close - -""", - raw=True, - ) - assert Status.get('/requests/total') == 6, 'pipeline' - - sock = client.get(port=8081, no_recv=True) - - time.sleep(1) - - assert Status.get('/requests/total') == 7, 'no receive' - - sock.close() - - -def test_status_connections(): - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - "*:8081": {"pass": "applications/delayed"}, - }, - "routes": [{"action": {"return": 200}}], - "applications": { - "delayed": app_default("delayed"), - }, - }, - ) - - Status.init() - - # accepted, closed - - assert client.get()['status'] == 200 - check_connections(1, 0, 0, 1) - - # idle - - (_, sock) = client.get( - headers={'Host': 'localhost', 'Connection': 'keep-alive'}, - start=True, - read_timeout=1, - ) - - check_connections(2, 0, 1, 1) - - client.get(sock=sock) - check_connections(2, 0, 0, 2) - - # active - - (_, sock) = client.get( - headers={ - 'Host': 'localhost', - 'X-Delay': '2', - 'Connection': 'close', - }, - port=8081, - start=True, - read_timeout=1, - ) - check_connections(3, 1, 0, 2) - - client.get(sock=sock) - check_connections(3, 0, 0, 3) - - -def test_status_applications(): - def check_applications(expert): - apps = list(client.conf_get('/status/applications').keys()).sort() - assert apps == expert.sort() - - def check_application(name, running, starting, idle, active): - assert Status.get(f'/applications/{name}') == { - 'processes': { - 'running': running, - 'starting': starting, - 'idle': idle, - }, - 'requests': {'active': active}, - } - - client.load('delayed') - Status.init() - - check_applications(['delayed']) - check_application('delayed', 0, 0, 0, 0) - - # idle - - assert client.get()['status'] == 200 - check_application('delayed', 1, 0, 1, 0) - - assert 'success' in client.conf('4', 'applications/delayed/processes') - check_application('delayed', 4, 0, 4, 0) - - # active - - (_, sock) = client.get( - headers={ - 'Host': 'localhost', - 'X-Delay': '2', - 'Connection': 'close', - }, - start=True, - read_timeout=1, - ) - check_application('delayed', 4, 0, 3, 1) - sock.close() - - # starting - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "applications/restart"}, - "*:8081": {"pass": "applications/delayed"}, - }, - "routes": [], - "applications": { - "restart": app_default("restart", "longstart"), - "delayed": app_default("delayed"), - }, - }, - ) - Status.init() - - check_applications(['delayed', 'restart']) - check_application('restart', 0, 0, 0, 0) - check_application('delayed', 0, 0, 0, 0) - - client.get(read_timeout=1) - - check_application('restart', 0, 1, 0, 1) - check_application('delayed', 0, 0, 0, 0) - - -def test_status_proxy(): - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - "*:8081": {"pass": "applications/empty"}, - }, - "routes": [ - { - "match": {"uri": "/"}, - "action": {"proxy": "http://127.0.0.1:8081"}, - } - ], - "applications": { - "empty": app_default(), - }, - }, - ) - - Status.init() - - assert client.get()['status'] == 200 - check_connections(2, 0, 0, 2) - assert Status.get('/requests/total') == 2, 'proxy' diff --git a/test/test_status_tls.py b/test/test_status_tls.py deleted file mode 100644 index f69f021e..00000000 --- a/test/test_status_tls.py +++ /dev/null @@ -1,31 +0,0 @@ -from unit.applications.tls import ApplicationTLS -from unit.status import Status - -prerequisites = {'modules': {'openssl': 'any'}} - -client = ApplicationTLS() - - -def test_status_tls_requests(): - client.certificate() - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "routes"}, - "*:8081": { - "pass": "routes", - "tls": {"certificate": "default"}, - }, - }, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ) - - Status.init() - - assert client.get()['status'] == 200 - assert client.get_ssl(port=8081)['status'] == 200 - - assert Status.get('/requests/total') == 2 diff --git a/test/test_tls.py b/test/test_tls.py deleted file mode 100644 index 09921773..00000000 --- a/test/test_tls.py +++ /dev/null @@ -1,703 +0,0 @@ -import io -import ssl -import subprocess -import time -from pathlib import Path - -import pytest - -from unit.applications.tls import ApplicationTLS -from unit.option import option - -prerequisites = {'modules': {'python': 'any', 'openssl': 'any'}} - -client = ApplicationTLS() - - -def add_tls(application='empty', cert='default', port=8080): - assert 'success' in client.conf( - { - "pass": f"applications/{application}", - "tls": {"certificate": cert}, - }, - f'listeners/*:{port}', - ) - - -def ca(cert='root', out='localhost'): - subprocess.check_output( - [ - 'openssl', - 'ca', - '-batch', - '-config', - f'{option.temp_dir}/ca.conf', - '-keyfile', - f'{option.temp_dir}/{cert}.key', - '-cert', - f'{option.temp_dir}/{cert}.crt', - '-in', - f'{option.temp_dir}/{out}.csr', - '-out', - f'{option.temp_dir}/{out}.crt', - ], - stderr=subprocess.STDOUT, - ) - - -def context_cert_req(cert='root'): - context = ssl.create_default_context() - context.check_hostname = False - context.verify_mode = ssl.CERT_REQUIRED - context.load_verify_locations(f'{option.temp_dir}/{cert}.crt') - - return context - - -def generate_ca_conf(): - Path(f'{option.temp_dir}/ca.conf').write_text( - f"""[ ca ] -default_ca = myca - -[ myca ] -new_certs_dir = {option.temp_dir} -database = {option.temp_dir}/certindex -default_md = sha256 -policy = myca_policy -serial = {option.temp_dir}/certserial -default_days = 1 -x509_extensions = myca_extensions -copy_extensions = copy - -[ myca_policy ] -commonName = optional - -[ myca_extensions ] -basicConstraints = critical,CA:TRUE""", - encoding='utf-8', - ) - - Path(f'{option.temp_dir}/certserial').write_text('1000', encoding='utf-8') - Path(f'{option.temp_dir}/certindex').touch() - Path(f'{option.temp_dir}/certindex.attr').touch() - - -def remove_tls(application='empty', port=8080): - assert 'success' in client.conf( - {"pass": f"applications/{application}"}, f'listeners/*:{port}' - ) - - -def req(name='localhost', subject=None): - subj = subject if subject is not None else f'/CN={name}/' - - subprocess.check_output( - [ - 'openssl', - 'req', - '-new', - '-subj', - subj, - '-config', - f'{option.temp_dir}/openssl.conf', - '-out', - f'{option.temp_dir}/{name}.csr', - '-keyout', - f'{option.temp_dir}/{name}.key', - ], - stderr=subprocess.STDOUT, - ) - - -def test_tls_listener_option_add(): - client.load('empty') - - client.certificate() - - add_tls() - - assert client.get_ssl()['status'] == 200, 'add listener option' - - -def test_tls_listener_option_remove(): - client.load('empty') - - client.certificate() - - add_tls() - - client.get_ssl() - - remove_tls() - - assert client.get()['status'] == 200, 'remove listener option' - - -def test_tls_certificate_remove(): - client.load('empty') - - client.certificate() - - assert 'success' in client.conf_delete( - '/certificates/default' - ), 'remove certificate' - - -def test_tls_certificate_remove_used(): - client.load('empty') - - client.certificate() - - add_tls() - - assert 'error' in client.conf_delete( - '/certificates/default' - ), 'remove certificate' - - -def test_tls_certificate_remove_nonexisting(): - client.load('empty') - - client.certificate() - - add_tls() - - assert 'error' in client.conf_delete( - '/certificates/blah' - ), 'remove nonexistings certificate' - - -@pytest.mark.skip('not yet') -def test_tls_certificate_update(): - client.load('empty') - - client.certificate() - - add_tls() - - cert_old = ssl.get_server_certificate(('127.0.0.1', 8080)) - - client.certificate() - - assert cert_old != ssl.get_server_certificate( - ('127.0.0.1', 8080) - ), 'update certificate' - - -@pytest.mark.skip('not yet') -def test_tls_certificate_key_incorrect(): - client.load('empty') - - client.certificate('first', False) - client.certificate('second', False) - - assert 'error' in client.certificate_load( - 'first', 'second' - ), 'key incorrect' - - -def test_tls_certificate_change(): - client.load('empty') - - client.certificate() - client.certificate('new') - - add_tls() - - cert_old = ssl.get_server_certificate(('127.0.0.1', 8080)) - - add_tls(cert='new') - - assert cert_old != ssl.get_server_certificate( - ('127.0.0.1', 8080) - ), 'change certificate' - - -def test_tls_certificate_key_rsa(): - client.load('empty') - - client.certificate() - - assert ( - client.conf_get('/certificates/default/key') == 'RSA (2048 bits)' - ), 'certificate key rsa' - - -def test_tls_certificate_key_ec(temp_dir): - client.load('empty') - - client.openssl_conf() - - subprocess.check_output( - [ - 'openssl', - 'ecparam', - '-noout', - '-genkey', - '-out', - f'{temp_dir}/ec.key', - '-name', - 'prime256v1', - ], - stderr=subprocess.STDOUT, - ) - - subprocess.check_output( - [ - 'openssl', - 'req', - '-x509', - '-new', - '-subj', - '/CN=ec/', - '-config', - f'{temp_dir}/openssl.conf', - '-key', - f'{temp_dir}/ec.key', - '-out', - f'{temp_dir}/ec.crt', - ], - stderr=subprocess.STDOUT, - ) - - client.certificate_load('ec') - - assert ( - client.conf_get('/certificates/ec/key') == 'ECDH' - ), 'certificate key ec' - - -def test_tls_certificate_chain_options(date_to_sec_epoch, sec_epoch): - client.load('empty') - date_format = '%b %d %X %Y %Z' - - client.certificate() - - chain = client.conf_get('/certificates/default/chain') - - assert len(chain) == 1, 'certificate chain length' - - cert = chain[0] - - assert ( - cert['subject']['common_name'] == 'default' - ), 'certificate subject common name' - assert ( - cert['issuer']['common_name'] == 'default' - ), 'certificate issuer common name' - - assert ( - abs( - sec_epoch - - date_to_sec_epoch(cert['validity']['since'], date_format) - ) - < 60 - ), 'certificate validity since' - assert ( - date_to_sec_epoch(cert['validity']['until'], date_format) - - date_to_sec_epoch(cert['validity']['since'], date_format) - == 2592000 - ), 'certificate validity until' - - -def test_tls_certificate_chain(temp_dir): - client.load('empty') - - client.certificate('root', False) - - req('int') - req('end') - - generate_ca_conf() - - ca(cert='root', out='int') - ca(cert='int', out='end') - - crt_path = f'{temp_dir}/end-int.crt' - end_path = f'{temp_dir}/end.crt' - int_path = f'{temp_dir}/int.crt' - - with open(crt_path, 'wb') as crt, open(end_path, 'rb') as end, open( - int_path, 'rb' - ) as inter: - crt.write(end.read() + inter.read()) - - # incomplete chain - - assert 'success' in client.certificate_load( - 'end', 'end' - ), 'certificate chain end upload' - - chain = client.conf_get('/certificates/end/chain') - assert len(chain) == 1, 'certificate chain end length' - assert ( - chain[0]['subject']['common_name'] == 'end' - ), 'certificate chain end subject common name' - assert ( - chain[0]['issuer']['common_name'] == 'int' - ), 'certificate chain end issuer common name' - - add_tls(cert='end') - - ctx_cert_req = context_cert_req() - try: - resp = client.get_ssl(context=ctx_cert_req) - except ssl.SSLError: - resp = None - - assert resp is None, 'certificate chain incomplete chain' - - # intermediate - - assert 'success' in client.certificate_load( - 'int', 'int' - ), 'certificate chain int upload' - - chain = client.conf_get('/certificates/int/chain') - assert len(chain) == 1, 'certificate chain int length' - assert ( - chain[0]['subject']['common_name'] == 'int' - ), 'certificate chain int subject common name' - assert ( - chain[0]['issuer']['common_name'] == 'root' - ), 'certificate chain int issuer common name' - - add_tls(cert='int') - - assert client.get_ssl()['status'] == 200, 'certificate chain intermediate' - - # intermediate server - - assert 'success' in client.certificate_load( - 'end-int', 'end' - ), 'certificate chain end-int upload' - - chain = client.conf_get('/certificates/end-int/chain') - assert len(chain) == 2, 'certificate chain end-int length' - assert ( - chain[0]['subject']['common_name'] == 'end' - ), 'certificate chain end-int int subject common name' - assert ( - chain[0]['issuer']['common_name'] == 'int' - ), 'certificate chain end-int int issuer common name' - assert ( - chain[1]['subject']['common_name'] == 'int' - ), 'certificate chain end-int end subject common name' - assert ( - chain[1]['issuer']['common_name'] == 'root' - ), 'certificate chain end-int end issuer common name' - - add_tls(cert='end-int') - - assert ( - client.get_ssl(context=ctx_cert_req)['status'] == 200 - ), 'certificate chain intermediate server' - - -def test_tls_certificate_chain_long(temp_dir): - client.load('empty') - - generate_ca_conf() - - # Minimum chain length is 3. - chain_length = 10 - - for i in range(chain_length): - if i == 0: - client.certificate('root', False) - elif i == chain_length - 1: - req('end') - else: - req(f'int{i}') - - for i in range(chain_length - 1): - if i == 0: - ca(cert='root', out='int1') - elif i == chain_length - 2: - ca(cert=f'int{(chain_length - 2)}', out='end') - else: - ca(cert=f'int{i}', out=f'int{(i + 1)}') - - for i in range(chain_length - 1, 0, -1): - path = ( - f'{temp_dir}/end.crt' - if i == chain_length - 1 - else f'{temp_dir}/int{i}.crt' - ) - - with open(f'{temp_dir}/all.crt', 'a', encoding='utf-8') as chain, open( - path, encoding='utf-8' - ) as cert: - chain.write(cert.read()) - - assert 'success' in client.certificate_load( - 'all', 'end' - ), 'certificate chain upload' - - chain = client.conf_get('/certificates/all/chain') - assert len(chain) == chain_length - 1, 'certificate chain length' - - add_tls(cert='all') - - assert ( - client.get_ssl(context=context_cert_req())['status'] == 200 - ), 'certificate chain long' - - -def test_tls_certificate_empty_cn(): - client.certificate('root', False) - - req(subject='/') - - generate_ca_conf() - ca() - - assert 'success' in client.certificate_load('localhost', 'localhost') - - cert = client.conf_get('/certificates/localhost') - assert cert['chain'][0]['subject'] == {}, 'empty subject' - assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer' - - -def test_tls_certificate_empty_cn_san(): - client.certificate('root', False) - - client.openssl_conf( - rewrite=True, alt_names=["example.com", "www.example.net"] - ) - - req(subject='/') - - generate_ca_conf() - ca() - - assert 'success' in client.certificate_load('localhost', 'localhost') - - cert = client.conf_get('/certificates/localhost') - assert cert['chain'][0]['subject'] == { - 'alt_names': ['example.com', 'www.example.net'] - }, 'subject alt_names' - assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer' - - -def test_tls_certificate_empty_cn_san_ip(): - client.certificate('root', False) - - client.openssl_conf( - rewrite=True, - alt_names=['example.com', 'www.example.net', 'IP|10.0.0.1'], - ) - - req(subject='/') - - generate_ca_conf() - ca() - - assert 'success' in client.certificate_load('localhost', 'localhost') - - cert = client.conf_get('/certificates/localhost') - assert cert['chain'][0]['subject'] == { - 'alt_names': ['example.com', 'www.example.net'] - }, 'subject alt_names' - assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer' - - -def test_tls_keepalive(): - client.load('mirror') - - assert client.get()['status'] == 200, 'init' - - client.certificate() - - add_tls(application='mirror') - - (resp, sock) = client.post_ssl( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body='0123456789', - read_timeout=1, - ) - - assert resp['body'] == '0123456789', 'keepalive 1' - - resp = client.post_ssl( - headers={ - 'Host': 'localhost', - 'Connection': 'close', - }, - sock=sock, - body='0123456789', - ) - - assert resp['body'] == '0123456789', 'keepalive 2' - - -def test_tls_no_close_notify(): - client.certificate() - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": { - "pass": "routes", - "tls": {"certificate": "default"}, - } - }, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ), 'load application configuration' - - (_, sock) = client.get_ssl(start=True) - - time.sleep(5) - - sock.close() - - -@pytest.mark.skip('not yet') -def test_tls_keepalive_certificate_remove(): - client.load('empty') - - assert client.get()['status'] == 200, 'init' - - client.certificate() - - add_tls() - - (resp, sock) = client.get_ssl( - headers={'Host': 'localhost', 'Connection': 'keep-alive'}, - start=True, - read_timeout=1, - ) - - assert 'success' in client.conf( - {"pass": "applications/empty"}, 'listeners/*:8080' - ) - assert 'success' in client.conf_delete('/certificates/default') - - try: - resp = client.get_ssl(sock=sock) - - except KeyboardInterrupt: - raise - - except: - resp = None - - assert resp is None, 'keepalive remove certificate' - - -@pytest.mark.skip('not yet') -def test_tls_certificates_remove_all(): - client.load('empty') - - client.certificate() - - assert 'success' in client.conf_delete( - '/certificates' - ), 'remove all certificates' - - -def test_tls_application_respawn(findall, skip_alert, wait_for_record): - client.load('mirror') - - client.certificate() - - assert 'success' in client.conf('1', 'applications/mirror/processes') - - add_tls(application='mirror') - - (_, sock) = client.post_ssl( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body='0123456789', - read_timeout=1, - ) - - app_id = findall(r'(\d+)#\d+ "mirror" application started')[0] - - subprocess.check_output(['kill', '-9', app_id]) - - skip_alert(fr'process {app_id} exited on signal 9') - - wait_for_record(fr' (?!{app_id}#)(\d+)#\d+ "mirror" application started') - - resp = client.post_ssl(sock=sock, body='0123456789') - - assert resp['status'] == 200, 'application respawn status' - assert resp['body'] == '0123456789', 'application respawn body' - - -def test_tls_url_scheme(): - client.load('variables') - - assert ( - client.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Custom-Header': '', - 'Connection': 'close', - } - )['headers']['Wsgi-Url-Scheme'] - == 'http' - ), 'url scheme http' - - client.certificate() - - add_tls(application='variables') - - assert ( - client.post_ssl( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Custom-Header': '', - 'Connection': 'close', - } - )['headers']['Wsgi-Url-Scheme'] - == 'https' - ), 'url scheme https' - - -def test_tls_big_upload(): - client.load('upload') - - client.certificate() - - add_tls(application='upload') - - filename = 'test.txt' - data = '0123456789' * 9000 - - res = client.post_ssl( - body={ - 'file': { - 'filename': filename, - 'type': 'text/plain', - 'data': io.StringIO(data), - } - } - ) - assert res['status'] == 200, 'status ok' - assert res['body'] == f'{filename}{data}' - - -def test_tls_multi_listener(): - client.load('empty') - - client.certificate() - - add_tls() - add_tls(port=8081) - - assert client.get_ssl()['status'] == 200, 'listener #1' - - assert client.get_ssl(port=8081)['status'] == 200, 'listener #2' diff --git a/test/test_tls_conf_command.py b/test/test_tls_conf_command.py deleted file mode 100644 index 5a9a3f32..00000000 --- a/test/test_tls_conf_command.py +++ /dev/null @@ -1,119 +0,0 @@ -import ssl - -import pytest - -from unit.applications.tls import ApplicationTLS - -prerequisites = {'modules': {'openssl': 'any'}} - -client = ApplicationTLS() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - client.certificate() - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": { - "pass": "routes", - "tls": {"certificate": "default"}, - } - }, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ), 'load application configuration' - - -def test_tls_conf_command(): - def check_no_connection(): - try: - client.get_ssl() - pytest.fail('Unexpected connection.') - - except (ssl.SSLError, ConnectionRefusedError): - pass - - # Set one conf_commands (disable protocol). - - (_, sock) = client.get_ssl(start=True) - - shared_ciphers = sock.shared_ciphers() - - if not shared_ciphers: - pytest.skip('no shared ciphers') - - protocols = list(set(c[1] for c in shared_ciphers)) - protocol = sock.cipher()[1] - - if '/' in protocol: - pytest.skip('Complex protocol format.') - - assert 'success' in client.conf( - { - "certificate": "default", - "conf_commands": {"protocol": f'-{protocol}'}, - }, - 'listeners/*:8080/tls', - ), 'protocol disabled' - - sock.close() - - if len(protocols) > 1: - (_, sock) = client.get_ssl(start=True) - - cipher = sock.cipher() - assert cipher[1] != protocol, 'new protocol used' - - shared_ciphers = sock.shared_ciphers() - ciphers = list(set(c for c in shared_ciphers if c[1] == cipher[1])) - - sock.close() - else: - check_no_connection() - pytest.skip('One TLS protocol available only.') - - # Set two conf_commands (disable protocol and cipher). - - assert 'success' in client.conf( - { - "certificate": "default", - "conf_commands": { - "protocol": f'-{protocol}', - "cipherstring": f"{cipher[1]}:!{cipher[0]}", - }, - }, - 'listeners/*:8080/tls', - ), 'cipher disabled' - - if len(ciphers) > 1: - (_, sock) = client.get_ssl(start=True) - - cipher_new = sock.cipher() - assert cipher_new[1] == cipher[1], 'previous protocol used' - assert cipher_new[0] != cipher[0], 'new cipher used' - - sock.close() - - else: - check_no_connection() - - -def test_tls_conf_command_invalid(skip_alert): - skip_alert(r'SSL_CONF_cmd', r'failed to apply new conf') - - def check_conf_commands(conf_commands): - assert 'error' in client.conf( - {"certificate": "default", "conf_commands": conf_commands}, - 'listeners/*:8080/tls', - ), 'ivalid conf_commands' - - check_conf_commands([]) - check_conf_commands("blah") - check_conf_commands({"": ""}) - check_conf_commands({"blah": ""}) - check_conf_commands({"protocol": {}}) - check_conf_commands({"protocol": "blah"}) - check_conf_commands({"protocol": "TLSv1.2", "blah": ""}) diff --git a/test/test_tls_session.py b/test/test_tls_session.py deleted file mode 100644 index 8da0306a..00000000 --- a/test/test_tls_session.py +++ /dev/null @@ -1,140 +0,0 @@ -import socket -import time - -import pytest - -pytest.importorskip('OpenSSL.SSL') -from OpenSSL.SSL import ( - TLSv1_2_METHOD, - SESS_CACHE_CLIENT, - OP_NO_TICKET, - Context, - Connection, - _lib, -) -from unit.applications.tls import ApplicationTLS - -prerequisites = {'modules': {'openssl': 'any'}} - -client = ApplicationTLS() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - client.certificate() - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": { - "pass": "routes", - "tls": {"certificate": "default", "session": {}}, - } - }, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ), 'load application configuration' - - -def add_session(cache_size=None, timeout=None): - session = {} - - if cache_size is not None: - session['cache_size'] = cache_size - if timeout is not None: - session['timeout'] = timeout - - return client.conf(session, 'listeners/*:8080/tls/session') - - -def connect(ctx=None, session=None): - sock = socket.create_connection(('127.0.0.1', 8080)) - - if ctx is None: - ctx = Context(TLSv1_2_METHOD) - ctx.set_session_cache_mode(SESS_CACHE_CLIENT) - ctx.set_options(OP_NO_TICKET) - - conn = Connection(ctx, sock) - conn.set_connect_state() - - if session is not None: - conn.set_session(session) - - conn.do_handshake() - conn.shutdown() - - return ( - conn, - conn.get_session(), - ctx, - _lib.SSL_session_reused(conn._ssl), - ) - - -@pytest.mark.skipif( - not hasattr(_lib, 'SSL_session_reused'), - reason='session reuse is not supported', -) -def test_tls_session(): - _, sess, ctx, reused = connect() - assert not reused, 'new connection' - - _, _, _, reused = connect(ctx, sess) - assert not reused, 'no cache' - - assert 'success' in add_session(cache_size=2) - - _, sess, ctx, reused = connect() - assert not reused, 'new connection cache' - - _, _, _, reused = connect(ctx, sess) - assert reused, 'cache' - - _, _, _, reused = connect(ctx, sess) - assert reused, 'cache 2' - - # check that at least one session of four is not reused - - conns = [connect() for _ in range(4)] - assert True not in [c[-1] for c in conns], 'cache small all new' - - conns_again = [connect(c[2], c[1]) for c in conns] - assert False in [c[-1] for c in conns_again], 'cache small no reuse' - - # all four sessions are reused - - assert 'success' in add_session(cache_size=8) - - conns = [connect() for _ in range(4)] - assert True not in [c[-1] for c in conns], 'cache big all new' - - conns_again = [connect(c[2], c[1]) for c in conns] - assert False not in [c[-1] for c in conns_again], 'cache big reuse' - - -@pytest.mark.skipif( - not hasattr(_lib, 'SSL_session_reused'), - reason='session reuse is not supported', -) -def test_tls_session_timeout(): - assert 'success' in add_session(cache_size=5, timeout=1) - - _, sess, ctx, reused = connect() - assert not reused, 'new connection' - - _, _, _, reused = connect(ctx, sess) - assert reused, 'no timeout' - - time.sleep(3) - - _, _, _, reused = connect(ctx, sess) - assert not reused, 'timeout' - - -def test_tls_session_invalid(): - assert 'error' in add_session(cache_size=-1) - assert 'error' in add_session(cache_size={}) - assert 'error' in add_session(timeout=-1) - assert 'error' in add_session(timeout={}) diff --git a/test/test_tls_sni.py b/test/test_tls_sni.py deleted file mode 100644 index 61d72125..00000000 --- a/test/test_tls_sni.py +++ /dev/null @@ -1,301 +0,0 @@ -import ssl -import subprocess - -import pytest - -from unit.applications.tls import ApplicationTLS -from unit.option import option - -prerequisites = {'modules': {'openssl': 'any'}} - -client = ApplicationTLS() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ) - - -def add_tls(cert='default'): - assert 'success' in client.conf( - {"pass": "routes", "tls": {"certificate": cert}}, - 'listeners/*:8080', - ) - - -def check_cert(host, expect, ctx): - resp, sock = client.get_ssl( - headers={ - 'Host': host, - 'Content-Length': '0', - 'Connection': 'close', - }, - start=True, - context=ctx, - ) - - assert resp['status'] == 200 - assert sock.getpeercert()['subject'][0][0][1] == expect - - -def config_bundles(bundles): - client.certificate('root', False) - - for b in bundles: - client.openssl_conf(rewrite=True, alt_names=bundles[b]['alt_names']) - subj = f'/CN={bundles[b]["subj"]}/' if 'subj' in bundles[b] else '/' - - subprocess.check_output( - [ - 'openssl', - 'req', - '-new', - '-subj', - subj, - '-config', - f'{option.temp_dir}/openssl.conf', - '-out', - f'{option.temp_dir}/{b}.csr', - '-keyout', - f'{option.temp_dir}/{b}.key', - ], - stderr=subprocess.STDOUT, - ) - - generate_ca_conf() - - for b in bundles: - subj = f'/CN={bundles[b]["subj"]}/' if 'subj' in bundles[b] else '/' - - subprocess.check_output( - [ - 'openssl', - 'ca', - '-batch', - '-subj', - subj, - '-config', - f'{option.temp_dir}/ca.conf', - '-keyfile', - f'{option.temp_dir}/root.key', - '-cert', - f'{option.temp_dir}/root.crt', - '-in', - f'{option.temp_dir}/{b}.csr', - '-out', - f'{option.temp_dir}/{b}.crt', - ], - stderr=subprocess.STDOUT, - ) - - load_certs(bundles) - - context = ssl.create_default_context() - context.check_hostname = False - context.verify_mode = ssl.CERT_REQUIRED - context.load_verify_locations(f'{option.temp_dir}/root.crt') - - return context - - -def generate_ca_conf(): - with open(f'{option.temp_dir}/ca.conf', 'w', encoding='utf-8') as f: - f.write( - f"""[ ca ] -default_ca = myca - -[ myca ] -new_certs_dir = {option.temp_dir} -database = {option.temp_dir}/certindex -default_md = sha256 -policy = myca_policy -serial = {option.temp_dir}/certserial -default_days = 1 -x509_extensions = myca_extensions -copy_extensions = copy - -[ myca_policy ] -commonName = optional - -[ myca_extensions ] -basicConstraints = critical,CA:TRUE""" - ) - - with open(f'{option.temp_dir}/certserial', 'w', encoding='utf-8') as f: - f.write('1000') - - with open(f'{option.temp_dir}/certindex', 'w', encoding='utf-8') as f: - f.write('') - - -def load_certs(bundles): - for bname, bvalue in bundles.items(): - assert 'success' in client.certificate_load( - bname, bname - ), f'certificate {bvalue["subj"]} upload' - - -def remove_tls(): - assert 'success' in client.conf({"pass": "routes"}, 'listeners/*:8080') - - -def test_tls_sni(): - bundles = { - "default": {"subj": "default", "alt_names": ["default"]}, - "localhost.com": { - "subj": "localhost.com", - "alt_names": ["alt1.localhost.com"], - }, - "example.com": { - "subj": "example.com", - "alt_names": ["alt1.example.com", "alt2.example.com"], - }, - } - ctx = config_bundles(bundles) - add_tls(["default", "localhost.com", "example.com"]) - - check_cert('alt1.localhost.com', bundles['localhost.com']['subj'], ctx) - check_cert('alt2.example.com', bundles['example.com']['subj'], ctx) - check_cert('blah', bundles['default']['subj'], ctx) - - -def test_tls_sni_no_hostname(): - bundles = { - "localhost.com": {"subj": "localhost.com", "alt_names": []}, - "example.com": { - "subj": "example.com", - "alt_names": ["example.com"], - }, - } - ctx = config_bundles(bundles) - add_tls(["localhost.com", "example.com"]) - - resp, sock = client.get_ssl( - headers={'Content-Length': '0', 'Connection': 'close'}, - start=True, - context=ctx, - ) - assert resp['status'] == 200 - assert ( - sock.getpeercert()['subject'][0][0][1] - == bundles['localhost.com']['subj'] - ) - - -def test_tls_sni_upper_case(): - bundles = { - "localhost.com": {"subj": "LOCALHOST.COM", "alt_names": []}, - "example.com": { - "subj": "example.com", - "alt_names": ["ALT1.EXAMPLE.COM", "*.ALT2.EXAMPLE.COM"], - }, - } - ctx = config_bundles(bundles) - add_tls(["localhost.com", "example.com"]) - - check_cert('localhost.com', bundles['localhost.com']['subj'], ctx) - check_cert('LOCALHOST.COM', bundles['localhost.com']['subj'], ctx) - check_cert('EXAMPLE.COM', bundles['localhost.com']['subj'], ctx) - check_cert('ALT1.EXAMPLE.COM', bundles['example.com']['subj'], ctx) - check_cert('WWW.ALT2.EXAMPLE.COM', bundles['example.com']['subj'], ctx) - - -def test_tls_sni_only_bundle(): - bundles = { - "localhost.com": { - "subj": "localhost.com", - "alt_names": ["alt1.localhost.com", "alt2.localhost.com"], - } - } - ctx = config_bundles(bundles) - add_tls(["localhost.com"]) - - check_cert('domain.com', bundles['localhost.com']['subj'], ctx) - check_cert('alt1.domain.com', bundles['localhost.com']['subj'], ctx) - - -def test_tls_sni_wildcard(): - bundles = { - "localhost.com": {"subj": "localhost.com", "alt_names": []}, - "example.com": { - "subj": "example.com", - "alt_names": ["*.example.com", "*.alt.example.com"], - }, - } - ctx = config_bundles(bundles) - add_tls(["localhost.com", "example.com"]) - - check_cert('example.com', bundles['localhost.com']['subj'], ctx) - check_cert('www.example.com', bundles['example.com']['subj'], ctx) - check_cert('alt.example.com', bundles['example.com']['subj'], ctx) - check_cert('www.alt.example.com', bundles['example.com']['subj'], ctx) - check_cert('www.alt.example.ru', bundles['localhost.com']['subj'], ctx) - - -def test_tls_sni_duplicated_bundle(): - bundles = { - "localhost.com": { - "subj": "localhost.com", - "alt_names": ["localhost.com", "alt2.localhost.com"], - } - } - ctx = config_bundles(bundles) - add_tls(["localhost.com", "localhost.com"]) - - check_cert('localhost.com', bundles['localhost.com']['subj'], ctx) - check_cert('alt2.localhost.com', bundles['localhost.com']['subj'], ctx) - - -def test_tls_sni_same_alt(): - bundles = { - "localhost": {"subj": "subj1", "alt_names": "same.altname.com"}, - "example": {"subj": "subj2", "alt_names": "same.altname.com"}, - } - ctx = config_bundles(bundles) - add_tls(["localhost", "example"]) - - check_cert('localhost', bundles['localhost']['subj'], ctx) - check_cert('example', bundles['localhost']['subj'], ctx) - - -def test_tls_sni_empty_cn(): - bundles = {"localhost": {"alt_names": ["alt.localhost.com"]}} - ctx = config_bundles(bundles) - add_tls(["localhost"]) - - resp, sock = client.get_ssl( - headers={ - 'Host': 'domain.com', - 'Content-Length': '0', - 'Connection': 'close', - }, - start=True, - context=ctx, - ) - - assert resp['status'] == 200 - assert sock.getpeercert()['subjectAltName'][0][1] == 'alt.localhost.com' - - -def test_tls_sni_invalid(): - _ = config_bundles({"localhost": {"subj": "subj1", "alt_names": ''}}) - add_tls(["localhost"]) - - def check_certificate(cert): - assert 'error' in client.conf( - {"pass": "routes", "tls": {"certificate": cert}}, - 'listeners/*:8080', - ) - - check_certificate('') - check_certificate('blah') - check_certificate([]) - check_certificate(['blah']) - check_certificate(['localhost', 'blah']) - check_certificate(['localhost', []]) diff --git a/test/test_tls_tickets.py b/test/test_tls_tickets.py deleted file mode 100644 index 5e899a9b..00000000 --- a/test/test_tls_tickets.py +++ /dev/null @@ -1,202 +0,0 @@ -import socket - -import pytest - -pytest.importorskip('OpenSSL.SSL') -from OpenSSL.SSL import ( - TLSv1_2_METHOD, - Context, - Connection, - _lib, -) -from unit.applications.tls import ApplicationTLS - -prerequisites = {'modules': {'openssl': 'any'}} - -client = ApplicationTLS() - -TICKET = 'U1oDTh11mMxODuw12gS0EXX1E/PkZG13cJNQ6m5+6BGlfPTjNlIEw7PSVU3X1gTE' -TICKET2 = '5AV0DSYIYbZWZQB7fCnTHZmMxtotb/aXjam+n2XS79lTvX3Tq9xGqpC8XKNEF2lt' -TICKET80 = '6Pfil8lv/k8zf8MndPpfXaO5EAV6dhME6zs6CfUyq2yziynQwSywtKQMqHGnJ2HR\ -49TZXi/Y4/8RSIO7QPsU51/HLR1gWIMhVM2m9yh93Bw=' - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - client.certificate() - - listener_conf = { - "pass": "routes", - "tls": { - "certificate": "default", - "session": {"cache_size": 0, "tickets": True}, - }, - } - - assert 'success' in client.conf( - { - "listeners": { - "*:8080": listener_conf, - "*:8081": listener_conf, - "*:8082": listener_conf, - }, - "routes": [{"action": {"return": 200}}], - "applications": {}, - } - ), 'load application configuration' - - -def connect(ctx=None, session=None, port=8080): - sock = socket.create_connection(('127.0.0.1', port)) - - if ctx is None: - ctx = Context(TLSv1_2_METHOD) - - conn = Connection(ctx, sock) - conn.set_connect_state() - - if session is not None: - conn.set_session(session) - - conn.do_handshake() - conn.shutdown() - - return ( - conn.get_session(), - ctx, - _lib.SSL_session_reused(conn._ssl), - ) - - -def has_ticket(sess): - return _lib.SSL_SESSION_has_ticket(sess._session) - - -def set_tickets(tickets=True, port=8080): - assert 'success' in client.conf( - {"cache_size": 0, "tickets": tickets}, - f'listeners/*:{port}/tls/session', - ) - - -@pytest.mark.skipif( - not hasattr(_lib, 'SSL_SESSION_has_ticket'), - reason='ticket check is not supported', -) -def test_tls_ticket(): - sess, ctx, reused = connect() - assert has_ticket(sess), 'tickets True' - assert not reused, 'tickets True not reused' - - sess, ctx, reused = connect(ctx, sess) - assert has_ticket(sess), 'tickets True reconnect' - assert reused, 'tickets True reused' - - set_tickets(tickets=False) - - sess, _, _ = connect() - assert not has_ticket(sess), 'tickets False' - - assert 'success' in client.conf_delete( - 'listeners/*:8080/tls/session/tickets' - ), 'tickets default configure' - - sess, _, _ = connect() - assert not has_ticket(sess), 'tickets default (false)' - - -@pytest.mark.skipif( - not hasattr(_lib, 'SSL_SESSION_has_ticket'), - reason='ticket check is not supported', -) -def test_tls_ticket_string(): - set_tickets(TICKET) - sess, ctx, _ = connect() - assert has_ticket(sess), 'tickets string' - - sess2, _, reused = connect(ctx, sess) - assert has_ticket(sess2), 'tickets string reconnect' - assert reused, 'tickets string reused' - - sess2, _, reused = connect(ctx, sess, port=8081) - assert has_ticket(sess2), 'connect True' - assert not reused, 'connect True not reused' - - set_tickets(TICKET2, port=8081) - - sess2, _, reused = connect(ctx, sess, port=8081) - assert has_ticket(sess2), 'wrong ticket' - assert not reused, 'wrong ticket not reused' - - set_tickets(TICKET80) - - sess, ctx, _ = connect() - assert has_ticket(sess), 'tickets string 80' - - sess2, _, reused = connect(ctx, sess) - assert has_ticket(sess2), 'tickets string 80 reconnect' - assert reused, 'tickets string 80 reused' - - sess2, _, reused = connect(ctx, sess, port=8081) - assert has_ticket(sess2), 'wrong ticket 80' - assert not reused, 'wrong ticket 80 not reused' - - -@pytest.mark.skipif( - not hasattr(_lib, 'SSL_SESSION_has_ticket'), - reason='ticket check is not supported', -) -def test_tls_ticket_array(): - set_tickets([]) - - sess, ctx, _ = connect() - assert not has_ticket(sess), 'tickets array empty' - - set_tickets([TICKET, TICKET2]) - set_tickets(TICKET, port=8081) - set_tickets(TICKET2, port=8082) - - sess, ctx, _ = connect() - _, _, reused = connect(ctx, sess, port=8081) - assert not reused, 'not last ticket' - _, _, reused = connect(ctx, sess, port=8082) - assert reused, 'last ticket' - - sess, ctx, _ = connect(port=8081) - _, _, reused = connect(ctx, sess) - assert reused, 'first ticket' - - sess, ctx, _ = connect(port=8082) - _, _, reused = connect(ctx, sess) - assert reused, 'second ticket' - - assert 'success' in client.conf_delete( - 'listeners/*:8080/tls/session/tickets/0' - ), 'removed first ticket' - assert 'success' in client.conf_post( - f'"{TICKET}"', 'listeners/*:8080/tls/session/tickets' - ), 'add new ticket to the end of array' - - sess, ctx, _ = connect() - _, _, reused = connect(ctx, sess, port=8082) - assert not reused, 'not last ticket 2' - _, _, reused = connect(ctx, sess, port=8081) - assert reused, 'last ticket 2' - - -def test_tls_ticket_invalid(): - def check_tickets(tickets): - assert 'error' in client.conf( - {"tickets": tickets}, - 'listeners/*:8080/tls/session', - ) - - check_tickets({}) - check_tickets('!?&^' * 16) - check_tickets(f'{TICKET[:-2]}!{TICKET[3:]}') - check_tickets(TICKET[:-1]) - check_tickets(f'{TICKET}b') - check_tickets(f'{TICKET}blah') - check_tickets([True, TICKET, TICKET2]) - check_tickets([TICKET, 'blah', TICKET2]) - check_tickets([TICKET, TICKET2, []]) diff --git a/test/test_unix_abstract.py b/test/test_unix_abstract.py deleted file mode 100644 index 6e304293..00000000 --- a/test/test_unix_abstract.py +++ /dev/null @@ -1,105 +0,0 @@ -from unit.applications.lang.python import ApplicationPython -from unit.option import option - -prerequisites = { - 'modules': {'python': 'any'}, - 'features': {'unix_abstract': True}, -} - -client = ApplicationPython() - - -def test_unix_abstract_source(): - addr = '\0sock' - - def source(source): - assert 'success' in client.conf(f'"{source}"', 'routes/0/match/source') - - assert 'success' in client.conf( - { - "listeners": { - "127.0.0.1:8080": {"pass": "routes"}, - f"unix:@{addr[1:]}": {"pass": "routes"}, - }, - "routes": [ - { - "match": {"source": "!0.0.0.0/0"}, - "action": {"return": 200}, - } - ], - "applications": {}, - } - ) - - assert client.get(sock_type='unix', addr=addr)['status'] == 200, 'neg ipv4' - - source("!::/0") - assert client.get(sock_type='unix', addr=addr)['status'] == 200, 'neg ipv6' - - source("unix") - assert client.get()['status'] == 404, 'ipv4' - assert client.get(sock_type='unix', addr=addr)['status'] == 200, 'unix' - - -def test_unix_abstract_client_ip(): - def get_xff(xff, sock_type='ipv4'): - address = { - 'ipv4': ('127.0.0.1', 8080), - 'ipv6': ('::1', 8081), - 'unix': ('\0sock', None), - } - (addr, port) = address[sock_type] - - return client.get( - sock_type=sock_type, - addr=addr, - port=port, - headers={'Connection': 'close', 'X-Forwarded-For': xff}, - )['body'] - - client_ip_dir = f"{option.test_dir}/python/client_ip" - assert 'success' in client.conf( - { - "listeners": { - "127.0.0.1:8080": { - "client_ip": { - "header": "X-Forwarded-For", - "source": "unix", - }, - "pass": "applications/client_ip", - }, - "[::1]:8081": { - "client_ip": { - "header": "X-Forwarded-For", - "source": "unix", - }, - "pass": "applications/client_ip", - }, - "unix:@sock": { - "client_ip": { - "header": "X-Forwarded-For", - "source": "unix", - }, - "pass": "applications/client_ip", - }, - }, - "applications": { - "client_ip": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": client_ip_dir, - "working_directory": client_ip_dir, - "module": "wsgi", - } - }, - } - ) - - assert get_xff('1.1.1.1') == '127.0.0.1', 'bad source ipv4' - assert get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6' - - for ip in [ - '1.1.1.1', - '::11.22.33.44', - ]: - assert get_xff(ip, 'unix') == ip, 'replace' diff --git a/test/test_upstreams_rr.py b/test/test_upstreams_rr.py deleted file mode 100644 index a2dc5c68..00000000 --- a/test/test_upstreams_rr.py +++ /dev/null @@ -1,493 +0,0 @@ -import os -import re - -import pytest - -from unit.applications.lang.python import ApplicationPython -from unit.option import option - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "upstreams/one"}, - "*:8090": {"pass": "upstreams/two"}, - "*:8081": {"pass": "routes/one"}, - "*:8082": {"pass": "routes/two"}, - "*:8083": {"pass": "routes/three"}, - }, - "upstreams": { - "one": { - "servers": { - "127.0.0.1:8081": {}, - "127.0.0.1:8082": {}, - }, - }, - "two": { - "servers": { - "127.0.0.1:8081": {}, - "127.0.0.1:8082": {}, - }, - }, - }, - "routes": { - "one": [{"action": {"return": 200}}], - "two": [{"action": {"return": 201}}], - "three": [{"action": {"return": 202}}], - }, - "applications": {}, - }, - ), 'upstreams initial configuration' - - client.cpu_count = os.cpu_count() - - -def get_resps(req=100, port=8080): - resps = [0] - - for _ in range(req): - status = client.get(port=port)['status'] - if 200 > status or status > 209: - continue - - ups = status % 10 - if ups > len(resps) - 1: - resps.extend([0] * (ups - len(resps) + 1)) - - resps[ups] += 1 - - return resps - - -def get_resps_sc(req=100, port=8080): - to_send = b"""GET / HTTP/1.1 -Host: localhost - -""" * ( - req - 1 - ) - - to_send += b"""GET / HTTP/1.1 -Host: localhost -Connection: close - -""" - - resp = client.http(to_send, raw_resp=True, raw=True, port=port) - status = re.findall(r'HTTP\/\d\.\d\s(\d\d\d)', resp) - status = list(filter(lambda x: x[:2] == '20', status)) - ups = list(map(lambda x: int(x[-1]), status)) - - resps = [0] * (max(ups) + 1) - for _, up in enumerate(ups): - resps[up] += 1 - - return resps - - -def test_upstreams_rr_no_weight(): - resps = get_resps() - assert sum(resps) == 100, 'no weight sum' - assert abs(resps[0] - resps[1]) <= client.cpu_count, 'no weight' - - assert 'success' in client.conf_delete( - 'upstreams/one/servers/127.0.0.1:8081' - ), 'no weight server remove' - - resps = get_resps(req=50) - assert resps[1] == 50, 'no weight 2' - - assert 'success' in client.conf( - {}, 'upstreams/one/servers/127.0.0.1:8081' - ), 'no weight server revert' - - resps = get_resps() - assert sum(resps) == 100, 'no weight 3 sum' - assert abs(resps[0] - resps[1]) <= client.cpu_count, 'no weight 3' - - assert 'success' in client.conf( - {}, 'upstreams/one/servers/127.0.0.1:8083' - ), 'no weight server new' - - resps = get_resps() - assert sum(resps) == 100, 'no weight 4 sum' - assert max(resps) - min(resps) <= client.cpu_count, 'no weight 4' - - resps = get_resps_sc(req=30) - assert resps[0] == 10, 'no weight 4 0' - assert resps[1] == 10, 'no weight 4 1' - assert resps[2] == 10, 'no weight 4 2' - - -def test_upstreams_rr_weight(): - assert 'success' in client.conf( - {"weight": 3}, 'upstreams/one/servers/127.0.0.1:8081' - ), 'configure weight' - - resps = get_resps_sc() - assert resps[0] == 75, 'weight 3 0' - assert resps[1] == 25, 'weight 3 1' - - assert 'success' in client.conf_delete( - 'upstreams/one/servers/127.0.0.1:8081/weight' - ), 'configure weight remove' - resps = get_resps_sc(req=10) - assert resps[0] == 5, 'weight 0 0' - assert resps[1] == 5, 'weight 0 1' - - assert 'success' in client.conf( - '1', 'upstreams/one/servers/127.0.0.1:8081/weight' - ), 'configure weight 1' - - resps = get_resps_sc() - assert resps[0] == 50, 'weight 1 0' - assert resps[1] == 50, 'weight 1 1' - - assert 'success' in client.conf( - { - "127.0.0.1:8081": {"weight": 3}, - "127.0.0.1:8083": {"weight": 2}, - }, - 'upstreams/one/servers', - ), 'configure weight 2' - - resps = get_resps_sc() - assert resps[0] == 60, 'weight 2 0' - assert resps[2] == 40, 'weight 2 1' - - -def test_upstreams_rr_weight_rational(): - def set_weights(w1, w2): - assert 'success' in client.conf( - { - "127.0.0.1:8081": {"weight": w1}, - "127.0.0.1:8082": {"weight": w2}, - }, - 'upstreams/one/servers', - ), 'configure weights' - - def check_reqs(w1, w2, reqs=10): - resps = get_resps_sc(req=reqs) - assert resps[0] == reqs * w1 / (w1 + w2), 'weight 1' - assert resps[1] == reqs * w2 / (w1 + w2), 'weight 2' - - def check_weights(w1, w2): - set_weights(w1, w2) - check_reqs(w1, w2) - - check_weights(0, 1) - check_weights(0, 999999.0123456) - check_weights(1, 9) - check_weights(100000, 900000) - check_weights(1, 0.25) - check_weights(1, 0.25) - check_weights(0.2, 0.8) - check_weights(1, 1.5) - check_weights(1e-3, 1e-3) - check_weights(1e-20, 1e-20) - check_weights(1e4, 1e4) - check_weights(1000000, 1000000) - - set_weights(0.25, 0.25) - assert 'success' in client.conf_delete( - 'upstreams/one/servers/127.0.0.1:8081/weight' - ), 'delete weight' - check_reqs(1, 0.25) - - assert 'success' in client.conf( - { - "127.0.0.1:8081": {"weight": 0.1}, - "127.0.0.1:8082": {"weight": 1}, - "127.0.0.1:8083": {"weight": 0.9}, - }, - 'upstreams/one/servers', - ), 'configure weights' - resps = get_resps_sc(req=20) - assert resps[0] == 1, 'weight 3 1' - assert resps[1] == 10, 'weight 3 2' - assert resps[2] == 9, 'weight 3 3' - - -def test_upstreams_rr_independent(): - def sum_resps(*args): - sum_r = [0] * len(args[0]) - for arg in args: - sum_r = [x + y for x, y in zip(sum_r, arg)] - - return sum_r - - resps = get_resps_sc(req=30, port=8090) - assert resps[0] == 15, 'dep two before 0' - assert resps[1] == 15, 'dep two before 1' - - resps = get_resps_sc(req=30) - assert resps[0] == 15, 'dep one before 0' - assert resps[1] == 15, 'dep one before 1' - - assert 'success' in client.conf( - '2', 'upstreams/two/servers/127.0.0.1:8081/weight' - ), 'configure dep weight' - - resps = get_resps_sc(req=30, port=8090) - assert resps[0] == 20, 'dep two 0' - assert resps[1] == 10, 'dep two 1' - - resps = get_resps_sc(req=30) - assert resps[0] == 15, 'dep one 0' - assert resps[1] == 15, 'dep one 1' - - assert 'success' in client.conf( - '1', 'upstreams/two/servers/127.0.0.1:8081/weight' - ), 'configure dep weight 1' - - r_one, r_two = [0, 0], [0, 0] - for _ in range(10): - r_one = sum_resps(r_one, get_resps(req=10)) - r_two = sum_resps(r_two, get_resps(req=10, port=8090)) - - assert sum(r_one) == 100, 'dep one mix sum' - assert abs(r_one[0] - r_one[1]) <= client.cpu_count, 'dep one mix' - assert sum(r_two) == 100, 'dep two mix sum' - assert abs(r_two[0] - r_two[1]) <= client.cpu_count, 'dep two mix' - - -def test_upstreams_rr_delay(): - delayed_dir = f'{option.test_dir}/python/delayed' - assert 'success' in client.conf( - { - "listeners": { - "*:8080": {"pass": "upstreams/one"}, - "*:8081": {"pass": "routes"}, - "*:8082": {"pass": "routes"}, - }, - "upstreams": { - "one": { - "servers": { - "127.0.0.1:8081": {}, - "127.0.0.1:8082": {}, - }, - }, - }, - "routes": [ - { - "match": {"destination": "*:8081"}, - "action": {"pass": "applications/delayed"}, - }, - { - "match": {"destination": "*:8082"}, - "action": {"return": 201}, - }, - ], - "applications": { - "delayed": { - "type": client.get_application_type(), - "processes": {"spare": 0}, - "path": delayed_dir, - "working_directory": delayed_dir, - "module": "wsgi", - } - }, - }, - ), 'upstreams initial configuration' - - req = 50 - - socks = [] - for i in range(req): - delay = 1 if i % 5 == 0 else 0 - sock = client.get( - headers={ - 'Host': 'localhost', - 'Content-Length': '0', - 'X-Delay': str(delay), - 'Connection': 'close', - }, - no_recv=True, - ) - socks.append(sock) - - resps = [0, 0] - for i in range(req): - resp = client.recvall(socks[i]).decode() - socks[i].close() - - m = re.search(r'HTTP/1.1 20(\d)', resp) - assert m is not None, 'status' - resps[int(m.group(1))] += 1 - - assert sum(resps) == req, 'delay sum' - assert abs(resps[0] - resps[1]) <= client.cpu_count, 'delay' - - -def test_upstreams_rr_active_req(): - conns = 5 - socks = [] - socks2 = [] - - for _ in range(conns): - sock = client.get(no_recv=True) - socks.append(sock) - - sock2 = client.http( - b"""POST / HTTP/1.1 -Host: localhost -Content-Length: 10 -Connection: close - -""", - no_recv=True, - raw=True, - ) - socks2.append(sock2) - - # Send one more request and read response to make sure that previous - # requests had enough time to reach server. - - assert client.get()['body'] == '' - - assert 'success' in client.conf( - {"127.0.0.1:8083": {"weight": 2}}, - 'upstreams/one/servers', - ), 'active req new server' - assert 'success' in client.conf_delete( - 'upstreams/one/servers/127.0.0.1:8083' - ), 'active req server remove' - assert 'success' in client.conf_delete( - 'listeners/*:8080' - ), 'delete listener' - assert 'success' in client.conf_delete( - 'upstreams/one' - ), 'active req upstream remove' - - for i in range(conns): - assert ( - client.http(b'', sock=socks[i], raw=True)['body'] == '' - ), 'active req GET' - - assert ( - client.http(b"""0123456789""", sock=socks2[i], raw=True)['body'] - == '' - ), 'active req POST' - - -def test_upstreams_rr_bad_server(): - assert 'success' in client.conf( - {"weight": 1}, 'upstreams/one/servers/127.0.0.1:8084' - ), 'configure bad server' - - resps = get_resps_sc(req=30) - assert resps[0] == 10, 'bad server 0' - assert resps[1] == 10, 'bad server 1' - assert sum(resps) == 20, 'bad server sum' - - -def test_upstreams_rr_pipeline(): - resps = get_resps_sc() - - assert resps[0] == 50, 'pipeline 0' - assert resps[1] == 50, 'pipeline 1' - - -def test_upstreams_rr_post(): - resps = [0, 0] - for _ in range(50): - resps[client.get()['status'] % 10] += 1 - resps[client.post(body='0123456789')['status'] % 10] += 1 - - assert sum(resps) == 100, 'post sum' - assert abs(resps[0] - resps[1]) <= client.cpu_count, 'post' - - -def test_upstreams_rr_unix(temp_dir): - addr_0 = f'{temp_dir}/sock_0' - addr_1 = f'{temp_dir}/sock_1' - - assert 'success' in client.conf( - { - "*:8080": {"pass": "upstreams/one"}, - f"unix:{addr_0}": {"pass": "routes/one"}, - f"unix:{addr_1}": {"pass": "routes/two"}, - }, - 'listeners', - ), 'configure listeners unix' - - assert 'success' in client.conf( - {f"unix:{addr_0}": {}, f"unix:{addr_1}": {}}, - 'upstreams/one/servers', - ), 'configure servers unix' - - resps = get_resps_sc() - - assert resps[0] == 50, 'unix 0' - assert resps[1] == 50, 'unix 1' - - -def test_upstreams_rr_ipv6(): - assert 'success' in client.conf( - { - "*:8080": {"pass": "upstreams/one"}, - "[::1]:8081": {"pass": "routes/one"}, - "[::1]:8082": {"pass": "routes/two"}, - }, - 'listeners', - ), 'configure listeners ipv6' - - assert 'success' in client.conf( - {"[::1]:8081": {}, "[::1]:8082": {}}, 'upstreams/one/servers' - ), 'configure servers ipv6' - - resps = get_resps_sc() - - assert resps[0] == 50, 'ipv6 0' - assert resps[1] == 50, 'ipv6 1' - - -def test_upstreams_rr_servers_empty(): - assert 'success' in client.conf( - {}, 'upstreams/one/servers' - ), 'configure servers empty' - assert client.get()['status'] == 502, 'servers empty' - - assert 'success' in client.conf( - {"127.0.0.1:8081": {"weight": 0}}, 'upstreams/one/servers' - ), 'configure servers empty one' - assert client.get()['status'] == 502, 'servers empty one' - assert 'success' in client.conf( - { - "127.0.0.1:8081": {"weight": 0}, - "127.0.0.1:8082": {"weight": 0}, - }, - 'upstreams/one/servers', - ), 'configure servers empty two' - assert client.get()['status'] == 502, 'servers empty two' - - -def test_upstreams_rr_invalid(): - assert 'error' in client.conf({}, 'upstreams'), 'upstreams empty' - assert 'error' in client.conf({}, 'upstreams/one'), 'named upstreams empty' - assert 'error' in client.conf( - {}, 'upstreams/one/servers/127.0.0.1' - ), 'invalid address' - assert 'error' in client.conf( - {}, 'upstreams/one/servers/127.0.0.1:8081/blah' - ), 'invalid server option' - - def check_weight(w): - assert 'error' in client.conf( - w, 'upstreams/one/servers/127.0.0.1:8081/weight' - ), 'invalid weight option' - - check_weight({}) - check_weight('-1') - check_weight('1.') - check_weight('1.1.') - check_weight('.') - check_weight('.01234567890123') - check_weight('1000001') - check_weight('2e6') diff --git a/test/test_usr1.py b/test/test_usr1.py deleted file mode 100644 index ecb4d8fd..00000000 --- a/test/test_usr1.py +++ /dev/null @@ -1,85 +0,0 @@ -import os -import signal -from pathlib import Path - -from unit.applications.lang.python import ApplicationPython -from unit.log import Log -from unit.utils import waitforfiles - -prerequisites = {'modules': {'python': 'any'}} - -client = ApplicationPython() - - -def test_usr1_access_log(search_in_file, temp_dir, unit_pid, wait_for_record): - client.load('empty') - - log = 'access.log' - log_new = 'new.log' - log_path = f'{temp_dir}/{log}' - - assert 'success' in client.conf( - f'"{log_path}"', 'access_log' - ), 'access log configure' - - assert waitforfiles(log_path), 'open' - - Path(log_path).rename(f'{temp_dir}/{log_new}') - - assert client.get()['status'] == 200 - - assert ( - wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', log_new) is not None - ), 'rename new' - assert not Path(log_path).is_file(), 'rename old' - - os.kill(unit_pid, signal.SIGUSR1) - - assert waitforfiles(log_path), 'reopen' - - assert client.get(url='/usr1')['status'] == 200 - - assert ( - wait_for_record(r'"GET /usr1 HTTP/1.1" 200 0 "-" "-"', log) is not None - ), 'reopen 2' - assert search_in_file(r'/usr1', log_new) is None, 'rename new 2' - - -def test_usr1_unit_log(search_in_file, temp_dir, unit_pid, wait_for_record): - client.load('log_body') - - log_new = 'new.log' - log_path = f'{temp_dir}/unit.log' - log_path_new = f'{temp_dir}/{log_new}' - - Path(log_path).rename(log_path_new) - - Log.swap(log_new) - - try: - body = 'body_for_a_log_new\n' - assert client.post(body=body)['status'] == 200 - - assert wait_for_record(body, log_new) is not None, 'rename new' - assert not Path(log_path).is_file(), 'rename old' - - os.kill(unit_pid, signal.SIGUSR1) - - assert waitforfiles(log_path), 'reopen' - - body = 'body_for_a_log_unit\n' - assert client.post(body=body)['status'] == 200 - - assert wait_for_record(body) is not None, 'rename new' - assert search_in_file(body, log_new) is None, 'rename new 2' - - finally: - # merge two log files into unit.log to check alerts - - path_log = Path(log_path) - log = path_log.read_text(encoding='utf-8', errors='ignore') + Path( - log_path_new - ).read_text(encoding='utf-8', errors='ignore') - path_log.write_text(log, encoding='utf-8', errors='ignore') - - Log.swap(log_new) diff --git a/test/test_variables.py b/test/test_variables.py deleted file mode 100644 index 9aab8a62..00000000 --- a/test/test_variables.py +++ /dev/null @@ -1,540 +0,0 @@ -import re -import time -from pathlib import Path - -import pytest - -from unit.applications.lang.python import ApplicationPython -from unit.applications.proto import ApplicationProto -from unit.option import option - -client = ApplicationProto() -client_python = ApplicationPython() - - -@pytest.fixture(autouse=True) -def setup_method_fixture(): - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [{"action": {"return": 200}}], - }, - ), 'configure routes' - - -def set_format(log_format): - assert 'success' in client.conf( - { - 'path': f'{option.temp_dir}/access.log', - 'format': log_format, - }, - 'access_log', - ), 'access_log format' - - -def test_variables_dollar(): - assert 'success' in client.conf("301", 'routes/0/action/return') - - def check_dollar(location, expect): - assert 'success' in client.conf( - f'"{location}"', - 'routes/0/action/location', - ) - assert client.get()['headers']['Location'] == expect - - check_dollar( - 'https://${host}${uri}path${dollar}dollar', - 'https://localhost/path$dollar', - ) - check_dollar('path$dollar${dollar}', 'path$$') - - -def test_variables_request_time(wait_for_record): - set_format('$uri $request_time') - - sock = client.http(b'', raw=True, no_recv=True) - - time.sleep(1) - - assert client.get(url='/r_time_1', sock=sock)['status'] == 200 - assert wait_for_record(r'\/r_time_1 0\.\d{3}', 'access.log') is not None - - sock = client.http( - b"""G""", - no_recv=True, - raw=True, - ) - - time.sleep(2) - - client.http( - b"""ET /r_time_2 HTTP/1.1 -Host: localhost -Connection: close - -""", - sock=sock, - raw=True, - ) - assert wait_for_record(r'\/r_time_2 [1-9]\.\d{3}', 'access.log') is not None - - -def test_variables_method(search_in_file, wait_for_record): - set_format('$method') - - reg = r'^GET$' - assert search_in_file(reg, 'access.log') is None - assert client.get()['status'] == 200 - assert wait_for_record(reg, 'access.log') is not None, 'method GET' - - reg = r'^POST$' - assert search_in_file(reg, 'access.log') is None - assert client.post()['status'] == 200 - assert wait_for_record(reg, 'access.log') is not None, 'method POST' - - -def test_variables_request_uri(search_in_file, wait_for_record): - set_format('$request_uri') - - def check_request_uri(req_uri): - reg = fr'^{re.escape(req_uri)}$' - - assert search_in_file(reg, 'access.log') is None - assert client.get(url=req_uri)['status'] == 200 - assert wait_for_record(reg, 'access.log') is not None - - check_request_uri('/3') - check_request_uri('/4*') - check_request_uri('/4%2A') - check_request_uri('/9?q#a') - - -def test_variables_uri(search_in_file, wait_for_record): - set_format('$uri') - - def check_uri(uri, expect=None): - expect = uri if expect is None else expect - reg = fr'^{re.escape(expect)}$' - - assert search_in_file(reg, 'access.log') is None - assert client.get(url=uri)['status'] == 200 - assert wait_for_record(reg, 'access.log') is not None - - check_uri('/3') - check_uri('/4*') - check_uri('/5%2A', '/5*') - check_uri('/9?q#a', '/9') - - -def test_variables_uri_no_cache(temp_dir): - Path(f'{temp_dir}/foo/bar').mkdir(parents=True) - Path(f'{temp_dir}/foo/bar/index.html').write_text('index', encoding='utf-8') - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "action": { - "rewrite": "/foo${uri}/", - "share": f'{temp_dir}$uri', - } - } - ], - } - ) - - assert client.get(url='/bar')['status'] == 200 - - -def test_variables_host(search_in_file, wait_for_record): - set_format('$host') - - def check_host(host, expect=None): - expect = host if expect is None else expect - reg = fr'^{re.escape(expect)}$' - - assert search_in_file(reg, 'access.log') is None - assert ( - client.get(headers={'Host': host, 'Connection': 'close'})['status'] - == 200 - ) - assert wait_for_record(reg, 'access.log') is not None - - check_host('localhost') - check_host('localhost1.', 'localhost1') - check_host('localhost2:8080', 'localhost2') - check_host('.localhost') - check_host('www.localhost') - - -def test_variables_remote_addr(search_in_file, wait_for_record): - set_format('$remote_addr') - - assert client.get()['status'] == 200 - assert wait_for_record(r'^127\.0\.0\.1$', 'access.log') is not None - - assert 'success' in client.conf( - {"[::1]:8080": {"pass": "routes"}}, 'listeners' - ) - - reg = r'^::1$' - assert search_in_file(reg, 'access.log') is None - assert client.get(sock_type='ipv6')['status'] == 200 - assert wait_for_record(reg, 'access.log') is not None - - -def test_variables_time_local( - date_to_sec_epoch, search_in_file, wait_for_record -): - set_format('$uri $time_local $uri') - - assert search_in_file(r'/time_local', 'access.log') is None - assert client.get(url='/time_local')['status'] == 200 - assert wait_for_record(r'/time_local', 'access.log') is not None, 'time log' - date = search_in_file(r'^\/time_local (.*) \/time_local$', 'access.log')[1] - assert ( - abs( - date_to_sec_epoch(date, '%d/%b/%Y:%X %z') - - time.mktime(time.localtime()) - ) - < 5 - ), '$time_local' - - -def test_variables_request_line(search_in_file, wait_for_record): - set_format('$request_line') - - reg = r'^GET \/r_line HTTP\/1\.1$' - assert search_in_file(reg, 'access.log') is None - assert client.get(url='/r_line')['status'] == 200 - assert wait_for_record(reg, 'access.log') is not None - - -def test_variables_request_id(search_in_file, wait_for_record, findall): - set_format('$uri $request_id $request_id') - - assert search_in_file(r'/request_id', 'access.log') is None - assert client.get(url='/request_id_1')['status'] == 200 - assert client.get(url='/request_id_2')['status'] == 200 - assert wait_for_record(r'/request_id_2', 'access.log') is not None - - id1 = findall( - r'^\/request_id_1 ([0-9a-f]{32}) ([0-9a-f]{32})$', 'access.log' - )[0] - id2 = findall( - r'^\/request_id_2 ([0-9a-f]{32}) ([0-9a-f]{32})$', 'access.log' - )[0] - - assert id1[0] == id1[1], 'same ids first' - assert id2[0] == id2[1], 'same ids second' - assert id1[0] != id2[0], 'first id != second id' - - -def test_variables_status(search_in_file, wait_for_record): - set_format('$status') - - assert 'success' in client.conf("418", 'routes/0/action/return') - - reg = r'^418$' - assert search_in_file(reg, 'access.log') is None - assert client.get()['status'] == 418 - assert wait_for_record(reg, 'access.log') is not None - - -def test_variables_header_referer(search_in_file, wait_for_record): - set_format('$method $header_referer') - - def check_referer(referer): - reg = fr'^GET {re.escape(referer)}$' - - assert search_in_file(reg, 'access.log') is None - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Connection': 'close', - 'Referer': referer, - } - )['status'] - == 200 - ) - assert wait_for_record(reg, 'access.log') is not None - - check_referer('referer-value') - check_referer('') - check_referer('no') - - -def test_variables_header_user_agent(search_in_file, wait_for_record): - set_format('$method $header_user_agent') - - def check_user_agent(user_agent): - reg = fr'^GET {re.escape(user_agent)}$' - - assert search_in_file(reg, 'access.log') is None - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Connection': 'close', - 'User-Agent': user_agent, - } - )['status'] - == 200 - ) - assert wait_for_record(reg, 'access.log') is not None - - check_user_agent('MSIE') - check_user_agent('') - check_user_agent('no') - - -def test_variables_many(search_in_file, wait_for_record): - def check_vars(uri, expect): - reg = fr'^{re.escape(expect)}$' - - assert search_in_file(reg, 'access.log') is None - assert client.get(url=uri)['status'] == 200 - assert wait_for_record(reg, 'access.log') is not None - - set_format('$uri$method') - check_vars('/1', '/1GET') - - set_format('${uri}${method}') - check_vars('/2', '/2GET') - - set_format('${uri}$method') - check_vars('/3', '/3GET') - - set_format('$method$method') - check_vars('/', 'GETGET') - - -def test_variables_dynamic(wait_for_record): - set_format('$header_foo$cookie_foo$arg_foo') - - assert ( - client.get( - url='/?foo=h', - headers={'Foo': 'b', 'Cookie': 'foo=la', 'Connection': 'close'}, - )['status'] - == 200 - ) - assert wait_for_record(r'^blah$', 'access.log') is not None - - -def test_variables_dynamic_arguments(search_in_file, wait_for_record): - def check_arg(url, expect=None): - expect = url if expect is None else expect - reg = fr'^{re.escape(expect)}$' - - assert search_in_file(reg, 'access.log') is None - assert client.get(url=url)['status'] == 200 - assert wait_for_record(reg, 'access.log') is not None - - def check_no_arg(url): - assert client.get(url=url)['status'] == 200 - assert search_in_file(r'^0$', 'access.log') is None - - set_format('$arg_foo_bar') - check_arg('/?foo_bar=1', '1') - check_arg('/?foo_b%61r=2', '2') - check_arg('/?bar&foo_bar=3&foo', '3') - check_arg('/?foo_bar=l&foo_bar=4', '4') - check_no_arg('/') - check_no_arg('/?foo_bar=') - check_no_arg('/?Foo_bar=0') - check_no_arg('/?foo-bar=0') - check_no_arg('/?foo_bar=0&foo_bar=l') - - set_format('$arg_foo_b%61r') - check_no_arg('/?foo_b=0') - check_no_arg('/?foo_bar=0') - - set_format('$arg_f!~') - check_no_arg('/?f=0') - check_no_arg('/?f!~=0') - - -def test_variables_dynamic_headers(search_in_file, wait_for_record): - def check_header(header, value): - reg = fr'^{value}$' - - assert search_in_file(reg, 'access.log') is None - assert ( - client.get(headers={header: value, 'Connection': 'close'})['status'] - == 200 - ) - assert wait_for_record(reg, 'access.log') is not None - - def check_no_header(header): - assert ( - client.get(headers={header: '0', 'Connection': 'close'})['status'] - == 200 - ) - assert search_in_file(r'^0$', 'access.log') is None - - set_format('$header_foo_bar') - check_header('foo-bar', '1') - check_header('Foo-Bar', '2') - check_no_header('foo_bar') - check_no_header('foobar') - - set_format('$header_Foo_Bar') - check_header('Foo-Bar', '4') - check_header('foo-bar', '5') - check_no_header('foo_bar') - check_no_header('foobar') - - -def test_variables_dynamic_cookies(search_in_file, wait_for_record): - def check_no_cookie(cookie): - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Cookie': cookie, - 'Connection': 'close', - }, - )['status'] - == 200 - ) - assert search_in_file(r'^0$', 'access.log') is None - - set_format('$cookie_foo_bar') - - reg = r'^1$' - assert search_in_file(reg, 'access.log') is None - assert ( - client.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'foo_bar=1', - 'Connection': 'close', - }, - )['status'] - == 200 - ) - assert wait_for_record(reg, 'access.log') is not None - - check_no_cookie('fOo_bar=0') - check_no_cookie('foo_bar=') - - -def test_variables_response_header(temp_dir, wait_for_record): - # If response has two headers with the same name then first value - # will be stored in variable. - # $response_header_transfer_encoding value can be 'chunked' or null only. - - # return - - set_format( - 'return@$response_header_server@$response_header_date@' - '$response_header_content_length@$response_header_connection' - ) - - assert client.get()['status'] == 200 - assert ( - wait_for_record(r'return@Unit/.*@.*GMT@0@close', 'access.log') - is not None - ) - - # share - - Path(f'{temp_dir}/foo').mkdir() - Path(f'{temp_dir}/foo/index.html').write_text('index', encoding='utf-8') - - assert 'success' in client.conf( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "action": { - "share": f'{temp_dir}$uri', - } - } - ], - } - ) - - set_format( - 'share@$response_header_last_modified@$response_header_etag@' - '$response_header_content_type@$response_header_server@' - '$response_header_date@$response_header_content_length@' - '$response_header_connection' - ) - - assert client.get(url='/foo/index.html')['status'] == 200 - assert ( - wait_for_record( - r'share@.*GMT@".*"@text/html@Unit/.*@.*GMT@5@close', 'access.log' - ) - is not None - ) - - # redirect - - set_format( - 'redirect@$response_header_location@$response_header_server@' - '$response_header_date@$response_header_content_length@' - '$response_header_connection' - ) - - assert client.get(url='/foo')['status'] == 301 - assert ( - wait_for_record(r'redirect@/foo/@Unit/.*@.*GMT@0@close', 'access.log') - is not None - ) - - # error - - set_format( - 'error@$response_header_content_type@$response_header_server@' - '$response_header_date@$response_header_content_length@' - '$response_header_connection' - ) - - assert client.get(url='/blah')['status'] == 404 - assert ( - wait_for_record(r'error@text/html@Unit/.*@.*GMT@54@close', 'access.log') - is not None - ) - - -def test_variables_response_header_application(require, wait_for_record): - require({'modules': {'python': 'any'}}) - - client_python.load('chunked') - - set_format('$uri@$response_header_transfer_encoding') - - assert client_python.get(url='/1')['status'] == 200 - assert wait_for_record(r'/1@chunked', 'access.log') is not None - - -def test_variables_invalid(temp_dir): - def check_variables(log_format): - assert 'error' in client.conf( - { - 'path': f'{temp_dir}/access.log', - 'format': log_format, - }, - 'access_log', - ), 'access_log format' - - check_variables("$") - check_variables("${") - check_variables("${}") - check_variables("$ur") - check_variables("$uri$$host") - check_variables("$uriblah") - check_variables("${uri") - check_variables("${{uri}") - check_variables("$ar") - check_variables("$arg") - check_variables("$arg_") - check_variables("$cookie") - check_variables("$cookie_") - check_variables("$header") - check_variables("$header_") diff --git a/test/unit/__init__.py b/test/unit/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/unit/applications/__init__.py b/test/unit/applications/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/unit/applications/lang/__init__.py b/test/unit/applications/lang/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/unit/applications/lang/go.py b/test/unit/applications/lang/go.py deleted file mode 100644 index 2479d4f6..00000000 --- a/test/unit/applications/lang/go.py +++ /dev/null @@ -1,105 +0,0 @@ -import os -import shutil -import subprocess - -from unit.applications.proto import ApplicationProto -from unit.option import option - - -class ApplicationGo(ApplicationProto): - @staticmethod - def prepare_env(script, name='app', static=False): - try: - subprocess.check_output(['which', 'go']) - except subprocess.CalledProcessError: - return None - - temp_dir = f'{option.temp_dir}/go/' - - if not os.path.exists(temp_dir): - os.mkdir(temp_dir) - - cache_dir = f'{option.cache_dir}/go-build' - - if not os.path.exists(cache_dir): - os.mkdir(cache_dir) - - env = os.environ.copy() - env['GOPATH'] = f'{option.current_dir}/build/go' - env['GOCACHE'] = cache_dir - - shutil.copy2(f'{option.test_dir}/go/{script}/{name}.go', temp_dir) - - if static: - args = [ - 'go', - 'build', - '-tags', - 'netgo', - '-ldflags', - '-extldflags "-static"', - '-o', - f'{temp_dir}{name}', - f'{temp_dir}{name}.go', - ] - else: - args = [ - 'go', - 'build', - '-o', - f'{temp_dir}{name}', - f'{temp_dir}{name}.go', - ] - - replace_path = f'{option.current_dir}/build/go/src/unit.nginx.org/go' - - with open(f'{temp_dir}go.mod', 'w', encoding='utf-8') as f: - f.write( - f"""module test/app -require unit.nginx.org/go v0.0.0 -replace unit.nginx.org/go => {replace_path} -""" - ) - - if option.detailed: - print(f'\n$ GOPATH={env["GOPATH"]} {" ".join(args)}') - - try: - output = subprocess.check_output( - args, env=env, cwd=temp_dir, stderr=subprocess.STDOUT - ) - - except KeyboardInterrupt: - raise - - except subprocess.CalledProcessError: - return None - - return output - - def load(self, script, name='app', **kwargs): - static_build = False - - wdir = f'{option.test_dir}/go/{script}' - executable = f'{option.temp_dir}/go/{name}' - - if 'isolation' in kwargs and 'rootfs' in kwargs['isolation']: - wdir = "/go/" - executable = f"/go/{name}" - static_build = True - - ApplicationGo.prepare_env(script, name, static=static_build) - - conf = { - "listeners": {"*:8080": {"pass": f"applications/{script}"}}, - "applications": { - script: { - "type": "external", - "processes": {"spare": 0}, - "working_directory": wdir, - "executable": executable, - }, - }, - } - - self._load_conf(conf, **kwargs) diff --git a/test/unit/applications/lang/java.py b/test/unit/applications/lang/java.py deleted file mode 100644 index 351d04ce..00000000 --- a/test/unit/applications/lang/java.py +++ /dev/null @@ -1,112 +0,0 @@ -import glob -import os -import shutil -import subprocess - -import pytest -from unit.applications.proto import ApplicationProto -from unit.option import option - - -class ApplicationJava(ApplicationProto): - def __init__(self, application_type='java'): - self.application_type = application_type - - def prepare_env(self, script): - app_path = f'{option.temp_dir}/java' - web_inf_path = f'{app_path}/WEB-INF/' - classes_path = f'{web_inf_path}classes/' - script_path = f'{option.test_dir}/java/{script}/' - - if not os.path.isdir(app_path): - os.makedirs(app_path) - - src = [] - - for f in os.listdir(script_path): - file_path = f'{script_path}{f}' - - if f.endswith('.java'): - src.append(file_path) - continue - - if f.startswith('.') or f == 'Makefile': - continue - - if os.path.isdir(file_path): - if f == 'WEB-INF': - continue - - shutil.copytree(file_path, f'{app_path}/{f}') - continue - - if f == 'web.xml': - if not os.path.isdir(web_inf_path): - os.makedirs(web_inf_path) - - shutil.copy2(file_path, web_inf_path) - else: - shutil.copy2(file_path, app_path) - - if src: - if not os.path.isdir(classes_path): - os.makedirs(classes_path) - - classpath = ( - f'{option.current_dir}/build/tomcat-servlet-api-9.0.86.jar' - ) - - ws_jars = glob.glob( - f'{option.current_dir}/build/websocket-api-java*.jar' - ) - - if not ws_jars: - pytest.fail('websocket api jar not found.') - - javac = [ - 'javac', - '-target', - '8', - '-source', - '8', - '-nowarn', - '-encoding', - 'utf-8', - '-d', - classes_path, - '-classpath', - f'{classpath}:{ws_jars[0]}', - ] - javac.extend(src) - - if option.detailed: - print(f'\n$ {" ".join(javac)}') - - try: - subprocess.check_output(javac, stderr=subprocess.STDOUT) - - except KeyboardInterrupt: - raise - - except subprocess.CalledProcessError: - pytest.fail("Can't run javac process.") - - def load(self, script, **kwargs): - self.prepare_env(script) - - script_path = f'{option.test_dir}/java/{script}/' - self._load_conf( - { - "listeners": {"*:8080": {"pass": f"applications/{script}"}}, - "applications": { - script: { - "unit_jars": f'{option.current_dir}/build', - "type": self.get_application_type(), - "processes": {"spare": 0}, - "working_directory": script_path, - "webapp": f'{option.temp_dir}/java', - } - }, - }, - **kwargs, - ) diff --git a/test/unit/applications/lang/node.py b/test/unit/applications/lang/node.py deleted file mode 100644 index ff95fbd5..00000000 --- a/test/unit/applications/lang/node.py +++ /dev/null @@ -1,60 +0,0 @@ -import shutil -from urllib.parse import quote - -from unit.applications.proto import ApplicationProto -from unit.option import option -from unit.utils import public_dir - - -class ApplicationNode(ApplicationProto): - def __init__(self, application_type='node', es_modules=False): - self.application_type = application_type - self.es_modules = es_modules - - def prepare_env(self, script): - # copy application - shutil.copytree( - f'{option.test_dir}/node/{script}', f'{option.temp_dir}/node' - ) - - # copy modules - shutil.copytree( - f'{option.current_dir}/node/node_modules', - f'{option.temp_dir}/node/node_modules', - ) - - public_dir(f'{option.temp_dir}/node') - - def load(self, script, name='app.js', **kwargs): - self.prepare_env(script) - - if self.es_modules: - arguments = [ - "node", - "--loader", - "unit-http/loader.mjs", - "--require", - "unit-http/loader", - name, - ] - - else: - arguments = ["node", "--require", "unit-http/loader", name] - - self._load_conf( - { - "listeners": { - "*:8080": {"pass": f"applications/{quote(script, '')}"} - }, - "applications": { - script: { - "type": "external", - "processes": {"spare": 0}, - "working_directory": f'{option.temp_dir}/node', - "executable": '/usr/bin/env', - "arguments": arguments, - } - }, - }, - **kwargs, - ) diff --git a/test/unit/applications/lang/perl.py b/test/unit/applications/lang/perl.py deleted file mode 100644 index e99c2aca..00000000 --- a/test/unit/applications/lang/perl.py +++ /dev/null @@ -1,25 +0,0 @@ -from unit.applications.proto import ApplicationProto -from unit.option import option - - -class ApplicationPerl(ApplicationProto): - def __init__(self, application_type='perl'): - self.application_type = application_type - - def load(self, script, name='psgi.pl', **kwargs): - script_path = f'{option.test_dir}/perl/{script}' - - self._load_conf( - { - "listeners": {"*:8080": {"pass": f"applications/{script}"}}, - "applications": { - script: { - "type": self.get_application_type(), - "processes": {"spare": 0}, - "working_directory": script_path, - "script": f'{script_path}/{name}', - } - }, - }, - **kwargs, - ) diff --git a/test/unit/applications/lang/php.py b/test/unit/applications/lang/php.py deleted file mode 100644 index ac59ec1b..00000000 --- a/test/unit/applications/lang/php.py +++ /dev/null @@ -1,48 +0,0 @@ -from pathlib import Path -import shutil - -from unit.applications.proto import ApplicationProto -from unit.option import option - - -class ApplicationPHP(ApplicationProto): - def __init__(self, application_type='php'): - self.application_type = application_type - - def load(self, script, index='index.php', **kwargs): - script_path = f'{option.test_dir}/php/{script}' - - if kwargs.get('isolation') and kwargs['isolation'].get('rootfs'): - rootfs = kwargs['isolation']['rootfs'] - - Path(f'{rootfs}/app/php/').mkdir(parents=True, exist_ok=True) - - if not Path(f'{rootfs}/app/php/{script}').exists(): - shutil.copytree(script_path, f'{rootfs}/app/php/{script}') - - script_path = f'/app/php/{script}' - - app = { - "type": self.get_application_type(), - "processes": kwargs.pop('processes', {"spare": 0}), - "root": script_path, - "working_directory": script_path, - "index": index, - } - - for attr in ( - 'environment', - 'limits', - 'options', - 'targets', - ): - if attr in kwargs: - app[attr] = kwargs.pop(attr) - - self._load_conf( - { - "listeners": {"*:8080": {"pass": f"applications/{script}"}}, - "applications": {script: app}, - }, - **kwargs, - ) diff --git a/test/unit/applications/lang/python.py b/test/unit/applications/lang/python.py deleted file mode 100644 index 67684b04..00000000 --- a/test/unit/applications/lang/python.py +++ /dev/null @@ -1,66 +0,0 @@ -from pathlib import Path -import shutil -from urllib.parse import quote - -from unit.applications.proto import ApplicationProto -from unit.option import option - - -class ApplicationPython(ApplicationProto): - def __init__(self, application_type='python', load_module='wsgi'): - self.application_type = application_type - self.load_module = load_module - - def load(self, script, name=None, module=None, **kwargs): - if name is None: - name = script - - if module is None: - module = self.load_module - - if script[0] == '/': - script_path = script - else: - script_path = f'{option.test_dir}/python/{script}' - - if kwargs.get('isolation') and kwargs['isolation'].get('rootfs'): - rootfs = kwargs['isolation']['rootfs'] - - Path(f'{rootfs}/app/python/').mkdir(parents=True, exist_ok=True) - - if not Path(f'{rootfs}/app/python/{name}').exists(): - shutil.copytree(script_path, f'{rootfs}/app/python/{name}') - - script_path = f'/app/python/{name}' - - app = { - "type": self.get_application_type(), - "processes": kwargs.pop('processes', {"spare": 0}), - "path": script_path, - "working_directory": script_path, - "module": module, - } - - for attr in ( - 'callable', - 'environment', - 'home', - 'limits', - 'path', - 'protocol', - 'targets', - 'threads', - 'prefix', - ): - if attr in kwargs: - app[attr] = kwargs.pop(attr) - - self._load_conf( - { - "listeners": { - "*:8080": {"pass": f"applications/{quote(name, '')}"} - }, - "applications": {name: app}, - }, - **kwargs, - ) diff --git a/test/unit/applications/lang/ruby.py b/test/unit/applications/lang/ruby.py deleted file mode 100644 index 1268f8c7..00000000 --- a/test/unit/applications/lang/ruby.py +++ /dev/null @@ -1,44 +0,0 @@ -import shutil - -from unit.applications.proto import ApplicationProto -from unit.option import option -from unit.utils import public_dir - - -class ApplicationRuby(ApplicationProto): - def __init__(self, application_type='ruby'): - self.application_type = application_type - - def prepare_env(self, script): - shutil.copytree( - f'{option.test_dir}/ruby/{script}', - f'{option.temp_dir}/ruby/{script}', - ) - - public_dir(f'{option.temp_dir}/ruby/{script}') - - def load(self, script, name='config.ru', **kwargs): - self.prepare_env(script) - - script_path = f'{option.temp_dir}/ruby/{script}' - - app = { - "type": self.get_application_type(), - "processes": {"spare": 0}, - "working_directory": script_path, - "script": f'{script_path}/{name}', - } - - for key in [ - 'hooks', - ]: - if key in kwargs: - app[key] = kwargs[key] - - self._load_conf( - { - "listeners": {"*:8080": {"pass": f"applications/{script}"}}, - "applications": {script: app}, - }, - **kwargs, - ) diff --git a/test/unit/applications/proto.py b/test/unit/applications/proto.py deleted file mode 100644 index 7a1636c6..00000000 --- a/test/unit/applications/proto.py +++ /dev/null @@ -1,32 +0,0 @@ -import os - -from unit.control import Control -from unit.option import option - - -class ApplicationProto(Control): - application_type = None - - def get_application_type(self): - current_test = ( - os.environ.get('PYTEST_CURRENT_TEST').split(':')[-1].split(' ')[0] - ) - - return option.generated_tests.get(current_test, self.application_type) - - def _load_conf(self, conf, **kwargs): - if 'applications' in conf: - for app in conf['applications'].keys(): - app_conf = conf['applications'][app] - - for key in [ - 'user', - 'group', - 'isolation', - 'processes', - 'threads', - ]: - if key in kwargs: - app_conf[key] = kwargs[key] - - assert 'success' in self.conf(conf), 'load application configuration' diff --git a/test/unit/applications/tls.py b/test/unit/applications/tls.py deleted file mode 100644 index 75354dd9..00000000 --- a/test/unit/applications/tls.py +++ /dev/null @@ -1,111 +0,0 @@ -import os -import ssl -import subprocess - -from unit.applications.proto import ApplicationProto -from unit.option import option - - -class ApplicationTLS(ApplicationProto): - def __init__(self): - self._default_context = ssl.create_default_context() - self._default_context.check_hostname = False - self._default_context.verify_mode = ssl.CERT_NONE - - def certificate(self, name='default', load=True): - self.openssl_conf() - - subprocess.check_output( - [ - 'openssl', - 'req', - '-x509', - '-new', - '-subj', - f'/CN={name}/', - '-config', - f'{option.temp_dir}/openssl.conf', - '-out', - f'{option.temp_dir}/{name}.crt', - '-keyout', - f'{option.temp_dir}/{name}.key', - ], - stderr=subprocess.STDOUT, - ) - - if load: - self.certificate_load(name) - - def certificate_load(self, crt, key=None): - if key is None: - key = crt - - key_path = f'{option.temp_dir}/{key}.key' - crt_path = f'{option.temp_dir}/{crt}.crt' - - with open(key_path, 'rb') as k, open(crt_path, 'rb') as c: - return self.conf(k.read() + c.read(), f'/certificates/{crt}') - - def get_ssl(self, **kwargs): - context = kwargs.get('context', self._default_context) - return self.get(wrapper=context.wrap_socket, **kwargs) - - def post_ssl(self, **kwargs): - context = kwargs.get('context', self._default_context) - return self.post(wrapper=context.wrap_socket, **kwargs) - - def openssl_conf(self, rewrite=False, alt_names=None): - alt_names = alt_names or [] - conf_path = f'{option.temp_dir}/openssl.conf' - - if not rewrite and os.path.exists(conf_path): - return - - # Generates alt_names section with dns names - a_names = '[alt_names]\n' - for i, k in enumerate(alt_names, 1): - k = k.split('|') - - if k[0] == 'IP': - a_names += f'IP.{i} = {k[1]}\n' - else: - a_names += f'DNS.{i} = {k[0]}\n' - - # Generates section for sign request extension - a_sec = f'''req_extensions = myca_req_extensions - -[ myca_req_extensions ] -subjectAltName = @alt_names - -{a_names}''' - - with open(conf_path, 'w', encoding='utf-8') as f: - f.write( - f'''[ req ] -default_bits = 2048 -encrypt_key = no -distinguished_name = req_distinguished_name - -{a_sec if alt_names else ""} -[ req_distinguished_name ]''' - ) - - def load(self, script, name=None): - if name is None: - name = script - - script_path = f'{option.test_dir}/python/{script}' - self._load_conf( - { - "listeners": {"*:8080": {"pass": f"applications/{name}"}}, - "applications": { - name: { - "type": "python", - "processes": {"spare": 0}, - "path": script_path, - "working_directory": script_path, - "module": "wsgi", - } - }, - } - ) diff --git a/test/unit/applications/websockets.py b/test/unit/applications/websockets.py deleted file mode 100644 index a8e563d0..00000000 --- a/test/unit/applications/websockets.py +++ /dev/null @@ -1,237 +0,0 @@ -import base64 -import hashlib -import itertools -import random -import select -import struct - -import pytest - -from unit.applications.proto import ApplicationProto - -GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - - -class ApplicationWebsocket(ApplicationProto): - - OP_CONT = 0x00 - OP_TEXT = 0x01 - OP_BINARY = 0x02 - OP_CLOSE = 0x08 - OP_PING = 0x09 - OP_PONG = 0x0A - CLOSE_CODES = [1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011] - - def key(self): - raw_key = bytes(random.getrandbits(8) for _ in range(16)) - return base64.b64encode(raw_key).decode() - - def accept(self, key): - sha1 = hashlib.sha1((key + GUID).encode()).digest() - return base64.b64encode(sha1).decode() - - def upgrade(self, headers=None): - key = None - - if headers is None: - key = self.key() - headers = { - 'Host': 'localhost', - 'Upgrade': 'websocket', - 'Connection': 'Upgrade', - 'Sec-WebSocket-Key': key, - 'Sec-WebSocket-Protocol': 'chat, phone, video', - 'Sec-WebSocket-Version': 13, - } - - sock = self.get( - headers=headers, - no_recv=True, - ) - - resp = '' - while True: - rlist = select.select([sock], [], [], 60)[0] - if not rlist: - pytest.fail("Can't read response from server.") - - resp += sock.recv(4096).decode() - - if resp.startswith('HTTP/') and '\r\n\r\n' in resp: - resp = self._resp_to_dict(resp) - break - - return (resp, sock, key) - - def apply_mask(self, data, mask): - return bytes(b ^ m for b, m in zip(data, itertools.cycle(mask))) - - def serialize_close(self, code=1000, reason=''): - return struct.pack('!H', code) + reason.encode('utf-8') - - def frame_read(self, sock, read_timeout=60): - def recv_bytes(sock, bytes_len): - data = b'' - while True: - rlist = select.select([sock], [], [], read_timeout)[0] - if not rlist: - # For all current cases if the "read_timeout" was changed - # than test do not expect to get a response from server. - if read_timeout == 60: - pytest.fail("Can't read response from server.") - break - - data += sock.recv(bytes_len - len(data)) - - if len(data) == bytes_len: - break - - return data - - frame = {} - - (head1,) = struct.unpack('!B', recv_bytes(sock, 1)) - (head2,) = struct.unpack('!B', recv_bytes(sock, 1)) - - frame['fin'] = bool(head1 & 0b10000000) - frame['rsv1'] = bool(head1 & 0b01000000) - frame['rsv2'] = bool(head1 & 0b00100000) - frame['rsv3'] = bool(head1 & 0b00010000) - frame['opcode'] = head1 & 0b00001111 - frame['mask'] = head2 & 0b10000000 - - length = head2 & 0b01111111 - if length == 126: - data = recv_bytes(sock, 2) - (length,) = struct.unpack('!H', data) - elif length == 127: - data = recv_bytes(sock, 8) - (length,) = struct.unpack('!Q', data) - - if frame['mask']: - mask_bits = recv_bytes(sock, 4) - - data = b'' - - if length != 0: - data = recv_bytes(sock, length) - - if frame['mask']: - data = self.apply_mask(data, mask_bits) - - if frame['opcode'] == self.OP_CLOSE: - if length >= 2: - (code,) = struct.unpack('!H', data[:2]) - reason = data[2:].decode('utf-8') - if not (code in self.CLOSE_CODES or 3000 <= code < 5000): - pytest.fail('Invalid status code') - frame['code'] = code - frame['reason'] = reason - elif length == 0: - frame['code'] = 1005 - frame['reason'] = '' - else: - pytest.fail('Close frame too short') - - frame['data'] = data - - if frame['mask']: - pytest.fail('Received frame with mask') - - return frame - - def frame_to_send( - self, - opcode, - data, - fin=True, - length=None, - rsv1=False, - rsv2=False, - rsv3=False, - mask=True, - ): - frame = b'' - - if isinstance(data, str): - data = data.encode('utf-8') - - head1 = ( - (0b10000000 if fin else 0) - | (0b01000000 if rsv1 else 0) - | (0b00100000 if rsv2 else 0) - | (0b00010000 if rsv3 else 0) - | opcode - ) - - head2 = 0b10000000 if mask else 0 - - data_length = len(data) if length is None else length - if data_length < 126: - frame += struct.pack('!BB', head1, head2 | data_length) - elif data_length < 65536: - frame += struct.pack('!BBH', head1, head2 | 126, data_length) - else: - frame += struct.pack('!BBQ', head1, head2 | 127, data_length) - - if mask: - mask_bits = struct.pack('!I', random.getrandbits(32)) - frame += mask_bits - - if mask: - frame += self.apply_mask(data, mask_bits) - else: - frame += data - - return frame - - def frame_write(self, sock, *args, **kwargs): - chopsize = kwargs.pop('chopsize') if 'chopsize' in kwargs else None - - frame = self.frame_to_send(*args, **kwargs) - - if chopsize is None: - try: - sock.sendall(frame) - except BrokenPipeError: - pass - - else: - pos = 0 - frame_len = len(frame) - while pos < frame_len: - end = min(pos + chopsize, frame_len) - try: - sock.sendall(frame[pos:end]) - except BrokenPipeError: - end = frame_len - pos = end - - def message(self, sock, mes_type, message, fragmention_size=None, **kwargs): - message_len = len(message) - - if fragmention_size is None: - fragmention_size = message_len - - if message_len <= fragmention_size: - self.frame_write(sock, mes_type, message, **kwargs) - return - - pos = 0 - op_code = mes_type - while pos < message_len: - end = min(pos + fragmention_size, message_len) - fin = end == message_len - self.frame_write(sock, op_code, message[pos:end], fin=fin, **kwargs) - op_code = self.OP_CONT - pos = end - - def message_read(self, sock, read_timeout=60): - frame = self.frame_read(sock, read_timeout=read_timeout) - - while not frame['fin']: - temp = self.frame_read(sock, read_timeout=read_timeout) - frame['data'] += temp['data'] - frame['fin'] = temp['fin'] - - return frame diff --git a/test/unit/check/check_prerequisites.py b/test/unit/check/check_prerequisites.py deleted file mode 100644 index ea319346..00000000 --- a/test/unit/check/check_prerequisites.py +++ /dev/null @@ -1,64 +0,0 @@ -import pytest - -from unit.option import option - - -def check_prerequisites(prerequisites): - if 'privileged_user' in prerequisites: - if prerequisites['privileged_user'] and not option.is_privileged: - pytest.skip( - 'privileged user required', - allow_module_level=True, - ) - elif not prerequisites['privileged_user'] and option.is_privileged: - pytest.skip( - 'unprivileged user required', - allow_module_level=True, - ) - - missed = [] - - # check modules - - if 'modules' in prerequisites: - available = option.available['modules'] - - for module in prerequisites['modules']: - if module in available and available[module]: - continue - - missed.append(module) - - if missed: - pytest.skip( - f'Unit has no {", ".join(missed)} module(s)', - allow_module_level=True, - ) - - # check features - - if 'features' in prerequisites: - available = option.available['features'] - require = prerequisites['features'] - - for feature in require: - avail_feature = available[feature] - - if feature in available and avail_feature: - if isinstance(require[feature], list) and isinstance( - avail_feature, dict - ): - avail_keys = avail_feature.keys() - - for key in require[feature]: - if key not in avail_keys: - missed.append(f'{feature}/{key}') - continue - - missed.append(feature) - - if missed: - pytest.skip( - f'{", ".join(missed)} feature(s) not supported', - allow_module_level=True, - ) diff --git a/test/unit/check/chroot.py b/test/unit/check/chroot.py deleted file mode 100644 index 466b6ba4..00000000 --- a/test/unit/check/chroot.py +++ /dev/null @@ -1,30 +0,0 @@ -import json - -from unit.http import HTTP1 -from unit.option import option - -http = HTTP1() - - -def check_chroot(): - return ( - 'success' - in http.put( - url='/config', - sock_type='unix', - addr=f'{option.temp_dir}/control.unit.sock', - body=json.dumps( - { - "listeners": {"*:8080": {"pass": "routes"}}, - "routes": [ - { - "action": { - "share": option.temp_dir, - "chroot": option.temp_dir, - } - } - ], - } - ), - )['body'] - ) diff --git a/test/unit/check/discover_available.py b/test/unit/check/discover_available.py deleted file mode 100644 index 1383a0c3..00000000 --- a/test/unit/check/discover_available.py +++ /dev/null @@ -1,49 +0,0 @@ -import subprocess -import sys - -from unit.check.chroot import check_chroot -from unit.check.go import check_go -from unit.check.isolation import check_isolation -from unit.check.njs import check_njs -from unit.check.node import check_node -from unit.check.regex import check_regex -from unit.check.tls import check_openssl -from unit.check.unix_abstract import check_unix_abstract -from unit.log import Log -from unit.option import option - - -def discover_available(unit): - output_version = subprocess.check_output( - [unit['unitd'], '--version'], stderr=subprocess.STDOUT - ).decode() - - option.configure_flag['asan'] = '-fsanitize=address' in output_version - - # wait for controller start - - if Log.wait_for_record(r'controller started') is None: - Log.print_log() - sys.exit("controller didn't start") - - # discover modules from log file - - for module in Log.findall(r'module: ([a-zA-Z]+) (.*) ".*"$'): - versions = option.available['modules'].setdefault(module[0], []) - if module[1] not in versions: - versions.append(module[1]) - - # discover modules using check - - option.available['modules']['go'] = check_go() - option.available['modules']['njs'] = check_njs(output_version) - option.available['modules']['node'] = check_node() - option.available['modules']['openssl'] = check_openssl(output_version) - option.available['modules']['regex'] = check_regex(output_version) - - # Discover features using check. Features should be discovered after - # modules since some features can require modules. - - option.available['features']['chroot'] = check_chroot() - option.available['features']['isolation'] = check_isolation() - option.available['features']['unix_abstract'] = check_unix_abstract() diff --git a/test/unit/check/go.py b/test/unit/check/go.py deleted file mode 100644 index 1ecd429b..00000000 --- a/test/unit/check/go.py +++ /dev/null @@ -1,5 +0,0 @@ -from unit.applications.lang.go import ApplicationGo - - -def check_go(): - return ApplicationGo.prepare_env('empty') is not None diff --git a/test/unit/check/isolation.py b/test/unit/check/isolation.py deleted file mode 100644 index 861c0818..00000000 --- a/test/unit/check/isolation.py +++ /dev/null @@ -1,160 +0,0 @@ -import json -from pathlib import Path - -from unit.applications.lang.go import ApplicationGo -from unit.applications.lang.java import ApplicationJava -from unit.applications.lang.node import ApplicationNode -from unit.applications.lang.ruby import ApplicationRuby -from unit.http import HTTP1 -from unit.option import option -from unit.utils import getns - -allns = ['pid', 'mnt', 'ipc', 'uts', 'cgroup', 'net'] -http = HTTP1() - - -def check_isolation(): - available = option.available - - conf = '' - if 'go' in available['modules']: - ApplicationGo().prepare_env('empty', 'app') - - conf = { - "listeners": {"*:8080": {"pass": "applications/empty"}}, - "applications": { - "empty": { - "type": "external", - "processes": {"spare": 0}, - "working_directory": f"{option.test_dir}/go/empty", - "executable": f"{option.test_dir}/go/app", - "isolation": {"namespaces": {"credential": True}}, - }, - }, - } - - elif 'python' in available['modules']: - conf = { - "listeners": {"*:8080": {"pass": "applications/empty"}}, - "applications": { - "empty": { - "type": "python", - "processes": {"spare": 0}, - "path": f"{option.test_dir}/python/empty", - "working_directory": f"{option.test_dir}/python/empty", - "module": "wsgi", - "isolation": {"namespaces": {"credential": True}}, - } - }, - } - - elif 'php' in available['modules']: - conf = { - "listeners": {"*:8080": {"pass": "applications/phpinfo"}}, - "applications": { - "phpinfo": { - "type": "php", - "processes": {"spare": 0}, - "root": f"{option.test_dir}/php/phpinfo", - "working_directory": f"{option.test_dir}/php/phpinfo", - "index": "index.php", - "isolation": {"namespaces": {"credential": True}}, - } - }, - } - - elif 'ruby' in available['modules']: - ApplicationRuby().prepare_env('empty') - - conf = { - "listeners": {"*:8080": {"pass": "applications/empty"}}, - "applications": { - "empty": { - "type": "ruby", - "processes": {"spare": 0}, - "working_directory": f"{option.temp_dir}/ruby/empty", - "script": f"{option.temp_dir}/ruby/empty/config.ru", - "isolation": {"namespaces": {"credential": True}}, - } - }, - } - - elif 'java' in available['modules']: - ApplicationJava().prepare_env('empty') - - conf = { - "listeners": {"*:8080": {"pass": "applications/empty"}}, - "applications": { - "empty": { - "unit_jars": f"{option.current_dir}/build", - "type": "java", - "processes": {"spare": 0}, - "working_directory": f"{option.temp_dir}/java/empty/", - "webapp": f"{option.temp_dir}/java", - "isolation": {"namespaces": {"credential": True}}, - } - }, - } - - elif 'node' in available['modules']: - ApplicationNode().prepare_env('basic') - - conf = { - "listeners": {"*:8080": {"pass": "applications/basic"}}, - "applications": { - "basic": { - "type": "external", - "processes": {"spare": 0}, - "working_directory": f"{option.temp_dir}/node", - "executable": "app.js", - "isolation": {"namespaces": {"credential": True}}, - } - }, - } - - elif 'perl' in available['modules']: - conf = { - "listeners": {"*:8080": {"pass": "applications/body_empty"}}, - "applications": { - "body_empty": { - "type": "perl", - "processes": {"spare": 0}, - "working_directory": f"{option.test_dir}/perl/body_empty", - "script": f"{option.test_dir}/perl/body_empty/psgi.pl", - "isolation": {"namespaces": {"credential": True}}, - } - }, - } - - else: - return False - - resp = http.put( - url='/config', - sock_type='unix', - addr=f'{option.temp_dir}/control.unit.sock', - body=json.dumps(conf), - ) - - if 'success' not in resp['body']: - return False - - userns = getns('user') - if not userns: - return False - - isolation = {'user': userns} - - path_clone = Path('/proc/sys/kernel/unprivileged_userns_clone') - if ( - path_clone.exists() - and path_clone.read_text(encoding='utf-8').rstrip() == '1' - ): - isolation['unprivileged_userns_clone'] = True - - for ns in allns: - ns_value = getns(ns) - if ns_value: - isolation[ns] = ns_value - - return isolation diff --git a/test/unit/check/njs.py b/test/unit/check/njs.py deleted file mode 100644 index 363a1b62..00000000 --- a/test/unit/check/njs.py +++ /dev/null @@ -1,5 +0,0 @@ -import re - - -def check_njs(output_version): - return re.search('--njs', output_version) diff --git a/test/unit/check/node.py b/test/unit/check/node.py deleted file mode 100644 index b206e914..00000000 --- a/test/unit/check/node.py +++ /dev/null @@ -1,17 +0,0 @@ -import subprocess -from pathlib import Path - -from unit.option import option - - -def check_node(): - if not Path(f'{option.current_dir}/node/node_modules').exists(): - return False - - try: - v_bytes = subprocess.check_output(['/usr/bin/env', 'node', '-v']) - - return [str(v_bytes, 'utf-8').lstrip('v').rstrip()] - - except subprocess.CalledProcessError: - return False diff --git a/test/unit/check/regex.py b/test/unit/check/regex.py deleted file mode 100644 index 83e93f2d..00000000 --- a/test/unit/check/regex.py +++ /dev/null @@ -1,5 +0,0 @@ -import re - - -def check_regex(output_version): - return not re.search('--no-regex', output_version) diff --git a/test/unit/check/tls.py b/test/unit/check/tls.py deleted file mode 100644 index 9cc2a5f9..00000000 --- a/test/unit/check/tls.py +++ /dev/null @@ -1,11 +0,0 @@ -import re -import subprocess - - -def check_openssl(output_version): - try: - subprocess.check_output(['which', 'openssl']) - except subprocess.CalledProcessError: - return False - - return re.search('--openssl', output_version) diff --git a/test/unit/check/unix_abstract.py b/test/unit/check/unix_abstract.py deleted file mode 100644 index 8fc7dd84..00000000 --- a/test/unit/check/unix_abstract.py +++ /dev/null @@ -1,25 +0,0 @@ -import json - -from unit.http import HTTP1 -from unit.option import option - -http = HTTP1() - - -def check_unix_abstract(): - return ( - 'success' - in http.put( - url='/config', - sock_type='unix', - addr=f'{option.temp_dir}/control.unit.sock', - body=json.dumps( - { - "listeners": { - f'unix:@{option.temp_dir}/sock': {"pass": "routes"} - }, - "routes": [], - } - ), - )['body'] - ) diff --git a/test/unit/control.py b/test/unit/control.py deleted file mode 100644 index 8cdf1887..00000000 --- a/test/unit/control.py +++ /dev/null @@ -1,59 +0,0 @@ -import json - -from unit.http import HTTP1 -from unit.option import option - - -def args_handler(conf_func): - def args_wrapper(self, *args): - argcount = conf_func.__code__.co_argcount - url_default = '/config' - conf = None - - if argcount == 2: - url = args[0] if len(args) == 1 else url_default - - elif argcount == 3: - conf = args[0] - - if isinstance(conf, (dict, list)): - conf = json.dumps(conf) - - url = args[1] if len(args) == 2 else url_default - - url = url if url.startswith('/') else f'{url_default}/{url}' - arguments = (self, url) if conf is None else (self, conf, url) - - return json.loads(conf_func(*arguments)) - - return args_wrapper - - -class Control(HTTP1): - @args_handler - def conf(self, conf, url): - return self.put(**self._get_args(url, conf))['body'] - - @args_handler - def conf_get(self, url): - return self.get(**self._get_args(url))['body'] - - @args_handler - def conf_delete(self, url): - return self.delete(**self._get_args(url))['body'] - - @args_handler - def conf_post(self, conf, url): - return self.post(**self._get_args(url, conf))['body'] - - def _get_args(self, url, conf=None): - args = { - 'url': url, - 'sock_type': 'unix', - 'addr': f'{option.temp_dir}/control.unit.sock', - } - - if conf is not None: - args['body'] = conf - - return args diff --git a/test/unit/http.py b/test/unit/http.py deleted file mode 100644 index 9401501b..00000000 --- a/test/unit/http.py +++ /dev/null @@ -1,359 +0,0 @@ -import binascii -import io -import json -import os -import re -import select -import socket - -import pytest - -from unit.option import option - - -class HTTP1: - def http(self, start_str, **kwargs): - sock_type = kwargs.get('sock_type', 'ipv4') - port = kwargs.get('port', 8080) - url = kwargs.get('url', '/') - http = 'HTTP/1.0' if 'http_10' in kwargs else 'HTTP/1.1' - - headers = kwargs.get( - 'headers', {'Host': 'localhost', 'Connection': 'close'} - ) - - body = kwargs.get('body', b'') - crlf = '\r\n' - - if 'addr' not in kwargs: - addr = '::1' if sock_type == 'ipv6' else '127.0.0.1' - else: - addr = kwargs['addr'] - - sock_types = { - 'ipv4': socket.AF_INET, - 'ipv6': socket.AF_INET6, - 'unix': socket.AF_UNIX, - } - - if 'sock' not in kwargs: - sock = socket.socket(sock_types[sock_type], socket.SOCK_STREAM) - - if sock_type in (sock_types['ipv4'], sock_types['ipv6']): - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - - if 'wrapper' in kwargs: - server_hostname = headers.get('Host', None) - sock = kwargs['wrapper'](sock, server_hostname=server_hostname) - - connect_args = addr if sock_type == 'unix' else (addr, port) - try: - sock.connect(connect_args) - except (ConnectionRefusedError, FileNotFoundError): - sock.close() - pytest.fail("Client can't connect to the server.") - - else: - sock = kwargs['sock'] - - if 'raw' not in kwargs: - req = f'{start_str} {url} {http}{crlf}' - - if body != b'': - if isinstance(body, str): - body = body.encode() - elif isinstance(body, dict): - body, content_type = self.form_encode(body) - - headers['Content-Type'] = content_type - - if 'Content-Length' not in headers: - headers['Content-Length'] = len(body) - - for header, value in headers.items(): - if isinstance(value, list): - for v in value: - req += f'{header}: {v}{crlf}' - - else: - req += f'{header}: {value}{crlf}' - - req = (req + crlf).encode() + body - - else: - req = start_str - - sock.sendall(req) - - encoding = kwargs.get('encoding', 'utf-8') - - self.log_out(req, encoding) - - resp = '' - - if 'no_recv' not in kwargs: - recvall_kwargs = {} - - if 'read_timeout' in kwargs: - recvall_kwargs['read_timeout'] = kwargs['read_timeout'] - - if 'read_buffer_size' in kwargs: - recvall_kwargs['buff_size'] = kwargs['read_buffer_size'] - - resp = self.recvall(sock, **recvall_kwargs).decode( - encoding, errors='ignore' - ) - - else: - return sock - - self.log_in(resp) - - if 'raw_resp' not in kwargs: - resp = self._resp_to_dict(resp) - - headers = resp.get('headers') - if headers and headers.get('Transfer-Encoding') == 'chunked': - resp['body'] = self._parse_chunked_body(resp['body']).decode( - encoding - ) - - if 'json' in kwargs: - resp = self._parse_json(resp) - - if 'start' not in kwargs: - sock.close() - return resp - - return (resp, sock) - - def log_out(self, log, encoding): - if option.detailed: - print('>>>') - log = self.log_truncate(log) - try: - print(log.decode(encoding, 'ignore')) - except UnicodeEncodeError: - print(log) - - def log_in(self, log): - if option.detailed: - print('<<<') - log = self.log_truncate(log) - try: - print(log) - except UnicodeEncodeError: - print(log.encode()) - - def log_truncate(self, log, limit=1024): - len_log = len(log) - if len_log > limit: - log = log[:limit] - appendix = f'(...logged {limit} of {len_log} bytes)' - - if isinstance(log, bytes): - appendix = appendix.encode() - - log = f'{log}{appendix}' - - return log - - def delete(self, **kwargs): - return self.http('DELETE', **kwargs) - - def get(self, **kwargs): - return self.http('GET', **kwargs) - - def head(self, **kwargs): - return self.http('HEAD', **kwargs) - - def post(self, **kwargs): - return self.http('POST', **kwargs) - - def put(self, **kwargs): - return self.http('PUT', **kwargs) - - def recvall(self, sock, **kwargs): - timeout_default = 60 - - timeout = kwargs.get('read_timeout', timeout_default) - buff_size = kwargs.get('buff_size', 4096) - - data = b'' - while True: - rlist = select.select([sock], [], [], timeout)[0] - if not rlist: - # For all current cases if the "read_timeout" was changed - # than test do not expect to get a response from server. - if timeout == timeout_default: - pytest.fail("Can't read response from server.") - break - - try: - part = sock.recv(buff_size) - - except KeyboardInterrupt: - raise - - except: - break - - data += part - - if not part: - break - - return data - - def _resp_to_dict(self, resp): - m = re.search(r'(.*?\x0d\x0a?)\x0d\x0a?(.*)', resp, re.M | re.S) - - if not m: - return {} - - headers_text, body = m.group(1), m.group(2) - headers_lines = re.findall('(.*?)\x0d\x0a?', headers_text, re.M | re.S) - - status = re.search( - r'^HTTP\/\d\.\d\s(\d+)|$', headers_lines.pop(0) - ).group(1) - - headers = {} - for line in headers_lines: - m = re.search(r'(.*)\:\s(.*)', line) - - if m.group(1) not in headers: - headers[m.group(1)] = m.group(2) - - elif isinstance(headers[m.group(1)], list): - headers[m.group(1)].append(m.group(2)) - - else: - headers[m.group(1)] = [headers[m.group(1)], m.group(2)] - - return {'status': int(status), 'headers': headers, 'body': body} - - def _parse_chunked_body(self, raw_body): - if isinstance(raw_body, str): - raw_body = bytes(raw_body.encode()) - - crlf = b'\r\n' - chunks = raw_body.split(crlf) - - if len(chunks) < 3: - pytest.fail('Invalid chunked body') - - if chunks.pop() != b'': - pytest.fail('No CRLF at the end of the body') - - try: - last_size = int(chunks[-2], 16) - - except ValueError: - pytest.fail('Invalid zero size chunk') - - if last_size != 0 or chunks[-1] != b'': - pytest.fail('Incomplete body') - - body = b'' - while len(chunks) >= 2: - try: - size = int(chunks.pop(0), 16) - - except ValueError: - pytest.fail('Invalid chunk size') - - if size == 0: - assert len(chunks) == 1, 'last zero size' - break - - temp_body = crlf.join(chunks) - - body += temp_body[:size] - - temp_body = temp_body[size + len(crlf) :] - - chunks = temp_body.split(crlf) - - return body - - def _parse_json(self, resp): - headers = resp['headers'] - - assert 'Content-Type' in headers - assert headers['Content-Type'] == 'application/json' - - resp['body'] = json.loads(resp['body']) - - return resp - - def getjson(self, **kwargs): - return self.get(json=True, **kwargs) - - def form_encode(self, fields): - is_multipart = False - - for _, value in fields.items(): - if isinstance(value, dict): - is_multipart = True - break - - if is_multipart: - body, content_type = self.multipart_encode(fields) - - else: - body, content_type = self.form_url_encode(fields) - - return body, content_type - - def form_url_encode(self, fields): - data = "&".join( - f'{name}={value}' for name, value in fields.items() - ).encode() - return data, 'application/x-www-form-urlencoded' - - def multipart_encode(self, fields): - boundary = binascii.hexlify(os.urandom(16)).decode('ascii') - - body = '' - - for field, value in fields.items(): - filename = '' - datatype = '' - - if isinstance(value, dict): - datatype = 'text/plain' - filename = value['filename'] - - if value.get('type'): - datatype = value['type'] - - if not isinstance(value['data'], io.IOBase): - pytest.fail('multipart encoding of file requires a stream.') - - data = value['data'].read() - - elif isinstance(value, str): - data = value - - else: - pytest.fail('multipart requires a string or stream data') - - body += ( - f'--{boundary}\r\nContent-Disposition: form-data;' - f'name="{field}"' - ) - - if filename != '': - body += f'; filename="{filename}"' - - body += '\r\n' - - if datatype != '': - body += f'Content-Type: {datatype}\r\n' - - body += f'\r\n{data}\r\n' - - body += f'--{boundary}--\r\n' - - return body.encode(), f'multipart/form-data; boundary={boundary}' diff --git a/test/unit/log.py b/test/unit/log.py deleted file mode 100644 index 7d7e355a..00000000 --- a/test/unit/log.py +++ /dev/null @@ -1,113 +0,0 @@ -import os -import re -import sys -import time - -from unit.option import option - -UNIT_LOG = 'unit.log' - - -def print_log_on_assert(func): - def inner_function(*args, **kwargs): - try: - func(*args, **kwargs) - except AssertionError as exception: - Log.print_log(*args, **kwargs) - raise exception - - return inner_function - - -class Log: - pos = {} - - @staticmethod - @print_log_on_assert - def check_alerts(log=None): - if log is None: - log = Log.read() - - found = False - alerts = re.findall(r'.+\[alert\].+', log) - - if alerts: - found = True - - if option.detailed: - print('\nAll alerts/sanitizer errors found in log:') - _ = [print(alert) for alert in alerts] - - if option.skip_alerts: - for skip in option.skip_alerts: - alerts = [al for al in alerts if re.search(skip, al) is None] - - assert not alerts, 'alert(s)' - - if not option.skip_sanitizer: - sanitizer_errors = re.findall('.+Sanitizer.+', log) - - assert not sanitizer_errors, 'sanitizer error(s)' - - if found and option.detailed: - print('skipped.') - - @staticmethod - def findall(pattern, name=UNIT_LOG, flags=re.M): - return re.findall(pattern, Log.read(name), flags) - - @staticmethod - def get_path(name=UNIT_LOG): - return f'{option.temp_dir}/{name}' - - @staticmethod - def open(name=UNIT_LOG, encoding='utf-8'): - file = open(Log.get_path(name), 'r', encoding=encoding, errors='ignore') - file.seek(Log.pos.get(name, 0)) - - return file - - @staticmethod - def print_log(log=None): - Log.print_path() - - if option.print_log: - os.set_blocking(sys.stdout.fileno(), True) - sys.stdout.flush() - - if log is None: - log = Log.read() - - sys.stdout.write(log) - - @staticmethod - def print_path(): - print(f'Path to {UNIT_LOG}:\n{Log.get_path()}\n') - - @staticmethod - def read(*args, **kwargs): - with Log.open(*args, **kwargs) as file: - return file.read() - - @staticmethod - def set_pos(pos, name=UNIT_LOG): - Log.pos[name] = pos - - @staticmethod - def swap(name): - pos = Log.pos.get(UNIT_LOG, 0) - Log.pos[UNIT_LOG] = Log.pos.get(name, 0) - Log.pos[name] = pos - - @staticmethod - def wait_for_record(pattern, name=UNIT_LOG, wait=150, flags=re.M): - with Log.open(name) as file: - for _ in range(wait): - found = re.search(pattern, file.read(), flags) - - if found is not None: - break - - time.sleep(0.1) - - return found diff --git a/test/unit/option.py b/test/unit/option.py deleted file mode 100644 index 7c66c619..00000000 --- a/test/unit/option.py +++ /dev/null @@ -1,26 +0,0 @@ -import os -import platform - - -class Options: - _options = { - 'architecture': platform.architecture()[0], - 'available': {'modules': {}, 'features': {}}, - 'configure_flag': {}, - 'is_privileged': os.geteuid() == 0, - 'skip_alerts': [], - 'skip_sanitizer': False, - 'system': platform.system(), - } - - def __setattr__(self, name, value): - Options._options[name] = value - - def __getattr__(self, name): - if name in Options._options: - return Options._options[name] - - raise AttributeError - - -option = Options() diff --git a/test/unit/status.py b/test/unit/status.py deleted file mode 100644 index 95096a96..00000000 --- a/test/unit/status.py +++ /dev/null @@ -1,45 +0,0 @@ -from unit.control import Control - - -class Status: - _status = None - control = Control() - - def _check_zeros(): - assert Status.control.conf_get('/status') == { - 'connections': { - 'accepted': 0, - 'active': 0, - 'idle': 0, - 'closed': 0, - }, - 'requests': {'total': 0}, - 'applications': {}, - } - - def init(status=None): - Status._status = ( - status if status is not None else Status.control.conf_get('/status') - ) - - def diff(): - def find_diffs(d1, d2): - if isinstance(d1, dict) and isinstance(d2, dict): - return { - k: find_diffs(d1.get(k, 0), d2.get(k, 0)) - for k in d1 - if k in d2 - } - - return d1 - d2 - - return find_diffs(Status.control.conf_get('/status'), Status._status) - - def get(path='/'): - path_lst = path.split('/')[1:] - diff = Status.diff() - - for part in path_lst: - diff = diff[part] - - return diff diff --git a/test/unit/utils.py b/test/unit/utils.py deleted file mode 100644 index cd823e27..00000000 --- a/test/unit/utils.py +++ /dev/null @@ -1,123 +0,0 @@ -import glob -import os -import socket -import subprocess -import time - -import pytest - - -def public_dir(path): - os.chmod(path, 0o777) - - for root, dirs, files in os.walk(path): - for d in dirs: - try: - os.chmod(os.path.join(root, d), 0o777) - except FileNotFoundError: - pass - for f in files: - try: - os.chmod(os.path.join(root, f), 0o777) - except FileNotFoundError: - pass - - -def waitforfiles(*files, timeout=50): - for _ in range(timeout): - wait = False - - for f in files: - if not os.path.exists(f): - wait = True - break - - if not wait: - return True - - time.sleep(0.1) - - return False - - -def waitforglob(pattern, count=1, timeout=50): - for _ in range(timeout): - n = 0 - - for _ in glob.glob(pattern): - n += 1 - - if n == count: - return True - - time.sleep(0.1) - - return False - - -def waitforsocket(port): - for _ in range(50): - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: - try: - sock.settimeout(5) - sock.connect(('127.0.0.1', port)) - return - - except ConnectionRefusedError: - time.sleep(0.1) - - except KeyboardInterrupt: - raise - - pytest.fail(f"Can't connect to the 127.0.0.1:{port}") - - -def check_findmnt(): - try: - return subprocess.check_output( - ['findmnt', '--raw'], stderr=subprocess.STDOUT - ).decode() - except FileNotFoundError: - return False - - -def findmnt(): - out = check_findmnt() - - if not out: - pytest.skip('requires findmnt') - - return out - - -def waitformount(template, timeout=50): - for _ in range(timeout): - if findmnt().find(template) != -1: - return True - - time.sleep(0.1) - - return False - - -def waitforunmount(template, timeout=50): - for _ in range(timeout): - if findmnt().find(template) == -1: - return True - - time.sleep(0.1) - - return False - - -def getns(nstype): - # read namespace id from symlink file: - # it points to: ':[]' - # # eg.: 'pid:[4026531836]' - nspath = f'/proc/self/ns/{nstype}' - data = None - - if os.path.exists(nspath): - data = int(os.readlink(nspath)[len(nstype) + 2 : -1]) - - return data diff --git a/tools/README.md b/tools/README.md deleted file mode 100644 index e7caae34..00000000 --- a/tools/README.md +++ /dev/null @@ -1,106 +0,0 @@ -# Unit Tools - -This directory contains useful tools for installing, configuring, and -managing NGINX Unit. They may not be part of official packages and -should be considered experimental. - -* [`setup-unit`](#setup-unit) -* [`unitc`](#unitc) - ---- - -## setup-unit - -### A script that simplifies installing and configuring an NGINX Unit server for first-time users - -* `setup-unit repo-config` configures your package manager with the NGINX -Unit repository for later installation. -* `setup-unit welcome` creates an initial configuration to serve a welcome -web page with NGINX Unit. - ---- - -## unitc - -### A curl wrapper for managing NGINX Unit configuration - -```USAGE: unitc [options] URI``` - - * **URI** specifies the target in Unit's control API, e.g. `/config` . - * Configuration data is read from stdin. - * [jq](https://stedolan.github.io/jq/) is used to prettify JSON output, if - available. - -| Options | | -|---------|-| -| filename … | Read configuration data consecutively from the specified files instead of stdin. -| _HTTP method_ | It is usually not required to specify a HTTP method. `GET` is used to read the configuration. `PUT` is used when making configuration changes unless a specific method is provided. -| `edit` | Opens **URI** in the default editor for interactive configuration. The [jq](https://stedolan.github.io/jq/) tool is required for this option. -| `INSERT` | A _virtual_ HTTP method that prepends data when the URI specifies an existing array. The [jq](https://stedolan.github.io/jq/) tool is required for this option. -| `-f` \| `--format YAML` | Convert configuration data to/from YAML format. The [yq](https://github.com/mikefarah/yq) tool is required for this option. -| `-q` \| `--quiet` | No output to stdout. - -Options are case insensitive and can appear in any order. For example, a -redundant part of the configuration can be identified by its URI, and -followed by `delete` in a subsequent command. - -Options may be combined. For example, `edit -f yaml` will open the -configuration URI in a text editor, in YAML format. - -### Local Configuration -For local instances of Unit, the control socket is automatically detected. -The error log is monitored; when changes occur, new log entries are shown. - -| Options | | -|---------|-| -| `-l` \| `--nolog` | Do not monitor the error log after configuration changes. - -#### Local Examples -```shell -unitc /config -unitc /config < unitconf.json -echo '{"*:8080": {"pass": "routes"}}' | unitc /config/listeners -unitc /config/applications/my_app DELETE -unitc /certificates/bundle cert.pem key.pem -``` - -### Remote Configuration -For remote instances of NGINX Unit, the control socket on the remote host can -be set with the `$UNIT_CTRL` environment variable. The remote control socket -can be accessed over TCP, SSH, or Docker containers on the host, depending on -the type of control socket: - - * `ssh://[user@]remote_host[:ssh_port]/path/to/control.socket` - * `http://remote_host:unit_control_port` - * `docker://container_ID[/path/to/control.socket]` - -> **Note:** SSH is recommended for remote confguration. Consider the -> [security implications](https://unit.nginx.org/howto/security/#secure-socket-and-state) -> of managing remote configuration over plaintext HTTP. - -| Options | | -|---------|-| -| `ssh://…` | Specify the remote Unix control socket on the command line. -| `http://…`*URI* | For remote TCP control sockets, the URI may include the protocol, hostname, and port. -| `docker://…` | Specify the local container ID/name. The default Unix control socket can be overridden. - -#### Remote Examples -```shell -unitc http://192.168.0.1:8080/status -UNIT_CTRL=http://192.168.0.1:8080 unitc /status - -export UNIT_CTRL=ssh://root@unithost/var/run/control.unit.sock -unitc /config/routes -cat catchall_route.json | unitc POST /config/routes -echo '{"match":{"uri":"/wp-admin/*"},"action":{"return":403}}' | unitc INSERT /config/routes -``` - -#### Docker Examples -```shell -unitc docker://d43251184c54 /config -echo '{"http": {"log_route": true}}' | unitc docker://d43251184c54 /settings -unitc docker://f4f3d9e918e6/root/unit.sock /control/applications/my_app/restart -UNIT_CTRL=docker://4d0431488982 unitc /status/requests/total -``` - ---- diff --git a/tools/setup-unit b/tools/setup-unit deleted file mode 100755 index 688e87a1..00000000 --- a/tools/setup-unit +++ /dev/null @@ -1,1673 +0,0 @@ -#!/usr/bin/env bash - -##################################################################### -# -# Copyright (C) NGINX, Inc. -# Author: NGINX Unit Team, F5 Inc. -# Copyright 2024, Alejandro Colomar -# -##################################################################### - - -if test -n ${BASH_VERSION} && test "${BASH_VERSINFO[0]}" -eq 3; then - >&2 cat <<__EOF__ ; -Your version of bash(1) isn't supported by this script. You're probably -running on macOS. We recommend that you either install a newer version -of bash(1) or run this script with another shell, such as zsh(1): - - $ ${SUDO_USER:+sudo }zsh $0 ... -__EOF__ - exit 1; -fi; - - -set -Eefuo pipefail; - -test -v BASH_VERSION \ -&& shopt -s lastpipe; - -test -v ZSH_VERSION \ -&& setopt sh_word_split; - - -export LC_ALL=C - -dry_run='no'; - -help_unit() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 [-h[h]] COMMAND [ARGS] - - Subcommands - ├── repo-config [-hn] [PKG-MANAGER OS-NAME OS-VERSION] - └── welcome [-hn] - -DESCRIPTION - This script simplifies installing and configuring an NGINX Unit server - for first-time users. - - Run '$0 COMMAND -h' for more information on a command. - -COMMANDS - repo-config - Configure your package manager with the NGINX Unit repository - for later installation. - - welcome - Create an initial configuration to serve a welcome web page - with NGINX Unit. - -OPTIONS - -h, --help - Print this help. - - -hh, --help-more - Print help for more (advanced) commands. - -__EOF__ -} - -help_more_unit() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 [-h[h]] COMMAND [ARGS] - - Subcommands - ├── cmd [-h] - ├── ctl [-h] [-s SOCK] SUBCOMMAND [ARGS] - │ ├── edit [-h] PATH - │ ├── http [-h] [-c CURLOPT] METHOD PATH - │ └── insert [-h] PATH INDEX - ├── freeport [-h] - ├── json-ins [-hn] JSON INDEX - ├── os-probe [-h] - ├── ps [-h] [-t TYPE] - ├── repo-config [-hn] [PKG-MANAGER OS-NAME OS-VERSION] - ├── restart [-hls] - ├── sock [-h] SUBCOMMAND [ARGS] - │ ├── filter [-chs] - │ └── find [-h] - └── welcome [-hn] - -DESCRIPTION - This script simplifies installing and configuring - an NGINX Unit server for first-time users. - - Run '$0 COMMAND -h' for more information on a command. - -COMMANDS - cmd Print the invocation line of unitd(8). - - ctl Control a running unitd(8) instance via its control API socket. - - freeport - Print an available TCP port. - - json-ins - Insert a JSON element read from standard input into a JSON - array read from a file at a given INDEX. - - os-probe - Probe the OS and print details about its version. - - ps List unitd(8) processes. - - repo-config - Configure your package manager with the NGINX Unit - repository for later installation. - - restart - Restart all running unitd(8) instances. - - sock Print the control API socket address. - - welcome - Create an initial configuration to serve a welcome web page - with NGINX Unit. - -OPTIONS - -h, --help - Print basic help (some commands are hidden). - - -hh, --help-more - Print the hidden help with more commands. - -__EOF__ -} - -info() -{ - >&2 echo "$(basename "$0"): info: $*"; -} - -warn() -{ - >&2 echo "$(basename "$0"): error: $*"; -} - -err() -{ - >&2 echo "$(basename "$0"): error: $*"; - exit 1; -} - -dry_run_echo() -{ - if test "$dry_run" = "yes"; then - echo "$*"; - fi; -} - -dry_run_eval() -{ - if test "$dry_run" = "yes"; then - echo " $*"; - else - eval "$*"; - fi; -} - -run_trap() -{ - trap -p "$1" \ - | tr -d '\n' \ - | sed "s/[^']*'\(.*\)'[^']*/\1/" \ - | sed "s/'\\\\''/'/g" \ - | read -r trap_cmd; - - eval $trap_cmd; - trap - "$1"; -} - - -help_unit_cmd() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 cmd [-h] - -DESCRIPTION - Print the invocation line of running unitd(8) instances. - -OPTIONS - -h, --help - Print this help. - -__EOF__ -} - - -unit_cmd() -{ - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_cmd; - exit 0; - ;; - -*) - err "cmd: $1: Unknown option."; - ;; - *) - err "cmd: $1: Unknown argument."; - ;; - esac; - shift; - done; - - unit_ps -t m \ - | sed 's/.*\[\(.*\)].*/\1/'; -} - - -help_unit_ctl() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 ctl [-h] [-s SOCK] SUBCOMMAND [ARGS] - - Subcommands - ├── edit [-h] PATH - ├── http [-h] [-c CURLOPT] METHOD PATH - └── insert [-h] PATH INDEX - -DESCRIPTION - Control a running unitd(8) instance through its control API socket. - - Run '$0 ctl SUBCOMMAND -h' for more information on a - subcommand. - -SUBCOMMANDS - edit Edit the unitd(8) configuration with an editor. - - http Send an HTTP request to the control API socket. - - insert Insert an element at the specified index into an array in the - JSON configuration. - -OPTIONS - -h, --help - Print this help. - - -s, --sock SOCK - Use SOCK as the control API socket address. If not specified, - the script tries to find it. This value is used by subcommands. - - The socket can be a tcp(7) socket or a unix(7) socket; in - the case of a unix(7) socket, it can exist locally or on - a remote machine, accessed through ssh(1). Accepted syntax - for SOCK: - - unix:/path/to/control.sock - ssh://[user@]host[:port]/path/to/control.sock - [http[s]://]host[:port] - - The last form is less secure than the first two; have a look: - - -ENVIRONMENT - Options take precedence over their equivalent environment variables; - if both are specified, the command-line option is used. - - UNIT_CTL_SOCK - Equivalent to the option -s (--sock). - -__EOF__ -} - - -unit_ctl() -{ - - if test -v UNIT_CTL_SOCK; then - local sock="$UNIT_CTL_SOCK"; - fi; - - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_ctl; - exit 0; - ;; - -s | --sock) - if ! test $# -ge 2; then - err "ctl: $1: Missing argument."; - fi; - local sock="$2"; - shift; - ;; - -*) - err "ctl: $1: Unknown option."; - ;; - *) - break; - ;; - esac; - shift; - done; - - if test ! $# -ge 1; then - err 'ctl: Missing subcommand.'; - fi; - - if ! test -v sock; then - local sock="$(unit_sock_find)"; - fi; - - if echo $sock | grep '^ssh://' >/dev/null; then - local remote="$(echo $sock | sed 's,\(ssh://[^/]*\).*,\1,')"; - local sock="$(echo $sock | sed 's,ssh://[^/]*\(.*\),unix:\1,')"; - - local remote_sock="$(echo "$sock" | unit_sock_filter -s)"; - local local_sock="$(mktemp -u -p /var/run/unit/)"; - local ssh_ctrl="$(mktemp -u -p /var/run/unit/)"; - - mkdir -p /var/run/unit/; - - ssh -fMNnT -S "$ssh_ctrl" \ - -o 'ExitOnForwardFailure yes' \ - -L "$local_sock:$remote_sock" "$remote"; - - trap "ssh -S '$ssh_ctrl' -O exit '$remote' 2>/dev/null; - unlink '$local_sock';" EXIT; - - sock="unix:$local_sock"; - fi; - - case $1 in - edit) - shift; - unit_ctl_edit ---s "$sock" $@; - ;; - http) - shift; - unit_ctl_http ---s "$sock" $@; - ;; - insert) - shift; - unit_ctl_insert ---s "$sock" $@; - ;; - *) - err "ctl: $1: Unknown argument."; - ;; - esac; - - if test -v remote; then - run_trap EXIT; - fi; -} - - -help_unit_ctl_edit() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 ctl [CTL-OPTS] edit [-h] PATH - -DESCRIPTION - Edit the JSON configuration with an editor. The current configuration - is downloaded into a temporary file, open with the editor, and then - sent back to the control API socket. - - The following editors are tried in this order of preference: \$VISUAL, - \$EDITOR, editor(1), vi(1), vim(1), ed(1). - - -OPTIONS - -h, --help - Print this help. - -ENVIRONMENT - VISUAL - EDITOR - See environ(7). - -SEE ALSO - $0 ctl http -h; - - update-alternatives(1) - -__EOF__ -} - - -unit_ctl_edit() -{ - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_ctl_edit; - exit 0; - ;; - ---s | ----sock) - local sock="$2"; - shift; - ;; - -*) - err "ctl: edit: $1: Unknown option."; - ;; - *) - break; - ;; - esac; - shift; - done; - - if ! test $# -ge 1; then - err 'ctl: edit: PATH: Missing argument.'; - fi; - local req_path="$1"; - - echo "$req_path" \ - | sed 's%^/js_modules/.*%.js%' \ - | sed 's%^/config\>.*%.json%' \ - | sed 's%^/.*%.txt%' \ - | xargs mktemp --suffix \ - | read -r tmp; - - unit_ctl_http ---s "$sock" -c --no-progress-meter GET "$req_path" \ - "$tmp"; - - $( - ((test -v VISUAL && test -n "$VISUAL") && printf '%s\n' "$VISUAL") \ - || ((test -v EDITOR && test -n "$EDITOR") && printf '%s\n' "$EDITOR") \ - || command -v editor \ - || command -v vi \ - || command -v vim \ - || echo ed; - ) "$tmp"; - - trap "info 'ctl: edit: Invalid configuration saved in <$tmp>.'" ERR - - unit_ctl_http ---s "$sock" PUT "$req_path" <"$tmp"; - - trap - ERR; -} - - -help_unit_ctl_http() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 ctl [CTL-OPTS] http [-h] [-c CURLOPT] METHOD PATH - -DESCRIPTION - Send an HTTP request to the unitd(8) control API socket. - - The payload is read from standard input. - -OPTIONS - -c, --curl CURLOPT - Pass CURLOPT as an option to curl. This script is implemented - in terms of curl(1), so it's useful to be able to tweak its - behavior. The option can be cumulatively used multiple times - (the result is also appended to UNIT_CTL_HTTP_CURLOPTS). - - -h, --help - Print this help. - -ENVIRONMENT - UNIT_CTL_HTTP_CURLOPTS - Equivalent to the option -c (--curl). - -EXAMPLES - $0 ctl http -c --no-progress-meter GET /config >tmp; - -SEE ALSO - - -__EOF__ -} - - -unit_ctl_http() -{ - local curl_options="${UNIT_CTL_HTTP_CURLOPTS:-}"; - - while test $# -ge 1; do - case "$1" in - -c | --curl) - if ! test $# -ge 2; then - err "ctl: http: $1: Missing argument."; - fi; - curl_options="$curl_options $2"; - shift; - ;; - -h | --help) - help_unit_ctl_http; - exit 0; - ;; - ---s | ----sock) - local sock="$2"; - shift; - ;; - -*) - err "ctl: http: $1: Unknown option."; - ;; - *) - break; - ;; - esac; - shift; - done; - - if ! test $# -ge 1; then - err 'ctl: http: METHOD: Missing argument.'; - fi; - local method="$1"; - - if ! test $# -ge 2; then - err 'ctl: http: PATH: Missing argument.'; - fi; - local req_path="$2"; - - curl --fail-with-body $curl_options -X $method -d@- \ - $(echo "$sock" | unit_sock_filter -c)${req_path}; -} - - -help_unit_ctl_insert() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 ctl [CTL-OPTS] insert [-h] PATH INDEX - -DESCRIPTION - Insert an element at the specified position (INDEX) into the JSON array - located at PATH in unitd(8) control API. - - The new element is read from standard input. - -OPTIONS - -h, --help - Print this help. - -SEE ALSO - $0 ctl http -h; - -__EOF__ -} - - -unit_ctl_insert() -{ - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_ctl_insert; - exit 0; - ;; - ---s | ----sock) - local sock="$2"; - shift; - ;; - -*) - err "ctl: insert: $1: Unknown option."; - ;; - *) - break; - ;; - esac; - shift; - done; - - if ! test $# -ge 1; then - err 'ctl: insert: PATH: Missing argument.'; - fi; - local req_path="$1"; - - if ! test $# -ge 2; then - err 'ctl: insert: INDEX: Missing argument.'; - fi; - local idx="$2"; - - local old="$(mktemp)"; - - unit_ctl_http ---s "$sock" -c --no-progress-meter GET "$req_path" \ - "$old"; - - unit_json_ins "$old" "$idx" \ - | unit_ctl_http ---s "$sock" PUT "$req_path"; -} - - -help_unit_ctl_welcome() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 welcome [-hn] - -DESCRIPTION - This script tests an NGINX Unit installation by creating an initial - configuration and serving a welcome web page. Recommended for - first-time users. - -OPTIONS - -h, --help - Print this help. - - -n, --dry-run - Dry run. Print the commands to be run instead of actually - running them. Each command is preceded by a line explaining - what it does. - -__EOF__ -} - - -unit_ctl_welcome() -{ - while test $# -ge 1; do - case "$1" in - -f | --force) - local force='yes'; - ;; - -h | --help) - help_unit_ctl_welcome; - exit 0; - ;; - -n | --dry-run) - dry_run='yes'; - ;; - -*) - err "welcome: $1: Unknown option."; - ;; - *) - err "welcome: $1: Unknown argument."; - ;; - esac; - shift; - done; - - command -v curl >/dev/null \ - || err 'welcome: curl(1) not found in PATH. It must be installed to run this script.'; - - www='/srv/www/unit/index.html'; - if test -e "$www" && ! test -v force || ! test -w /srv; then - www="$HOME/srv/www/unit/index.html"; - fi; - if test -e "$www" && ! test -v force; then - www="$(mktemp)"; - mv "$www" "$www.html"; - www="$www.html" - fi; - - unit_ps -t m \ - | wc -l \ - | read -r nprocs \ - ||: - - if test 0 -eq "$nprocs"; then - warn "welcome: NGINX Unit isn't running."; - warn 'For help with starting NGINX Unit, see:'; - err " "; - elif test 1 -ne "$nprocs"; then - err 'welcome: Only one NGINX Unit instance should be running.'; - fi; - - local sock="$(unit_sock_find)"; - local curl_opt="$(unit_sock_find | unit_sock_filter -c)"; - - curl $curl_opt/ >/dev/null 2>&1 \ - || err "welcome: Can't reach the control API socket."; - - if ! test -v force; then - unit_cmd \ - | read -r cmd; - - # Check unitd is not configured already. - echo "$cmd" \ - | if grep '\--statedir' >/dev/null; then - echo "$cmd" \ - | sed 's/ --/\n--/g' \ - | grep '\--statedir' \ - | cut -d' ' -f2; - else - $cmd --help \ - | sed -n '/\--statedir/,+1p' \ - | grep 'default:' \ - | sed 's/ *default: "\(.*\)"/\1/'; - fi \ - | sed 's,$,/conf.json,' \ - | read -r conffile \ - ||:; - - if test -e $conffile; then - if ! unit_ctl_http ---s "$sock" 'GET' '/config' /dev/null | grep -q '^{}.\?$'; # The '.\?' is for the possible carriage return. - then - warn 'welcome: NGINX Unit is already configured. To overwrite'; - err 'its current configuration, run the script again with --force.'; - fi; - fi; - fi; - - ( - unit_freeport \ - || err "welcome: Can't find an available port."; - ) \ - | read -r port; - - dry_run_echo 'Create a file to serve:'; - dry_run_eval "mkdir -p $(dirname $www);"; - dry_run_eval "tee '$www' >/dev/null"' <<__EOF__; - - - - Welcome to NGINX Unit - - - -

Welcome to NGINX Unit

-

Congratulations! NGINX Unit is installed and running.

-

Useful Links

- - -

Next steps

- -

Check Current Configuration

-
-

Unit'"'"'s control API is currently listening for configuration changes - on the '"$(unit_sock_find | grep -q '^unix:' && echo 'Unix socket' || echo 'socket')"' at - '"$(unit_sock_find)"'
- To see the current configuration:

-
'"${SUDO_USER:+sudo }"'curl '"$curl_opt"'/config
-
- -

Change Listener Port

-
-

This page is served over a random TCP high port. To choose the default HTTP port (80), - replace the "listeners" object:

-
echo '"'"'{"*:80": {"pass": "routes"}}'"'"' | '"${SUDO_USER:+sudo }"'curl -X PUT -d@- '"$curl_opt"'/config/listeners
- Then remove the port number from the address bar and reload the page. -
- -
-

NGINX Unit — the universal web app server
- NGINX, Inc. © 2024

- - -__EOF__'; - dry_run_echo; - dry_run_echo 'Give it appropriate permissions:'; - dry_run_eval "chmod 644 '$www';"; - dry_run_echo; - - dry_run_echo 'Configure unitd:' - dry_run_eval "cat <<__EOF__ \\ - | sed 's/8080/$port/' \\ - | curl -X PUT -d@- $curl_opt/config; - { - \"listeners\": { - \"*:8080\": { - \"pass\": \"routes\" - } - }, - \"routes\": [{ - \"action\": { - \"share\": \"$www\" - } - }] - } -__EOF__"; - - dry_run_echo; - - echo; - echo 'You may want to try the following commands now:'; - echo; - echo 'Check out current unitd configuration:'; - echo " ${SUDO_USER:+sudo} curl $curl_opt/config"; - echo; - echo 'Browse the welcome page:'; - echo " curl http://localhost:$port/"; -} - - -help_unit_freeport() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 freeport [-h] - -DESCRIPTION - Print an available TCP port. - -OPTIONS - -h, --help - Print this help. - -__EOF__ -} - - -unit_freeport() -{ - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_freeport; - exit 0; - ;; - -*) - err "freeport: $1: Unknown option."; - ;; - *) - err "freeport: $1: Unknown argument."; - ;; - esac; - shift; - done; - - freeport="$(mktemp -t freeport-XXXXXX)"; - - cat <<__EOF__ \ - | cc -x c -o $freeport -; - #include - #include - #include - #include - #include - #include - - - int32_t get_free_port(void); - - - int - main(void) - { - int32_t port; - - port = get_free_port(); - if (port == -1) - exit(EXIT_FAILURE); - - printf("%d\n", port); - exit(EXIT_SUCCESS); - } - - - int32_t - get_free_port(void) - { - int sfd; - int32_t port; - socklen_t len; - struct sockaddr_in addr; - - port = -1; - - sfd = socket(PF_INET, SOCK_STREAM, 0); - if (sfd == -1) { - perror("socket()"); - return -1; - } - - bzero(&addr, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(0); // random port - - len = sizeof(addr); - if (bind(sfd, (struct sockaddr *) &addr, len)) { - perror("bind()"); - goto fail; - } - - if (getsockname(sfd, (struct sockaddr *) &addr, &len)) { - perror("getsockname()"); - goto fail; - } - - port = ntohs(addr.sin_port); - - fail: - close(sfd); - return port; - } -__EOF__ - - $freeport; -} - - -help_unit_json_ins() -{ -cat <<__EOF__ ; -SYNOPSIS - $0 json-ins [-hn] JSON INDEX - -ARGUMENTS - JSON Path to a JSON file containing a top-level array. - - INDEX Position in the array to insert the element at. - -DESCRIPTION - Insert a JSON element read from standard input into a JSON array read - from a file at a given INDEX. - - The resulting array is printed to standard output. - -OPTIONS - -h, --help - Print this help. - - -n, --dry-run - Dry run. Print the command to be run instead of actually - running it. - -__EOF__ -} - - -unit_json_ins() -{ - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_json_ins; - exit 0; - ;; - -n | --dry-run) - dry_run='yes'; - ;; - -*) - err "json-ins: $1: Unknown option."; - ;; - *) - break; - ;; - esac; - shift; - done; - - if ! test $# -ge 1; then - err 'json-ins: JSON: Missing argument.'; - fi; - local arr=$1; - - if ! test $# -ge 2; then - err 'json-ins: INDEX: Missing argument.'; - fi; - local idx=$2; - - dry_run_eval "( - jq '.[0:$idx]' <'$arr'; - echo '['; - jq .; - echo ']'; - jq '.[$idx:]' <'$arr'; - ) \\ - | sed '/^\[]$/d' \\ - | sed '/^]$/{N;s/^]\n\[$/,/}' \\ - | jq .;" -} - - -help_unit_os_probe() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 os-probe [-h] - -DESCRIPTION - This script probes the OS and prints three fields, delimited by ':'; - the first is the package manager, the second is the OS name, the third - is the OS version. - -OPTIONS - -h, --help - Print this help. - -__EOF__ -} - - -unit_os_probe() -{ - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_os_probe; - exit 0; - ;; - -*) - err "os-probe: $1: Unknown option."; - ;; - *) - err "os-probe: $1: Unknown argument."; - ;; - esac; - shift; - done; - - local os=$(uname | tr '[:upper:]' '[:lower:]') - - if [ "$os" != 'linux' ] && [ "$os" != 'freebsd' ]; then - err "os-probe: The OS isn't Linux or FreeBSD; can't proceed." - fi - - if [ "$os" = 'linux' ]; then - if command -v apt-get >/dev/null; then - local pkgMngr='apt'; - elif command -v dnf >/dev/null; then - local pkgMngr='dnf'; - elif command -v yum >/dev/null; then - local pkgMngr='yum'; - else - local pkgMngr=''; - fi; - - local osRelease='/etc/os-release'; - - if [ -f "$osRelease" ]; then - # The value for the ID and VERSION_ID may or may not be in quotes - local osName=$(grep "^ID=" "$osRelease" | sed s/\"//g | awk -F= '{ print $2 }' ||:) - local osVersion=$(grep '^VERSION_ID=' "$osRelease" | sed s/\"//g | awk -F= '{ print $2 }' || lsb_release -cs) - else - err "os-probe: Unable to determine OS and version, or the OS isn't supported." - fi - else - local pkgMngr='pkg'; - local osName=$os - local osVersion=$(uname -rs | awk -F '[ -]' '{print $2}' ||:) - if [ -z "$osVersion" ]; then - err 'os-probe: Unable to get the FreeBSD version.' - fi - fi - - osName=$(echo "$osName" | tr '[:upper:]' '[:lower:]') - echo "$pkgMngr:$osName:$osVersion" -} - - -help_unit_ps() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 ps [-h] [-t TYPE] - -DESCRIPTION - List unitd(8) processes. - -OPTIONS - -h, --help - Print this help. - - -t, --type TYPE - List only processes of type TYPE. The available types are: - - - controller (c) - - main (m) - - router (r) - -__EOF__ -} - - -unit_ps() -{ - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_ps; - exit 0; - ;; - -t | --type) - if ! test $# -ge 2; then - err "ps: $1: Missing argument."; - fi; - local type=; - case "$2" in - c | controller) - local type_c='c'; - ;; - m | main) - local type_m='m'; - ;; - r | router) - local type_r='r'; - ;; - esac; - shift; - ;; - -*) - err "ps: $1: Unknown option."; - ;; - *) - err "ps: $1: Unknown argument."; - ;; - esac; - shift; - done; - - ps awwx \ - | if test -v type; then - grep ${type_c:+-e 'unit: controller'} \ - ${type_m:+-e 'unit: main'} \ - ${type_r:+-e 'unit: router'}; - else - grep 'unit: '; - fi \ - | grep -v grep \ - ||: -} - - -help_unit_repo_config() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 repo-config [-hn] [PKG-MANAGER OS-NAME OS-VERSION] - -DESCRIPTION - This script configures the NGINX Unit repository for the system - package manager. - - The script automatically detects the OS and proceeds accordingly. - However, if this automatic selection fails, you may specify the - package manager and the OS name and version. - -ARGUMENTS - PKG-MANAGER - Supported: 'apt', 'dnf', and 'yum'. - - OS-NAME - Supported: 'debian', 'ubuntu', 'fedora', 'rhel', and 'amzn2'. - - OS-VERSION - For most distributions, this should be a numeric value; for - Debian derivatives, use the codename instead. - -OPTIONS - -h, --help - Print this help. - - -n, --dry-run - Dry run. Print the commands to be run instead of actually - running them. Each command is preceded by a line explaining - what it does. - -EXAMPLES - $ $(basename "$0") repo-config apt debian bullseye; - $ $(basename "$0") repo-config apt ubuntu jammy; - $ $(basename "$0") repo-config dnf fedora 36; - $ $(basename "$0") repo-config dnf rhel 9; - $ $(basename "$0") repo-config yum amzn2 2; - -__EOF__ -} - - -unit_repo_config() -{ - installAPT () - { - local os_name="$2"; - - dry_run_echo "Install on $os_name"; - dry_run_echo; - dry_run_eval 'curl --output /usr/share/keyrings/nginx-keyring.gpg https://unit.nginx.org/keys/nginx-keyring.gpg;'; - dry_run_echo; - dry_run_eval 'apt-get install -y apt-transport-https lsb-release ca-certificates;'; - - if test $# -ge 3; then - local os_version="$3"; - else - local os_version='$(lsb_release -cs)'; - fi; - - dry_run_echo; - dry_run_eval "printf 'deb [signed-by=/usr/share/keyrings/nginx-keyring.gpg] https://packages.nginx.org/unit/$os_name/ %s unit\n' \"$os_version\" | tee /etc/apt/sources.list.d/unit.list;"; - dry_run_eval "printf 'deb-src [signed-by=/usr/share/keyrings/nginx-keyring.gpg] https://packages.nginx.org/unit/$os_name/ %s unit\n' \"$os_version\" | tee -a /etc/apt/sources.list.d/unit.list;"; - dry_run_echo; - dry_run_eval 'apt-get update;'; - } - - installYumDnf () - { - local pkg_mngr="$1"; - local os_name="$2"; - - if test $# -ge 3; then - local os_version="$3"; - else - local os_version='\$releasever'; - fi; - - dry_run_echo "Install on $os_name"; - dry_run_echo; - - dry_run_eval "cat >/etc/yum.repos.d/unit.repo <<__EOF__ -[unit] -name=unit repo -baseurl=https://packages.nginx.org/unit/$os_name/$os_version/\\\$basearch/ -gpgcheck=0 -enabled=1 -__EOF__"; - - dry_run_echo; - dry_run_eval "$pkg_mngr makecache;"; - } - - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_repo_config; - exit 0; - ;; - -n | --dry-run) - dry_run='yes'; - ;; - -*) - err "repo-config: $1: Unknown option."; - ;; - *) - break; - ;; - esac; - shift; - done; - - if test $# -ge 1; then - local pkg_mngr="$1"; - - if ! test $# -ge 2; then - err "repo-config: OS-NAME: Missing argument."; - fi; - local os_name="$2"; - - if ! test $# -ge 3; then - err "repo-config: OS-VERSION: Missing argument."; - fi; - local os_version="$3"; - fi; - - command -v curl >/dev/null \ - || err 'repo-config: curl(1) not found in PATH. It must be installed to run this script.'; - - echo 'This script sets up the NGINX Unit repository'; - - if ! test $# -ge 3; then - local os_pkg_name_version=$(unit_os_probe || warn "On macOS, try 'brew install nginx/unit/unit'.") - local pkg_mngr=$(echo "$os_pkg_name_version" | awk -F: '{print $1}') - local os_name=$(echo "$os_pkg_name_version" | awk -F: '{print $2}') - local os_version=$(echo "$os_pkg_name_version" | awk -F: '{print $3}') - fi; - - # Call the appropriate installation function - case "$pkg_mngr" in - apt) - case "$os_name" in - debian | ubuntu) - installAPT "$pkg_mngr" "$os_name" ${3:+$os_version}; - ;; - *) - err "repo-config: $os_name: The OS isn't supported."; - ;; - esac - ;; - yum | dnf) - case "$os_name" in - rhel | amzn | fedora) - installYumDnf "$pkg_mngr" "$os_name" "$os_version" ${3:+ovr}; - ;; - *) - err "repo-config: $os_name: The OS isn't supported."; - ;; - esac; - ;; - *) - err "repo-config: $pkg_mngr: The package manager isn't supported."; - ;; - esac; - - echo - echo 'All done; the NGINX Unit repository is set up.'; - echo "Configured with '$pkg_mngr' on '$os_name' '$os_version'."; - echo 'Further steps: ' -} - - -help_unit_restart() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 restart [-hls] - -DESCRIPTION - Restart all running unitd(8) instances. - -OPTIONS - -h, --help - Print this help. - - -l, --log - Reset log file. - - -s, --statedir - Reset \$statedir. - -CAVEATS - This command will ask for confirmation before removing - directories; please review those prompts with care, as unknown - bugs in the command may attempt to wipe your file system. - -__EOF__ -} - - -unit_restart() -{ - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_restart; - exit 0; - ;; - -l | --log) - local log_flag='yes'; - ;; - -s | --statedir) - local state_flag='yes'; - ;; - -*) - err "restart: $1: Unknown option."; - ;; - *) - err "restart: $1: Unknown argument."; - ;; - esac; - shift; - done; - - local cmds="$(unit_cmd)"; - - pkill -e unitd; - - printf '%s\n' "$cmds" \ - | while read -r cmd; do - if test -v log_flag; then - ( - echo "$cmd" \ - | grep '\--log' \ - | sed 's/.*--log \+\([^ ]\+\).*/\1/' \ - || eval $cmd --help \ - | grep -A1 '\--log FILE' \ - | grep 'default:' \ - | sed 's/.*"\(.*\)".*/\1/'; - ) \ - | xargs rm -f; - fi; - - if test -v state_flag; then - ( - echo "$cmd" \ - | grep '\--statedir' \ - | sed 's/.*--statedir \+\([^ ]\+\).*/\1/' \ - || eval $cmd --help \ - | grep -A1 '\--statedir DIR' \ - | grep 'default:' \ - | sed 's/.*"\(.*\)".*/\1/'; - ) \ - | xargs -I {} find {} -mindepth 1 -maxdepth 1 \ - | xargs rm -rfi; - fi; - - eval $cmd; - done; -} - - -help_unit_sock() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 sock [-h] SUBCOMMAND [ARGS] - - Subcommands - ├── filter [-ch] - └── find [-h] - -DESCRIPTION - Print the control API socket address of running unitd(8) - instances. - - Run '$0 sock SUBCOMMAND -h' for more information on a - subcommand. - -SUBCOMMANDS - filter Filter the output of the 'find' subcommand and transform it - to something suitable for running other commands, such as - curl(1) or ssh(1). - - find Find and print the control API socket address of running - unitd(8) instances. - -OPTIONS - -h, --help - Print this help. - -__EOF__ -} - - -unit_sock() -{ - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_sock; - exit 0; - ;; - -*) - err "sock: $1: Unknown option."; - ;; - *) - break; - ;; - esac; - shift; - done; - - if ! test $# -ge 1; then - err 'sock: Missing subcommand.'; - fi; - - case $1 in - filter) - shift; - unit_sock_filter $@; - ;; - find) - shift; - unit_sock_find $@; - ;; - *) - err "sock: $1: Unknown subcommand."; - ;; - esac; -} - - -help_unit_sock_filter() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 sock filter [-chs] - -DESCRIPTION - Filter the output of the 'sock find' command and transform it to - something suitable for running other commands, such as - curl(1) or ssh(1). - -OPTIONS - -c, --curl - Print an argument suitable for curl(1). - - -h, --help - Print this help. - - -s, --ssh - Print a socket address suitable for use in an ssh(1) tunnel. - -__EOF__ -} - - -unit_sock_filter() -{ - while test $# -ge 1; do - case "$1" in - -c | --curl) - if test -v ssh_flag; then - err "sock: filter: $1: Missing argument."; - fi; - local curl_flag='yes'; - ;; - -h | --help) - help_unit_sock_filter; - exit 0; - ;; - -s | --ssh) - if test -v curl_flag; then - err "sock: filter: $1: Missing argument."; - fi; - local ssh_flag='yes'; - ;; - -*) - err "sock: filter: $1: Unknown option."; - ;; - *) - err "sock: filter: $1: Unknown argument."; - ;; - esac; - shift; - done; - - while read -r control; do - - if test -v curl_flag; then - if echo "$control" | grep '^unix:' >/dev/null; then - unix_socket="$(echo "$control" | sed 's/unix:/--unix-socket /')"; - host='http://localhost'; - else - unix_socket=''; - host="$control"; - fi; - - echo "$unix_socket $host"; - - elif test -v ssh_flag; then - echo "$control" \ - | sed -E 's,^(unix:|http://|https://),,'; - - else - echo "$control"; - fi; - done; -} - - -help_unit_sock_find() -{ - cat <<__EOF__ ; -SYNOPSIS - $0 sock find [-h] - -DESCRIPTION - Find and print the control API socket address of running - unitd(8) instances. - -OPTIONS - -h, --help - Print this help. - -__EOF__ -} - - -unit_sock_find() -{ - while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit_sock_find; - exit 0; - ;; - -*) - err "sock: find: $1: Unknown option."; - ;; - *) - err "sock: find: $1: Unknown argument."; - ;; - esac; - shift; - done; - - unit_cmd \ - | while read -r cmd; do - if echo "$cmd" | grep '\--control' >/dev/null; then - echo "$cmd" \ - | sed 's/ --/\n--/g' \ - | grep '\--control' \ - | cut -d' ' -f2; - else - if ! command -v $cmd >/dev/null; then - local cmd='unitd'; - fi; - $cmd --help \ - | sed -n '/\--control/,+1p' \ - | grep 'default:' \ - | sed 's/ *default: "\(.*\)"/\1/'; - fi; - done; -} - - -while test $# -ge 1; do - case "$1" in - -h | --help) - help_unit; - exit 0; - ;; - -hh | --help-more) - help_more_unit; - exit 0; - ;; - -*) - err "$1: Unknown option."; - ;; - *) - break; - ;; - esac; - shift; -done; - -if ! test $# -ge 1; then - err "Missing command."; -fi; - -case $1 in -cmd) - shift; - unit_cmd $@; - ;; -ctl) - shift; - unit_ctl $@; - ;; -freeport) - shift; - unit_freeport $@; - ;; -json-ins) - shift; - unit_json_ins $@; - ;; -os-probe) - shift; - unit_os_probe $@; - ;; -ps) - shift; - unit_ps $@; - ;; -repo-config) - shift; - unit_repo_config $@; - ;; -restart) - shift; - unit_restart $@; - ;; -sock) - shift; - unit_sock $@; - ;; -welcome) - shift; - unit_ctl_welcome $@; - ;; -*) - err "$1: Unknown command."; - ;; -esac; diff --git a/tools/unitc b/tools/unitc deleted file mode 100755 index 9fba4c6d..00000000 --- a/tools/unitc +++ /dev/null @@ -1,330 +0,0 @@ -#!/bin/bash -# unitc - a curl wrapper for configuring NGINX Unit -# https://github.com/nginx/unit/tree/master/tools -# NGINX, Inc. (c) 2024 - -# Defaults -# -ERROR_LOG=/dev/null -REMOTE=0 -SHOW_LOG=1 -NOLOG=0 -QUIET=0 -CONVERT=0 -URI="" -RPC_CMD="" -METHOD=PUT -CONF_FILES=() - -while [ $# -gt 0 ]; do - OPTION=$(echo $1 | tr '[a-z]' '[A-Z]') - case $OPTION in - "-F" | "--FORMAT") - case $(echo $2 | tr '[a-z]' '[A-Z]') in - "YAML") - CONVERT=1 - if hash yq 2> /dev/null; then - CONVERT_TO_JSON="yq eval -P --output-format=json" - CONVERT_FROM_JSON="yq eval -P --output-format=yaml" - else - echo "${0##*/}: ERROR: yq(1) is required to use YAML format; install at " - exit 1 - fi - ;; - "") - echo "${0##*/}: ERROR: Must specify configuration format" - exit 1 - ;; - *) - echo "${0##*/}: ERROR: Invalid format ($2)" - exit 1 - ;; - esac - shift; shift - ;; - - "-H" | "--HELP") - shift - ;; - - "-L" | "--NOLOG" | "--NO-LOG") - NOLOG=1 - shift - ;; - - "-Q" | "--QUIET") - QUIET=1 - shift - ;; - - "GET" | "PUT" | "POST" | "DELETE" | "INSERT" | "EDIT") - METHOD=$OPTION - shift - ;; - - "HEAD" | "PATCH" | "PURGE" | "OPTIONS") - echo "${0##*/}: ERROR: Invalid HTTP method ($OPTION)" - exit 1 - ;; - - *) - if [ -f $1 ] && [ -r $1 ]; then - CONF_FILES+=($1) - if [ "${1##*.}" = "yaml" ]; then - echo "${0##*/}: INFO: converting $1 to JSON" - shift; set -- "--format" "yaml" "$@" # Apply the command line option - else - shift - fi - elif [ "${1:0:1}" = "/" ] || [ "${1:0:4}" = "http" ] && [ "$URI" = "" ]; then - URI=$1 - shift - elif [ "${1:0:6}" = "ssh://" ]; then - UNIT_CTRL=$1 - shift - elif [ "${1:0:9}" = "docker://" ]; then - UNIT_CTRL=$1 - shift - else - echo "${0##*/}: ERROR: Invalid option ($1)" - exit 1 - fi - ;; - esac -done - -if [ "$URI" = "" ]; then - cat << __EOF__ -${0##*/} - a curl wrapper for managing NGINX Unit configuration - -USAGE: ${0##*/} [options] URI - -• URI is for Unit's control API target, e.g. /config -• A local Unit control socket is detected unless a remote one is specified. -• Configuration data is read from stdin. -• All options are case-insensitive (excluding filenames and URIs). - -General options - filename … # Read configuration data from files instead of stdin - HTTP method # Default=GET, or PUT when config data is present - EDIT # Opens the URI contents in \$EDITOR - INSERT # Virtual HTTP method; prepend data to an array - -f | --format YAML # Convert configuration data to/from YAML format - -q | --quiet # No output to stdout - -Local options - -l | --nolog # Do not monitor the Unit log file after config changes - -Remote options - ssh://[user@]remote_host[:port]/path/to/control.socket # Remote Unix socket - http://remote_host:port/URI # Remote TCP socket - docker://container_ID[/non-default/control.socket] # Container on host - - A remote Unit instance may also be defined with the \$UNIT_CTRL environment - variable as http://remote_host:port or ssh://… or docker://… (as above). - -__EOF__ - exit 1 -fi - -# Figure out if we're running on the Unit host, or remotely -# -if [ "$UNIT_CTRL" = "" ]; then - if [ "${URI:0:4}" = "http" ]; then - REMOTE=1 - UNIT_CTRL=$(echo "$URI" | cut -f1-3 -d/) - URI=/$(echo "$URI" | cut -f4- -d/) - fi -elif [ "${UNIT_CTRL:0:6}" = "ssh://" ]; then - REMOTE=1 - RPC_CMD="ssh $(echo $UNIT_CTRL | cut -f1-3 -d/)" - UNIT_CTRL="--unix-socket /$(echo $UNIT_CTRL | cut -f4- -d/) _" -elif [ "${UNIT_CTRL:0:9}" = "docker://" ]; then - RPC_CMD="docker exec -i $(echo $UNIT_CTRL | cut -f3 -d/)" - DOCKSOCK=/$(echo "$UNIT_CTRL" | cut -f4- -d/) - if [ "$DOCKSOCK" = "/" ]; then - DOCKSOCK="/var/run/control.unit.sock" # Use default location if no path - fi - UNIT_CTRL="--unix-socket $DOCKSOCK _" - REMOTE=1 -elif [ "${URI:0:1}" = "/" ]; then - REMOTE=1 -fi - -if [ $REMOTE -eq 0 ]; then - # Check if Unit is running, find the main process - # - PID=($(ps ax | grep unit:\ main | grep -v \ grep | awk '{print $1}')) - if [ ${#PID[@]} -eq 0 ]; then - echo "${0##*/}: ERROR: unitd not running (set \$UNIT_CTRL to configure a remote instance)" - exit 1 - elif [ ${#PID[@]} -gt 1 ]; then - echo "${0##*/}: ERROR: multiple unitd processes detected (${PID[@]})" - exit 1 - fi - - # Read the significant unitd conifuration from cache file (or create it) - # - if [ -r /tmp/${0##*/}.$PID.env ]; then - source /tmp/${0##*/}.$PID.env - else - # Check we have all the tools we will need (that we didn't already use) - # - MISSING=$(hash curl tr cut sed tail sleep 2>&1 | cut -f4 -d: | tr -d '\n') - if [ "$MISSING" != "" ]; then - echo "${0##*/}: ERROR: cannot find$MISSING: please install or add to \$PATH" - exit 1 - fi - - # Obtain any optional startup parameters from the 'unitd: main' process - # so we can get the actual control address and error log location. - # Command line options and output of ps(1) is notoriously variable across - # different *nix/BSD platforms so multiple attempts might be needed. - # - PARAMS=$((ps -wwo args=COMMAND -p $PID || ps $PID) 2> /dev/null | grep unit | tr '[]' ^ | cut -f2 -d^ | sed -e 's/ --/\n--/g') - if [ "$PARAMS" = "" ]; then - echo "${0##*/}: WARNING: unable to identify unitd command line parameters for PID $PID, assuming unitd defaults from \$PATH" - PARAMS=unitd - fi - CTRL_ADDR=$(echo "$PARAMS" | grep '\--control ' | cut -f2 -d' ') - if [ "$CTRL_ADDR" = "" ]; then - CTRL_ADDR=$($(echo "$PARAMS") --help | grep -A1 '\--control ADDRESS' | tail -1 | cut -f2 -d\") - fi - if [ "$CTRL_ADDR" = "" ]; then - echo "${0##*/}: ERROR: cannot detect control socket. Did you start unitd with a relative path? Try starting unitd with --control option." - exit 2 - fi - - # Prepare for network or Unix socket addressing - # - if [ $(echo $CTRL_ADDR | grep -c ^unix:) -eq 1 ]; then - SOCK_FILE=$(echo $CTRL_ADDR | cut -f2- -d:) - if [ -r $SOCK_FILE ]; then - UNIT_CTRL="--unix-socket $SOCK_FILE _" - else - echo "${0##*/}: ERROR: cannot read unitd control socket: $SOCK_FILE" - ls -l $SOCK_FILE - exit 2 - fi - else - UNIT_CTRL="http://$CTRL_ADDR" - fi - - # Get error log filename - # - ERROR_LOG=$(echo "$PARAMS" | grep '\--log' | cut -f2 -d' ') - if [ "$ERROR_LOG" = "" ]; then - ERROR_LOG=$($(echo "$PARAMS") --help | grep -A1 '\--log' | tail -1 | cut -f2 -d\") - fi - if [ "$ERROR_LOG" = "" ]; then - echo "${0##*/}: WARNING: cannot detect unit log file (will not be monitored). If you started unitd from a relative path then try using the --log option." - ERROR_LOG=/dev/null - fi - - # Cache the discovery for this unit PID (and cleanup any old files) - # - rm -f /tmp/${0##*/}.* 2> /dev/null - echo UNIT_CTRL=\"${UNIT_CTRL}\" > /tmp/${0##*/}.$PID.env - echo ERROR_LOG=${ERROR_LOG} >> /tmp/${0##*/}.$PID.env - fi -fi - -# Choose presentation style -# -if [ $QUIET -eq 1 ]; then - OUTPUT="tail -c 0" # Equivalent to >/dev/null -elif [ $CONVERT -eq 1 ]; then - OUTPUT=$CONVERT_FROM_JSON -elif hash jq 2> /dev/null; then - OUTPUT="jq" -else - OUTPUT="cat" -fi - -# Get current length of error log before we make any changes -# -if [ -f $ERROR_LOG ] && [ -r $ERROR_LOG ]; then - LOG_LEN=$(wc -l < $ERROR_LOG) -else - NOLOG=1 -fi - -# Adjust HTTP method and curl params based on presence of stdin payload -# -if [ -t 0 ] && [ ${#CONF_FILES[@]} -eq 0 ]; then - if [ "$METHOD" = "DELETE" ]; then - $RPC_CMD curl -X $METHOD $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT - elif [ "$METHOD" = "EDIT" ]; then - EDITOR=$(test "$EDITOR" && printf '%s' "$EDITOR" || command -v editor || command -v vim || echo vi) - EDIT_FILENAME=/tmp/${0##*/}.$$${URI//\//_} - $RPC_CMD curl -fsS $UNIT_CTRL$URI > $EDIT_FILENAME || exit 2 - if [ "${URI:0:12}" = "/js_modules/" ]; then - if ! hash jq 2> /dev/null; then - echo "${0##*/}: ERROR: jq(1) is required to edit JavaScript modules; install at " - exit 1 - fi - jq -r < $EDIT_FILENAME > $EDIT_FILENAME.js # Unescape linebreaks for a better editing experience - EDIT_FILE=$EDIT_FILENAME.js - $EDITOR $EDIT_FILENAME.js || exit 2 - # Remove the references, delete old config, push new config+reference - $RPC_CMD curl -fsS $UNIT_CTRL/config/settings/js_module > /tmp/${0##*/}.$$_js_module && \ - $RPC_CMD curl -X DELETE $UNIT_CTRL/config/settings/js_module && \ - $RPC_CMD curl -fsSX DELETE $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ - printf "%s" "$(< $EDIT_FILENAME.js)" | $RPC_CMD curl -fX PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ - cat /tmp/${0##*/}.$$_js_module | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL/config/settings/js_module 2> /tmp/${0##*/}.$$ - elif [ $CONVERT -eq 1 ]; then - $CONVERT_FROM_JSON < $EDIT_FILENAME > $EDIT_FILENAME.yaml - $EDITOR $EDIT_FILENAME.yaml || exit 2 - $CONVERT_TO_JSON < $EDIT_FILENAME.yaml | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT - else - tr -d '\r' < $EDIT_FILENAME > $EDIT_FILENAME.json # Remove carriage-return from newlines - $EDITOR $EDIT_FILENAME.json || exit 2 - cat $EDIT_FILENAME.json | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT - fi - else - SHOW_LOG=$(echo $URI | grep -c ^/control/) - $RPC_CMD curl $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT - fi -else - if [ "$METHOD" = "INSERT" ]; then - if ! hash jq 2> /dev/null; then - echo "${0##*/}: ERROR: jq(1) is required to use the INSERT method; install at " - exit 1 - fi - NEW_ELEMENT=$(cat ${CONF_FILES[@]}) - echo $NEW_ELEMENT | jq > /dev/null || exit $? # Test the input is valid JSON before proceeding - OLD_ARRAY=$($RPC_CMD curl -s $UNIT_CTRL$URI) - if [ "$(echo $OLD_ARRAY | jq -r type)" = "array" ]; then - echo $OLD_ARRAY | jq ". |= [$NEW_ELEMENT] + ." | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT - else - echo "${0##*/}: ERROR: the INSERT method expects an array" - exit 3 - fi - else - if [ $CONVERT -eq 1 ]; then - cat ${CONF_FILES[@]} | $CONVERT_TO_JSON > /tmp/${0##*/}.$$_json - CONF_FILES=(/tmp/${0##*/}.$$_json) - fi - cat ${CONF_FILES[@]} | $RPC_CMD curl -X $METHOD --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT - fi -fi - -CURL_STATUS=${PIPESTATUS[0]} -if [ $CURL_STATUS -ne 0 ]; then - echo "${0##*/}: ERROR: curl(1) exited with an error ($CURL_STATUS)" - if [ $CURL_STATUS -eq 7 ] && [ $REMOTE -eq 0 ]; then - echo "${0##*/}: Check that you have permission to access the Unit control socket, or try again with sudo(8)" - else - echo "${0##*/}: Trying to access $UNIT_CTRL$URI" - cat /tmp/${0##*/}.$$ && rm -f /tmp/${0##*/}.$$ - fi - exit 4 -fi -rm -f /tmp/${0##*/}.$$* 2> /dev/null - -if [ $SHOW_LOG -gt 0 ] && [ $NOLOG -eq 0 ] && [ $QUIET -eq 0 ]; then - echo -n "${0##*/}: Waiting for log..." - sleep $SHOW_LOG - echo "" - sed -n $((LOG_LEN+1)),\$p $ERROR_LOG -fi diff --git a/version b/version deleted file mode 100644 index 285c11ae..00000000 --- a/version +++ /dev/null @@ -1,5 +0,0 @@ - -# Copyright (C) NGINX, Inc. - -NXT_VERSION=1.32.1 -NXT_VERNUM=13201 diff --git a/pkg/docker/welcome.html b/welcome.html similarity index 100% rename from pkg/docker/welcome.html rename to welcome.html diff --git a/pkg/docker/welcome.json b/welcome.json similarity index 100% rename from pkg/docker/welcome.json rename to welcome.json diff --git a/pkg/docker/welcome.md b/welcome.md similarity index 100% rename from pkg/docker/welcome.md rename to welcome.md