InPanel 1.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- inpanel/__init__.py +29 -0
- inpanel/acme.py +289 -0
- inpanel/aliyuncs.py +269 -0
- inpanel/app.py +514 -0
- inpanel/apt.py +223 -0
- inpanel/base.py +200 -0
- inpanel/config.py +139 -0
- inpanel/data/config.ini +29 -0
- inpanel/data/history +5 -0
- inpanel/data/runlogs.ini +12 -0
- inpanel/data/update_info.ini +4 -0
- inpanel/dnf.py +225 -0
- inpanel/lib/__init__.py +9 -0
- inpanel/lib/async_process.py +98 -0
- inpanel/lib/filelock.py +82 -0
- inpanel/lib/magic.py +233 -0
- inpanel/lib/pxssh.py +310 -0
- inpanel/lib/pyDes.py +867 -0
- inpanel/mod/__init__.py +0 -0
- inpanel/mod/apt.py +316 -0
- inpanel/mod/certificate.py +268 -0
- inpanel/mod/config.py +372 -0
- inpanel/mod/cron.py +315 -0
- inpanel/mod/disk.py +322 -0
- inpanel/mod/dnf.py +239 -0
- inpanel/mod/file.py +722 -0
- inpanel/mod/firewall.py +199 -0
- inpanel/mod/firewall_base.py +137 -0
- inpanel/mod/firewall_firewalld.py +170 -0
- inpanel/mod/firewall_iptables.py +176 -0
- inpanel/mod/firewall_macos.py +213 -0
- inpanel/mod/firewall_ufw.py +128 -0
- inpanel/mod/ftp.py +231 -0
- inpanel/mod/httpd.py +1205 -0
- inpanel/mod/lighttpd.py +26 -0
- inpanel/mod/login.py +98 -0
- inpanel/mod/mysql.py +577 -0
- inpanel/mod/named.py +26 -0
- inpanel/mod/nginx.py +2327 -0
- inpanel/mod/package.py +33 -0
- inpanel/mod/package_apt.py +62 -0
- inpanel/mod/package_base.py +77 -0
- inpanel/mod/package_dnf.py +62 -0
- inpanel/mod/package_map.py +366 -0
- inpanel/mod/package_yum.py +64 -0
- inpanel/mod/php.py +289 -0
- inpanel/mod/process.py +291 -0
- inpanel/mod/proftpd.py +26 -0
- inpanel/mod/pureftpd.py +26 -0
- inpanel/mod/query.py +108 -0
- inpanel/mod/server.py +1319 -0
- inpanel/mod/service.py +262 -0
- inpanel/mod/setting.py +228 -0
- inpanel/mod/shell.py +78 -0
- inpanel/mod/ssh.py +280 -0
- inpanel/mod/system.py +220 -0
- inpanel/mod/task.py +1337 -0
- inpanel/mod/ufw.py +14 -0
- inpanel/mod/user.py +306 -0
- inpanel/mod/vsftpd.py +67 -0
- inpanel/mod/yum.py +243 -0
- inpanel/plugins/__init__.py +10 -0
- inpanel/plugins/__pycache__/__init__.cpython-313.pyc +0 -0
- inpanel/plugins/acme/static/index.html +10 -0
- inpanel/plugins/acme/static/index.js +13 -0
- inpanel/plugins/shadowsocks-libev/__pycache__/info.cpython-313.pyc +0 -0
- inpanel/plugins/shadowsocks-libev/info.py +73 -0
- inpanel/plugins/shadowsocks-libev/static/index.html +70 -0
- inpanel/plugins/shadowsocks-libev/static/index.js +18 -0
- inpanel/public/css/global.css +138 -0
- inpanel/public/favicon.ico +0 -0
- inpanel/public/images/alipay.jpg +0 -0
- inpanel/public/images/loading.gif +0 -0
- inpanel/public/images/weixin.jpg +0 -0
- inpanel/public/index.html +94 -0
- inpanel/public/js/controllers/controllers.js +566 -0
- inpanel/public/js/controllers/database.js +590 -0
- inpanel/public/js/controllers/ecs.js +624 -0
- inpanel/public/js/controllers/file.js +940 -0
- inpanel/public/js/controllers/plugins.js +105 -0
- inpanel/public/js/controllers/service.js +1460 -0
- inpanel/public/js/controllers/site.js +1241 -0
- inpanel/public/js/controllers/utils.js +2319 -0
- inpanel/public/js/core.js +221 -0
- inpanel/public/js/directives.js +784 -0
- inpanel/public/js/filters.js +395 -0
- inpanel/public/js/services.js +257 -0
- inpanel/public/lib/angular/1.0.2/angular-resource.min.js +10 -0
- inpanel/public/lib/angular/1.0.2/angular.min.js +158 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.css +587 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.css.map +1 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.min.css +6 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.min.css.map +1 -0
- inpanel/public/lib/bootstrap/css/bootstrap.css +6757 -0
- inpanel/public/lib/bootstrap/css/bootstrap.css.map +1 -0
- inpanel/public/lib/bootstrap/css/bootstrap.min.css +6 -0
- inpanel/public/lib/bootstrap/css/bootstrap.min.css.map +1 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.svg +288 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
- inpanel/public/lib/bootstrap/img/glyphicons-halflings-white.png +0 -0
- inpanel/public/lib/bootstrap/img/glyphicons-halflings.png +0 -0
- inpanel/public/lib/bootstrap/js/bootstrap.js +2377 -0
- inpanel/public/lib/bootstrap/js/bootstrap.min.js +7 -0
- inpanel/public/lib/bootstrap/js/npm.js +13 -0
- inpanel/public/lib/codemirror/codemirror-compressed.js +1 -0
- inpanel/public/lib/codemirror/codemirror.css +173 -0
- inpanel/public/lib/jquery/jquery-1.12.4.min.js +5 -0
- inpanel/public/lib/md5/md5.js +379 -0
- inpanel/public/lib/md5/md5.min.js +1 -0
- inpanel/public/partials/database/index.html +172 -0
- inpanel/public/partials/database/mysql/dbedit.html +462 -0
- inpanel/public/partials/database/mysql/dbnew.html +348 -0
- inpanel/public/partials/database/mysql/useredit.html +310 -0
- inpanel/public/partials/database/mysql/usernew.html +97 -0
- inpanel/public/partials/directives/message.html +20 -0
- inpanel/public/partials/directives/navbar.html +25 -0
- inpanel/public/partials/directives/selector.html +57 -0
- inpanel/public/partials/directives/srvbase.html +72 -0
- inpanel/public/partials/directives/srvext.html +34 -0
- inpanel/public/partials/directives/srvfile.html +23 -0
- inpanel/public/partials/directives/srvinstall.html +34 -0
- inpanel/public/partials/directives/srvlog.html +23 -0
- inpanel/public/partials/directives/srvminiop.html +28 -0
- inpanel/public/partials/directives/srvuninstall.html +38 -0
- inpanel/public/partials/directives/srvupdate.html +30 -0
- inpanel/public/partials/ecs/account.html +156 -0
- inpanel/public/partials/ecs/ecs.html +198 -0
- inpanel/public/partials/ecs/index.html +40 -0
- inpanel/public/partials/ecs/setings.html +459 -0
- inpanel/public/partials/file/file.html +501 -0
- inpanel/public/partials/file/trash.html +95 -0
- inpanel/public/partials/ftp.html +36 -0
- inpanel/public/partials/log.html +83 -0
- inpanel/public/partials/login.html +79 -0
- inpanel/public/partials/logout.html +22 -0
- inpanel/public/partials/main.html +534 -0
- inpanel/public/partials/plugins/index.html +55 -0
- inpanel/public/partials/plugins/plugins.html +13 -0
- inpanel/public/partials/secure.html +13 -0
- inpanel/public/partials/service/apache.html +147 -0
- inpanel/public/partials/service/cron.html +71 -0
- inpanel/public/partials/service/index.html +293 -0
- inpanel/public/partials/service/iptables.html +40 -0
- inpanel/public/partials/service/lighttpd.html +63 -0
- inpanel/public/partials/service/mariadb.html +113 -0
- inpanel/public/partials/service/memcache.html +36 -0
- inpanel/public/partials/service/minio.html +44 -0
- inpanel/public/partials/service/mongodb.html +44 -0
- inpanel/public/partials/service/mysql.html +113 -0
- inpanel/public/partials/service/named.html +61 -0
- inpanel/public/partials/service/nginx.html +296 -0
- inpanel/public/partials/service/ntp.html +40 -0
- inpanel/public/partials/service/php.html +250 -0
- inpanel/public/partials/service/proftpd.html +59 -0
- inpanel/public/partials/service/pureftpd.html +59 -0
- inpanel/public/partials/service/redis.html +40 -0
- inpanel/public/partials/service/samba.html +58 -0
- inpanel/public/partials/service/sendmail.html +40 -0
- inpanel/public/partials/service/ssh.html +186 -0
- inpanel/public/partials/service/tomcat.html +65 -0
- inpanel/public/partials/service/vsftpd.html +195 -0
- inpanel/public/partials/setting.html +299 -0
- inpanel/public/partials/site/apache/site.html +277 -0
- inpanel/public/partials/site/index.html +344 -0
- inpanel/public/partials/site/nginx/site.html +558 -0
- inpanel/public/partials/sorry.html +19 -0
- inpanel/public/partials/storage/autofm.html +103 -0
- inpanel/public/partials/storage/backup.html +42 -0
- inpanel/public/partials/storage/index.html +360 -0
- inpanel/public/partials/storage/migrate.html +93 -0
- inpanel/public/partials/storage/movedata.html +98 -0
- inpanel/public/partials/storage/remote.html +77 -0
- inpanel/public/partials/utils/cron.html +486 -0
- inpanel/public/partials/utils/firewall.html +266 -0
- inpanel/public/partials/utils/index.html +193 -0
- inpanel/public/partials/utils/network.html +118 -0
- inpanel/public/partials/utils/process.html +239 -0
- inpanel/public/partials/utils/repository.html +373 -0
- inpanel/public/partials/utils/shell.html +28 -0
- inpanel/public/partials/utils/ssl.html +319 -0
- inpanel/public/partials/utils/time.html +109 -0
- inpanel/public/partials/utils/user.html +359 -0
- inpanel/public/robots.txt +2 -0
- inpanel/remote.py +109 -0
- inpanel/templates/file/preview.html +34 -0
- inpanel/templates/index.html +93 -0
- inpanel/utils.py +282 -0
- inpanel/web.py +1811 -0
- inpanel/yum.py +756 -0
- inpanel-1.2.1.dist-info/METADATA +399 -0
- inpanel-1.2.1.dist-info/RECORD +198 -0
- inpanel-1.2.1.dist-info/WHEEL +5 -0
- inpanel-1.2.1.dist-info/entry_points.txt +2 -0
- inpanel-1.2.1.dist-info/licenses/LICENSE +30 -0
- inpanel-1.2.1.dist-info/top_level.txt +1 -0
inpanel/mod/nginx.py
ADDED
|
@@ -0,0 +1,2327 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2017-2026 Jackson Dou
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# InPanel is distributed under the terms of the (new) BSD License.
|
|
7
|
+
# The full license can be found in 'LICENSE'.
|
|
8
|
+
|
|
9
|
+
'''Module for Nginx Management'''
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import pprint
|
|
13
|
+
import re
|
|
14
|
+
from glob import glob
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import tornado
|
|
18
|
+
|
|
19
|
+
from ..base import COMMENTFLAG, DEBUG, GENBY, config_path
|
|
20
|
+
from .config import Config
|
|
21
|
+
from ..utils import is_valid_domain, is_valid_ip, is_valid_ipv4, is_valid_ipv6, is_url, version_get
|
|
22
|
+
|
|
23
|
+
# d stand for directive, and c stand for context
|
|
24
|
+
DIRECTIVES = {
|
|
25
|
+
# REF: http://wiki.nginx.org/CoreModule
|
|
26
|
+
'daemon': ['_'],
|
|
27
|
+
'env': ['_'],
|
|
28
|
+
'debug_points': ['_'],
|
|
29
|
+
'error_log': ['_', 'http', 'server', 'location'],
|
|
30
|
+
'include': ['_', 'http', 'server', 'location'],
|
|
31
|
+
'lock_file': ['_'],
|
|
32
|
+
'master_process': ['_'],
|
|
33
|
+
'pcre_jit': ['_'],
|
|
34
|
+
'pid': ['_'],
|
|
35
|
+
# 'ssl_engine': ['_'],
|
|
36
|
+
'timer_resolution': ['_'],
|
|
37
|
+
'user': ['_'],
|
|
38
|
+
'worker_cpu_affinity': ['_'],
|
|
39
|
+
'worker_priority': ['_'],
|
|
40
|
+
'worker_processes': ['_'],
|
|
41
|
+
'worker_rlimit_core': ['_'],
|
|
42
|
+
'worker_rlimit_nofile': ['_'],
|
|
43
|
+
'worker_rlimit_sigpending': ['_'],
|
|
44
|
+
'working_directory': ['_'],
|
|
45
|
+
|
|
46
|
+
# REF: http://wiki.nginx.org/EventsModule
|
|
47
|
+
'events': ['_'],
|
|
48
|
+
'accept_mutex': ['events'],
|
|
49
|
+
'accept_mutex_delay': ['events'],
|
|
50
|
+
'debug_connection': ['events'],
|
|
51
|
+
'devpoll_changes': ['events'],
|
|
52
|
+
'devpoll_events': ['events'],
|
|
53
|
+
'kqueue_changes': ['events'],
|
|
54
|
+
'kqueue_events': ['events'],
|
|
55
|
+
'epoll_events': ['events'],
|
|
56
|
+
'multi_accept': ['events'],
|
|
57
|
+
'rtsig_signo': ['events'],
|
|
58
|
+
'rtsig_overflow_events': ['events'],
|
|
59
|
+
'rtsig_overflow_test': ['events'],
|
|
60
|
+
'rtsig_overflow_threshold': ['events'],
|
|
61
|
+
'use': ['events'],
|
|
62
|
+
'worker_connections': ['events'],
|
|
63
|
+
|
|
64
|
+
# REF: http://wiki.nginx.org/HttpCoreModule
|
|
65
|
+
'http': ['_'],
|
|
66
|
+
'aio': ['http', 'server', 'location'],
|
|
67
|
+
'alias': ['location'],
|
|
68
|
+
'chunked_transfer_encoding': ['http', 'server', 'location'],
|
|
69
|
+
'client_body_in_file_only': ['http', 'server', 'location'],
|
|
70
|
+
'client_body_in_single_buffer': ['http', 'server', 'location'],
|
|
71
|
+
'client_body_buffer_size': ['http', 'server', 'location'],
|
|
72
|
+
'client_body_temp_path': ['http', 'server', 'location'],
|
|
73
|
+
'client_body_timeout': ['http', 'server', 'location'],
|
|
74
|
+
'client_header_buffer_size': ['http', 'server'],
|
|
75
|
+
'client_header_timeout': ['http', 'server'],
|
|
76
|
+
'client_max_body_size': ['http', 'server', 'location'],
|
|
77
|
+
'connection_pool_size': ['http', 'server'],
|
|
78
|
+
'default_type': ['http', 'server', 'location'],
|
|
79
|
+
'directio': ['http', 'server', 'location'],
|
|
80
|
+
'directio_alignment': ['http', 'server', 'location'],
|
|
81
|
+
'disable_symlinks': ['http', 'server', 'location'],
|
|
82
|
+
'error_page': ['http', 'server', 'location', 'if in location', 'if'], #+if
|
|
83
|
+
'if_modified_since': ['http', 'server', 'location'],
|
|
84
|
+
'ignore_invalid_headers': ['http', 'server'],
|
|
85
|
+
'internal': ['location'],
|
|
86
|
+
'keepalive_disable': ['http', 'server', 'location'],
|
|
87
|
+
'keepalive_timeout': ['http', 'server', 'location'],
|
|
88
|
+
'keepalive_requests': ['http', 'server', 'location'],
|
|
89
|
+
'large_client_header_buffers': ['http', 'server'],
|
|
90
|
+
'limit_except': ['location'],
|
|
91
|
+
'limit_rate': ['http', 'server', 'location', 'if in location', 'if'], #+if
|
|
92
|
+
'limit_rate_after': ['http', 'server', 'location', 'if in location', 'if'], #+if
|
|
93
|
+
'lingering_close': ['http', 'server', 'location'],
|
|
94
|
+
'lingering_time': ['http', 'server', 'location'],
|
|
95
|
+
'lingering_timeout': ['http', 'server', 'location'],
|
|
96
|
+
'listen': ['server'],
|
|
97
|
+
'location': ['server', 'location'],
|
|
98
|
+
'log_not_found': ['http', 'server', 'location'],
|
|
99
|
+
'log_subrequest': ['http', 'server', 'location'],
|
|
100
|
+
'max_ranges': ['http', 'server', 'location'],
|
|
101
|
+
'merge_slashes': ['http', 'server'],
|
|
102
|
+
'msie_padding': ['http', 'server', 'location'],
|
|
103
|
+
'msie_refresh': ['http', 'server', 'location'],
|
|
104
|
+
'open_file_cache': ['http', 'server', 'location'],
|
|
105
|
+
'open_file_cache_errors': ['http', 'server', 'location'],
|
|
106
|
+
'open_file_cache_min_uses': ['http', 'server', 'location'],
|
|
107
|
+
'open_file_cache_valid': ['http', 'server', 'location'],
|
|
108
|
+
'optimize_server_names': ['http', 'server'],
|
|
109
|
+
'port_in_redirect': ['http', 'server', 'location'],
|
|
110
|
+
'post_action': ['http', 'server', 'location'],
|
|
111
|
+
'postpone_output': ['http', 'server', 'location'],
|
|
112
|
+
'read_ahead': ['http', 'server', 'location'],
|
|
113
|
+
'recursive_error_pages': ['http', 'server', 'location'],
|
|
114
|
+
'request_pool_size': ['http', 'server'],
|
|
115
|
+
'reset_timedout_connection': ['http', 'server', 'location'],
|
|
116
|
+
'resolver': ['http', 'server', 'location'],
|
|
117
|
+
'resolver_timeout': ['http', 'server', 'location'],
|
|
118
|
+
'root': ['http', 'server', 'location', 'if in location', 'if'], #+if
|
|
119
|
+
'satisfy': ['http', 'server', 'location'],
|
|
120
|
+
'satisfy_any': ['http', 'server', 'location'],
|
|
121
|
+
'send_lowat': ['http', 'server', 'location'],
|
|
122
|
+
'send_timeout': ['http', 'server', 'location'],
|
|
123
|
+
'sendfile': ['http', 'server', 'location', 'if in location', 'if'], #+if
|
|
124
|
+
'sendfile_max_chunk': ['http', 'server', 'location'],
|
|
125
|
+
'server': ['http', 'upstream'],
|
|
126
|
+
'server_name': ['server'],
|
|
127
|
+
'server_name_in_redirect': ['http', 'server', 'location'],
|
|
128
|
+
'server_names_hash_max_size': ['http'],
|
|
129
|
+
'server_names_hash_bucket_size':['http'],
|
|
130
|
+
'server_tokens': ['http', 'server', 'location'],
|
|
131
|
+
'tcp_nodelay': ['http', 'server', 'location'],
|
|
132
|
+
'tcp_nopush': ['http', 'server', 'location'],
|
|
133
|
+
'try_files': ['server', 'location'],
|
|
134
|
+
'types': ['http', 'server', 'location'],
|
|
135
|
+
'types_hash_bucket_size': ['http', 'server', 'location'],
|
|
136
|
+
'types_hash_max_size': ['http', 'server', 'location'],
|
|
137
|
+
'underscores_in_headers': ['http', 'server'],
|
|
138
|
+
'variables_hash_bucket_size': ['http'],
|
|
139
|
+
'variables_hash_max_size': ['http'],
|
|
140
|
+
|
|
141
|
+
# REF: http://wiki.nginx.org/HttpAccessModule
|
|
142
|
+
'allow': ['http', 'server', 'location', 'limit_except'],
|
|
143
|
+
'deny': ['http', 'server', 'location', 'limit_except'],
|
|
144
|
+
|
|
145
|
+
# REF: http://wiki.nginx.org/HttpAuthBasicModule
|
|
146
|
+
'auth_basic': ['http', 'server', 'location', 'limit_except'],
|
|
147
|
+
'auth_basic_user_file': ['http', 'server', 'location', 'limit_except'],
|
|
148
|
+
|
|
149
|
+
# REF: http://wiki.nginx.org/HttpAutoindexModule
|
|
150
|
+
'autoindex': ['http', 'server', 'location'],
|
|
151
|
+
'autoindex_exact_size': ['http', 'server', 'location'],
|
|
152
|
+
'autoindex_localtime': ['http', 'server', 'location'],
|
|
153
|
+
|
|
154
|
+
# REF: http://wiki.nginx.org/HttpBrowserModule
|
|
155
|
+
'ancient_browser': ['http', 'server', 'location'],
|
|
156
|
+
'ancient_browser_value': ['http', 'server', 'location'],
|
|
157
|
+
'modern_browser': ['http', 'server', 'location'],
|
|
158
|
+
'modern_browser_value': ['http', 'server', 'location'],
|
|
159
|
+
|
|
160
|
+
# REF: http://wiki.nginx.org/HttpCharsetModule
|
|
161
|
+
'charset': ['http', 'server', 'location', 'if in location', 'if'], #+if
|
|
162
|
+
'charset_map': ['http'],
|
|
163
|
+
'charset_types': ['http', 'server', 'location'],
|
|
164
|
+
'override_charset': ['http', 'server', 'location', 'if in location', 'if'], #+if
|
|
165
|
+
'source_charset': ['http', 'server', 'location', 'if in location', 'if'], #+if
|
|
166
|
+
|
|
167
|
+
# REF: http://wiki.nginx.org/HttpEmptyGifModule
|
|
168
|
+
'empty_gif': ['location'],
|
|
169
|
+
|
|
170
|
+
# REF: http://wiki.nginx.org/HttpFastcgiModule
|
|
171
|
+
'fastcgi_bind': ['http', 'server', 'location'],
|
|
172
|
+
'fastcgi_buffer_size': ['http', 'server', 'location'],
|
|
173
|
+
'fastcgi_buffers': ['http', 'server', 'location'],
|
|
174
|
+
'fastcgi_busy_buffers_size': ['http', 'server', 'location'],
|
|
175
|
+
'fastcgi_cache': ['http', 'server', 'location'],
|
|
176
|
+
'fastcgi_cache_bypass': ['http', 'server', 'location'],
|
|
177
|
+
'fastcgi_cache_key': ['http', 'server', 'location'],
|
|
178
|
+
'fastcgi_cache_lock': ['http', 'server', 'location'],
|
|
179
|
+
'fastcgi_cache_lock_timeout': ['http', 'server', 'location'],
|
|
180
|
+
'fastcgi_cache_methods': ['http', 'server', 'location'],
|
|
181
|
+
'fastcgi_cache_min_uses': ['http', 'server', 'location'],
|
|
182
|
+
'fastcgi_cache_path': ['http'],
|
|
183
|
+
'fastcgi_cache_use_stale': ['http', 'server', 'location'],
|
|
184
|
+
'fastcgi_cache_valid': ['http', 'server', 'location'],
|
|
185
|
+
'fastcgi_connect_timeout': ['http', 'server', 'location'],
|
|
186
|
+
'fastcgi_hide_header': ['http', 'server', 'location'],
|
|
187
|
+
'fastcgi_ignore_client_abort': ['http', 'server', 'location'],
|
|
188
|
+
'fastcgi_ignore_headers': ['http', 'server', 'location'],
|
|
189
|
+
'fastcgi_index': ['http', 'server', 'location'],
|
|
190
|
+
'fastcgi_intercept_errors': ['http', 'server', 'location'],
|
|
191
|
+
'fastcgi_keep_conn': ['http', 'server', 'location'],
|
|
192
|
+
'fastcgi_max_temp_file_size': ['http', 'server', 'location'],
|
|
193
|
+
'fastcgi_next_upstream': ['http', 'server', 'location'],
|
|
194
|
+
'fastcgi_no_cache': ['http', 'server', 'location'],
|
|
195
|
+
'fastcgi_param': ['http', 'server', 'location'],
|
|
196
|
+
'fastcgi_pass': ['location', 'if in location', 'if'], #+if
|
|
197
|
+
'fastcgi_pass_header': ['http', 'server', 'location'],
|
|
198
|
+
'fastcgi_pass_request_body': ['http', 'server', 'location'],
|
|
199
|
+
'fastcgi_pass_request_headers': ['http', 'server', 'location'],
|
|
200
|
+
'fastcgi_read_timeout': ['http', 'server', 'location'],
|
|
201
|
+
'fastcgi_redirect_errors': ['http', 'server', 'location'],
|
|
202
|
+
'fastcgi_send_timeout': ['http', 'server', 'location'],
|
|
203
|
+
'fastcgi_split_path_info': ['location'],
|
|
204
|
+
'fastcgi_store': ['http', 'server', 'location'],
|
|
205
|
+
'fastcgi_store_access': ['http', 'server', 'location'],
|
|
206
|
+
'fastcgi_temp_file_write_size': ['http', 'server', 'location'],
|
|
207
|
+
'fastcgi_temp_path': ['http', 'server', 'location'],
|
|
208
|
+
|
|
209
|
+
# REF: http://wiki.nginx.org/HttpGeoModule
|
|
210
|
+
'geo': ['http'],
|
|
211
|
+
|
|
212
|
+
# REF: http://wiki.nginx.org/HttpGzipModule
|
|
213
|
+
'gzip': ['http', 'server', 'location', 'if in location', 'if'], #+if
|
|
214
|
+
'gzip_buffers': ['http', 'server', 'location'],
|
|
215
|
+
'gzip_comp_level': ['http', 'server', 'location'],
|
|
216
|
+
'gzip_disable': ['http', 'server', 'location'],
|
|
217
|
+
'gzip_http_version': ['http', 'server', 'location'],
|
|
218
|
+
'gzip_min_length': ['http', 'server', 'location'],
|
|
219
|
+
'gzip_proxied': ['http', 'server', 'location'],
|
|
220
|
+
'gzip_types': ['http', 'server', 'location'],
|
|
221
|
+
'gzip_vary': ['http', 'server', 'location'],
|
|
222
|
+
|
|
223
|
+
# REF: http://wiki.nginx.org/HttpHeadersModule
|
|
224
|
+
'add_header': ['http', 'server', 'location'],
|
|
225
|
+
'expires': ['http', 'server', 'location'],
|
|
226
|
+
|
|
227
|
+
# REF: http://wiki.nginx.org/HttpIndexModule
|
|
228
|
+
'index': ['http', 'server', 'location'],
|
|
229
|
+
|
|
230
|
+
# REF: http://wiki.nginx.org/HttpLimitReqModule
|
|
231
|
+
'limit_req': ['http', 'server', 'location'],
|
|
232
|
+
'limit_req_log_level': ['http', 'server', 'location'],
|
|
233
|
+
'limit_req_zone': ['http'],
|
|
234
|
+
|
|
235
|
+
# Deprecated in 1.1.8
|
|
236
|
+
# REF: http://wiki.nginx.org/HttpLimitZoneModule
|
|
237
|
+
'limit_zone': ['http'],
|
|
238
|
+
#'limit_conn': ['http', 'server', 'location'],
|
|
239
|
+
#'limit_conn_log_level': ['http', 'server', 'location'],
|
|
240
|
+
|
|
241
|
+
# REF: http://wiki.nginx.org/HttpLimitConnModule
|
|
242
|
+
'limit_conn': ['http', 'server', 'location'],
|
|
243
|
+
'limit_conn_zone': ['http'],
|
|
244
|
+
'limit_conn_log_level': ['http', 'server', 'location'],
|
|
245
|
+
|
|
246
|
+
# REF: http://wiki.nginx.org/HttpLogModule
|
|
247
|
+
'access_log': ['http', 'server', 'location', 'if in location', 'limit_except', 'if'], #+if
|
|
248
|
+
'log_format': ['http'],
|
|
249
|
+
'open_log_file_cache': ['http', 'server', 'location'],
|
|
250
|
+
|
|
251
|
+
# REF: http://wiki.nginx.org/HttpMapModule
|
|
252
|
+
'map': ['http'],
|
|
253
|
+
'map_hash_max_size': ['http'],
|
|
254
|
+
'map_hash_bucket_size': ['http'],
|
|
255
|
+
|
|
256
|
+
# REF: http://wiki.nginx.org/HttpMemcachedModule
|
|
257
|
+
'memcached_pass': ['location', 'if in location', 'if'], #+if
|
|
258
|
+
'memcached_connect_timeout': ['http', 'server', 'location'],
|
|
259
|
+
'memcached_read_timeout': ['http', 'server', 'location'],
|
|
260
|
+
'memcached_send_timeout': ['http', 'server', 'location'],
|
|
261
|
+
'memcached_buffer_size': ['http', 'server', 'location'],
|
|
262
|
+
'memcached_next_upstream': ['http', 'server', 'location'],
|
|
263
|
+
|
|
264
|
+
# REF: http://wiki.nginx.org/HttpProxyModule
|
|
265
|
+
'proxy_bind': ['http', 'server', 'location'],
|
|
266
|
+
'proxy_buffer_size': ['http', 'server', 'location'],
|
|
267
|
+
'proxy_buffering': ['http', 'server', 'location'],
|
|
268
|
+
'proxy_buffers': ['http', 'server', 'location'],
|
|
269
|
+
'proxy_busy_buffers_size': ['http', 'server', 'location'],
|
|
270
|
+
'proxy_cache': ['http', 'server', 'location'],
|
|
271
|
+
'proxy_cache_bypass': ['http', 'server', 'location'],
|
|
272
|
+
'proxy_cache_key': ['http', 'server', 'location'],
|
|
273
|
+
'proxy_cache_lock': ['http', 'server', 'location'],
|
|
274
|
+
'proxy_cache_lock_timeout': ['http', 'server', 'location'],
|
|
275
|
+
'proxy_cache_methods': ['http', 'server', 'location'],
|
|
276
|
+
'proxy_cache_min_uses': ['http', 'server', 'location'],
|
|
277
|
+
'proxy_cache_path': ['http'],
|
|
278
|
+
'proxy_cache_use_stale': ['http', 'server', 'location'],
|
|
279
|
+
'proxy_cache_valid': ['http', 'server', 'location'],
|
|
280
|
+
'proxy_connect_timeout': ['http', 'server', 'location'],
|
|
281
|
+
'proxy_cookie_domain': ['http', 'server', 'location'],
|
|
282
|
+
'proxy_cookie_path': ['http', 'server', 'location'],
|
|
283
|
+
'proxy_headers_hash_bucket_size':['http', 'server', 'location'],
|
|
284
|
+
'proxy_headers_hash_max_size': ['http', 'server', 'location'],
|
|
285
|
+
'proxy_hide_header': ['http', 'server', 'location'],
|
|
286
|
+
'proxy_http_version': ['http', 'server', 'location'],
|
|
287
|
+
'proxy_ignore_client_abort': ['http', 'server', 'location'],
|
|
288
|
+
'proxy_ignore_headers': ['http', 'server', 'location'],
|
|
289
|
+
'proxy_intercept_errors': ['http', 'server', 'location'],
|
|
290
|
+
'proxy_max_temp_file_size': ['http', 'server', 'location'],
|
|
291
|
+
'proxy_method': ['http', 'server', 'location'],
|
|
292
|
+
'proxy_next_upstream': ['http', 'server', 'location'],
|
|
293
|
+
'proxy_no_cache': ['http', 'server', 'location'],
|
|
294
|
+
'proxy_pass': ['location', 'if in location', 'limit_except', 'if'], #+if
|
|
295
|
+
'proxy_pass_header': ['http', 'server', 'location'],
|
|
296
|
+
'proxy_pass_request_body': ['http', 'server', 'location'],
|
|
297
|
+
'proxy_pass_request_headers': ['http', 'server', 'location'],
|
|
298
|
+
'proxy_redirect': ['http', 'server', 'location'],
|
|
299
|
+
'proxy_read_timeout': ['http', 'server', 'location'],
|
|
300
|
+
'proxy_redirect_errors': ['http', 'server', 'location'],
|
|
301
|
+
'proxy_send_lowat': ['http', 'server', 'location'],
|
|
302
|
+
'proxy_send_timeout': ['http', 'server', 'location'],
|
|
303
|
+
'proxy_set_body': ['http', 'server', 'location'],
|
|
304
|
+
'proxy_set_header': ['http', 'server', 'location'],
|
|
305
|
+
'proxy_ssl_session_reuse': ['http', 'server', 'location'],
|
|
306
|
+
'proxy_store': ['http', 'server', 'location'],
|
|
307
|
+
'proxy_store_access': ['http', 'server', 'location'],
|
|
308
|
+
'proxy_temp_file_write_size': ['http', 'server', 'location'],
|
|
309
|
+
'proxy_temp_path': ['http', 'server', 'location'],
|
|
310
|
+
'proxy_upstream_fail_timeout': ['http', 'server', 'location'],
|
|
311
|
+
'proxy_upstream_max_fails': ['http', 'server', 'location'],
|
|
312
|
+
|
|
313
|
+
# REF: http://wiki.nginx.org/HttpRefererModule
|
|
314
|
+
'valid_referers': ['server', 'location'],
|
|
315
|
+
|
|
316
|
+
# REF: http://wiki.nginx.org/HttpRewriteModule
|
|
317
|
+
'break': ['server', 'location', 'if'],
|
|
318
|
+
'if': ['server', 'location'],
|
|
319
|
+
'return': ['server', 'location', 'if'],
|
|
320
|
+
'rewrite': ['server', 'location', 'if'],
|
|
321
|
+
'rewrite_log': ['server', 'location', 'if'],
|
|
322
|
+
'set': ['server', 'location', 'if'],
|
|
323
|
+
'uninitialized_variable_warn': ['server', 'location', 'if'],
|
|
324
|
+
|
|
325
|
+
# REF: http://wiki.nginx.org/HttpScgiModule
|
|
326
|
+
'scgi_bind': ['http', 'server', 'location'],
|
|
327
|
+
'scgi_buffer_size': ['http', 'server', 'location'],
|
|
328
|
+
'scgi_buffering': ['http', 'server', 'location'],
|
|
329
|
+
'scgi_buffers': ['http', 'server', 'location'],
|
|
330
|
+
'scgi_busy_buffers_size': ['http', 'server', 'location', 'if'],
|
|
331
|
+
'scgi_cache': ['http', 'server', 'location'],
|
|
332
|
+
'scgi_cache_bypass': ['http', 'server', 'location'],
|
|
333
|
+
'scgi_cache_key': ['http', 'server', 'location'],
|
|
334
|
+
'scgi_cache_methods': ['http', 'server', 'location'],
|
|
335
|
+
'scgi_cache_min_uses': ['http', 'server', 'location'],
|
|
336
|
+
'scgi_cache_path': ['http'],
|
|
337
|
+
'scgi_cache_use_stale': ['http', 'server', 'location'],
|
|
338
|
+
'scgi_cache_valid': ['http', 'server', 'location'],
|
|
339
|
+
'scgi_connect_timeout': ['http', 'server', 'location'],
|
|
340
|
+
'scgi_hide_header': ['http', 'server', 'location'],
|
|
341
|
+
'scgi_ignore_client_abort': ['http', 'server', 'location'],
|
|
342
|
+
'scgi_ignore_headers': ['http', 'server', 'location'],
|
|
343
|
+
'scgi_intercept_errors': ['http', 'server', 'location'],
|
|
344
|
+
'scgi_max_temp_file_size': ['http', 'server', 'location'], #?
|
|
345
|
+
'scgi_next_upstream': ['http', 'server', 'location'],
|
|
346
|
+
'scgi_no_cache': ['http', 'server', 'location'],
|
|
347
|
+
'scgi_param': ['http', 'server', 'location'],
|
|
348
|
+
'scgi_pass': ['location', 'if in location', 'if'], #+if
|
|
349
|
+
'scgi_pass_header': ['http', 'server', 'location'],
|
|
350
|
+
'scgi_pass_request_body': ['http', 'server', 'location'],
|
|
351
|
+
'scgi_pass_request_headers': ['http', 'server', 'location'],
|
|
352
|
+
'scgi_read_timeout': ['http', 'server', 'location'],
|
|
353
|
+
'scgi_send_timeout': ['http', 'server', 'location'],
|
|
354
|
+
'scgi_store': ['http', 'server', 'location'],
|
|
355
|
+
'scgi_store_access': ['http', 'server', 'location'],
|
|
356
|
+
'scgi_temp_file_write_size': ['http', 'server', 'location'],
|
|
357
|
+
'scgi_temp_path': ['http', 'server', 'location'],
|
|
358
|
+
|
|
359
|
+
# REF: http://wiki.nginx.org/HttpSplitClientsModule
|
|
360
|
+
'split_clients': ['http'],
|
|
361
|
+
|
|
362
|
+
# REF: http://wiki.nginx.org/HttpSsiModule
|
|
363
|
+
'ssi': ['http', 'server', 'location', 'if in location', 'if'], #+if
|
|
364
|
+
'ssi_silent_errors': ['http', 'server', 'location'],
|
|
365
|
+
'ssi_types': ['http', 'server', 'location'],
|
|
366
|
+
'ssi_value_length': ['http', 'server', 'location'],
|
|
367
|
+
|
|
368
|
+
# REF: http://wiki.nginx.org/HttpUpstreamModule
|
|
369
|
+
'ip_hash': ['upstream'],
|
|
370
|
+
'keepalive': ['upstream'],
|
|
371
|
+
'least_conn': ['upstream'],
|
|
372
|
+
#'server': ['upstream'],
|
|
373
|
+
'upstream': ['http'],
|
|
374
|
+
|
|
375
|
+
# REF: http://wiki.nginx.org/HttpUseridModule
|
|
376
|
+
'userid': ['http', 'server', 'location'],
|
|
377
|
+
'userid_domain': ['http', 'server', 'location'],
|
|
378
|
+
'userid_expires': ['http', 'server', 'location'],
|
|
379
|
+
'userid_name': ['http', 'server', 'location'],
|
|
380
|
+
'userid_p3p': ['http', 'server', 'location'],
|
|
381
|
+
'userid_path': ['http', 'server', 'location'],
|
|
382
|
+
'userid_service': ['http', 'server', 'location'],
|
|
383
|
+
|
|
384
|
+
# REF: http://wiki.nginx.org/HttpUwsgiModule
|
|
385
|
+
'uwsgi_bind': ['http', 'server', 'location'],
|
|
386
|
+
'uwsgi_buffer_size': ['http', 'server', 'location'],
|
|
387
|
+
'uwsgi_buffering': ['http', 'server', 'location'],
|
|
388
|
+
'uwsgi_buffers': ['http', 'server', 'location'],
|
|
389
|
+
'uwsgi_busy_buffers_size': ['http', 'server', 'location', 'if'],
|
|
390
|
+
'uwsgi_cache': ['http', 'server', 'location'],
|
|
391
|
+
'uwsgi_cache_bypass': ['http', 'server', 'location'],
|
|
392
|
+
'uwsgi_cache_key': ['http', 'server', 'location'],
|
|
393
|
+
'uwsgi_cache_lock': ['http', 'server', 'location'],
|
|
394
|
+
'uwsgi_cache_lock_timeout': ['http', 'server', 'location'],
|
|
395
|
+
'uwsgi_cache_methods': ['http', 'server', 'location'],
|
|
396
|
+
'uwsgi_cache_min_uses': ['http', 'server', 'location'],
|
|
397
|
+
'uwsgi_cache_path': ['http', 'server', 'location'],
|
|
398
|
+
'uwsgi_cache_use_stale': ['http', 'server', 'location'],
|
|
399
|
+
'uwsgi_cache_valid': ['http', 'server', 'location'],
|
|
400
|
+
'uwsgi_connect_timeout': ['http', 'server', 'location'],
|
|
401
|
+
'uwsgi_hide_header': ['http', 'server', 'location'],
|
|
402
|
+
'uwsgi_ignore_client_abort': ['http', 'server', 'location'],
|
|
403
|
+
'uwsgi_ignore_headers': ['http', 'server', 'location'],
|
|
404
|
+
'uwsgi_intercept_errors': ['http', 'server', 'location'],
|
|
405
|
+
'uwsgi_max_temp_file_size': ['http', 'server', 'location'], #?
|
|
406
|
+
'uwsgi_modifier1': ['server', 'location'],
|
|
407
|
+
'uwsgi_modifier2': ['server', 'location'],
|
|
408
|
+
'uwsgi_next_upstream': ['http', 'server', 'location'],
|
|
409
|
+
'uwsgi_no_cache': ['http', 'server', 'location'],
|
|
410
|
+
'uwsgi_param': ['http', 'server', 'location'],
|
|
411
|
+
'uwsgi_pass': ['location', 'if in location', 'if'], #+if
|
|
412
|
+
'uwsgi_pass_header': ['http', 'server', 'location'],
|
|
413
|
+
'uwsgi_pass_request_body': ['http', 'server', 'location'],
|
|
414
|
+
'uwsgi_pass_request_headers': ['http', 'server', 'location'],
|
|
415
|
+
'uwsgi_read_timeout': ['http', 'server', 'location'],
|
|
416
|
+
'uwsgi_send_timeout': ['http', 'server', 'location'],
|
|
417
|
+
'uwsgi_store': ['http', 'server', 'location'],
|
|
418
|
+
'uwsgi_store_access': ['http', 'server', 'location'],
|
|
419
|
+
'uwsgi_string': ['server', 'location'],
|
|
420
|
+
'uwsgi_temp_file_write_size': ['http', 'server', 'location', 'if'],
|
|
421
|
+
'uwsgi_temp_path': ['http', 'server', 'location'],
|
|
422
|
+
|
|
423
|
+
# REF: http://wiki.nginx.org/HttpSslModule
|
|
424
|
+
'ssl': ['http', 'server'],
|
|
425
|
+
'ssl_certificate': ['http', 'server'],
|
|
426
|
+
'ssl_certificate_key': ['http', 'server'],
|
|
427
|
+
'ssl_ciphers': ['http', 'server'],
|
|
428
|
+
'ssl_client_certificate': ['http', 'server'],
|
|
429
|
+
'ssl_crl': ['http', 'server'],
|
|
430
|
+
'ssl_dhparam': ['http', 'server'],
|
|
431
|
+
'ssl_prefer_server_ciphers': ['http', 'server'],
|
|
432
|
+
'ssl_protocols': ['http', 'server'],
|
|
433
|
+
'ssl_verify_client': ['http', 'server'],
|
|
434
|
+
'ssl_verify_depth': ['http', 'server'],
|
|
435
|
+
'ssl_session_cache': ['http', 'server'],
|
|
436
|
+
'ssl_session_timeout': ['http', 'server'],
|
|
437
|
+
'ssl_engine': ['http', 'server'],
|
|
438
|
+
|
|
439
|
+
# REF: http://wiki.nginx.org/X-accel
|
|
440
|
+
# no directive
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
# module name : can has param if act as a context
|
|
444
|
+
# if False then a module name with param would considered a directive
|
|
445
|
+
MODULES = {
|
|
446
|
+
'events': False,
|
|
447
|
+
'http': False,
|
|
448
|
+
'server': False,
|
|
449
|
+
'upstream': True,
|
|
450
|
+
'location': True,
|
|
451
|
+
'types': False,
|
|
452
|
+
'if': True,
|
|
453
|
+
'limit_except': True,
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
DEFAULTVALS = {
|
|
457
|
+
'client_max_body_size': '1m',
|
|
458
|
+
'keepalive_timeout': '75s',
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
# load nginx module config
|
|
462
|
+
nginx_config = Config(str(Path(config_path) / 'module/nginx.ini'))
|
|
463
|
+
# print('nginx_config', nginx_config.get_config())
|
|
464
|
+
base_config = nginx_config.get('base', 'config')
|
|
465
|
+
base_servers = nginx_config.get('base', 'servers')
|
|
466
|
+
|
|
467
|
+
if base_config and Path(base_config).exists():
|
|
468
|
+
NGINXCONF = base_config
|
|
469
|
+
else:
|
|
470
|
+
NGINXCONF = '/etc/nginx/nginx.conf'
|
|
471
|
+
|
|
472
|
+
if base_servers and Path(base_servers).exists():
|
|
473
|
+
SERVERCONF = base_servers
|
|
474
|
+
else:
|
|
475
|
+
SERVERCONF = '/etc/nginx/conf.d/'
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def loadconfig(conf=None, getlineinfo=False):
|
|
479
|
+
"""Load nginx config and return a dict.
|
|
480
|
+
"""
|
|
481
|
+
|
|
482
|
+
if not conf:
|
|
483
|
+
conf = NGINXCONF
|
|
484
|
+
if not Path(conf).exists():
|
|
485
|
+
return False
|
|
486
|
+
return _loadconfig(conf, getlineinfo)
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def _loadconfig(conf, getlineinfo, config=None, context_stack=None):
|
|
490
|
+
"""Recursively load nginx config and return a dict.
|
|
491
|
+
"""
|
|
492
|
+
if not config:
|
|
493
|
+
file_i = 0
|
|
494
|
+
context = '_'
|
|
495
|
+
config = {'_files': [conf], '_': [{}], '_isdirty': False}
|
|
496
|
+
context_stack = [context]
|
|
497
|
+
cconfig = config[context][-1]
|
|
498
|
+
else:
|
|
499
|
+
if getlineinfo:
|
|
500
|
+
if conf not in config['_files']:
|
|
501
|
+
file_i = len(config['_files'])
|
|
502
|
+
config['_files'].append(conf)
|
|
503
|
+
else:
|
|
504
|
+
file_i = config['_files'].index(conf)
|
|
505
|
+
cconfig = config
|
|
506
|
+
for c in context_stack: cconfig = cconfig[c][-1]
|
|
507
|
+
context = context_stack[-1]
|
|
508
|
+
|
|
509
|
+
line_buffer = []
|
|
510
|
+
|
|
511
|
+
with open(conf, encoding='utf-8') as f:
|
|
512
|
+
for line_i, line in enumerate(f):
|
|
513
|
+
line = line.strip()
|
|
514
|
+
if DEBUG:
|
|
515
|
+
print('----------' + line)
|
|
516
|
+
|
|
517
|
+
# deal with our speical comment string
|
|
518
|
+
line_disabled = False
|
|
519
|
+
if line.startswith(COMMENTFLAG):
|
|
520
|
+
while line.startswith(COMMENTFLAG): line = line[3:]
|
|
521
|
+
line = line.strip()
|
|
522
|
+
line_disabled = True
|
|
523
|
+
|
|
524
|
+
if not line or line.startswith('#'): continue
|
|
525
|
+
|
|
526
|
+
# deal with comment and detect inpanel flag in comment
|
|
527
|
+
fields = line.split('#', 1)
|
|
528
|
+
line = fields[0].strip()
|
|
529
|
+
gen_by_inpanel = False
|
|
530
|
+
if len(fields) > 1 and fields[1].strip() == GENBY:
|
|
531
|
+
gen_by_inpanel = True
|
|
532
|
+
|
|
533
|
+
# context up
|
|
534
|
+
if line == '}':
|
|
535
|
+
if getlineinfo:
|
|
536
|
+
cconfig['_range']['end'] = {'file': file_i, 'line': [line_i, 1]}
|
|
537
|
+
if DEBUG:
|
|
538
|
+
print(context_stack, '-', context_stack[-1])
|
|
539
|
+
context_stack.pop()
|
|
540
|
+
context = context_stack[-1]
|
|
541
|
+
if DEBUG:
|
|
542
|
+
print('=', context_stack)
|
|
543
|
+
cconfig = config
|
|
544
|
+
for c in context_stack: cconfig = cconfig[c][-1]
|
|
545
|
+
continue
|
|
546
|
+
|
|
547
|
+
# this line may not ending, combine it with next line
|
|
548
|
+
if line[-1] not in (';', '{', '}'):
|
|
549
|
+
line_buffer.append(line)
|
|
550
|
+
continue
|
|
551
|
+
elif len(line_buffer)>0:
|
|
552
|
+
line_buffer.append(line)
|
|
553
|
+
line = ''.join(line_buffer)
|
|
554
|
+
line_count = len(line_buffer)
|
|
555
|
+
line_buffer = []
|
|
556
|
+
else:
|
|
557
|
+
line_count = 1
|
|
558
|
+
|
|
559
|
+
# only support one directive at a line
|
|
560
|
+
## one line may contain serveral directives
|
|
561
|
+
#parts = re.split('[;{}]', line)
|
|
562
|
+
#for part_i, part in enumerate(parts):
|
|
563
|
+
# if not part or part.startswith('#'): continue
|
|
564
|
+
# fields = part.split()
|
|
565
|
+
fields = line.split()
|
|
566
|
+
key = fields[0].strip(';') # some directive have no value like ip_hash
|
|
567
|
+
#value = ' '.join(fields[1:]).strip()
|
|
568
|
+
value = ' '.join(fields[1:]).strip(';')
|
|
569
|
+
|
|
570
|
+
if key in DIRECTIVES and context in DIRECTIVES[key]:
|
|
571
|
+
if (not key in MODULES # not in module name list
|
|
572
|
+
or key in MODULES # or in module name list
|
|
573
|
+
and not MODULES[key] # and this module can't has param
|
|
574
|
+
and value != '{'): # but actually it has
|
|
575
|
+
if getlineinfo:
|
|
576
|
+
v = {'file': file_i, 'line': [line_i-line_count+1, line_count], 'value': value}
|
|
577
|
+
else:
|
|
578
|
+
v = value
|
|
579
|
+
if key in cconfig:
|
|
580
|
+
cconfig[key].append(v)
|
|
581
|
+
else:
|
|
582
|
+
cconfig[key] = [v]
|
|
583
|
+
if key == 'include': # expand include files
|
|
584
|
+
includepath = value
|
|
585
|
+
if not includepath.startswith('/'):
|
|
586
|
+
includepath = str(Path(config['_files'][0]).parent / includepath)
|
|
587
|
+
confs = glob(includepath)
|
|
588
|
+
# order by domain name, excluding tld
|
|
589
|
+
# getdm = lambda x: x.split('/')[-1].split('.')[-3::-1]
|
|
590
|
+
# confs = sorted(confs, lambda x,y: cmp(getdm(x), getdm(y)))
|
|
591
|
+
for subconf in confs:
|
|
592
|
+
if Path(subconf).is_file():
|
|
593
|
+
if DEBUG:
|
|
594
|
+
print('\n**********', subconf, '\n')
|
|
595
|
+
_loadconfig(subconf, getlineinfo, config, context_stack)
|
|
596
|
+
else:
|
|
597
|
+
context = key
|
|
598
|
+
if DEBUG: print(context_stack, '+', context)
|
|
599
|
+
context_stack.append(context)
|
|
600
|
+
if DEBUG: print('=', context_stack)
|
|
601
|
+
if context in cconfig:
|
|
602
|
+
cconfig[context].append({})
|
|
603
|
+
else:
|
|
604
|
+
cconfig[context] = [{}]
|
|
605
|
+
cconfig = cconfig[context][-1]
|
|
606
|
+
value = value.strip('{').strip()
|
|
607
|
+
if getlineinfo:
|
|
608
|
+
cconfig['_param'] = {'file': file_i, 'line': [line_i-line_count+1, line_count], 'disabled': line_disabled, 'value': value}
|
|
609
|
+
# record the context range
|
|
610
|
+
cconfig['_range'] = {'begin': {'file': file_i, 'line': [line_i-line_count+1, line_count]}}
|
|
611
|
+
cconfig['_inpanel'] = gen_by_inpanel
|
|
612
|
+
else:
|
|
613
|
+
cconfig['_param'] = value
|
|
614
|
+
cconfig['_disabled'] = line_disabled
|
|
615
|
+
cconfig['_inpanel'] = gen_by_inpanel
|
|
616
|
+
|
|
617
|
+
return config
|
|
618
|
+
|
|
619
|
+
def _context_gethttp(config=None):
|
|
620
|
+
"""Get http context config.
|
|
621
|
+
"""
|
|
622
|
+
if not config or config['_isdirty']:
|
|
623
|
+
config = loadconfig(NGINXCONF, True)
|
|
624
|
+
return config['_'][0]['http'][0]
|
|
625
|
+
|
|
626
|
+
def _context_getservers(disabled=None, config=None, getlineinfo=True):
|
|
627
|
+
"""Get server context configs.
|
|
628
|
+
"""
|
|
629
|
+
if not config or config['_isdirty']:
|
|
630
|
+
config = loadconfig(NGINXCONF, getlineinfo)
|
|
631
|
+
http = config['_'][0]['http'][0]
|
|
632
|
+
if not 'server' in http:
|
|
633
|
+
return []
|
|
634
|
+
servers = http['server']
|
|
635
|
+
if disabled == None or not getlineinfo:
|
|
636
|
+
return servers
|
|
637
|
+
else:
|
|
638
|
+
return [server for server in servers
|
|
639
|
+
if server['_param']['disabled']==disabled]
|
|
640
|
+
|
|
641
|
+
def _context_getserver(ip, port, server_name, config=None, disabled=None, getlineinfo=True):
|
|
642
|
+
"""Get a server context config by server name.
|
|
643
|
+
|
|
644
|
+
If disabled is set to None, all servers would be return.
|
|
645
|
+
If disabled is set to True, only disabled servers would be return.
|
|
646
|
+
If disabled is set to False, only normal servers would be return.
|
|
647
|
+
"""
|
|
648
|
+
if not config or config['_isdirty']:
|
|
649
|
+
config = loadconfig(NGINXCONF, getlineinfo)
|
|
650
|
+
cnfservers = _context_getservers(disabled=disabled, config=config, getlineinfo=getlineinfo)
|
|
651
|
+
if not ip or ip in ('*', '0.0.0.0'): ip = ''
|
|
652
|
+
if is_valid_ipv6(ip) and not is_valid_ipv4(ip):
|
|
653
|
+
ip = '[' + ip + ']'
|
|
654
|
+
for s in cnfservers:
|
|
655
|
+
if getlineinfo:
|
|
656
|
+
server_names = ' '.join([v['value'] for v in s['server_name']]).split()
|
|
657
|
+
listens = [v['value'].split()[0] for v in s['listen']]
|
|
658
|
+
else:
|
|
659
|
+
server_names = ' '.join([v for v in s['server_name']]).split()
|
|
660
|
+
listens = [v.split()[0] for v in s['listen']]
|
|
661
|
+
find_listen = ip and ['%s:%s' % (ip, port)] or [port, '*:%s' % port, '0.0.0.0:%s' % port]
|
|
662
|
+
if server_name in server_names and any([i in listens for i in find_listen]):
|
|
663
|
+
return s
|
|
664
|
+
return False
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
def _context_getupstreams(server_name, config=None, disabled=None, getlineinfo=True):
|
|
668
|
+
"""Get upstream list related to a server.
|
|
669
|
+
"""
|
|
670
|
+
if not config or config['_isdirty']:
|
|
671
|
+
config = loadconfig(NGINXCONF, getlineinfo)
|
|
672
|
+
upstreams = http_get('upstream', config)
|
|
673
|
+
if not upstreams: return False
|
|
674
|
+
if getlineinfo:
|
|
675
|
+
upstreams = [upstream for upstream in upstreams
|
|
676
|
+
if upstream['_param']['value'].startswith('backend_of_%s_' % server_name)]
|
|
677
|
+
else:
|
|
678
|
+
upstreams = [upstream for upstream in upstreams
|
|
679
|
+
if upstream['_param'].startswith('backend_of_%s_' % server_name)]
|
|
680
|
+
|
|
681
|
+
if disabled == None or not getlineinfo:
|
|
682
|
+
return upstreams
|
|
683
|
+
else:
|
|
684
|
+
return [upstream for upstream in upstreams
|
|
685
|
+
if upstream['_param']['disabled']==disabled]
|
|
686
|
+
|
|
687
|
+
def _comment(filepath, start, end):
|
|
688
|
+
"""Commend some lines in the file.
|
|
689
|
+
"""
|
|
690
|
+
if not Path(filepath).is_file(): return False
|
|
691
|
+
data = []
|
|
692
|
+
with open(filepath, encoding='utf-8') as f:
|
|
693
|
+
for i, line in enumerate(f):
|
|
694
|
+
if i >= start and i <= end:
|
|
695
|
+
if not line.startswith(COMMENTFLAG):
|
|
696
|
+
data.append(COMMENTFLAG)
|
|
697
|
+
data.append(line)
|
|
698
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
699
|
+
f.write(''.join(data))
|
|
700
|
+
return True
|
|
701
|
+
|
|
702
|
+
def _uncomment(filepath, start, end):
|
|
703
|
+
"""Uncommend some lines in the file.
|
|
704
|
+
"""
|
|
705
|
+
if not Path(filepath).is_file():
|
|
706
|
+
return False
|
|
707
|
+
data = []
|
|
708
|
+
with open(filepath, encoding='utf-8') as f:
|
|
709
|
+
for i, line in enumerate(f):
|
|
710
|
+
if i >= start and i <= end:
|
|
711
|
+
while line.startswith(COMMENTFLAG):
|
|
712
|
+
line = line[3:]
|
|
713
|
+
data.append(line)
|
|
714
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
715
|
+
f.write(''.join(data))
|
|
716
|
+
return True
|
|
717
|
+
|
|
718
|
+
def _delete(filepath, start, end, delete_emptyfile=True):
|
|
719
|
+
"""Delete some lines in the file.
|
|
720
|
+
|
|
721
|
+
If delete_emptyfile is set to True, then the empty file will
|
|
722
|
+
be deleted from file system.
|
|
723
|
+
"""
|
|
724
|
+
if not Path(filepath).is_file(): return False
|
|
725
|
+
data = []
|
|
726
|
+
with open(filepath, encoding='utf-8') as f:
|
|
727
|
+
for i, line in enumerate(f):
|
|
728
|
+
if i >= start and i <= end:
|
|
729
|
+
continue
|
|
730
|
+
data.append(line)
|
|
731
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
732
|
+
f.write(''.join(data))
|
|
733
|
+
if delete_emptyfile:
|
|
734
|
+
if ''.join(data).strip() == '':
|
|
735
|
+
Path(filepath).unlink()
|
|
736
|
+
return True
|
|
737
|
+
|
|
738
|
+
def _getcontextrange(context, config):
|
|
739
|
+
"""Return the range of the input context, including the file path.
|
|
740
|
+
|
|
741
|
+
Return format:
|
|
742
|
+
[filepath, line_start, line_end]
|
|
743
|
+
"""
|
|
744
|
+
file_i = context['_range']['begin']['file']
|
|
745
|
+
filepath = config['_files'][file_i]
|
|
746
|
+
line_start = context['_range']['begin']['line'][0]
|
|
747
|
+
line_end = context['_range']['end']['line'][0]
|
|
748
|
+
return [filepath, line_start, line_end]
|
|
749
|
+
|
|
750
|
+
def _context_commentserver(ip, port, server_name, config=None):
|
|
751
|
+
"""Comment a context using InPanel's special comment string '#v#'
|
|
752
|
+
"""
|
|
753
|
+
if not config or config['_isdirty']:
|
|
754
|
+
config = loadconfig(NGINXCONF, True)
|
|
755
|
+
scontext = _context_getserver(ip, port, server_name, config=config)
|
|
756
|
+
if not scontext: return False
|
|
757
|
+
filepath, line_start, line_end = _getcontextrange(scontext, config)
|
|
758
|
+
return _comment(filepath, line_start, line_end)
|
|
759
|
+
|
|
760
|
+
def _context_uncommentserver(ip, port, server_name, config=None):
|
|
761
|
+
"""Uncomment a InPanel's special-commented context.
|
|
762
|
+
"""
|
|
763
|
+
if not config or config['_isdirty']:
|
|
764
|
+
config = loadconfig(NGINXCONF, True)
|
|
765
|
+
scontext = _context_getserver(ip, port, server_name, config=config)
|
|
766
|
+
if not scontext: return False
|
|
767
|
+
filepath, line_start, line_end = _getcontextrange(scontext, config)
|
|
768
|
+
return _uncomment(filepath, line_start, line_end)
|
|
769
|
+
|
|
770
|
+
def _context_deleteserver(ip, port, server_name, config=None, disabled=None):
|
|
771
|
+
"""Delete a server context.
|
|
772
|
+
"""
|
|
773
|
+
if not config or config['_isdirty']:
|
|
774
|
+
config = loadconfig(NGINXCONF, True)
|
|
775
|
+
scontext = _context_getserver(ip, port, server_name, config=config, disabled=disabled)
|
|
776
|
+
if not scontext: return False
|
|
777
|
+
filepath, line_start, line_end = _getcontextrange(scontext, config)
|
|
778
|
+
config['_isdirty'] = True
|
|
779
|
+
return _delete(filepath, line_start, line_end)
|
|
780
|
+
|
|
781
|
+
def _context_commentupstreams(server_name, config=None):
|
|
782
|
+
"""Comment upstreams by server names.
|
|
783
|
+
"""
|
|
784
|
+
if not config or config['_isdirty']:
|
|
785
|
+
config = loadconfig(NGINXCONF, True)
|
|
786
|
+
upstreams = _context_getupstreams(server_name, config=config)
|
|
787
|
+
if not upstreams: return True
|
|
788
|
+
for upstream in upstreams:
|
|
789
|
+
filepath, line_start, line_end = _getcontextrange(upstream, config)
|
|
790
|
+
if not _comment(filepath, line_start, line_end): return False
|
|
791
|
+
return True
|
|
792
|
+
|
|
793
|
+
def _context_uncommentupstreams(server_name, config=None):
|
|
794
|
+
"""Uncomment upstreams by server names.
|
|
795
|
+
"""
|
|
796
|
+
if not config or config['_isdirty']:
|
|
797
|
+
config = loadconfig(NGINXCONF, True)
|
|
798
|
+
upstreams = _context_getupstreams(server_name, config=config)
|
|
799
|
+
if not upstreams: return True
|
|
800
|
+
for upstream in upstreams:
|
|
801
|
+
filepath, line_start, line_end = _getcontextrange(upstream, config)
|
|
802
|
+
if not _uncomment(filepath, line_start, line_end): return False
|
|
803
|
+
return True
|
|
804
|
+
|
|
805
|
+
def _context_deleteupstreams(server_name, config=None, disabled=None):
|
|
806
|
+
"""Delete upstreams by server name.
|
|
807
|
+
"""
|
|
808
|
+
while True:
|
|
809
|
+
# we need to reload config after delete one upstream
|
|
810
|
+
if not config or config['_isdirty']:
|
|
811
|
+
config = loadconfig(NGINXCONF, True)
|
|
812
|
+
upstreams = _context_getupstreams(server_name, config=config, disabled=disabled)
|
|
813
|
+
if not upstreams: return True
|
|
814
|
+
for upstream in upstreams:
|
|
815
|
+
filepath, line_start, line_end = _getcontextrange(upstream, config)
|
|
816
|
+
config['_isdirty'] = True
|
|
817
|
+
if not _delete(filepath, line_start, line_end): return False
|
|
818
|
+
break # only delete the first one
|
|
819
|
+
return True
|
|
820
|
+
|
|
821
|
+
def _context_http_init_limit_conn(config=None, version=None):
|
|
822
|
+
"""Init limit_conn_zone in http context.
|
|
823
|
+
|
|
824
|
+
We only recognize limit_conn_zone with name "addr".
|
|
825
|
+
|
|
826
|
+
Return True if initialized do.
|
|
827
|
+
Or False if nothing to do with it.
|
|
828
|
+
"""
|
|
829
|
+
if not config or config['_isdirty']:
|
|
830
|
+
config = loadconfig(NGINXCONF, True)
|
|
831
|
+
|
|
832
|
+
if not version or version_get(version, '1.1.8'):
|
|
833
|
+
conn_zones = http_get('limit_conn_zone')
|
|
834
|
+
if not conn_zones:
|
|
835
|
+
http_set('limit_conn_zone', '$binary_remote_addr zone=addr:10m', config)
|
|
836
|
+
return True
|
|
837
|
+
else:
|
|
838
|
+
addr_conn_zone_found = False
|
|
839
|
+
for conn_zone in conn_zones:
|
|
840
|
+
zonename = conn_zone.split('zone=', 1)[-1].split(':', 1)[0]
|
|
841
|
+
if zonename == 'addr':
|
|
842
|
+
addr_conn_zone_found = True
|
|
843
|
+
break
|
|
844
|
+
if not addr_conn_zone_found:
|
|
845
|
+
conn_zones.append('$binary_remote_addr zone=addr:10m')
|
|
846
|
+
http_set('limit_conn_zone', conn_zones, config)
|
|
847
|
+
return True
|
|
848
|
+
else:
|
|
849
|
+
return False
|
|
850
|
+
else:
|
|
851
|
+
conn_zones = http_get('limit_zone')
|
|
852
|
+
if not conn_zones:
|
|
853
|
+
http_set('limit_zone', 'addr $binary_remote_addr 10m', config)
|
|
854
|
+
return True
|
|
855
|
+
else:
|
|
856
|
+
addr_conn_zone_found = False
|
|
857
|
+
for conn_zone in conn_zones:
|
|
858
|
+
zonename = conn_zone.split()[0]
|
|
859
|
+
if zonename == 'addr':
|
|
860
|
+
addr_conn_zone_found = True
|
|
861
|
+
break
|
|
862
|
+
if not addr_conn_zone_found:
|
|
863
|
+
conn_zones.append('addr $binary_remote_addr 10m')
|
|
864
|
+
http_set('limit_zone', conn_zones, config)
|
|
865
|
+
return True
|
|
866
|
+
else:
|
|
867
|
+
return False
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
def _context_server_clear_default_server(ip, port, config=None):
|
|
871
|
+
"""Clear the default_server flag at specified ip:port.
|
|
872
|
+
"""
|
|
873
|
+
if not config or config['_isdirty']:
|
|
874
|
+
config = loadconfig(NGINXCONF, True)
|
|
875
|
+
cnfservers = _context_getservers(config=config)
|
|
876
|
+
found = False
|
|
877
|
+
for cnfserver in cnfservers:
|
|
878
|
+
listens = cnfserver['listen']
|
|
879
|
+
for listen in listens:
|
|
880
|
+
if 'default_server' in listen['value']:
|
|
881
|
+
_replace([(config['_files'][listen['file']], listen['line'][0], listen['line'][1])],
|
|
882
|
+
['listen %s;' % listen['value'].replace('default_server', '').strip()])
|
|
883
|
+
found = True
|
|
884
|
+
break
|
|
885
|
+
if found: break
|
|
886
|
+
return found
|
|
887
|
+
|
|
888
|
+
def _replace(positions, lines):
|
|
889
|
+
"""Replace the lines specified in list positions to new lines.
|
|
890
|
+
|
|
891
|
+
Structure of positions:
|
|
892
|
+
[
|
|
893
|
+
(filepath, line_start, line_count),
|
|
894
|
+
...
|
|
895
|
+
]
|
|
896
|
+
Parameter positions can not be empty.
|
|
897
|
+
|
|
898
|
+
* If the new lines is empty, old lines with be deleted.
|
|
899
|
+
* If the new lines is less than the old lines, the rest old lines
|
|
900
|
+
will also be deleted.
|
|
901
|
+
* If the new lines is more than the old lines, then new value will
|
|
902
|
+
append after the last line of the old lines.
|
|
903
|
+
"""
|
|
904
|
+
# merge line positions by filepath
|
|
905
|
+
# struct: {'/path/to/file': [3, 4, 10, ...], ...}
|
|
906
|
+
files = {}
|
|
907
|
+
for pos in positions:
|
|
908
|
+
filepath, line_start, line_count = pos
|
|
909
|
+
if not filepath in files:
|
|
910
|
+
files[filepath] = []
|
|
911
|
+
for i in range(line_count):
|
|
912
|
+
files[filepath].append(line_start+i)
|
|
913
|
+
# replace line by line
|
|
914
|
+
for filepath, line_nums in files.items():
|
|
915
|
+
flines = []
|
|
916
|
+
with open(filepath, encoding='utf-8') as f:
|
|
917
|
+
for i, fline in enumerate(f):
|
|
918
|
+
if i in line_nums:
|
|
919
|
+
if len(lines) > 0:
|
|
920
|
+
# replace with a new line
|
|
921
|
+
line = lines[0]
|
|
922
|
+
lines = lines[1:]
|
|
923
|
+
# detect the space at the start of the old line
|
|
924
|
+
# this aim to keep the indent of the line
|
|
925
|
+
space = ''
|
|
926
|
+
for c in fline:
|
|
927
|
+
if c not in (' ', '\t'):
|
|
928
|
+
break
|
|
929
|
+
space += c
|
|
930
|
+
flines.append(''.join([space, line, '\n']))
|
|
931
|
+
else:
|
|
932
|
+
# no more new line, delete the old line
|
|
933
|
+
continue
|
|
934
|
+
else:
|
|
935
|
+
if i > line_nums[-1] and len(lines) > 0:
|
|
936
|
+
# exceed the last old line, insert the rest new lines here
|
|
937
|
+
# detect the indent of the last line
|
|
938
|
+
space = ''
|
|
939
|
+
if len(flines)>0: # last line exists
|
|
940
|
+
for c in flines[-1]:
|
|
941
|
+
if c not in (' ', '\t'):
|
|
942
|
+
break
|
|
943
|
+
space += c
|
|
944
|
+
for line in lines:
|
|
945
|
+
flines.append(''.join([space, line, '\n']))
|
|
946
|
+
lines = []
|
|
947
|
+
flines.append(fline)
|
|
948
|
+
# write back to file
|
|
949
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
950
|
+
f.write(''.join(flines))
|
|
951
|
+
|
|
952
|
+
def _insert(filepath, line_start, lines):
|
|
953
|
+
"""Insert the lines to the specified position.
|
|
954
|
+
"""
|
|
955
|
+
flines = []
|
|
956
|
+
with open(filepath, encoding='utf-8') as f:
|
|
957
|
+
for i, fline in enumerate(f):
|
|
958
|
+
if i == line_start:
|
|
959
|
+
# detect the indent of the last not empty line
|
|
960
|
+
space = ''
|
|
961
|
+
flines_len = len(flines)
|
|
962
|
+
if flines_len>0: # last line exists
|
|
963
|
+
line_i = -1
|
|
964
|
+
while flines[line_i].strip() == '' and -line_i <= flines_len:
|
|
965
|
+
line_i -= 1
|
|
966
|
+
for c in flines[line_i]:
|
|
967
|
+
if c not in (' ', '\t'):
|
|
968
|
+
break
|
|
969
|
+
space += c
|
|
970
|
+
if flines[line_i].strip().endswith('{'):
|
|
971
|
+
space += ' '
|
|
972
|
+
for line in lines:
|
|
973
|
+
flines.append(''.join([space, line, '\n']))
|
|
974
|
+
flines.append(fline)
|
|
975
|
+
# write back to file
|
|
976
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
977
|
+
f.write(''.join(flines))
|
|
978
|
+
|
|
979
|
+
def _detect_engines(context):
|
|
980
|
+
"""Detect engines in context.
|
|
981
|
+
"""
|
|
982
|
+
engine_flags = {
|
|
983
|
+
'root' : 'static',
|
|
984
|
+
'alias' : 'static_alias',
|
|
985
|
+
'fastcgi_pass': 'fastcgi',
|
|
986
|
+
'scgi_pass': 'scgi',
|
|
987
|
+
'uwsgi_pass': 'uwsgi',
|
|
988
|
+
'proxy_pass': 'proxy',
|
|
989
|
+
'rewrite': 'rewrite',
|
|
990
|
+
'return': 'return',
|
|
991
|
+
}
|
|
992
|
+
contexts = ['location', 'if', 'limit_except']
|
|
993
|
+
|
|
994
|
+
engines = []
|
|
995
|
+
for k, v in context.items():
|
|
996
|
+
if k in engine_flags:
|
|
997
|
+
if k == 'rewrite':
|
|
998
|
+
engines.extend([x and 'redirect' or 'rewrite' for x in _isredirect(v)])
|
|
999
|
+
else:
|
|
1000
|
+
engines.append(engine_flags[k])
|
|
1001
|
+
elif k in contexts:
|
|
1002
|
+
for ctx in context[k]:
|
|
1003
|
+
engines.extend(_detect_engines(ctx))
|
|
1004
|
+
|
|
1005
|
+
# return a uniq result
|
|
1006
|
+
engines = list(set(engines))
|
|
1007
|
+
if 'static_alias' in engines:
|
|
1008
|
+
if len(engines) == 1:
|
|
1009
|
+
engines[0] = 'static'
|
|
1010
|
+
else:
|
|
1011
|
+
engines = filter(lambda a: a != 'static_alias', engines)
|
|
1012
|
+
return engines
|
|
1013
|
+
|
|
1014
|
+
def _isredirect(values):
|
|
1015
|
+
"""Check if rewrite values is redirect.
|
|
1016
|
+
"""
|
|
1017
|
+
return [v.split().pop() in ('redirect', 'permanent') for v in values]
|
|
1018
|
+
|
|
1019
|
+
def getservers(config=None):
|
|
1020
|
+
"""Get servers from nginx configuration files.
|
|
1021
|
+
|
|
1022
|
+
Struct of server dict:
|
|
1023
|
+
{
|
|
1024
|
+
'server_names': [
|
|
1025
|
+
'test.com',
|
|
1026
|
+
'www.test.com'
|
|
1027
|
+
],
|
|
1028
|
+
'listens': [
|
|
1029
|
+
{'ip': '192.168.1.2', 'port': '80', 'default_server': true},
|
|
1030
|
+
{'ip': '*', 'port': '88', 'default_server': false}
|
|
1031
|
+
],
|
|
1032
|
+
'engines': [
|
|
1033
|
+
'static',
|
|
1034
|
+
'rewrite',
|
|
1035
|
+
'redirect',
|
|
1036
|
+
'fastcgi',
|
|
1037
|
+
'scgi',
|
|
1038
|
+
'uwsgi',
|
|
1039
|
+
'proxy',
|
|
1040
|
+
],
|
|
1041
|
+
}
|
|
1042
|
+
"""
|
|
1043
|
+
if not config or config['_isdirty']:
|
|
1044
|
+
config = loadconfig(NGINXCONF) # do not need to load lineinfo
|
|
1045
|
+
cnfservers = _context_getservers(config=config)
|
|
1046
|
+
servers = []
|
|
1047
|
+
for s in cnfservers:
|
|
1048
|
+
server = {}
|
|
1049
|
+
server['server_names'] = ' '.join(s['server_name']).split()
|
|
1050
|
+
# parse server and port, and check if is default server
|
|
1051
|
+
server['listens'] = []
|
|
1052
|
+
for listen in s['listen']:
|
|
1053
|
+
port_ip = listen.split()[0]
|
|
1054
|
+
port = port_ip.split(':')[-1]
|
|
1055
|
+
ip = port_ip[0:-(len(port) + 1)]
|
|
1056
|
+
ip = ip.lstrip('[').rstrip(']') # for IPv6
|
|
1057
|
+
server['listens'].append({
|
|
1058
|
+
'ip': ip or '*',
|
|
1059
|
+
'port': port,
|
|
1060
|
+
'default_server': 'default_server' in listen
|
|
1061
|
+
})
|
|
1062
|
+
engines = _detect_engines(s)
|
|
1063
|
+
engine_orders = ['static', 'fastcgi', 'scgi', 'uwsgi', 'redirect', 'proxy', 'rewrite', 'return']
|
|
1064
|
+
engines = [(engine_orders.index(engine), engine) for engine in engines]
|
|
1065
|
+
engines.sort()
|
|
1066
|
+
server['engines'] = list(zip(*engines))[1] if engines else []
|
|
1067
|
+
# check the status of this server
|
|
1068
|
+
server['status'] = 'off' if s['_disabled'] else 'on'
|
|
1069
|
+
servers.append(server)
|
|
1070
|
+
return servers
|
|
1071
|
+
|
|
1072
|
+
def http_get(directive, config=None):
|
|
1073
|
+
"""Get directive values in http context.
|
|
1074
|
+
"""
|
|
1075
|
+
if not config or config['_isdirty']:
|
|
1076
|
+
config = loadconfig(NGINXCONF)
|
|
1077
|
+
hcontext = _context_gethttp(config)
|
|
1078
|
+
if directive in hcontext:
|
|
1079
|
+
return hcontext[directive]
|
|
1080
|
+
elif directive in DEFAULTVALS:
|
|
1081
|
+
return DEFAULTVALS[directive]
|
|
1082
|
+
else:
|
|
1083
|
+
return None
|
|
1084
|
+
|
|
1085
|
+
def http_getfirst(directive, config=None):
|
|
1086
|
+
"""Get the first value of the directive in http context.
|
|
1087
|
+
"""
|
|
1088
|
+
values = http_get(directive, config)
|
|
1089
|
+
if values: return values[0]
|
|
1090
|
+
return None
|
|
1091
|
+
|
|
1092
|
+
def http_set(directive, values, config=None):
|
|
1093
|
+
"""Set a directive in http context.
|
|
1094
|
+
|
|
1095
|
+
If directive exists, the value will be replace in place.
|
|
1096
|
+
If directive not exists, new directive will be created at the beginning of http context.
|
|
1097
|
+
|
|
1098
|
+
Parameter values can be a list or a string.
|
|
1099
|
+
If values is set to empty list or None or empty string, then the directive will be deleted.
|
|
1100
|
+
"""
|
|
1101
|
+
if not config or config['_isdirty']:
|
|
1102
|
+
config = loadconfig(NGINXCONF, True)
|
|
1103
|
+
hcontext = _context_gethttp(config)
|
|
1104
|
+
|
|
1105
|
+
if not values:
|
|
1106
|
+
values = []
|
|
1107
|
+
elif isinstance(values, str):
|
|
1108
|
+
values = [values]
|
|
1109
|
+
values = ['%s %s;' % (directive, v) for v in values]
|
|
1110
|
+
|
|
1111
|
+
if directive in hcontext:
|
|
1112
|
+
# update or delete value
|
|
1113
|
+
dvalues = hcontext[directive]
|
|
1114
|
+
lines = [(config['_files'][dvalue['file']], dvalue['line'][0], dvalue['line'][1]) for dvalue in dvalues]
|
|
1115
|
+
_replace(lines, values)
|
|
1116
|
+
else:
|
|
1117
|
+
# add directive to the beginning of http context
|
|
1118
|
+
# some directive like proxy_cache_path should be declare before use the resource,
|
|
1119
|
+
# so we should insert it at the beginning
|
|
1120
|
+
begin = hcontext['_range']['begin']
|
|
1121
|
+
_insert(config['_files'][begin['file']], begin['line'][0]+begin['line'][1], values)
|
|
1122
|
+
|
|
1123
|
+
config['_isdirty'] = True
|
|
1124
|
+
|
|
1125
|
+
def disableserver(ip, port, server_name):
|
|
1126
|
+
"""Disable a server.
|
|
1127
|
+
"""
|
|
1128
|
+
_context_commentupstreams(server_name)
|
|
1129
|
+
return _context_commentserver(ip, port, server_name)
|
|
1130
|
+
|
|
1131
|
+
def enableserver(ip, port, server_name):
|
|
1132
|
+
"""Enable a server.
|
|
1133
|
+
"""
|
|
1134
|
+
_context_uncommentupstreams(server_name)
|
|
1135
|
+
return _context_uncommentserver(ip, port, server_name)
|
|
1136
|
+
|
|
1137
|
+
def deleteserver(ip, port, server_name, disabled=None):
|
|
1138
|
+
"""Delete a server.
|
|
1139
|
+
|
|
1140
|
+
If disabled is not None, it will only delete those servers which is disabled or enabled.
|
|
1141
|
+
"""
|
|
1142
|
+
_context_deleteupstreams(server_name, disabled=disabled)
|
|
1143
|
+
return _context_deleteserver(ip, port, server_name, disabled=disabled)
|
|
1144
|
+
|
|
1145
|
+
def servername_exists(ip, port, server_name, config=None):
|
|
1146
|
+
"""Check if the server_name at given ip:port is already exists.
|
|
1147
|
+
"""
|
|
1148
|
+
return _context_getserver(ip, port, server_name, config=config) and True or False
|
|
1149
|
+
|
|
1150
|
+
def getserver(ip, port, server_name, config=None):
|
|
1151
|
+
"""Get server setting from nginx config files.
|
|
1152
|
+
"""
|
|
1153
|
+
if not config or config['_isdirty']:
|
|
1154
|
+
config = loadconfig(NGINXCONF, False)
|
|
1155
|
+
scontext = _context_getserver(ip, port, server_name, config=config, getlineinfo=False)
|
|
1156
|
+
if not scontext: return False
|
|
1157
|
+
|
|
1158
|
+
server = {}
|
|
1159
|
+
server['_inpanel'] = scontext['_inpanel']
|
|
1160
|
+
server['server_names'] = []
|
|
1161
|
+
if 'server_name' in scontext:
|
|
1162
|
+
for name in scontext['server_name']:
|
|
1163
|
+
server['server_names'].extend(name.split())
|
|
1164
|
+
|
|
1165
|
+
server['listens'] = []
|
|
1166
|
+
if 'listen' in scontext:
|
|
1167
|
+
for listen in scontext['listen']:
|
|
1168
|
+
port_ip = listen.split()[0]
|
|
1169
|
+
port = port_ip.split(':')[-1]
|
|
1170
|
+
ip = port_ip[0:-(len(port) + 1)]
|
|
1171
|
+
ip = ip.lstrip('[').rstrip(']') # for IPv6
|
|
1172
|
+
server['listens'].append({
|
|
1173
|
+
'ip': ip or '',
|
|
1174
|
+
'port': port,
|
|
1175
|
+
'ssl': 'ssl' in listen,
|
|
1176
|
+
'default_server': 'default_server' in listen
|
|
1177
|
+
})
|
|
1178
|
+
|
|
1179
|
+
if 'charset' in scontext: server['charset'] = scontext['charset'][-1]
|
|
1180
|
+
if 'index' in scontext: server['index'] = scontext['index'][-1]
|
|
1181
|
+
if 'limit_rate' in scontext: server['limit_rate'] = scontext['limit_rate'][-1].replace('k','')
|
|
1182
|
+
if 'limit_conn' in scontext: server['limit_conn'] = scontext['limit_conn'][-1].split()[-1]
|
|
1183
|
+
if 'ssl' in scontext and scontext['ssl'][-1] == 'on': # deal with old config file
|
|
1184
|
+
for listen in server['listens']: listen['ssl'] = True
|
|
1185
|
+
if 'ssl_certificate' in scontext: server['ssl_crt'] = scontext['ssl_certificate'][-1]
|
|
1186
|
+
if 'ssl_certificate_key' in scontext: server['ssl_key'] = scontext['ssl_certificate_key'][-1]
|
|
1187
|
+
if 'rewrite' in scontext:
|
|
1188
|
+
server['rewrite_rules'] = ['rewrite %s' % rule for rule in scontext['rewrite']]
|
|
1189
|
+
|
|
1190
|
+
server['locations'] = []
|
|
1191
|
+
if 'location' in scontext:
|
|
1192
|
+
locs = scontext['location']
|
|
1193
|
+
for loc in locs:
|
|
1194
|
+
location = {}
|
|
1195
|
+
location['urlpath'] = loc['_param']
|
|
1196
|
+
if 'root' in loc:
|
|
1197
|
+
location['root'] = loc['root'][-1]
|
|
1198
|
+
elif 'root' in scontext: # deal with old config file
|
|
1199
|
+
location['root'] = scontext['root'][-1]
|
|
1200
|
+
if 'alias' in loc:
|
|
1201
|
+
location['root'] = loc['alias'][-1]
|
|
1202
|
+
if 'autoindex' in loc:
|
|
1203
|
+
location['autoindex'] = loc['autoindex'][-1] == 'on'
|
|
1204
|
+
|
|
1205
|
+
# detect redirect and rewrite
|
|
1206
|
+
# we treat redirect and rewrite conflict
|
|
1207
|
+
rewrites = []
|
|
1208
|
+
if 'rewrite' in loc:
|
|
1209
|
+
rewrites = loc['rewrite']
|
|
1210
|
+
if 'if' in loc:
|
|
1211
|
+
for ifstm in loc['if']:
|
|
1212
|
+
if re.sub(r'\s', '', ifstm['_param']) == '(!-e$request_filename)':
|
|
1213
|
+
location['rewrite_detect_file'] = True
|
|
1214
|
+
if 'rewrite' in ifstm:
|
|
1215
|
+
rewrites.extend(ifstm['rewrite'])
|
|
1216
|
+
|
|
1217
|
+
for rule in rewrites:
|
|
1218
|
+
rwinfo = rule.split()
|
|
1219
|
+
if rwinfo[-1] in ('permanent', 'redirect'):
|
|
1220
|
+
if rwinfo[1].endswith('$request_uri?') or rwinfo[1].endswith('$request_uri_alias?'):
|
|
1221
|
+
redirect_option = 'keep'
|
|
1222
|
+
redirect_url = rwinfo[1].replace('$request_uri?', '').replace('$request_uri_alias?', '')
|
|
1223
|
+
else:
|
|
1224
|
+
redirect_option = 'ignore'
|
|
1225
|
+
redirect_url = rwinfo[1]
|
|
1226
|
+
redirect_type = rwinfo[-1] == 'permanent' and '301' or '302'
|
|
1227
|
+
location['redirect_url'] = redirect_url
|
|
1228
|
+
location['redirect_type'] = redirect_type
|
|
1229
|
+
location['redirect_option'] = redirect_option
|
|
1230
|
+
else:
|
|
1231
|
+
if not 'rewrite_rules' in location:
|
|
1232
|
+
location['rewrite_rules'] = []
|
|
1233
|
+
location['rewrite_rules'].append('rewrite %s' % rule)
|
|
1234
|
+
|
|
1235
|
+
# detect fastcgi
|
|
1236
|
+
if 'fastcgi_pass' in loc:
|
|
1237
|
+
location['fastcgi_pass'] = loc['fastcgi_pass'][-1]
|
|
1238
|
+
elif 'location' in loc:
|
|
1239
|
+
for l in loc['location']:
|
|
1240
|
+
if 'fastcgi_pass' in l:
|
|
1241
|
+
location['fastcgi_pass'] = l['fastcgi_pass'][-1]
|
|
1242
|
+
break # only recoginze the first fastcgi setting
|
|
1243
|
+
|
|
1244
|
+
# detect proxy
|
|
1245
|
+
if 'proxy_pass' in loc:
|
|
1246
|
+
backend = loc['proxy_pass'][-1]
|
|
1247
|
+
if backend.startswith('http'): location['proxy_protocol'] = 'http'
|
|
1248
|
+
if backend.startswith('https'): location['proxy_protocol'] = 'https'
|
|
1249
|
+
if 'proxy_protocol' in location:
|
|
1250
|
+
if 'proxy_set_header' in loc:
|
|
1251
|
+
headers = loc['proxy_set_header']
|
|
1252
|
+
for header in headers:
|
|
1253
|
+
hinfo = re.split(r'\s+', header, 1)
|
|
1254
|
+
if len(hinfo) == 1: continue
|
|
1255
|
+
if hinfo[0] == 'X-Real-IP':
|
|
1256
|
+
if hinfo[1] == '$remote_addr':
|
|
1257
|
+
location['proxy_realip'] = True
|
|
1258
|
+
elif hinfo[0] == 'Host':
|
|
1259
|
+
location['proxy_host'] = hinfo[1]
|
|
1260
|
+
# detect upstream
|
|
1261
|
+
upstream_name = 'backend_of_%s_%s' % (server_name, location['urlpath'].replace('/', '_'))
|
|
1262
|
+
if backend == '%s://%s' % (location['proxy_protocol'], upstream_name):
|
|
1263
|
+
upstreams = http_get('upstream', config)
|
|
1264
|
+
for upstream in upstreams:
|
|
1265
|
+
if upstream['_param'] == upstream_name:
|
|
1266
|
+
if 'ip_hash' in upstream: location['proxy_balance'] = 'ip_hash'
|
|
1267
|
+
if 'least_conn' in upstream: location['proxy_balance'] = 'least_conn'
|
|
1268
|
+
if not 'proxy_balance' in location: location['proxy_balance'] = 'weight'
|
|
1269
|
+
if 'keepalive' in upstream: location['proxy_keepalive'] = upstream['keepalive'][-1]
|
|
1270
|
+
if 'server' in upstream:
|
|
1271
|
+
location['proxy_backends'] = []
|
|
1272
|
+
for s in upstream['server']:
|
|
1273
|
+
sinfo = s.split()
|
|
1274
|
+
backend = {}
|
|
1275
|
+
backend['server'] = sinfo[0]
|
|
1276
|
+
for t in sinfo[1:]:
|
|
1277
|
+
if t.startswith('weight='):
|
|
1278
|
+
backend['weight'] = t.replace('weight=', '')
|
|
1279
|
+
elif t.startswith('max_fails='):
|
|
1280
|
+
backend['max_fails'] = t.replace('max_fails=', '')
|
|
1281
|
+
elif t.startswith('fail_timeout='):
|
|
1282
|
+
backend['fail_timeout'] = t.replace('fail_timeout=', '').replace('s','')
|
|
1283
|
+
location['proxy_backends'].append(backend)
|
|
1284
|
+
break # found the right upstream
|
|
1285
|
+
# detect proxy cache
|
|
1286
|
+
if 'proxy_cache' in loc:
|
|
1287
|
+
cachename = loc['proxy_cache'][-1]
|
|
1288
|
+
if cachename.lower() != 'off':
|
|
1289
|
+
location['proxy_cache'] = cachename
|
|
1290
|
+
if 'proxy_cache_min_uses' in loc:
|
|
1291
|
+
location['proxy_cache_min_uses'] = loc['proxy_cache_min_uses'][-1]
|
|
1292
|
+
if 'proxy_cache_methods' in loc and 'POST' in loc['proxy_cache_methods'][-1].upper().split():
|
|
1293
|
+
location['proxy_cache_methods'] = 'POST'
|
|
1294
|
+
if 'proxy_cache_key' in loc:
|
|
1295
|
+
location['proxy_cache_key'] = loc['proxy_cache_key'][-1]
|
|
1296
|
+
if 'proxy_cache_use_stale' in loc:
|
|
1297
|
+
location['proxy_cache_use_stale'] = loc['proxy_cache_use_stale'][-1].split()
|
|
1298
|
+
if 'proxy_cache_valid' in loc:
|
|
1299
|
+
location['proxy_cache_valid'] = []
|
|
1300
|
+
for valid in loc['proxy_cache_valid']:
|
|
1301
|
+
fields = valid.split()
|
|
1302
|
+
for i in range(0, len(fields)-1):
|
|
1303
|
+
location['proxy_cache_valid'].append({'code': fields[i], 'time': fields[-1]})
|
|
1304
|
+
if 'proxy_cache_lock' in loc:
|
|
1305
|
+
location['proxy_cache_lock'] = loc['proxy_cache_lock'][-1].lower() == 'on'
|
|
1306
|
+
if 'proxy_cache_lock_timeout' in loc:
|
|
1307
|
+
location['proxy_cache_lock_timeout'] = loc['proxy_cache_lock_timeout'][-1].replace('s', '')
|
|
1308
|
+
|
|
1309
|
+
# detect error code
|
|
1310
|
+
if 'return' in loc:
|
|
1311
|
+
location['error_code'] = loc['return'][-1]
|
|
1312
|
+
|
|
1313
|
+
server['locations'].append(location)
|
|
1314
|
+
|
|
1315
|
+
return server
|
|
1316
|
+
|
|
1317
|
+
def addserver(server_names, listens, charset=None, index=None, locations=None,
|
|
1318
|
+
limit_rate=None, limit_conn=None, ssl_crt=None, ssl_key=None,
|
|
1319
|
+
rewrite_rules=None, conflict_check=True, version=None):
|
|
1320
|
+
"""Add a new server.
|
|
1321
|
+
|
|
1322
|
+
We create new config file for each server under /etc/nginx/conf.d/.
|
|
1323
|
+
Config file name depends on the first of server_names.
|
|
1324
|
+
|
|
1325
|
+
Parameter examples:
|
|
1326
|
+
* server_names: ['example.com', 'www.example.com']
|
|
1327
|
+
* listens:
|
|
1328
|
+
[
|
|
1329
|
+
{
|
|
1330
|
+
'ip': '',
|
|
1331
|
+
'port': '80',
|
|
1332
|
+
'ssl': True,
|
|
1333
|
+
'default_server': False
|
|
1334
|
+
}
|
|
1335
|
+
]
|
|
1336
|
+
* charset: 'utf-8'
|
|
1337
|
+
* index: 'index.html index.htm index.php'
|
|
1338
|
+
* locations:
|
|
1339
|
+
[
|
|
1340
|
+
{
|
|
1341
|
+
'urlpath': '/',
|
|
1342
|
+
'root': '/var/www/example',
|
|
1343
|
+
'fastcgi_pass': '127.0.0.1:9000',
|
|
1344
|
+
'rewrite_detect_file': True,
|
|
1345
|
+
'rewrite_rules': [
|
|
1346
|
+
'rewrite ^/$ /index.php last',
|
|
1347
|
+
'rewrite ^/(.*)$ /index.php/$1 last',
|
|
1348
|
+
],
|
|
1349
|
+
},
|
|
1350
|
+
{
|
|
1351
|
+
'urlpath': '/download',
|
|
1352
|
+
'root': '/var/www/example/download',
|
|
1353
|
+
'autoindex': True,
|
|
1354
|
+
},
|
|
1355
|
+
{
|
|
1356
|
+
'urlpath': '/redirect',
|
|
1357
|
+
'redirect_url': 'http://test.com/',
|
|
1358
|
+
'redirect_type': '301',
|
|
1359
|
+
'redirect_option': 'keep',
|
|
1360
|
+
},
|
|
1361
|
+
{
|
|
1362
|
+
'urlpath': '/proxy',
|
|
1363
|
+
'proxy_balance': 'weight',
|
|
1364
|
+
'proxy_protocol': 'http',
|
|
1365
|
+
'proxy_host': 'www.baidu.com',
|
|
1366
|
+
'proxy_charset': 'utf-8',
|
|
1367
|
+
'proxy_realip': True,
|
|
1368
|
+
'proxy_keepalive': 10,
|
|
1369
|
+
'proxy_backends': [
|
|
1370
|
+
{'server':'www.baidu.com'}
|
|
1371
|
+
],
|
|
1372
|
+
'proxy_cache': 'proxycache',
|
|
1373
|
+
'proxy_cache_min_uses': '5',
|
|
1374
|
+
'proxy_cache_methods': 'POST',
|
|
1375
|
+
'proxy_cache_key': '$scheme$proxy_host$request_uri',
|
|
1376
|
+
'proxy_cache_valid': [
|
|
1377
|
+
{
|
|
1378
|
+
'code': '200',
|
|
1379
|
+
'time': '1m',
|
|
1380
|
+
}
|
|
1381
|
+
],
|
|
1382
|
+
'proxy_cache_use_stale': [
|
|
1383
|
+
'error', 'timeout', 'invalid_header', 'updating',
|
|
1384
|
+
'http_500', 'http_502', 'http_503', 'http_504', 'http_404'
|
|
1385
|
+
],
|
|
1386
|
+
'proxy_cache_lock': True,
|
|
1387
|
+
'proxy_cache_lock_timeout': '5',
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
'urlpath': '/error',
|
|
1391
|
+
'error_code': '502',
|
|
1392
|
+
}
|
|
1393
|
+
]
|
|
1394
|
+
* limit_rate: '100'
|
|
1395
|
+
* limit_conn: '10'
|
|
1396
|
+
* ssl_crt: '/etc/nginx/ssl/server.crt'
|
|
1397
|
+
* ssl_key: '/etc/nginx/ssl/server.key'
|
|
1398
|
+
* rewrite_rules:
|
|
1399
|
+
[
|
|
1400
|
+
'rewrite ^ https://www.example.com$document_uri permanent'
|
|
1401
|
+
]
|
|
1402
|
+
"""
|
|
1403
|
+
# check if any of listen - server_name pair already exists
|
|
1404
|
+
if conflict_check:
|
|
1405
|
+
for server_name in server_names:
|
|
1406
|
+
for listen in listens:
|
|
1407
|
+
ip = 'ip' in listen and listen['ip'] or ''
|
|
1408
|
+
if servername_exists(ip, listen['port'], server_name):
|
|
1409
|
+
return False
|
|
1410
|
+
|
|
1411
|
+
# start generate the config string
|
|
1412
|
+
servercfg = ['server { # %s' % GENBY]
|
|
1413
|
+
|
|
1414
|
+
if limit_rate: servercfg.append(' limit_rate %sk;' % limit_rate)
|
|
1415
|
+
if limit_conn:
|
|
1416
|
+
_context_http_init_limit_conn(version=version)
|
|
1417
|
+
servercfg.append(' limit_conn addr %s;' % limit_conn)
|
|
1418
|
+
|
|
1419
|
+
for listen in listens:
|
|
1420
|
+
flag_ds = 'default_server' in listen and listen['default_server'] and ' default_server' or ''
|
|
1421
|
+
flag_ssl = 'ssl' in listen and listen['ssl'] and ' ssl' or ''
|
|
1422
|
+
ip = 'ip' in listen and listen['ip'] or ''
|
|
1423
|
+
if is_valid_ipv6(ip) and not is_valid_ipv4(ip):
|
|
1424
|
+
ip = '[' + ip + ']'
|
|
1425
|
+
port = listen['port']
|
|
1426
|
+
if ip:
|
|
1427
|
+
servercfg.append(' listen %s:%s%s%s;' % (ip, port, flag_ds, flag_ssl))
|
|
1428
|
+
else:
|
|
1429
|
+
servercfg.append(' listen %s%s%s;' % (port, flag_ds, flag_ssl))
|
|
1430
|
+
# if set to default server, we should clear the default_server flag
|
|
1431
|
+
if flag_ds: _context_server_clear_default_server(ip, port)
|
|
1432
|
+
|
|
1433
|
+
servercfg.append(' server_name %s;' % (' '.join(server_names)))
|
|
1434
|
+
|
|
1435
|
+
if charset: servercfg.append(' charset %s;' % charset)
|
|
1436
|
+
servercfg.append('')
|
|
1437
|
+
|
|
1438
|
+
if ssl_crt and ssl_key:
|
|
1439
|
+
if not Path(ssl_crt).is_file() or not Path(ssl_key).is_file(): return False
|
|
1440
|
+
servercfg.append(' ssl_certificate %s;' % ssl_crt)
|
|
1441
|
+
servercfg.append(' ssl_certificate_key %s;' % ssl_key)
|
|
1442
|
+
servercfg.append(' ssl_session_timeout 5m;')
|
|
1443
|
+
servercfg.append(' ssl_protocols SSLv2 SSLv3 TLSv1;')
|
|
1444
|
+
servercfg.append(' ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;')
|
|
1445
|
+
servercfg.append(' ssl_prefer_server_ciphers on;')
|
|
1446
|
+
servercfg.append('')
|
|
1447
|
+
|
|
1448
|
+
if index:
|
|
1449
|
+
servercfg.append(' index %s;' % index)
|
|
1450
|
+
servercfg.append('')
|
|
1451
|
+
|
|
1452
|
+
upstreams = {}
|
|
1453
|
+
if locations:
|
|
1454
|
+
urlpaths = [] # use to detect if urlpath duplicates
|
|
1455
|
+
for location in locations:
|
|
1456
|
+
urlpath = location['urlpath'].strip()
|
|
1457
|
+
if urlpath in urlpaths: return False
|
|
1458
|
+
urlpaths.append(urlpath)
|
|
1459
|
+
|
|
1460
|
+
servercfg.append(' location %s {' % urlpath)
|
|
1461
|
+
if 'root' in location:
|
|
1462
|
+
if urlpath.startswith('~'): # deal with old config
|
|
1463
|
+
servercfg.append(' root %s;' % location['root'])
|
|
1464
|
+
else:
|
|
1465
|
+
if urlpath == '/':
|
|
1466
|
+
servercfg.append(' root %s;' % location['root'])
|
|
1467
|
+
else:
|
|
1468
|
+
servercfg.append(' alias %s;' % location['root'])
|
|
1469
|
+
|
|
1470
|
+
if 'autoindex' in location:
|
|
1471
|
+
servercfg.append(' autoindex %s;' % (location['autoindex'] and 'on' or 'off'))
|
|
1472
|
+
|
|
1473
|
+
if 'fastcgi_pass' in location:
|
|
1474
|
+
if urlpath.startswith('~'): # deal with old config
|
|
1475
|
+
servercfg.append(' fastcgi_index index.php;')
|
|
1476
|
+
servercfg.append(r' fastcgi_split_path_info ^(.+\.php)(/?.+)$;')
|
|
1477
|
+
servercfg.append(' fastcgi_param PATH_INFO $fastcgi_path_info;')
|
|
1478
|
+
servercfg.append(' fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;')
|
|
1479
|
+
servercfg.append(' include fastcgi_params;')
|
|
1480
|
+
servercfg.append(' fastcgi_pass %s;' % location['fastcgi_pass'])
|
|
1481
|
+
else:
|
|
1482
|
+
if urlpath == '/':
|
|
1483
|
+
servercfg.append(r' location ~ ^/.+\.php {')
|
|
1484
|
+
servercfg.append(' fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;')
|
|
1485
|
+
else:
|
|
1486
|
+
servercfg.append(r' location ~ ^%s(/.+\.php) {' % urlpath)
|
|
1487
|
+
servercfg.append(' root %s;' % location['root'])
|
|
1488
|
+
servercfg.append(' set $fastcgi_script_alias $1;')
|
|
1489
|
+
servercfg.append(' fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_alias;')
|
|
1490
|
+
|
|
1491
|
+
servercfg.append(' fastcgi_index index.php;')
|
|
1492
|
+
servercfg.append(r' fastcgi_split_path_info ^(.+\.php)(/?.+)$;')
|
|
1493
|
+
servercfg.append(' fastcgi_param PATH_INFO $fastcgi_path_info;')
|
|
1494
|
+
servercfg.append(' fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;')
|
|
1495
|
+
servercfg.append(' include fastcgi_params;')
|
|
1496
|
+
servercfg.append(' fastcgi_pass %s;' % location['fastcgi_pass'])
|
|
1497
|
+
servercfg.append(' }')
|
|
1498
|
+
|
|
1499
|
+
if 'rewrite_rules' in location:
|
|
1500
|
+
rules = location['rewrite_rules']
|
|
1501
|
+
if 'rewrite_detect_file' in location and location['rewrite_detect_file']:
|
|
1502
|
+
servercfg.append(' if (!-e $request_filename)')
|
|
1503
|
+
servercfg.append(' {')
|
|
1504
|
+
for rule in rules:
|
|
1505
|
+
servercfg.append(' %s;' % rule)
|
|
1506
|
+
servercfg.append(' }')
|
|
1507
|
+
else:
|
|
1508
|
+
for rule in rules:
|
|
1509
|
+
servercfg.append(' %s;' % rule)
|
|
1510
|
+
|
|
1511
|
+
if 'redirect_url' in location:
|
|
1512
|
+
redirect_url = location['redirect_url']
|
|
1513
|
+
if redirect_url:
|
|
1514
|
+
redirect_type = 'redirect_type' in location and location['redirect_type'] or '302'
|
|
1515
|
+
redirect_option = 'redirect_option' in location and location['redirect_option'] or 'ignore'
|
|
1516
|
+
if urlpath == '/' or redirect_option == 'ignore':
|
|
1517
|
+
servercfg.append(' rewrite ^ %s%s %s;' % (redirect_url,
|
|
1518
|
+
redirect_option=='keep' and '$request_uri?' or '',
|
|
1519
|
+
redirect_type=='301' and 'permanent' or 'redirect'))
|
|
1520
|
+
else:
|
|
1521
|
+
servercfg.append(' if ($request_uri ~ ^%s(/.+)$) {' % urlpath)
|
|
1522
|
+
servercfg.append(' set $request_uri_alias $1;')
|
|
1523
|
+
servercfg.append(' rewrite ^ %s$request_uri_alias? %s;' % (redirect_url,
|
|
1524
|
+
redirect_type=='301' and 'permanent' or 'redirect'))
|
|
1525
|
+
servercfg.append(' }')
|
|
1526
|
+
|
|
1527
|
+
if 'proxy_backends' in location and location['proxy_backends']:
|
|
1528
|
+
if urlpath != '/':
|
|
1529
|
+
servercfg.append(' rewrite %s(.*) / break;' % urlpath)
|
|
1530
|
+
if 'proxy_charset' in location and location['proxy_charset']:
|
|
1531
|
+
servercfg.append(' charset %s;' % location['proxy_charset'])
|
|
1532
|
+
if 'proxy_host' in location and location['proxy_host']:
|
|
1533
|
+
servercfg.append(' proxy_set_header Host %s;' % location['proxy_host'])
|
|
1534
|
+
if 'proxy_realip' in location and location['proxy_realip']:
|
|
1535
|
+
servercfg.append(' proxy_set_header X-Real-IP $remote_addr;')
|
|
1536
|
+
proxy_protocol = 'proxy_protocol' in location and location['proxy_protocol'] or 'http'
|
|
1537
|
+
upstream_name = 'backend_of_%s_%s' % (server_names[0], urlpath.replace('/', '_'))
|
|
1538
|
+
servercfg.append(' proxy_pass %s://%s;' % (proxy_protocol, upstream_name))
|
|
1539
|
+
proxy_balance = 'proxy_balance' in location and location['proxy_balance'] or 'ip_hash'
|
|
1540
|
+
upstreams[upstream_name] = {
|
|
1541
|
+
'balance': proxy_balance,
|
|
1542
|
+
'keepalive': 'proxy_keepalive' in location and location['proxy_keepalive'] or None,
|
|
1543
|
+
'backends': location['proxy_backends']
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
if 'proxy_cache' in location and location['proxy_cache']:
|
|
1547
|
+
servercfg.append(' proxy_cache %s;' % location['proxy_cache'])
|
|
1548
|
+
if 'proxy_cache_min_uses' in location:
|
|
1549
|
+
servercfg.append(' proxy_cache_min_uses %s;' % location['proxy_cache_min_uses'])
|
|
1550
|
+
if 'proxy_cache_methods' in location:
|
|
1551
|
+
servercfg.append(' proxy_cache_methods %s;' % location['proxy_cache_methods'])
|
|
1552
|
+
if 'proxy_cache_key' in location:
|
|
1553
|
+
servercfg.append(' proxy_cache_key %s;' % location['proxy_cache_key'])
|
|
1554
|
+
if 'proxy_cache_valid' in location:
|
|
1555
|
+
for v in location['proxy_cache_valid']:
|
|
1556
|
+
servercfg.append(' proxy_cache_valid %s %s;' % (v['code'], v['time']))
|
|
1557
|
+
if 'proxy_cache_use_stale' in location:
|
|
1558
|
+
servercfg.append(' proxy_cache_use_stale %s;' % (' '.join(location['proxy_cache_use_stale'])))
|
|
1559
|
+
if 'proxy_cache_lock' in location and location['proxy_cache_lock']:
|
|
1560
|
+
servercfg.append(' proxy_cache_lock on;')
|
|
1561
|
+
if 'proxy_cache_lock_timeout' in location:
|
|
1562
|
+
servercfg.append(' proxy_cache_lock_timeout %ss;' % location['proxy_cache_lock_timeout'])
|
|
1563
|
+
|
|
1564
|
+
if 'error_code' in location: servercfg.append(' return %s;' % location['error_code'])
|
|
1565
|
+
|
|
1566
|
+
servercfg.append(' }')
|
|
1567
|
+
servercfg.append('')
|
|
1568
|
+
|
|
1569
|
+
if rewrite_rules:
|
|
1570
|
+
for rewrite_rule in rewrite_rules:
|
|
1571
|
+
if rewrite_rule: servercfg.append(' %s;' % rewrite_rule.strip())
|
|
1572
|
+
|
|
1573
|
+
# end of server context
|
|
1574
|
+
servercfg.append('}')
|
|
1575
|
+
|
|
1576
|
+
for upstream_name, upstream in upstreams.items():
|
|
1577
|
+
balance = upstream['balance']
|
|
1578
|
+
backends = upstream['backends']
|
|
1579
|
+
|
|
1580
|
+
servercfg.append('upstream %s { # %s' % (upstream_name, GENBY))
|
|
1581
|
+
|
|
1582
|
+
if len(backends) > 1: # have balance options
|
|
1583
|
+
if balance == 'ip_hash': servercfg.append(' ip_hash;')
|
|
1584
|
+
if balance == 'least_conn': servercfg.append(' least_conn;')
|
|
1585
|
+
if upstream['keepalive']: servercfg.append(' keepalive %s;' % upstream['keepalive'])
|
|
1586
|
+
for backend in backends:
|
|
1587
|
+
weight = fail_timeout = max_fails = ''
|
|
1588
|
+
if balance == 'weight' and 'weight' in backend and backend['weight']:
|
|
1589
|
+
weight = ' weight=%s' % backend['weight']
|
|
1590
|
+
if 'fail_timeout' in backend and backend['fail_timeout']:
|
|
1591
|
+
fail_timeout = ' fail_timeout=%ss' % backend['fail_timeout']
|
|
1592
|
+
if 'max_fails' in backend and backend['max_fails']:
|
|
1593
|
+
max_fails = ' max_fails=%s' % backend['max_fails']
|
|
1594
|
+
servercfg.append(' server %s%s%s%s;' % (backend['server'],
|
|
1595
|
+
weight, fail_timeout, max_fails))
|
|
1596
|
+
else:
|
|
1597
|
+
servercfg.append(' server %s;' % backends[0]['server'])
|
|
1598
|
+
|
|
1599
|
+
servercfg.append('}')
|
|
1600
|
+
|
|
1601
|
+
#print '\n'.join(servercfg)
|
|
1602
|
+
configfile = str(Path(SERVERCONF) / ('%s.conf' % server_names[0]))
|
|
1603
|
+
configfile_exists = Path(configfile).exists()
|
|
1604
|
+
|
|
1605
|
+
# check if need to add a new line at the end of the file to
|
|
1606
|
+
# avoid first line go to the same former } line
|
|
1607
|
+
if configfile_exists:
|
|
1608
|
+
with open(configfile, encoding='utf-8') as f:
|
|
1609
|
+
f.seek(-1, 2)
|
|
1610
|
+
if f.read(1) != '\n':
|
|
1611
|
+
servercfg.insert(0, '')
|
|
1612
|
+
with open(configfile, configfile_exists and 'a' or 'w', encoding='utf-8') as f:
|
|
1613
|
+
f.write('\n'.join(servercfg))
|
|
1614
|
+
return True
|
|
1615
|
+
|
|
1616
|
+
def updateserver(old_ip, old_port, old_server_name,
|
|
1617
|
+
server_names, listens, charset=None, index=None, locations=None,
|
|
1618
|
+
limit_rate=None, limit_conn=None, ssl_crt=None, ssl_key=None,
|
|
1619
|
+
rewrite_rules=None, version=None):
|
|
1620
|
+
"""Update an existing server.
|
|
1621
|
+
|
|
1622
|
+
If the old config is not in the right place, we would automatically delete it and
|
|
1623
|
+
create the new config to coresponding config file under /etc/nginx/conf.d/.
|
|
1624
|
+
"""
|
|
1625
|
+
# compare the old context and the new context
|
|
1626
|
+
# to check if the ip:port/server_name change and conflict status
|
|
1627
|
+
config = loadconfig(NGINXCONF, True)
|
|
1628
|
+
oldscontext = _context_getserver(old_ip, old_port, old_server_name, config)
|
|
1629
|
+
if not oldscontext:
|
|
1630
|
+
return False
|
|
1631
|
+
for server_name in server_names:
|
|
1632
|
+
for listen in listens:
|
|
1633
|
+
ip = 'ip' in listen and listen['ip'] or ''
|
|
1634
|
+
scontext = _context_getserver(ip, listen['port'], server_name)
|
|
1635
|
+
# server context found, but not equals to the old
|
|
1636
|
+
# this means conflict occur
|
|
1637
|
+
if scontext and scontext != oldscontext:
|
|
1638
|
+
return False
|
|
1639
|
+
|
|
1640
|
+
# init limit_conn_zone in http, this may cause http context change
|
|
1641
|
+
# reload config if change occur
|
|
1642
|
+
if limit_conn:
|
|
1643
|
+
if _context_http_init_limit_conn(version=version):
|
|
1644
|
+
config = loadconfig(NGINXCONF, True)
|
|
1645
|
+
|
|
1646
|
+
# disable the old server and relative upstreams
|
|
1647
|
+
if not _context_commentserver(old_ip, old_port, old_server_name, config=config):
|
|
1648
|
+
return False
|
|
1649
|
+
if not _context_commentupstreams(old_server_name, config=config):
|
|
1650
|
+
return False
|
|
1651
|
+
|
|
1652
|
+
# add the new server
|
|
1653
|
+
if not addserver(server_names, listens, charset=charset, index=index, locations=locations,
|
|
1654
|
+
limit_rate=limit_rate, limit_conn=limit_conn, ssl_crt=ssl_crt, ssl_key=ssl_key,
|
|
1655
|
+
rewrite_rules=rewrite_rules, conflict_check=False, version=version): return False
|
|
1656
|
+
|
|
1657
|
+
# only delete the disabled server
|
|
1658
|
+
_context_deleteupstreams(old_server_name, disabled=True)
|
|
1659
|
+
_context_deleteserver(old_ip, old_port, old_server_name, disabled=True)
|
|
1660
|
+
|
|
1661
|
+
return True
|
|
1662
|
+
|
|
1663
|
+
|
|
1664
|
+
if __name__ == '__main__':
|
|
1665
|
+
import pprint
|
|
1666
|
+
pp = pprint.PrettyPrinter(indent=4)
|
|
1667
|
+
|
|
1668
|
+
#_insert('/etc/nginx/nginx.conf', 31, ['gzip off'])
|
|
1669
|
+
#_replace([('/etc/nginx/nginx.conf', 31, 1)], ['gzip on', 'gzip off'])
|
|
1670
|
+
#http_set('gzip', 'off')
|
|
1671
|
+
#http_set('limit_conn_zone', '$binary_remote_addr zone=addr:10m')
|
|
1672
|
+
#print http_get('limit_conn_zone')
|
|
1673
|
+
#print http_getfirst('limit_conn_zone')
|
|
1674
|
+
|
|
1675
|
+
#pp.pprint(loadconfig(NGINXCONF, True))
|
|
1676
|
+
#pp.pprint(getservers())
|
|
1677
|
+
#pp.pprint(_context_getserver('0.0.0.0', '80', 'test.local'))
|
|
1678
|
+
#pp.pprint(disableserver('0.0.0.0', '80', 'test.local'))
|
|
1679
|
+
#pp.pprint(enableserver('0.0.0.0', '80', 'test.local'))
|
|
1680
|
+
#pp.pprint(deleteserver('0.0.0.0', '80', 'youmeiyoua.com'))
|
|
1681
|
+
|
|
1682
|
+
#print servername_exists('0.0.0.0', '80', 'www.paomi.local')
|
|
1683
|
+
|
|
1684
|
+
#print _context_server_clear_default_server('0.0.0.0', '8000')
|
|
1685
|
+
|
|
1686
|
+
#pp.pprint(deleteserver('0.0.0.0', '8000', 'test.db.local'))
|
|
1687
|
+
#pp.pprint(_context_getupstreams('test.db.local', disabled=True))
|
|
1688
|
+
#pp.pprint(_context_deleteupstreams('test.db.local'))
|
|
1689
|
+
#pp.pprint(_context_uncommentupstreams('test.db.local'))
|
|
1690
|
+
#pp.pprint(_context_getupstreams('test.db.local'))
|
|
1691
|
+
#pp.pprint(getserver('*', '80', 'www.baidu.com'))
|
|
1692
|
+
#print _context_getserver('*', '80', '192.168.0.13')
|
|
1693
|
+
|
|
1694
|
+
if 0:
|
|
1695
|
+
a =addserver(
|
|
1696
|
+
['example.com', 'test.db.local'],
|
|
1697
|
+
[{'port': '8000'}, {'port': '88'}],
|
|
1698
|
+
charset='utf-8',
|
|
1699
|
+
index='index.html index.htm index.php',
|
|
1700
|
+
locations=None,
|
|
1701
|
+
limit_rate='100k',
|
|
1702
|
+
limit_conn='10',
|
|
1703
|
+
rewrite_rules=['rewrite ^ https://www.example.com$document_uri permanent'])
|
|
1704
|
+
print(a)
|
|
1705
|
+
if 0:
|
|
1706
|
+
b = updateserver(
|
|
1707
|
+
'', '8000', 'test.db.local',
|
|
1708
|
+
['test.db.local'],
|
|
1709
|
+
[{'port': '8000', 'default_server': True}],
|
|
1710
|
+
charset='utf-8',
|
|
1711
|
+
index='index.html index.htm index.php',
|
|
1712
|
+
locations=[
|
|
1713
|
+
{
|
|
1714
|
+
'urlpath': '/',
|
|
1715
|
+
'root': '/var/www/example',
|
|
1716
|
+
'fastcgi_pass': '127.0.0.1:9000',
|
|
1717
|
+
}, {
|
|
1718
|
+
'urlpath': '/phpinfo',
|
|
1719
|
+
'root': '/var/www/phpinfo',
|
|
1720
|
+
'fastcgi_pass': '127.0.0.1:9000',
|
|
1721
|
+
}, {
|
|
1722
|
+
'urlpath': '/redirect',
|
|
1723
|
+
'redirect_url': 'http://www.baidu.com',
|
|
1724
|
+
'redirect_type': '301',
|
|
1725
|
+
'redirect_option': 'keep',
|
|
1726
|
+
}, {
|
|
1727
|
+
'urlpath': '/proxy',
|
|
1728
|
+
'proxy_balance': 'weight',
|
|
1729
|
+
'proxy_protocol': 'http',
|
|
1730
|
+
'proxy_host': 'www.baidu.com',
|
|
1731
|
+
'proxy_realip': True,
|
|
1732
|
+
'proxy_backends': [
|
|
1733
|
+
{'server':'www.citydog.me'},
|
|
1734
|
+
{'server':'www.baidu.com'},
|
|
1735
|
+
],
|
|
1736
|
+
},{
|
|
1737
|
+
'urlpath': '/error',
|
|
1738
|
+
'error_code': '502',
|
|
1739
|
+
}
|
|
1740
|
+
],
|
|
1741
|
+
limit_rate='100',
|
|
1742
|
+
limit_conn='10')
|
|
1743
|
+
print(b)
|
|
1744
|
+
|
|
1745
|
+
|
|
1746
|
+
def web_handler(context):
|
|
1747
|
+
action = context.get_argument('action', '')
|
|
1748
|
+
|
|
1749
|
+
if action == 'getservers':
|
|
1750
|
+
sites = getservers()
|
|
1751
|
+
context.write({'code': 0, 'msg': '', 'data': sites})
|
|
1752
|
+
|
|
1753
|
+
elif action in ('enableserver', 'disableserver', 'deleteserver'):
|
|
1754
|
+
ip = context.get_argument('ip', '')
|
|
1755
|
+
port = context.get_argument('port', '')
|
|
1756
|
+
name = context.get_argument('server_name', '')
|
|
1757
|
+
handler = getattr(sys.modules[__name__], action)
|
|
1758
|
+
opstr = {
|
|
1759
|
+
'enableserver': '启用',
|
|
1760
|
+
'disableserver': '停用',
|
|
1761
|
+
'deleteserver': '删除',
|
|
1762
|
+
}
|
|
1763
|
+
if handler(ip, port, name):
|
|
1764
|
+
context.write({'code': 0, 'msg': '站点 %s:%s %s成功!' % (name, port, opstr[action])})
|
|
1765
|
+
else:
|
|
1766
|
+
context.write({'code': -1, 'msg': '站点 %s:%s %s失败!' % (name, port, opstr[action])})
|
|
1767
|
+
|
|
1768
|
+
elif action == 'gethttpsettings':
|
|
1769
|
+
items = context.get_argument('items', '')
|
|
1770
|
+
items = items.split(',')
|
|
1771
|
+
|
|
1772
|
+
if 'limit_conn_zone' in items:
|
|
1773
|
+
items.append('limit_zone')
|
|
1774
|
+
|
|
1775
|
+
data = {}
|
|
1776
|
+
config = loadconfig()
|
|
1777
|
+
for item in items:
|
|
1778
|
+
if item.endswith('[]'):
|
|
1779
|
+
item = item[:-2]
|
|
1780
|
+
returnlist = True
|
|
1781
|
+
values = http_get(item, config)
|
|
1782
|
+
else:
|
|
1783
|
+
returnlist = False
|
|
1784
|
+
values = [http_getfirst(item, config)]
|
|
1785
|
+
|
|
1786
|
+
if values:
|
|
1787
|
+
if item == 'gzip':
|
|
1788
|
+
values = [v == 'on' for v in values if v]
|
|
1789
|
+
elif item == 'limit_rate':
|
|
1790
|
+
values = [v.replace('k', '') for v in values if v]
|
|
1791
|
+
elif item == 'limit_conn':
|
|
1792
|
+
values = [v.split()[-1] for v in values if v]
|
|
1793
|
+
elif item == 'limit_conn_zone':
|
|
1794
|
+
values = [v.split(':')[-1].replace('m', '') for v in values if v]
|
|
1795
|
+
elif item == 'limit_zone':
|
|
1796
|
+
values = [v.split()[-1].replace('m', '') for v in values if v]
|
|
1797
|
+
elif item == 'client_max_body_size':
|
|
1798
|
+
values = [v.replace('m', '') for v in values if v]
|
|
1799
|
+
elif item == 'keepalive_timeout':
|
|
1800
|
+
values = [v.replace('s', '') for v in values if v]
|
|
1801
|
+
elif item == 'allow':
|
|
1802
|
+
values = [v for v in values if v and v != 'all']
|
|
1803
|
+
elif item == 'deny':
|
|
1804
|
+
values = [v for v in values if v and v != 'all']
|
|
1805
|
+
elif item == 'proxy_cache_path':
|
|
1806
|
+
result = []
|
|
1807
|
+
for v in values:
|
|
1808
|
+
info = {}
|
|
1809
|
+
fields = v.split()
|
|
1810
|
+
info['path'] = fields[0]
|
|
1811
|
+
for field in fields[1:]:
|
|
1812
|
+
key, value = field.split('=', 1)
|
|
1813
|
+
if key == 'levels':
|
|
1814
|
+
levels = value.split(':')
|
|
1815
|
+
info['path_level_1'] = levels[0]
|
|
1816
|
+
if len(levels) > 1:
|
|
1817
|
+
info['path_level_2'] = levels[1]
|
|
1818
|
+
if len(levels) > 2:
|
|
1819
|
+
info['path_level_3'] = levels[2]
|
|
1820
|
+
elif key == 'keys_zone':
|
|
1821
|
+
t = value.split(':')
|
|
1822
|
+
info['name'] = t[0]
|
|
1823
|
+
if len(t) > 1:
|
|
1824
|
+
info['mem'] = t[1].replace('m', '')
|
|
1825
|
+
elif key == 'inactive':
|
|
1826
|
+
info['inactive'] = value[:-1]
|
|
1827
|
+
info['inactive_unit'] = value[-1]
|
|
1828
|
+
elif key == 'max_size':
|
|
1829
|
+
info['max_size'] = value[:-1]
|
|
1830
|
+
info['max_size_unit'] = value[-1]
|
|
1831
|
+
result.append(info)
|
|
1832
|
+
values = result
|
|
1833
|
+
|
|
1834
|
+
if item == 'limit_zone':
|
|
1835
|
+
item = 'limit_conn_zone'
|
|
1836
|
+
|
|
1837
|
+
if returnlist:
|
|
1838
|
+
data[item] = values
|
|
1839
|
+
else:
|
|
1840
|
+
data[item] = values and values[0] or ''
|
|
1841
|
+
context.write({'code': 0, 'msg': '', 'data': data})
|
|
1842
|
+
|
|
1843
|
+
elif action == 'sethttpsettings':
|
|
1844
|
+
version = context.get_argument('version', '')
|
|
1845
|
+
gzip = context.get_argument('gzip', '')
|
|
1846
|
+
limit_rate = context.get_argument('limit_rate', '')
|
|
1847
|
+
limit_conn = context.get_argument('limit_conn', '')
|
|
1848
|
+
limit_conn_zone = context.get_argument('limit_conn_zone', '')
|
|
1849
|
+
client_max_body_size = context.get_argument('client_max_body_size', '')
|
|
1850
|
+
keepalive_timeout = context.get_argument('keepalive_timeout', '')
|
|
1851
|
+
allow = context.get_argument('allow', '')
|
|
1852
|
+
deny = context.get_argument('deny', '')
|
|
1853
|
+
access_status = context.get_argument('access_status', '')
|
|
1854
|
+
|
|
1855
|
+
setting = {}
|
|
1856
|
+
setting['gzip'] = gzip == 'on' and 'on' or 'off'
|
|
1857
|
+
if not limit_rate.isdigit():
|
|
1858
|
+
limit_rate = ''
|
|
1859
|
+
setting['limit_rate'] = limit_rate and '%sk' % limit_rate or ''
|
|
1860
|
+
if not limit_conn.isdigit():
|
|
1861
|
+
limit_conn = ''
|
|
1862
|
+
setting['limit_conn'] = limit_conn and 'addr %s' % limit_conn or ''
|
|
1863
|
+
if not limit_conn_zone.isdigit():
|
|
1864
|
+
limit_conn_zone = '10'
|
|
1865
|
+
if not version or version_get(version, '1.1.8'):
|
|
1866
|
+
setting['limit_conn_zone'] = '$binary_remote_addr zone=addr:%sm' % limit_conn_zone
|
|
1867
|
+
setting['limit_zone'] = ''
|
|
1868
|
+
else:
|
|
1869
|
+
setting['limit_zone'] = 'addr $binary_remote_addr %sm' % limit_conn_zone
|
|
1870
|
+
setting['limit_conn_zone'] = ''
|
|
1871
|
+
if not client_max_body_size.isdigit():
|
|
1872
|
+
client_max_body_size = '1'
|
|
1873
|
+
setting['client_max_body_size'] = '%sm' % client_max_body_size
|
|
1874
|
+
if not keepalive_timeout.isdigit():
|
|
1875
|
+
keepalive_timeout = ''
|
|
1876
|
+
setting['keepalive_timeout'] = keepalive_timeout and '%ss' % keepalive_timeout or ''
|
|
1877
|
+
if access_status == 'white':
|
|
1878
|
+
setting['allow'] = [a.strip() for a in allow.split() if a.strip()]
|
|
1879
|
+
setting['deny'] = 'all'
|
|
1880
|
+
elif access_status == 'black':
|
|
1881
|
+
setting['deny'] = [a.strip() for a in deny.split() if a.strip()]
|
|
1882
|
+
setting['allow'] = ''
|
|
1883
|
+
else:
|
|
1884
|
+
setting['allow'] = setting['deny'] = ''
|
|
1885
|
+
|
|
1886
|
+
directives = ('gzip', 'limit_rate', 'limit_conn', 'limit_conn_zone', 'limit_zone',
|
|
1887
|
+
'client_max_body_size', 'keepalive_timeout', 'allow', 'deny')
|
|
1888
|
+
for directive in directives:
|
|
1889
|
+
if directive not in setting:
|
|
1890
|
+
continue
|
|
1891
|
+
value = setting[directive]
|
|
1892
|
+
if isinstance(value, str):
|
|
1893
|
+
value = _u(value)
|
|
1894
|
+
elif isinstance(value, list):
|
|
1895
|
+
for i, v in enumerate(value):
|
|
1896
|
+
value[i] = v
|
|
1897
|
+
http_set(directive, value)
|
|
1898
|
+
|
|
1899
|
+
context.write({'code': 0, 'msg': '设置保存成功!'})
|
|
1900
|
+
|
|
1901
|
+
elif action == 'setproxycachesettings':
|
|
1902
|
+
proxy_caches = tornado.escape.json_decode(context.get_argument('proxy_caches', ''))
|
|
1903
|
+
|
|
1904
|
+
values = []
|
|
1905
|
+
for cache in proxy_caches:
|
|
1906
|
+
fields = []
|
|
1907
|
+
if 'path' in cache and cache['path']:
|
|
1908
|
+
if not Path(cache['path']).exists() and 'autocreate' in cache and cache['autocreate']:
|
|
1909
|
+
try:
|
|
1910
|
+
Path(cache['path']).mkdir(parents=True, exist_ok=True)
|
|
1911
|
+
except:
|
|
1912
|
+
context.write({'code': -1, 'msg': '缓存目录 %s 创建失败!' % cache['path']})
|
|
1913
|
+
return
|
|
1914
|
+
else:
|
|
1915
|
+
context.write({'code': -1, 'msg': '请选择缓存目录!'})
|
|
1916
|
+
return
|
|
1917
|
+
fields.append(cache['path'])
|
|
1918
|
+
if not 'path_level_1' in cache or not cache['path_level_1'].isdigit() or \
|
|
1919
|
+
not 'path_level_2' in cache or not cache['path_level_2'].isdigit() or \
|
|
1920
|
+
not 'path_level_3' in cache or not cache['path_level_3'].isdigit():
|
|
1921
|
+
context.write({'code': -1, 'msg': '缓存目录名长度必须是数字!'})
|
|
1922
|
+
return
|
|
1923
|
+
if int(cache['path_level_1']) + int(cache['path_level_2']) + int(cache['path_level_3']) > 32:
|
|
1924
|
+
context.write({'code': -1, 'msg': '缓存目录名长度总和不能超过32位!'})
|
|
1925
|
+
return
|
|
1926
|
+
levels = [cache['path_level_1']]
|
|
1927
|
+
if int(cache['path_level_2']) > 0:
|
|
1928
|
+
levels.append(cache['path_level_2'])
|
|
1929
|
+
if int(cache['path_level_3']) > 0:
|
|
1930
|
+
levels.append(cache['path_level_3'])
|
|
1931
|
+
fields.append('levels=%s' % (':'.join(levels)))
|
|
1932
|
+
|
|
1933
|
+
if not 'name' in cache or cache['name'].strip() == '':
|
|
1934
|
+
context.write({'code': -1, 'msg': '缓存区名称不能为空!'})
|
|
1935
|
+
return
|
|
1936
|
+
if not 'mem' in cache or not cache['mem'].isdigit():
|
|
1937
|
+
context.write({'code': -1, 'msg': '缓存计数内存大小必须是数字!'})
|
|
1938
|
+
return
|
|
1939
|
+
fields.append('keys_zone=%s:%sm' % (cache['name'].strip(), cache['mem']))
|
|
1940
|
+
|
|
1941
|
+
if not 'inactive' in cache or not cache['inactive'].isdigit():
|
|
1942
|
+
context.write({'code': -1, 'msg': '缓存过期时间必须是数字!'})
|
|
1943
|
+
return
|
|
1944
|
+
if not 'inactive_unit' in cache or not cache['inactive_unit'] in ('s', 'm', 'h', 'd'):
|
|
1945
|
+
context.write({'code': -1, 'msg': '缓存过期时间单位错误!'})
|
|
1946
|
+
return
|
|
1947
|
+
fields.append('inactive=%s%s' % (cache['inactive'], cache['inactive_unit']))
|
|
1948
|
+
|
|
1949
|
+
if not 'max_size' in cache or not cache['max_size'].isdigit():
|
|
1950
|
+
context.write({'code': -1, 'msg': '缓存大小限制值必须是数字!'})
|
|
1951
|
+
return
|
|
1952
|
+
if not 'max_size_unit' in cache or not cache['max_size_unit'] in ('m', 'g'):
|
|
1953
|
+
context.write({'code': -1, 'msg': '缓存大小限制单位错误!'})
|
|
1954
|
+
return
|
|
1955
|
+
fields.append('max_size=%s%s' % (cache['max_size'], cache['max_size_unit']))
|
|
1956
|
+
|
|
1957
|
+
values.append(' '.join(fields))
|
|
1958
|
+
|
|
1959
|
+
http_set('proxy_cache_path', values)
|
|
1960
|
+
context.write({'code': 0, 'msg': '设置保存成功!'})
|
|
1961
|
+
|
|
1962
|
+
elif action == 'getserver':
|
|
1963
|
+
ip = context.get_argument('ip', '')
|
|
1964
|
+
port = context.get_argument('port', '')
|
|
1965
|
+
server_name = context.get_argument('server_name', '')
|
|
1966
|
+
serverinfo = getserver(ip, port, server_name)
|
|
1967
|
+
if serverinfo:
|
|
1968
|
+
context.write({'code': 0, 'msg': '站点信息读取成功!', 'data': serverinfo})
|
|
1969
|
+
else:
|
|
1970
|
+
context.write({'code': -1, 'msg': '站点不存在!'})
|
|
1971
|
+
|
|
1972
|
+
elif action in ('addserver', 'updateserver'):
|
|
1973
|
+
if action == 'updateserver':
|
|
1974
|
+
old_server_ip = context.get_argument('ip', '')
|
|
1975
|
+
old_server_port = context.get_argument('port', '')
|
|
1976
|
+
old_server_name = context.get_argument('server_name', '')
|
|
1977
|
+
|
|
1978
|
+
version = context.get_argument('version', '')
|
|
1979
|
+
setting = tornado.escape.json_decode(context.get_argument('setting', ''))
|
|
1980
|
+
|
|
1981
|
+
server_names = None
|
|
1982
|
+
if 'server_names' in setting:
|
|
1983
|
+
server_names = [s['name'].strip().lower() for s in setting['server_names'] if s['name'].strip()]
|
|
1984
|
+
for server_name in server_names:
|
|
1985
|
+
if server_name != '_' and not is_valid_domain(server_name):
|
|
1986
|
+
server_names = None
|
|
1987
|
+
break
|
|
1988
|
+
if not server_names:
|
|
1989
|
+
context.write({'code': -1, 'msg': '请输入有效的站点域名!'})
|
|
1990
|
+
return
|
|
1991
|
+
|
|
1992
|
+
listens = None
|
|
1993
|
+
if 'listens' in setting:
|
|
1994
|
+
listens = setting['listens']
|
|
1995
|
+
ipportpairs = []
|
|
1996
|
+
for listen in listens:
|
|
1997
|
+
if 'ip' in listen:
|
|
1998
|
+
if listen['ip'] not in ('', '*', '0.0.0.0') and not is_valid_ip(listen['ip']):
|
|
1999
|
+
listens = None
|
|
2000
|
+
break
|
|
2001
|
+
if not 'port' in listen:
|
|
2002
|
+
listens = None
|
|
2003
|
+
break
|
|
2004
|
+
elif not listen['port'].isdigit():
|
|
2005
|
+
listens = None
|
|
2006
|
+
break
|
|
2007
|
+
else:
|
|
2008
|
+
port = int(listen['port'])
|
|
2009
|
+
if port <= 0 or port > 65535:
|
|
2010
|
+
listens = None
|
|
2011
|
+
break
|
|
2012
|
+
ipport = '%s:%s' % (listen['ip'], listen['port'])
|
|
2013
|
+
if ipport in ipportpairs:
|
|
2014
|
+
context.write({'code': -1, 'msg': '监听的IP:端口重复!'})
|
|
2015
|
+
return
|
|
2016
|
+
if listen['ip'] in ('', '*', '0.0.0.0'):
|
|
2017
|
+
ipportpairs.append(ipport)
|
|
2018
|
+
if not listens:
|
|
2019
|
+
context.write({'code': -1, 'msg': '请输入有效的监听地址!'})
|
|
2020
|
+
return
|
|
2021
|
+
|
|
2022
|
+
charset = None
|
|
2023
|
+
charsets = ('', 'utf-8', 'gb2312', 'gbk', 'gb18030',
|
|
2024
|
+
'big5', 'euc-jp', 'euc-kr', 'iso-8859-2', 'shift_jis')
|
|
2025
|
+
if 'charset' in setting:
|
|
2026
|
+
charset = setting['charset']
|
|
2027
|
+
if charset not in charsets:
|
|
2028
|
+
context.write({'code': -1, 'msg': '请选择有效的字符编码!'})
|
|
2029
|
+
return
|
|
2030
|
+
|
|
2031
|
+
index = None
|
|
2032
|
+
if 'index' in setting:
|
|
2033
|
+
index = setting['index']
|
|
2034
|
+
|
|
2035
|
+
limit_rate = None
|
|
2036
|
+
if 'limit_rate' in setting:
|
|
2037
|
+
limit_rate = setting['limit_rate']
|
|
2038
|
+
if limit_rate and not limit_rate.isdigit():
|
|
2039
|
+
context.write({'code': -1, 'msg': '下载速度限制必须为数字!'})
|
|
2040
|
+
return
|
|
2041
|
+
|
|
2042
|
+
limit_conn = None
|
|
2043
|
+
if 'limit_conn' in setting:
|
|
2044
|
+
limit_conn = setting['limit_conn']
|
|
2045
|
+
if limit_conn and not limit_conn.isdigit():
|
|
2046
|
+
context.write({'code': -1, 'msg': '连接数限制必须为数字!'})
|
|
2047
|
+
return
|
|
2048
|
+
|
|
2049
|
+
ssl_crt = ssl_key = None
|
|
2050
|
+
if 'ssl_crt' in setting and 'ssl_key' in setting:
|
|
2051
|
+
if setting['ssl_crt'] or setting['ssl_key']:
|
|
2052
|
+
ssl_crt = setting['ssl_crt']
|
|
2053
|
+
ssl_key = setting['ssl_key']
|
|
2054
|
+
if not Path(ssl_crt).is_file() or not Path(ssl_key).is_file():
|
|
2055
|
+
context.write({'code': -1, 'msg': 'SSL证书或密钥不存在!'})
|
|
2056
|
+
return
|
|
2057
|
+
|
|
2058
|
+
rewrite_rules = None
|
|
2059
|
+
if 'rewrite_enable' in setting and setting['rewrite_enable']:
|
|
2060
|
+
if 'rewrite_rules' in setting:
|
|
2061
|
+
rules = setting['rewrite_rules'].split('\n')
|
|
2062
|
+
rewrite_rules = []
|
|
2063
|
+
for rule in rules:
|
|
2064
|
+
rule = rule.strip().strip(';')
|
|
2065
|
+
if rule == '':
|
|
2066
|
+
continue
|
|
2067
|
+
t = re.split(r'\s+', rule)
|
|
2068
|
+
if len(t) not in (3, 4) or \
|
|
2069
|
+
len(t) == 4 and (t[0] != 'rewrite' or t[-1] not in ('last', 'break', 'redirect', 'permanent')) or \
|
|
2070
|
+
len(t) == 3 and t[0] != 'rewrite':
|
|
2071
|
+
context.write({'code': -1, 'msg': 'Rewrite 规则 "%s" 格式有误!' % rule})
|
|
2072
|
+
return
|
|
2073
|
+
rewrite_rules.append(rule)
|
|
2074
|
+
|
|
2075
|
+
locations = []
|
|
2076
|
+
urlpaths = []
|
|
2077
|
+
if 'locations' in setting:
|
|
2078
|
+
locs = setting['locations']
|
|
2079
|
+
for loc in locs:
|
|
2080
|
+
if not 'urlpath' in loc:
|
|
2081
|
+
context.write({'code': -1, 'msg': '站点URL路径输入错误!'})
|
|
2082
|
+
return
|
|
2083
|
+
if not 'engine' in loc \
|
|
2084
|
+
or loc['engine'] not in ('static', 'fastcgi', 'redirect', 'proxy', 'error'):
|
|
2085
|
+
context.write({'code': -1, 'msg': '站点路径引擎选择存在错误!'})
|
|
2086
|
+
return
|
|
2087
|
+
if not loc['engine'] in loc:
|
|
2088
|
+
context.write({'code': -1, 'msg': '缺少站点路径配置!'})
|
|
2089
|
+
return
|
|
2090
|
+
location = {}
|
|
2091
|
+
location['urlpath'] = loc['urlpath']
|
|
2092
|
+
if loc['urlpath'] in urlpaths:
|
|
2093
|
+
context.write({'code': -1, 'msg': '重复的站点路径 %s!' % loc['urlpath']})
|
|
2094
|
+
return
|
|
2095
|
+
urlpaths.append(loc['urlpath'])
|
|
2096
|
+
locsetting = loc[loc['engine']]
|
|
2097
|
+
if loc['engine'] in ('static', 'fastcgi'):
|
|
2098
|
+
if not 'root' in locsetting:
|
|
2099
|
+
context.write({'code': -1, 'msg': '站点目录不能为空!'})
|
|
2100
|
+
return
|
|
2101
|
+
if not Path(locsetting['root']).exists():
|
|
2102
|
+
if 'autocreate' in locsetting and locsetting['autocreate']:
|
|
2103
|
+
try:
|
|
2104
|
+
Path(locsetting['root']).mkdir(parents=True, exist_ok=True)
|
|
2105
|
+
except:
|
|
2106
|
+
context.write({'code': -1, 'msg': '站点目录 %s 创建失败!' % locsetting['root']})
|
|
2107
|
+
return
|
|
2108
|
+
else:
|
|
2109
|
+
context.write({'code': -1, 'msg': '站点目录 %s 不存在!' % locsetting['root']})
|
|
2110
|
+
return
|
|
2111
|
+
location['root'] = locsetting['root']
|
|
2112
|
+
if 'charset' in locsetting and locsetting['charset'] in charsets:
|
|
2113
|
+
location['charset'] = locsetting['charset']
|
|
2114
|
+
if 'index' in locsetting:
|
|
2115
|
+
location['index'] = locsetting['index']
|
|
2116
|
+
if 'rewrite_enable' in locsetting and locsetting['rewrite_enable']:
|
|
2117
|
+
if 'rewrite_detect_file' in locsetting and locsetting['rewrite_detect_file']:
|
|
2118
|
+
location['rewrite_detect_file'] = True
|
|
2119
|
+
else:
|
|
2120
|
+
location['rewrite_detect_file'] = False
|
|
2121
|
+
location['rewrite_rules'] = []
|
|
2122
|
+
rwrules = locsetting['rewrite_rules'].split('\n')
|
|
2123
|
+
for rule in rwrules:
|
|
2124
|
+
rule = rule.strip().strip(';')
|
|
2125
|
+
if rule == '':
|
|
2126
|
+
continue
|
|
2127
|
+
t = re.split(r'\s+', rule)
|
|
2128
|
+
if len(t) not in (3, 4) or \
|
|
2129
|
+
len(t) == 4 and (t[0] != 'rewrite' or t[-1] not in ('last', 'break')) or \
|
|
2130
|
+
len(t) == 3 and t[0] != 'rewrite':
|
|
2131
|
+
context.write({'code': -1, 'msg': 'Rewrite 规则 "%s" 格式有误!' % rule})
|
|
2132
|
+
return
|
|
2133
|
+
location['rewrite_rules'].append(rule)
|
|
2134
|
+
if loc['engine'] == 'static':
|
|
2135
|
+
if 'autoindex' in locsetting and locsetting['autoindex']:
|
|
2136
|
+
location['autoindex'] = True
|
|
2137
|
+
elif loc['engine'] == 'fastcgi':
|
|
2138
|
+
if not 'fastcgi_pass' in locsetting or not locsetting['fastcgi_pass']:
|
|
2139
|
+
context.write({'code': -1, 'msg': '请输入FastCGI服务器地址!'})
|
|
2140
|
+
return
|
|
2141
|
+
fastcgi_pass = locsetting['fastcgi_pass']
|
|
2142
|
+
if not fastcgi_pass.startswith('unix:'):
|
|
2143
|
+
fields = fastcgi_pass.split(':', 1)
|
|
2144
|
+
if len(fields) > 1:
|
|
2145
|
+
server, port = fields
|
|
2146
|
+
else:
|
|
2147
|
+
server = fields[0]
|
|
2148
|
+
port = None
|
|
2149
|
+
if not is_valid_domain(server) or port and not port.isdigit():
|
|
2150
|
+
context.write({'code': -1, 'msg': 'FastCGI服务器地址 %s 输入有误!' % fastcgi_pass})
|
|
2151
|
+
return
|
|
2152
|
+
location['fastcgi_pass'] = fastcgi_pass
|
|
2153
|
+
elif loc['engine'] == 'redirect':
|
|
2154
|
+
if not 'url' in locsetting or not locsetting['url']:
|
|
2155
|
+
context.write({'code': -1, 'msg': '请输入要跳转到的 URL 地址!'})
|
|
2156
|
+
return
|
|
2157
|
+
if not is_url(locsetting['url']):
|
|
2158
|
+
context.write({'code': -1, 'msg': '跳转到的 URL 地址"%s"格式有误,请检查是否添加了 http:// 或 https:// 等!' % locsetting['url']})
|
|
2159
|
+
return
|
|
2160
|
+
location['redirect_url'] = locsetting['url']
|
|
2161
|
+
if 'type' in locsetting and locsetting['type'] in ('301', '302'):
|
|
2162
|
+
location['redirect_type'] = locsetting['type']
|
|
2163
|
+
if 'option' in locsetting and locsetting['option'] in ('keep', 'ignore'):
|
|
2164
|
+
location['redirect_option'] = locsetting['option']
|
|
2165
|
+
elif loc['engine'] == 'proxy':
|
|
2166
|
+
if not 'backends' in locsetting or not locsetting['backends']:
|
|
2167
|
+
context.write({'code': -1, 'msg': '反向代理后端不能为空!'})
|
|
2168
|
+
return
|
|
2169
|
+
if not 'protocol' in locsetting or not locsetting['protocol'] in ('http', 'https'):
|
|
2170
|
+
context.write({'code': -1, 'msg': '后端协议选择有误!'})
|
|
2171
|
+
return
|
|
2172
|
+
location['proxy_protocol'] = locsetting['protocol']
|
|
2173
|
+
if 'host' in locsetting and is_valid_domain(locsetting['host']):
|
|
2174
|
+
location['proxy_host'] = locsetting['host']
|
|
2175
|
+
if 'realip' in locsetting:
|
|
2176
|
+
location['proxy_realip'] = locsetting['realip'] and True or False
|
|
2177
|
+
|
|
2178
|
+
backends = [backend for backend in locsetting['backends']
|
|
2179
|
+
if 'server' in backend and backend['server'].strip()]
|
|
2180
|
+
if 'charset' in locsetting:
|
|
2181
|
+
if not locsetting['charset'] in charsets:
|
|
2182
|
+
context.write({'code': -1, 'msg': '请选择有效的字符编码!'})
|
|
2183
|
+
return
|
|
2184
|
+
if locsetting['charset']:
|
|
2185
|
+
location['proxy_charset'] = locsetting['charset']
|
|
2186
|
+
if len(backends) == 0:
|
|
2187
|
+
context.write({'code': -1, 'msg': '反向代理后端不能为空!'})
|
|
2188
|
+
return
|
|
2189
|
+
elif len(backends) > 1:
|
|
2190
|
+
if not 'balance' in locsetting or not locsetting['balance'] in ('weight', 'ip_hash', 'least_conn'):
|
|
2191
|
+
context.write({'code': -1, 'msg': '请设置负载均衡策略!'})
|
|
2192
|
+
return
|
|
2193
|
+
location['proxy_balance'] = locsetting['balance']
|
|
2194
|
+
if 'keepalive' in locsetting:
|
|
2195
|
+
if locsetting['keepalive'] and not locsetting['keepalive'].isdigit():
|
|
2196
|
+
context.write({'code': -1, 'msg': '后端保持连接数必须是数字!'})
|
|
2197
|
+
return
|
|
2198
|
+
if locsetting['keepalive']:
|
|
2199
|
+
location['proxy_keepalive'] = locsetting['keepalive']
|
|
2200
|
+
|
|
2201
|
+
location['proxy_backends'] = []
|
|
2202
|
+
for backend in backends:
|
|
2203
|
+
if not 'server' in backend:
|
|
2204
|
+
context.write({'code': -1, 'msg': '后端地址输入有误!'})
|
|
2205
|
+
return
|
|
2206
|
+
fields = backend['server'].split(':', 1)
|
|
2207
|
+
if len(fields) > 1:
|
|
2208
|
+
server, port = fields
|
|
2209
|
+
else:
|
|
2210
|
+
server = fields[0]
|
|
2211
|
+
port = None
|
|
2212
|
+
if not is_valid_domain(server) or port and not port.isdigit():
|
|
2213
|
+
context.write({'code': -1, 'msg': '后端地址 %s 输入有误!' % backend['server']})
|
|
2214
|
+
return
|
|
2215
|
+
proxy_backend = {'server': backend['server']}
|
|
2216
|
+
if len(backends) > 1:
|
|
2217
|
+
if location['proxy_balance'] in ('weight', 'ip_hash'):
|
|
2218
|
+
if location['proxy_balance'] == 'weight':
|
|
2219
|
+
if 'weight' in backend:
|
|
2220
|
+
if backend['weight'] and not backend['weight'].isdigit():
|
|
2221
|
+
context.write({'code': -1, 'msg': '后端权重值必须为数字!'})
|
|
2222
|
+
return
|
|
2223
|
+
if backend['weight']:
|
|
2224
|
+
proxy_backend['weight'] = backend['weight']
|
|
2225
|
+
if 'fail_timeout' in backend and 'max_fails' in backend:
|
|
2226
|
+
if backend['fail_timeout'] and not backend['fail_timeout'].isdigit():
|
|
2227
|
+
context.write({'code': -1, 'msg': '后端失效检测超时必须为数字!'})
|
|
2228
|
+
return
|
|
2229
|
+
if backend['max_fails'] and not backend['max_fails'].isdigit():
|
|
2230
|
+
context.write({'code': -1, 'msg': '后端失效检测次数必须为数字!'})
|
|
2231
|
+
return
|
|
2232
|
+
if backend['fail_timeout']:
|
|
2233
|
+
proxy_backend['fail_timeout'] = backend['fail_timeout']
|
|
2234
|
+
if backend['max_fails']:
|
|
2235
|
+
proxy_backend['max_fails'] = backend['max_fails']
|
|
2236
|
+
location['proxy_backends'].append(proxy_backend)
|
|
2237
|
+
|
|
2238
|
+
if 'proxy_cache_enable' in locsetting and locsetting['proxy_cache_enable']:
|
|
2239
|
+
if not 'proxy_cache' in locsetting or locsetting['proxy_cache'] == '':
|
|
2240
|
+
context.write({'code': -1, 'msg': '请选择缓存区域!'})
|
|
2241
|
+
return
|
|
2242
|
+
location['proxy_cache'] = locsetting['proxy_cache']
|
|
2243
|
+
if 'proxy_cache_min_uses' in locsetting and locsetting['proxy_cache_min_uses'] != '':
|
|
2244
|
+
if not locsetting['proxy_cache_min_uses'].isdigit():
|
|
2245
|
+
context.write({'code': -1, 'msg': '缓存条件的次数必须为数字!'})
|
|
2246
|
+
return
|
|
2247
|
+
location['proxy_cache_min_uses'] = locsetting['proxy_cache_min_uses']
|
|
2248
|
+
if 'proxy_cache_methods_post' in locsetting and locsetting['proxy_cache_methods_post']:
|
|
2249
|
+
location['proxy_cache_methods'] = 'POST'
|
|
2250
|
+
if 'proxy_cache_key' in locsetting:
|
|
2251
|
+
t = []
|
|
2252
|
+
ck = locsetting['proxy_cache_key']
|
|
2253
|
+
if 'schema' in ck and ck['schema']:
|
|
2254
|
+
t.append('$scheme')
|
|
2255
|
+
if 'host' in ck and ck['host']:
|
|
2256
|
+
t.append('$host')
|
|
2257
|
+
if 'proxy_host' in ck and ck['proxy_host']:
|
|
2258
|
+
t.append('$proxy_host')
|
|
2259
|
+
if 'uri' in ck and ck['uri']:
|
|
2260
|
+
t.append('$request_uri')
|
|
2261
|
+
if len(t) > 0:
|
|
2262
|
+
location['proxy_cache_key'] = ''.join(t)
|
|
2263
|
+
if 'proxy_cache_valid' in locsetting:
|
|
2264
|
+
t = []
|
|
2265
|
+
cvs = locsetting['proxy_cache_valid']
|
|
2266
|
+
for cv in cvs:
|
|
2267
|
+
if not 'code' in cv or not 'time' in cv or not 'time_unit' in cv:
|
|
2268
|
+
continue
|
|
2269
|
+
if cv['code'] not in ('200', '301', '302', '404', '500', '502', '503', '504', 'any'):
|
|
2270
|
+
context.write({'code': -1, 'msg': '缓存过期规则的状态码有误!'})
|
|
2271
|
+
return
|
|
2272
|
+
if not cv['time'].isdigit():
|
|
2273
|
+
context.write({'code': -1, 'msg': '缓存过期规则的过期时间必须为数字!'})
|
|
2274
|
+
return
|
|
2275
|
+
if not cv['time_unit'] in ('s', 'm', 'h', 'd'):
|
|
2276
|
+
context.write({'code': -1, 'msg': '缓存过期规则的过期时间单位有误!'})
|
|
2277
|
+
return
|
|
2278
|
+
t.append({'code': cv['code'], 'time': '%s%s' % (cv['time'], cv['time_unit'])})
|
|
2279
|
+
if len(t) > 0:
|
|
2280
|
+
location['proxy_cache_valid'] = t
|
|
2281
|
+
if 'proxy_cache_use_stale' in locsetting:
|
|
2282
|
+
t = []
|
|
2283
|
+
cus = locsetting['proxy_cache_use_stale']
|
|
2284
|
+
for k, v in cus.items():
|
|
2285
|
+
if not k in ('error', 'timeout', 'invalid_header', 'updating',
|
|
2286
|
+
'http_500', 'http_502', 'http_503', 'http_504', 'http_404') or not v:
|
|
2287
|
+
continue
|
|
2288
|
+
t.append(k)
|
|
2289
|
+
if len(t) > 0:
|
|
2290
|
+
location['proxy_cache_use_stale'] = t
|
|
2291
|
+
if 'proxy_cache_lock' in locsetting and locsetting['proxy_cache_lock']:
|
|
2292
|
+
location['proxy_cache_lock'] = True
|
|
2293
|
+
if 'proxy_cache_lock_timeout' in locsetting:
|
|
2294
|
+
if not locsetting['proxy_cache_lock_timeout'].isdigit():
|
|
2295
|
+
context.write({'code': -1, 'msg': '缓存锁定时间必须为数字!'})
|
|
2296
|
+
return
|
|
2297
|
+
location['proxy_cache_lock_timeout'] = locsetting['proxy_cache_lock_timeout']
|
|
2298
|
+
|
|
2299
|
+
elif loc['engine'] == 'error':
|
|
2300
|
+
if not 'code' in locsetting or not locsetting['code']:
|
|
2301
|
+
context.write({'code': -1, 'msg': '请选择错误代码!'})
|
|
2302
|
+
return
|
|
2303
|
+
if locsetting['code'] not in ('401', '403', '404', '500', '502'):
|
|
2304
|
+
context.write({'code': -1, 'msg': '错误代码选择有误!'})
|
|
2305
|
+
return
|
|
2306
|
+
location['error_code'] = locsetting['code']
|
|
2307
|
+
locations.append(location)
|
|
2308
|
+
|
|
2309
|
+
if action == 'addserver':
|
|
2310
|
+
if not addserver(server_names, listens,
|
|
2311
|
+
charset=charset, index=index, locations=locations,
|
|
2312
|
+
limit_rate=limit_rate, limit_conn=limit_conn,
|
|
2313
|
+
ssl_crt=ssl_crt, ssl_key=ssl_key,
|
|
2314
|
+
rewrite_rules=rewrite_rules, version=version):
|
|
2315
|
+
context.write({'code': -1, 'msg': '新站点添加失败!请检查站点域名是否重复。'})
|
|
2316
|
+
else:
|
|
2317
|
+
context.write({'code': 0, 'msg': '新站点添加成功!'})
|
|
2318
|
+
else:
|
|
2319
|
+
if not updateserver(old_server_ip, old_server_port, old_server_name,
|
|
2320
|
+
server_names, listens,
|
|
2321
|
+
charset=charset, index=index, locations=locations,
|
|
2322
|
+
limit_rate=limit_rate, limit_conn=limit_conn,
|
|
2323
|
+
ssl_crt=ssl_crt, ssl_key=ssl_key,
|
|
2324
|
+
rewrite_rules=rewrite_rules, version=version):
|
|
2325
|
+
context.write({'code': -1, 'msg': '站点设置更新失败!请检查配置信息(如域名是否重复?)'})
|
|
2326
|
+
else:
|
|
2327
|
+
context.write({'code': 0, 'msg': '站点设置更新成功!'})
|