├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .gitignore
├── .npmignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README-en_US.md
├── README.md
├── assets
├── fiddler
│ └── meta.xml
├── js
│ ├── log.js
│ ├── weinre.js
│ └── worker.js
├── launcher
│ ├── README.md
│ ├── linux
│ │ ├── README.md
│ │ └── whistle.gif
│ ├── mac
│ │ ├── README.md
│ │ ├── whistle-desktop.gif
│ │ ├── whistle.gif
│ │ └── whistle.zip
│ └── windows
│ │ ├── README.md
│ │ ├── whistle.gif
│ │ └── whistle.zip
├── menu.html
├── modal.html
└── tab.html
├── bin
├── ca
│ ├── cli.js
│ ├── index.d.ts
│ └── index.js
├── import.js
├── plugin.d.ts
├── plugin.js
├── proxy.js
├── status.js
├── use.js
├── util.js
└── whistle.js
├── biz
├── index.js
├── init.js
├── webui
│ ├── cgi-bin
│ │ ├── abort.js
│ │ ├── add-rules-values.js
│ │ ├── certs
│ │ │ ├── all.js
│ │ │ ├── remove.js
│ │ │ └── upload.js
│ │ ├── check-update.js
│ │ ├── composer.js
│ │ ├── cookies.js
│ │ ├── create-cert.js
│ │ ├── custom-frames.js
│ │ ├── custom-handler.js
│ │ ├── do-not-show-again.js
│ │ ├── download.js
│ │ ├── enable-http2.js
│ │ ├── get-cert.js
│ │ ├── get-custom-certs-files.js
│ │ ├── get-custom-certs-info.js
│ │ ├── get-data.js
│ │ ├── get-frames.js
│ │ ├── get-session.js
│ │ ├── hide-https-connects.js
│ │ ├── history.js
│ │ ├── https-status.js
│ │ ├── import-remote.js
│ │ ├── init.js
│ │ ├── intercept-https-connects.js
│ │ ├── log
│ │ │ └── set.js
│ │ ├── plugins
│ │ │ ├── add-registry.js
│ │ │ ├── disable-all-plugins.js
│ │ │ ├── disable-plugin.js
│ │ │ ├── get-plugins.js
│ │ │ ├── install.js
│ │ │ ├── is-enable.js
│ │ │ ├── registry-list.js
│ │ │ ├── uninstall.js
│ │ │ └── update-rules.js
│ │ ├── reset-local-address.js
│ │ ├── rootca.js
│ │ ├── rules
│ │ │ ├── account.js
│ │ │ ├── add.js
│ │ │ ├── allow-multiple-choice.js
│ │ │ ├── disable-all-rules.js
│ │ │ ├── disable-default.js
│ │ │ ├── enable-back-rules-first.js
│ │ │ ├── enable-default.js
│ │ │ ├── export.js
│ │ │ ├── import.js
│ │ │ ├── index.js
│ │ │ ├── list.js
│ │ │ ├── list2.js
│ │ │ ├── move-to.js
│ │ │ ├── project.js
│ │ │ ├── recycle
│ │ │ │ ├── list.js
│ │ │ │ ├── remove.js
│ │ │ │ └── view.js
│ │ │ ├── remove.js
│ │ │ ├── rename.js
│ │ │ ├── select.js
│ │ │ ├── set-sys-hosts.js
│ │ │ └── unselect.js
│ │ ├── server-info.js
│ │ ├── sessions
│ │ │ ├── create-temp-file.js
│ │ │ ├── expimp.js
│ │ │ ├── export.js
│ │ │ ├── get-temp-file.js
│ │ │ └── import.js
│ │ ├── set-custom-column.js
│ │ ├── set-dns-order.js
│ │ ├── set-ipv6-only.js
│ │ ├── socket
│ │ │ ├── abort.js
│ │ │ ├── change-status.js
│ │ │ └── data.js
│ │ ├── status.js
│ │ ├── top.js
│ │ ├── util.js
│ │ └── values
│ │ │ ├── add.js
│ │ │ ├── download.js
│ │ │ ├── export.js
│ │ │ ├── get.js
│ │ │ ├── import.js
│ │ │ ├── index.js
│ │ │ ├── list.js
│ │ │ ├── list2.js
│ │ │ ├── move-to.js
│ │ │ ├── recycle
│ │ │ ├── list.js
│ │ │ ├── remove.js
│ │ │ └── view.js
│ │ │ ├── remove.js
│ │ │ ├── rename.js
│ │ │ └── value.js
│ ├── htdocs.js
│ ├── htdocs
│ │ ├── editor.html
│ │ ├── img
│ │ │ ├── app
│ │ │ │ ├── alipay.png
│ │ │ │ ├── amap.png
│ │ │ │ ├── android.png
│ │ │ │ ├── baidu.png
│ │ │ │ ├── brave.png
│ │ │ │ ├── browser.png
│ │ │ │ ├── cfnetwork.png
│ │ │ │ ├── chrome.png
│ │ │ │ ├── cicc.png
│ │ │ │ ├── cronet.png
│ │ │ │ ├── dingtalk.png
│ │ │ │ ├── edge.png
│ │ │ │ ├── electron.png
│ │ │ │ ├── firefox.png
│ │ │ │ ├── huawei.png
│ │ │ │ ├── iphone.png
│ │ │ │ ├── jd.png
│ │ │ │ ├── mac.png
│ │ │ │ ├── opera.png
│ │ │ │ ├── pdd.png
│ │ │ │ ├── qq.png
│ │ │ │ ├── safari.png
│ │ │ │ ├── taobao.png
│ │ │ │ ├── tmall.png
│ │ │ │ ├── uc.png
│ │ │ │ ├── wechat.png
│ │ │ │ ├── weibo.png
│ │ │ │ ├── wework.png
│ │ │ │ └── windows.png
│ │ │ ├── favicon.ico
│ │ │ └── whistle.png
│ │ ├── index.html
│ │ ├── js
│ │ │ ├── decode.js
│ │ │ └── index.js
│ │ ├── preview.html
│ │ └── src
│ │ │ ├── css
│ │ │ ├── about.css
│ │ │ ├── base.css
│ │ │ ├── btn-group.css
│ │ │ ├── certs.css
│ │ │ ├── composer.css
│ │ │ ├── context-menu.css
│ │ │ ├── detail.css
│ │ │ ├── divider.css
│ │ │ ├── dropdown.css
│ │ │ ├── editor-settings.css
│ │ │ ├── editor.css
│ │ │ ├── export-dialog.css
│ │ │ ├── files-dialog.css
│ │ │ ├── filter-input.css
│ │ │ ├── frames.css
│ │ │ ├── iframe-dialog.css
│ │ │ ├── iframe.css
│ │ │ ├── image-view.css
│ │ │ ├── import-dialog.css
│ │ │ ├── index.css
│ │ │ ├── json-viewer.css
│ │ │ ├── kv.css
│ │ │ ├── large-dialog.css
│ │ │ ├── list-dialog.css
│ │ │ ├── list.css
│ │ │ ├── menu-item.css
│ │ │ ├── message.css
│ │ │ ├── modal.css
│ │ │ ├── network-settings.css
│ │ │ ├── online.css
│ │ │ ├── overview.css
│ │ │ ├── plugins-mgr.css
│ │ │ ├── plugins.css
│ │ │ ├── properties.css
│ │ │ ├── props-editor.css
│ │ │ ├── record-btn.css
│ │ │ ├── req-data.css
│ │ │ ├── req-detail.css
│ │ │ ├── res-detail.css
│ │ │ ├── service.css
│ │ │ ├── sync-dialog.css
│ │ │ ├── table.css
│ │ │ ├── textarea.css
│ │ │ ├── timeline.css
│ │ │ └── tools.css
│ │ │ ├── js
│ │ │ ├── about.js
│ │ │ ├── base-css.js
│ │ │ ├── bridge.js
│ │ │ ├── btn-group.js
│ │ │ ├── certs-info-dialog.js
│ │ │ ├── cgi.js
│ │ │ ├── columns.js
│ │ │ ├── components
│ │ │ │ ├── json
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── parse.js
│ │ │ │ │ └── stringify.js
│ │ │ │ └── react-json-tree
│ │ │ │ │ ├── ItemRange.js
│ │ │ │ │ ├── JSONArrayNode.js
│ │ │ │ │ ├── JSONArrow.js
│ │ │ │ │ ├── JSONIterableNode.js
│ │ │ │ │ ├── JSONNestedNode.js
│ │ │ │ │ ├── JSONNode.js
│ │ │ │ │ ├── JSONObjectNode.js
│ │ │ │ │ ├── JSONValueNode.js
│ │ │ │ │ ├── createStylingFromTheme.js
│ │ │ │ │ ├── getCollectionEntries.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── objType.js
│ │ │ │ │ ├── themes
│ │ │ │ │ └── solarized.js
│ │ │ │ │ └── utils
│ │ │ │ │ └── hexToRgb.js
│ │ │ ├── composer-list.js
│ │ │ ├── composer.js
│ │ │ ├── console.js
│ │ │ ├── context-menu.js
│ │ │ ├── cookies-dialog.js
│ │ │ ├── copy-btn.js
│ │ │ ├── data-center.js
│ │ │ ├── decode.js
│ │ │ ├── detail-dialog.js
│ │ │ ├── detail.js
│ │ │ ├── dialog.js
│ │ │ ├── divider.js
│ │ │ ├── dns-servers-dialog.js
│ │ │ ├── dropdown.js
│ │ │ ├── editor-dialog.js
│ │ │ ├── editor-settings.js
│ │ │ ├── editor.js
│ │ │ ├── enable-https-btn.js
│ │ │ ├── events.js
│ │ │ ├── expand-collapse.js
│ │ │ ├── export-dialog.js
│ │ │ ├── filter-btn.js
│ │ │ ├── filter-input.js
│ │ │ ├── forward-back-btn.js
│ │ │ ├── frame-composer.js
│ │ │ ├── frame-data.js
│ │ │ ├── frame-list.js
│ │ │ ├── frame-modal.js
│ │ │ ├── frames.js
│ │ │ ├── github-icon.js
│ │ │ ├── history-data.js
│ │ │ ├── https-settings.js
│ │ │ ├── iframe-dialog.js
│ │ │ ├── iframe.js
│ │ │ ├── iframes.js
│ │ │ ├── image-view.js
│ │ │ ├── import-dialog.js
│ │ │ ├── index.js
│ │ │ ├── inspector.js
│ │ │ ├── inspectors.js
│ │ │ ├── is-utf8.js
│ │ │ ├── json-dialog.js
│ │ │ ├── json-viewer.js
│ │ │ ├── kv-dialog.js
│ │ │ ├── large-dialog.js
│ │ │ ├── lazy-init.js
│ │ │ ├── list-dialog.js
│ │ │ ├── list-modal.js
│ │ │ ├── list.js
│ │ │ ├── menu-item.js
│ │ │ ├── message.js
│ │ │ ├── mock-dialog.js
│ │ │ ├── modal.js
│ │ │ ├── network-modal.js
│ │ │ ├── network-settings.js
│ │ │ ├── network.js
│ │ │ ├── online.js
│ │ │ ├── overview.js
│ │ │ ├── panel-tips.js
│ │ │ ├── parse-curl.js
│ │ │ ├── parse-rules.js
│ │ │ ├── plugins-mgr.js
│ │ │ ├── plugins-tabs.js
│ │ │ ├── plugins.js
│ │ │ ├── properties.js
│ │ │ ├── props-editor.js
│ │ │ ├── protocols.js
│ │ │ ├── qrcode-dialog.js
│ │ │ ├── qrcode.js
│ │ │ ├── record-btn.js
│ │ │ ├── recycle-bin.js
│ │ │ ├── req-data.js
│ │ │ ├── req-detail.js
│ │ │ ├── res-detail.js
│ │ │ ├── rule-list.js
│ │ │ ├── rules-dialog.js
│ │ │ ├── rules-hint.js
│ │ │ ├── rules-mode.js
│ │ │ ├── server-log.js
│ │ │ ├── service-btn.js
│ │ │ ├── share-via-url-btn.js
│ │ │ ├── storage.js
│ │ │ ├── sync-dialog.js
│ │ │ ├── tab-frame.js
│ │ │ ├── tab-mgr.js
│ │ │ ├── table.js
│ │ │ ├── tabs.js
│ │ │ ├── text-dialog.js
│ │ │ ├── textarea.js
│ │ │ ├── textview.js
│ │ │ ├── timeline.js
│ │ │ ├── tips-dialog.js
│ │ │ ├── token-dialog.js
│ │ │ ├── tool-box.js
│ │ │ ├── tools.js
│ │ │ ├── update-all-btn.js
│ │ │ ├── util.js
│ │ │ ├── win.js
│ │ │ └── workers.js
│ │ │ └── webpack.config.js
│ └── lib
│ │ ├── index.js
│ │ └── proxy.js
└── weinre
│ ├── index.js
│ └── server.js
├── docs
├── assets
│ ├── host01.png
│ ├── host02.png
│ └── whistle-en_US.png
├── i18n
│ ├── en
│ │ └── README.md
│ └── zh
│ │ ├── README.md
│ │ ├── about.md
│ │ ├── cli
│ │ ├── README.md
│ │ ├── add.md
│ │ ├── ca.md
│ │ ├── env.md
│ │ ├── exec.md
│ │ ├── install.md
│ │ ├── proxy.md
│ │ ├── start.md
│ │ └── status.md
│ │ ├── extensions
│ │ ├── README.md
│ │ ├── npm
│ │ │ ├── README.md
│ │ │ ├── api.md
│ │ │ └── dev.md
│ │ └── plugins
│ │ │ ├── README.md
│ │ │ ├── api.md
│ │ │ ├── dev.md
│ │ │ └── install.md
│ │ ├── feedback.md
│ │ ├── mobile
│ │ ├── README.md
│ │ ├── android.md
│ │ └── ios.md
│ │ ├── pc
│ │ ├── README.md
│ │ ├── firefox.md
│ │ ├── mac.md
│ │ ├── others.md
│ │ ├── switchyomega.md
│ │ └── windows.md
│ │ ├── quickstart.md
│ │ ├── rules
│ │ ├── README.md
│ │ ├── filters
│ │ │ └── README.md
│ │ ├── modify
│ │ │ ├── README.md
│ │ │ ├── request
│ │ │ │ └── README.md
│ │ │ └── response
│ │ │ │ └── README.md
│ │ ├── pattern
│ │ │ └── README.md
│ │ └── values
│ │ │ └── README.md
│ │ ├── update.md
│ │ └── webui
│ │ ├── README.md
│ │ ├── about.md
│ │ ├── files.md
│ │ ├── https.md
│ │ ├── network.md
│ │ ├── online.md
│ │ ├── plugins.md
│ │ ├── rules.md
│ │ └── values.md
└── zh
│ ├── README.md
│ ├── SUMMARY.md
│ ├── attention.md
│ ├── book.json
│ ├── cases.md
│ ├── cli.md
│ ├── custom-certs.md
│ ├── data.md
│ ├── feedback.md
│ ├── frequet.md
│ ├── gitbook
│ └── images
│ │ ├── apple-touch-icon-precomposed-152.png
│ │ └── favicon.ico
│ ├── img
│ ├── Android_proxy.png
│ ├── composer.gif
│ ├── firefox-proxy-1.jpg
│ ├── firefox-proxy-2.jpg
│ ├── host01.png
│ ├── host02.png
│ ├── http-request.png
│ ├── https.gif
│ ├── iOS-proxy-all.jpg
│ ├── iOS-proxy.jpg
│ ├── iOS_proxy.PNG
│ ├── iOS_proxy_settings.png
│ ├── ios10.3_ca.PNG
│ ├── linux-proxy-1.jpg
│ ├── linux-proxy-2.jpg
│ ├── log-basic.gif
│ ├── log-switch.gif
│ ├── mac-proxy-1.jpg
│ ├── mac-proxy-2.jpg
│ ├── network.gif
│ ├── online.gif
│ ├── plugin-list.png
│ ├── plugin1.png
│ ├── plugin2.png
│ ├── plugin3.png
│ ├── plugins.gif
│ ├── rules.gif
│ ├── seq.png
│ ├── settings.png
│ ├── start_w2.jpg
│ ├── switchyomega.jpg
│ ├── tunnel-request.png
│ ├── values.gif
│ ├── weinre.gif
│ └── windows_rootca.jpeg
│ ├── install.md
│ ├── mode-options.md
│ ├── mode.md
│ ├── options.md
│ ├── pattern.md
│ ├── plugins.md
│ ├── principle.md
│ ├── proxy.md
│ ├── questions.md
│ ├── quickstart.md
│ ├── rules
│ ├── @.md
│ ├── README.md
│ ├── accept.md
│ ├── attachment.md
│ ├── auth.md
│ ├── cache.md
│ ├── cipher.md
│ ├── css.md
│ ├── cssAppend.md
│ ├── cssBody.md
│ ├── cssPrepend.md
│ ├── delete.md
│ ├── disable.md
│ ├── dispatch.md
│ ├── enable.md
│ ├── etag.md
│ ├── filter.md
│ ├── forwardedFor.md
│ ├── headerReplace.md
│ ├── host.md
│ ├── hostname.md
│ ├── html.md
│ ├── htmlAppend.md
│ ├── htmlBody.md
│ ├── htmlPrepend.md
│ ├── http-proxy.md
│ ├── https-proxy.md
│ ├── ignore.md
│ ├── js.md
│ ├── jsAppend.md
│ ├── jsBody.md
│ ├── jsPrepend.md
│ ├── lineProps.md
│ ├── location.md
│ ├── log.md
│ ├── method.md
│ ├── pac.md
│ ├── params.md
│ ├── pathReplace.md
│ ├── pipe.md
│ ├── plugin.md
│ ├── proxy.md
│ ├── referer.md
│ ├── replaceStatus.md
│ ├── req.md
│ ├── reqAppend.md
│ ├── reqBody.md
│ ├── reqCharset.md
│ ├── reqCookies.md
│ ├── reqCors.md
│ ├── reqDelay.md
│ ├── reqHeaders.md
│ ├── reqMerge.md
│ ├── reqPrepend.md
│ ├── reqReplace.md
│ ├── reqScript.md
│ ├── reqSpeed.md
│ ├── reqType.md
│ ├── reqWrite.md
│ ├── reqWriteRaw.md
│ ├── res.md
│ ├── resAppend.md
│ ├── resBody.md
│ ├── resCharset.md
│ ├── resCookies.md
│ ├── resCors.md
│ ├── resDelay.md
│ ├── resHeaders.md
│ ├── resMerge.md
│ ├── resPrepend.md
│ ├── resReplace.md
│ ├── resScript.md
│ ├── resSpeed.md
│ ├── resType.md
│ ├── resWrite.md
│ ├── resWriteRaw.md
│ ├── responseFor.md
│ ├── rule
│ │ ├── README.md
│ │ ├── custom.md
│ │ ├── file.md
│ │ ├── locationHref.md
│ │ ├── rawfile.md
│ │ ├── redirect.md
│ │ ├── replace.md
│ │ ├── statusCode.md
│ │ ├── tpl.md
│ │ ├── xfile.md
│ │ ├── xrawfile.md
│ │ └── xtpl.md
│ ├── rulesFile.md
│ ├── sniCallback.md
│ ├── socks.md
│ ├── statusCode.md
│ ├── style.md
│ ├── trailers.md
│ ├── ua.md
│ ├── urlParams.md
│ └── weinre.md
│ ├── template.md
│ ├── update.md
│ └── webui
│ ├── README.md
│ ├── composer.md
│ ├── filter.md
│ ├── https.md
│ ├── log.md
│ ├── mock.md
│ ├── network.md
│ ├── online.md
│ ├── plugins.md
│ ├── rules.md
│ ├── settings.md
│ ├── values.md
│ ├── websocket.md
│ └── weinre.md
├── index.d.ts
├── index.js
├── lib
├── config.js
├── handlers
│ ├── error-handler.js
│ ├── file-proxy.js
│ ├── final-handler.js
│ ├── http-proxy.js
│ ├── index.js
│ └── plugin-handler.js
├── https
│ ├── ca.js
│ ├── h2.js
│ ├── index.js
│ └── load-cert.js
├── index.js
├── init.js
├── inspectors
│ ├── data.js
│ ├── index.js
│ ├── log.js
│ ├── req.js
│ ├── res.js
│ ├── rules.js
│ └── weinre.js
├── plugins
│ ├── get-plugins-sync.js
│ ├── get-plugins.js
│ ├── index.js
│ ├── load-plugin.js
│ ├── module-paths.js
│ ├── proxy.js
│ ├── shared-storage.js
│ └── util.js
├── rules
│ ├── dns.js
│ ├── index.js
│ ├── protocols.js
│ ├── recycle-bin.js
│ ├── rules.js
│ ├── storage.js
│ └── util.js
├── service
│ ├── data-center.js
│ ├── extract-saz.js
│ ├── generate-saz.js
│ ├── index.js
│ ├── installer.js
│ ├── plugin.js
│ ├── service.js
│ └── util.js
├── socket-mgr.js
├── tunnel.js
├── upgrade.js
└── util
│ ├── buf-util.js
│ ├── common.js
│ ├── data-server.js
│ ├── drain.js
│ ├── file-mgr.js
│ ├── file-writer-transform.js
│ ├── http-mgr.js
│ ├── index.js
│ ├── is-utf8.js
│ ├── log-server.js
│ ├── logger.js
│ ├── parse-query.js
│ ├── parse-url-safe.js
│ ├── parse-url.js
│ ├── patch.js
│ ├── perf.js
│ ├── process.js
│ ├── replace-pattern-transform.js
│ ├── replace-string-transform.js
│ ├── speed-transform.js
│ ├── transproto.js
│ ├── whistle-transform.js
│ └── zlib.js
├── package-lock.json
├── package.json
├── require.js
└── test
├── assets
├── certs
│ ├── _.cert.w2.org.crt
│ ├── _.cert.w2.org.key
│ ├── _root.crt
│ ├── cert.w2.org.key
│ ├── root.key
│ ├── test.crt
│ └── test.key
├── files
│ ├── 1.txt
│ ├── 2.txt
│ ├── 3.txt
│ ├── empty.txt
│ ├── gb2312.txt
│ ├── rules.txt
│ ├── storage
│ │ ├── .backup
│ │ │ ├── 1.test1.tx
│ │ │ ├── 2.test2.tx
│ │ │ ├── 3.test3.tx
│ │ │ └── properties
│ │ ├── files
│ │ │ ├── 1.test1.tx
│ │ │ ├── 2.test2.tx
│ │ │ └── 3.test3.tx
│ │ └── properties
│ └── test.txt
└── values
│ ├── rawFile.html
│ ├── rawFile2.js
│ ├── reqScript.js
│ ├── resScript.js
│ ├── rulesFile.js
│ ├── rulesFile.txt
│ ├── rulesFile2.js
│ ├── test.json
│ ├── test2.json
│ ├── test3.json
│ ├── tps.rules
│ ├── tps1.json
│ └── tps2.json
├── config.test.js
├── events.js
├── index.test.js
├── plugins
├── @test
│ └── whistle.test3
│ │ ├── index.js
│ │ ├── package.json
│ │ ├── rules.txt
│ │ └── test
│ │ └── abc
│ │ ├── abc
│ │ └── index.html
│ │ └── index.html
├── whistle.pipe-http
│ ├── index.js
│ ├── lib
│ │ ├── reqReadServer.js
│ │ ├── reqWriteServer.js
│ │ ├── resReadServer.js
│ │ └── resWriteServer.js
│ ├── package.json
│ └── rules.txt
├── whistle.pipe-tunnel
│ ├── index.js
│ ├── lib
│ │ ├── tunnelReqRead.js
│ │ ├── tunnelReqWrite.js
│ │ ├── tunnelResRead.js
│ │ └── tunnelResWrite.js
│ ├── package.json
│ └── rules.txt
├── whistle.pipe-ws
│ ├── index.js
│ ├── lib
│ │ ├── wsReqRead.js
│ │ ├── wsReqWrite.js
│ │ ├── wsResRead.js
│ │ └── wsResWrite.js
│ ├── package.json
│ └── rules.txt
├── whistle.test-values
│ ├── index.js
│ ├── package.json
│ └── rules.txt
├── whistle.test
│ ├── _rules.txt
│ ├── assets
│ │ ├── dispatch.js
│ │ ├── files
│ │ │ ├── append.txt
│ │ │ ├── bin
│ │ │ │ ├── body.txt
│ │ │ │ ├── bottom.txt
│ │ │ │ ├── file.txt
│ │ │ │ └── top.txt
│ │ │ ├── body.txt
│ │ │ ├── css.css
│ │ │ ├── html.html
│ │ │ ├── index.html
│ │ │ ├── js.js
│ │ │ ├── log.js
│ │ │ ├── pac.js
│ │ │ ├── prepend.txt
│ │ │ ├── rawfile.html
│ │ │ ├── ssi-include.html
│ │ │ ├── ssi1.html
│ │ │ ├── ssi2.html
│ │ │ ├── ssi3.html
│ │ │ └── tpl.js
│ │ └── values
│ │ │ ├── headers.json
│ │ │ ├── replace.json
│ │ │ ├── req.json
│ │ │ ├── reqCookies.json
│ │ │ ├── reqCors.json
│ │ │ ├── res.json
│ │ │ ├── resCookies.json
│ │ │ ├── resCors.json
│ │ │ ├── upload.json
│ │ │ ├── urlParams.json
│ │ │ └── urlReplace.json
│ ├── index.js
│ ├── lib
│ │ ├── resRulesServer.js
│ │ ├── rulesServer.js
│ │ ├── server.js
│ │ ├── statusServer.js
│ │ ├── tunnelRulesServer.js
│ │ ├── tunnelServer.js
│ │ ├── uiServer.js
│ │ └── util.js
│ ├── package.json
│ └── rules.txt
├── whistle.test1
│ ├── _rules.txt
│ ├── index.js
│ ├── lib
│ │ └── rulesServer.js
│ ├── package.json
│ └── rules.txt
└── whistle.test2
│ ├── _rules.txt
│ ├── index.js
│ ├── package.json
│ ├── rules.txt
│ └── test.txt
├── proxy
├── disable.test.js
└── enable.test.js
├── rules.txt
├── units
├── _normalizeConnectArgs.test.js
├── attachment.test.js
├── auth.test.js
├── cache.test.js
├── common.test.js
├── composer.test.js
├── connect.test.js
├── css.test.js
├── delete.test.js
├── disable.test.js
├── file.test.js
├── filter.test.js
├── fm.test.js
├── forward.test.js
├── host.test.js
├── html.test.js
├── https.test.js
├── ignore.test.js
├── insertFile.test.js
├── js.test.js
├── log.test.js
├── method.test.js
├── options.test.js
├── others.test.js
├── pac.test.js
├── params.test.js
├── plugin.test.js
├── plugins.test.js
├── proxy.test.js
├── range.test.js
├── rawfile.test.js
├── redirect.test.js
├── referer.test.js
├── replaceStatus.test.js
├── req.prepend.body.append.test.js
├── reqAppend.test.js
├── reqBody.test.js
├── reqCharset.test.js
├── reqCookies.test.js
├── reqCors.test.js
├── reqDelay.test.js
├── reqHeaders.test.js
├── reqPrepend.test.js
├── reqReplace.test.js
├── reqSpeed.test.js
├── reqType.test.js
├── res.prepend.body.append.test.js
├── resAppend.test.js
├── resBody.test.js
├── resCharset.test.js
├── resCookies.test.js
├── resCors.test.js
├── resDelay.test.js
├── resHeaders.test.js
├── resPrepend.test.js
├── resReplace.test.js
├── resSpeed.test.js
├── resType.test.js
├── rule.test.js
├── rulesFile.test.js
├── script.test.js
├── socks.test.js
├── ssi-include.test.js
├── statusCode.test.js
├── tpl.test.js
├── tplStr.test.js
├── tps.test.js
├── tunnel.test.js
├── tunnelPolicy.test.js
├── ua.test.js
├── ui.test.js
├── urlParams.test.js
├── urlReplace.test.js
├── utils.test.js
├── values.test.js
├── var.test.js
├── weinre.test.js
├── wildcard.test.js
├── write.test.js
├── ws.test.js
└── xfile.test.js
└── util.test.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "env",
4 | "react"
5 | ],
6 | "plugins": [
7 | "transform-class-properties",
8 | "transform-object-rest-spread"
9 | ],
10 | "ignore": [
11 | "./biz/webui/htdocs/src/js/components/json/eval.js"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | end_of_line = lf
7 | indent_size = 2
8 | indent_style = space
9 | insert_final_newline = true
10 | max_line_length = 80
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | max_line_length = 0
15 | trim_trailing_whitespace = false
16 |
17 | [COMMIT_EDITMSG]
18 | max_line_length = 0
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | /biz/webui/htdocs/js
3 | /biz/webui/htdocs/src/js/components
4 | /test/assets/values
5 | /test/plugins/whistle.test/assets
6 | /bin/import.js
7 | /test/all_whistles
8 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | biz/webui/htdocs/js/index.js diff=nodiff
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "10"
4 | - "11"
5 | - "12"
6 | - "13"
7 | - "14"
8 | - "15"
9 | - "16"
10 | - "17"
11 | - "18"
12 |
13 | install:
14 | - npm install
15 |
16 | script:
17 | - npm run cov
18 |
19 | after_script:
20 | - npm i codecov && codecov
21 |
--------------------------------------------------------------------------------
/assets/js/weinre.js:
--------------------------------------------------------------------------------
1 |
2 | ;(function() {
3 | if (typeof window === 'undefined' || window.WeinreServerURL) {
4 | return;
5 | }
6 | var prefixPath = window.__WHISTLE_PATH_PREFIX__;
7 | if (/^\/[\w./-]+$/.test(prefixPath) && prefixPath.length <= 128) {
8 | var len = prefixPath.length - 1;
9 | if (prefixPath[len] === '/') {
10 | prefixPath = prefixPath.substring(0, len);
11 | }
12 | } else {
13 | prefixPath = '';
14 | }
15 | var baseUrl = '$BASE_URL' + prefixPath;
16 | window.WeinreServerURL = baseUrl + '$WEINRE_PATH';
17 | var head = document.head || document.getElementsByTagName('head')[0] || document.documentElement;
18 | var script = document.createElement('script');
19 | script.async = true;
20 | script.charset = 'utf8';
21 | script.src = baseUrl + '$WEINRE_URL';
22 | if (head.firstChild) {
23 | head.insertBefore(script, head.firstChild);
24 | } else {
25 | head.appendChild(script);
26 | }
27 | })();
28 |
--------------------------------------------------------------------------------
/assets/launcher/README.md:
--------------------------------------------------------------------------------
1 | # 配置开机重启whistle
2 | 由于whistle是用Node实现的一个命令行程序,相对于客户端程序安装过程多了[安装node、配置代理](https://avwo.github.io/whistle/install.html)这两个步骤及通过命令行启动服务器,而不是点击桌面图标启动,具体参见[安装启动whistle](https://avwo.github.io/whistle/install.html);命令行程序也有一个好处:可以部署在服务器上。事实上,通过把启动脚本写在脚本文件里面(如bat文件)并存在桌面也可以实现双击图标启动whistle,且将该脚本文件放在开机启动项可以实现开机自动重启,具体根据不同的操作系统采取不同的策略:
3 |
4 | 1. [Windows](windows)
5 | 2. [Mac](mac)
6 | 3. [Linux](linux)
7 |
--------------------------------------------------------------------------------
/assets/launcher/linux/README.md:
--------------------------------------------------------------------------------
1 | # Linux上配置开机重启whistle
2 |
3 | Linux不完全支持双击脚本文件自动执行(需要whistle v1.0.0及以上版本),只能设置开机自动重启whistle,[安装完whistle](https://avwo.github.io/whistle/install.html)后执行`which w2`查看命令行安装的路径(一般为`/usr/local/bin/w2`),编辑启动执行的文件`sudo vi /etc/rc.d/rc.local`,在最后一行加入`/usr/local/bin/w2 restart`(`/usr/local/bin/w2`视`which w2`输出的字符串为准)。
4 |
5 | 
--------------------------------------------------------------------------------
/assets/launcher/linux/whistle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/assets/launcher/linux/whistle.gif
--------------------------------------------------------------------------------
/assets/launcher/mac/README.md:
--------------------------------------------------------------------------------
1 | # Mac上配置开机重启whistle
2 | 首先,下载Mac上的whistle脚步文件:[whistle.zip](https://github.com/avwo/whistle/blob/master/assets/launcher/mac/whistle.zip)。
3 |
4 | 1. 解压whistle.zip获取whistle脚本文件,把该脚本文件拷贝一份到**应用程序**,打开桌面即可看到whistle这个脚本文件,这样可以直接在Mac的桌面上刊登whistle的启动脚本,点击该文件即可重启whistle;
5 |
6 | 
7 |
8 | 2. **打开设置 --> 打开用户与群组 --> 打开登录项 --> 点击下方的+按钮 --> 在应用程序目录里选择whistle --> 勾选上复选框**,这样就配置好了开机自动重启whistle。
9 |
10 | 
11 |
--------------------------------------------------------------------------------
/assets/launcher/mac/whistle-desktop.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/assets/launcher/mac/whistle-desktop.gif
--------------------------------------------------------------------------------
/assets/launcher/mac/whistle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/assets/launcher/mac/whistle.gif
--------------------------------------------------------------------------------
/assets/launcher/mac/whistle.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/assets/launcher/mac/whistle.zip
--------------------------------------------------------------------------------
/assets/launcher/windows/README.md:
--------------------------------------------------------------------------------
1 | # Windows上配置开机重启whistle
2 | 首先,下载Windows上的whistle脚步文件:[whistle.zip](https://github.com/avwo/whistle/raw/master/assets/launcher/windows/whistle.zip)。
3 |
4 | 1. 解压whistle.zip获取whistle.bat的脚本文件,把该脚本文件拷贝一份到Windows的桌面,这样可以直接在Windows的桌面上看到whistle的启动脚本,双击即可重启whistle(会先弹出一个命令行窗口,等3秒左右就会自动消失);
5 |
6 | 2. 把桌面上的whistle.bat文件拖到桌面左下角的系统**开始菜单 --> 所有程序 --> 启动**目录下面,或者直接拷贝到系统目录`C:\Users\{yourAccount}\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup`(可以直接在开始菜单或者文件管理器中的输入框输入`%appData%\Microsoft\Windows\Start Menu\Programs\Startup`快速定位到启动菜单目录),这样就配置好了开机自动重启whistle。
7 |
8 | 
9 |
--------------------------------------------------------------------------------
/assets/launcher/windows/whistle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/assets/launcher/windows/whistle.gif
--------------------------------------------------------------------------------
/assets/launcher/windows/whistle.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/assets/launcher/windows/whistle.zip
--------------------------------------------------------------------------------
/bin/ca/index.d.ts:
--------------------------------------------------------------------------------
1 | export default function (certFile: String): void;
2 |
--------------------------------------------------------------------------------
/bin/import.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 |
3 | function importModle(filepath, callback) {
4 | return import(filepath).then(callback);
5 | }
6 |
7 | module.exports = function(filepath, callback) {
8 | try {
9 | return callback(require(filepath));
10 | } catch (e) {
11 | var code =e && e.code;
12 | if (code === 'ERR_REQUIRE_ESM') {
13 | // ignore eslint & fix type=module
14 | return importModle(filepath, callback);
15 | } else if (code === 'MODULE_NOT_FOUND' && /\.js$/i.test(filepath)) {
16 | filepath = filepath.slice(0, -3) + '.mjs';
17 | if (fs.existsSync(filepath)) {
18 | return importModle(filepath, callback);
19 | }
20 | }
21 | throw e;
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/bin/plugin.d.ts:
--------------------------------------------------------------------------------
1 |
2 | export function getWhistlePath(): string;
3 |
4 | export function install(cmd: string, argv: string[]): void;
5 |
6 | export function uninstall(argv: string[]): void;
7 |
--------------------------------------------------------------------------------
/biz/init.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | var ui = require('./webui/lib');
3 | var util = require('../lib/util');
4 |
5 | module.exports = function init(proxy, callback) {
6 | var config = proxy.config;
7 | ui.init(proxy);
8 | if (config.customUIPort) {
9 | var server = http.createServer();
10 | ui.setupServer(server);
11 | util.getBoundIp(config.uihost, function(host) {
12 | if (host) {
13 | config.customUIHost = host;
14 | server.listen(config.uiport, host, callback);
15 | } else {
16 | server.listen(config.uiport, callback);
17 | }
18 | });
19 | } else {
20 | callback();
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/abort.js:
--------------------------------------------------------------------------------
1 | var proxy = require('../lib/proxy');
2 | var socketMgr = proxy.socketMgr;
3 |
4 | function abort(reqId) {
5 | proxy.abortRequest(reqId);
6 | socketMgr.abort(reqId);
7 | }
8 |
9 | module.exports = function(req, res) {
10 | var list = req.body.list;
11 | if (list && typeof list === 'string') {
12 | list.split(',').forEach(abort);
13 | }
14 | res.json({ ec: 0 });
15 | };
16 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/add-rules-values.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../lib/rules/util').rules;
2 | var values = require('../../../lib/rules/util').values;
3 |
4 | module.exports = function(req, res) {
5 | var body = req.body;
6 | var clientId = body.clientId;
7 | var rulesData = body.rules;
8 | var valuesData = body.values;
9 | if (rulesData) {
10 | if (rulesData.name === 'Default') {
11 | rules.setDefault(rulesData.value, clientId);
12 | rules.enableDefault();
13 | } else {
14 | rules.add(rulesData.name, rulesData.value, clientId);
15 | rules.select(rulesData.name);
16 | }
17 | }
18 | if (valuesData) {
19 | values.add(valuesData.name, valuesData.value, clientId);
20 | }
21 | res.json({ec: 0, em: 'success'});
22 | };
23 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/certs/all.js:
--------------------------------------------------------------------------------
1 | var ca = require('../../../../lib/https/ca');
2 |
3 | module.exports = function(req, res) {
4 | res.json({
5 | certs: ca.getCustomCertsFiles(),
6 | dir: ca.CUSTOM_CERTS_DIR
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/certs/remove.js:
--------------------------------------------------------------------------------
1 | var ca = require('../../../../lib/https/ca');
2 |
3 |
4 | module.exports = function(req, res) {
5 | ca.removeCert(req.body);
6 | var isparsed = req.query.dataType === 'parsed';
7 | res.json(isparsed ? ca.getCustomCertsInfo() : ca.getCustomCertsFiles());
8 | };
9 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/certs/upload.js:
--------------------------------------------------------------------------------
1 | var ca = require('../../../../lib/https/ca');
2 |
3 |
4 | module.exports = function(req, res) {
5 | ca.uploadCerts(req.body);
6 | var isparsed = req.query.dataType === 'parsed';
7 | res.json(isparsed ? ca.getCustomCertsInfo() : ca.getCustomCertsFiles());
8 | };
9 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/cookies.js:
--------------------------------------------------------------------------------
1 | var sendGzip = require('./util').sendGzip;
2 | var proxy = require('../lib/proxy');
3 |
4 | module.exports = function(req, res) {
5 | sendGzip(req, res, {
6 | ec: 0,
7 | cookies: proxy.getCookiesByDomain(req.query.domain)
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/custom-frames.js:
--------------------------------------------------------------------------------
1 | var proxy = require('../lib/proxy');
2 | var socketMgr = proxy.socketMgr;
3 |
4 | module.exports = function(req, res) {
5 | var result = {};
6 | req.body.idList.forEach(function(reqId) {
7 | result[reqId] = socketMgr.getData(reqId);
8 | });
9 | req.body.frames.forEach(function(frame) {
10 | proxy.emit('frame', frame);
11 | });
12 | res.json(result);
13 | };
14 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/custom-handler.js:
--------------------------------------------------------------------------------
1 | var config = require('../../../lib/config');
2 |
3 | module.exports = function(req, res) {
4 | if (!config.customHandler) {
5 | return res.sendStatus(404);
6 | }
7 | config.customHandler(req, res);
8 | };
9 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/do-not-show-again.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../lib/rules/util').properties;
2 |
3 | module.exports = function(req, res) {
4 | properties.set('doNotShowAgainVersion', properties.getLatestVersion('latestVersion'));
5 | res.json({ec: 0, em: 'success'});
6 | };
7 |
8 |
9 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/enable-http2.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../lib/rules/util').properties;
2 |
3 | module.exports = function(req, res) {
4 | properties.setEnableHttp2(req.body.enableHttp2 == 1);
5 | res.json({ec: 0, em: 'success'});
6 | };
7 |
8 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/get-cert.js:
--------------------------------------------------------------------------------
1 | var ca = require('../../../lib/https/ca');
2 |
3 | var URL_RE = /^(?:(?:[\w.-]+:)?\/\/)?([\w.-]+)/i;
4 |
5 | function parseDomain(domain) {
6 | domain = domain && typeof domain === 'string' && domain.trim();
7 | if (!domain || domain.length > 64 || !URL_RE.test(domain)) {
8 | return;
9 | }
10 | return RegExp.$1;
11 | }
12 |
13 | module.exports = function(req, res) {
14 | var domain = parseDomain(req.query.domain);
15 | if (!domain) {
16 | return res.status(400).end('Bad Request');
17 | }
18 | if (domain === 'rootCA') {
19 | return res.json(ca.getRootCA());
20 | }
21 | res.json(ca.createCertificate(domain.toLowerCase()));
22 | };
23 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/get-custom-certs-files.js:
--------------------------------------------------------------------------------
1 | var getCustomCertsFiles = require('../../../lib/https/ca').getCustomCertsFiles;
2 |
3 | module.exports = function(req, res) {
4 | res.json(getCustomCertsFiles());
5 | };
6 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/get-custom-certs-info.js:
--------------------------------------------------------------------------------
1 | var getCustomCertsInfo = require('../../../lib/https/ca').getCustomCertsInfo;
2 | // 给第三方用的,不能删除
3 | module.exports = function(req, res) {
4 | res.json(getCustomCertsInfo());
5 | };
6 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/get-frames.js:
--------------------------------------------------------------------------------
1 | var proxy = require('../lib/proxy');
2 | var socketMgr = proxy.socketMgr;
3 |
4 | module.exports = function(req, res) {
5 | var frames = proxy.getFrames(req.query);
6 | if (frames && !frames.length &&
7 | !socketMgr.exists(req.query.curReqId)) {
8 | frames = undefined;
9 | }
10 | res.json({
11 | ec: 0,
12 | frames: frames
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/get-session.js:
--------------------------------------------------------------------------------
1 | var proxy = require('../lib/proxy');
2 |
3 | var emptyArr = [];
4 | var parseArray = function(str) {
5 | try {
6 | str = JSON.parse(str);
7 | return Array.isArray(str) ? str : emptyArr;
8 | } catch(e) {}
9 | return emptyArr;
10 | };
11 |
12 | module.exports = function(req, res) {
13 | var reqList = parseArray(req.query.reqList);
14 | var resList = parseArray(req.query.resList);
15 | var result = {};
16 | reqList.concat(resList).forEach(function(id) {
17 | if (result[id] != null) {
18 | return;
19 | }
20 | var item = proxy.getItem(id);
21 | if (!item) {
22 | result[id] = 0;
23 | return;
24 | }
25 | if ((item.requestTime && reqList.indexOf(id) !== -1) || item.endTime) {
26 | result[id] = item;
27 | }
28 | });
29 | res.json(result);
30 | };
31 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/hide-https-connects.js:
--------------------------------------------------------------------------------
1 | module.exports = function(req, res) {
2 | res.json({ec: 0, em: 'success'});
3 | };
4 |
5 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/history.js:
--------------------------------------------------------------------------------
1 | var util = require('./util');
2 | var properties = require('../../../lib/rules/util').properties;
3 |
4 | module.exports = function(req, res) {
5 | util.sendGzip(req, res, properties.getHistory());
6 | };
7 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/https-status.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../lib/rules/util').properties;
2 |
3 | module.exports = function(req, res) {
4 | res.json({
5 | ec: 0,
6 | enableCapture: properties.isEnableCapture(),
7 | enableHttp2: properties.isEnableHttp2()
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/intercept-https-connects.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../lib/rules/util').properties;
2 |
3 | module.exports = function(req, res) {
4 | properties.setEnableCapture(req.body.interceptHttpsConnects == 1);
5 | res.json({ec: 0, em: 'success'});
6 | };
7 |
8 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/log/set.js:
--------------------------------------------------------------------------------
1 | var proxy = require('../../lib/proxy');
2 |
3 | module.exports = function(req, res) {
4 | proxy.addLog(req.query);
5 | res.setHeader('content-type', 'image/png');
6 | res.end();
7 | };
8 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/plugins/add-registry.js:
--------------------------------------------------------------------------------
1 | var pluginMgr = require('../../lib/proxy').pluginMgr;
2 |
3 | module.exports = function(req, res) {
4 | pluginMgr.addRegistry(req.body.registry);
5 | res.json({ec: 0});
6 | };
7 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/plugins/disable-all-plugins.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../../lib/rules/util').properties;
2 | var pluginMgr = require('../../lib/proxy').pluginMgr;
3 |
4 | module.exports = function(req, res) {
5 | properties.set('disabledAllPlugins', req.body.disabledAllPlugins == 1);
6 | pluginMgr.updateRules();
7 | res.json({ec: 0, em: 'success'});
8 | };
9 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/plugins/disable-plugin.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../../lib/rules/util').properties;
2 | var pluginMgr = require('../../lib/proxy').pluginMgr;
3 |
4 | module.exports = function(req, res) {
5 | var disabledPlugins = properties.get('disabledPlugins') || {};
6 | if (req.body.disabled == 1) {
7 | disabledPlugins[req.body.name] = 1;
8 | } else {
9 | delete disabledPlugins[req.body.name];
10 | }
11 | properties.set('disabledPlugins', disabledPlugins);
12 | pluginMgr.updateRules();
13 | res.json({ec: 0, data: disabledPlugins});
14 | };
15 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/plugins/get-plugins.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../../lib/rules/util').properties;
2 | var pluginMgr = require('../../lib/proxy').pluginMgr;
3 |
4 | module.exports = function(req, res) {
5 | res.json({
6 | ec: 0,
7 | plugins: pluginMgr.getPlugins(),
8 | disabledPlugins: properties.get('disabledPlugins') || {},
9 | disabledAllPlugins: properties.get('disabledAllPlugins')
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/plugins/install.js:
--------------------------------------------------------------------------------
1 | var config = require('../../../../lib/config');
2 | var common = require('../../../../lib/util/common');
3 |
4 | module.exports = function(req, res) {
5 | if (!config.installPlugins) {
6 | return res.status(404).end();
7 | }
8 | var data = common.parsePlugins(req.body);
9 | data && config.installPlugins(data);
10 | res.json({ ec: 0, count: data ? data.pkgs.length : 0 });
11 | };
12 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/plugins/is-enable.js:
--------------------------------------------------------------------------------
1 | var pluginMgr = require('../../lib/proxy').pluginMgr;
2 | var config = require('../../../../lib/config');
3 |
4 | module.exports = function(req, res) {
5 | var name = req.headers[config.PROXY_ID_HEADER];
6 | res.json({
7 | ec: 0,
8 | enable: !!name && !!pluginMgr.getPlugin(name + ':')
9 | });
10 | };
11 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/plugins/registry-list.js:
--------------------------------------------------------------------------------
1 | var pluginMgr = require('../../lib/proxy').pluginMgr;
2 |
3 | module.exports = function(req, res) {
4 | res.json({ ec: 0, list: pluginMgr.getRegistryList() });
5 | };
6 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/plugins/uninstall.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var fs = require('fs');
3 | var pluginMgr = require('../../lib/proxy').pluginMgr;
4 |
5 | module.exports = function(req, res) {
6 | var plugin = pluginMgr.getModifiablePlugin(req.body.name);
7 | if (!plugin) {
8 | return res.json({ ec: 0 });
9 | }
10 | var pkgPath = path.join(plugin.path, 'package.json');
11 | var newPkgPath = pkgPath + '.' + Date.now();
12 | var retry;
13 | var handleCb = function(err) {
14 | if (err && err.code !== 'ENOENT') {
15 | if (!retry) {
16 | retry = true;
17 | return fs.unlink(pkgPath, handleCb);
18 | }
19 | return res.json({ ec: 2, em: err.message || 'Error' });
20 | }
21 | pluginMgr.refreshPlugins();
22 | res.json({ ec: 0 });
23 | };
24 | fs.rename(pkgPath, newPkgPath, handleCb);
25 | };
26 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/plugins/update-rules.js:
--------------------------------------------------------------------------------
1 | var config = require('../../../../lib/config');
2 | var pluginMgr = require('../../lib/proxy').pluginMgr;
3 |
4 | module.exports = function(req, res) {
5 | var name = req.headers[config.PROXY_ID_HEADER];
6 | pluginMgr.updatePluginRules(name);
7 | res.json({ec: 0});
8 | };
9 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/reset-local-address.js:
--------------------------------------------------------------------------------
1 | var util = require('../../../lib/util');
2 |
3 | module.exports = function(req, res) {
4 | util.localIpCache.reset();
5 | res.json({ec: 0, em: 'success'});
6 | };
7 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rootca.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../lib/rules/util').properties;
2 | var getRootCAFile = require('../../../lib/https/ca').getRootCAFile;
3 |
4 | module.exports = function(req, res) {
5 | var type = req.query.type;
6 | if (type !== 'crt' && type !== 'pem') {
7 | type = 'cer';
8 | }
9 | if (req.query.enableHttps) {
10 | properties.setEnableCapture(true);
11 | }
12 | res.download(getRootCAFile(), 'rootCA.' + type);
13 | };
14 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/account.js:
--------------------------------------------------------------------------------
1 | var getAccountRules = require('../../../../lib/rules/util').getAccountRules;
2 |
3 | module.exports = function(_, res) {
4 | res.json({ec: 0, rules: getAccountRules() });
5 | };
6 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/allow-multiple-choice.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../../lib/rules/util').properties;
2 | var proxy = require('../../lib/proxy');
3 |
4 | module.exports = function(req, res) {
5 | var enable = req.body.allowMultipleChoice == 1;
6 | properties.set('allowMultipleChoice', enable);
7 | proxy.emit('rulesDataChange', 'allowMultipleChoice', enable);
8 | res.json({ec: 0, em: 'success'});
9 | };
10 |
11 |
12 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/disable-all-rules.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../../lib/rules/util').properties;
2 | var rules = require('../../../../lib/rules/util').rules;
3 |
4 | module.exports = function(req, res) {
5 | properties.set('disabledAllRules', req.body.disabledAllRules == 1);
6 | rules.parseRules();
7 | res.json({ec: 0, em: 'success'});
8 | };
9 |
10 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/disable-default.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../../lib/rules/util').rules;
2 |
3 | module.exports = function(req, res) {
4 | rules.disableDefault();
5 | res.json({ec: 0, em: 'success', defaultRulesIsDisabled: rules.defaultRulesIsDisabled(), list: rules.getSelectedList()});
6 | };
7 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/enable-back-rules-first.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../../lib/rules/util').rules;
2 |
3 | module.exports = function(req, res) {
4 | rules.enableBackRulesFirst(req.body.backRulesFirst === '1');
5 | res.json({ec: 0, em: 'success'});
6 | };
7 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/enable-default.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../../lib/rules/util').rules;
2 |
3 | module.exports = function(req, res) {
4 | rules.enableDefault();
5 | rules.setDefault(req.body.value, req.body.clientId);
6 | res.json({ec: 0, em: 'success', defaultRulesIsDisabled: rules.defaultRulesIsDisabled(), list: rules.getSelectedList()});
7 | };
8 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/export.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../../lib/rules/util').rules;
2 | var util = require('../util');
3 |
4 | module.exports = function(req, res) {
5 | var exportRules = req.query.rules;
6 | try {
7 | exportRules = exportRules && JSON.parse(exportRules);
8 | } catch(e) {
9 | exportRules = null;
10 | }
11 | var result = {};
12 | if (!exportRules || exportRules.Default) {
13 | var defaultRules = rules.getDefault() || '';
14 | result.Default = defaultRules;
15 | }
16 | rules.list().forEach(function(file) {
17 | if (!exportRules || exportRules[file.name]) {
18 | result[file.name] = file.data;
19 | }
20 | });
21 | var filename = req.query.filename;
22 | if (filename && typeof filename === 'string') {
23 | if (!/\.(txt|json)/i.test(filename)) {
24 | filename += '.txt';
25 | }
26 | } else {
27 | filename = 'rules_' + util.formatDate() + '.txt';
28 | }
29 | res.attachment(filename).send(JSON.stringify(result, null, ' '));
30 | };
31 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/import.js:
--------------------------------------------------------------------------------
1 | var get = require('./index');
2 | var getReqData = require('../util').getReqData;
3 | var addRules = require('../../../../lib/rules/util').addRules;
4 |
5 | module.exports = function(req, res) {
6 | getReqData(req, function(err, result) {
7 | if (err) {
8 | res.status(200).json({ ec: 2, em: err.message });
9 | } else {
10 | addRules(result.data, result.replace, req.query.clientId);
11 | res.json(get());
12 | }
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/index.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../../lib/rules/util').rules;
2 | var properties = require('../../../../lib/rules/util').properties;
3 |
4 | module.exports = function get() {
5 | return {
6 | ec: 0,
7 | defaultRulesIsDisabled: rules.defaultRulesIsDisabled(),
8 | defaultRules: rules.getDefault(),
9 | allowMultipleChoice: properties.get('allowMultipleChoice'),
10 | backRulesFirst: properties.get('backRulesFirst'),
11 | list: rules.list()
12 | };
13 | };
14 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/list.js:
--------------------------------------------------------------------------------
1 | var get = require('./index');
2 |
3 | module.exports = function(req, res) {
4 | res.json(get());
5 | };
6 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/list2.js:
--------------------------------------------------------------------------------
1 | var get = require('./index');
2 |
3 | module.exports = function(req, res) {
4 | var rules = get();
5 | var data;
6 | if (req.query.order) {
7 | data = [{
8 | name: 'Default',
9 | value: rules.defaultRules
10 | }];
11 | rules.list.forEach(function(item) {
12 | data.push({
13 | name: item.name,
14 | value: item.data
15 | });
16 | });
17 | } else {
18 | data = {
19 | Default: rules.defaultRules
20 | };
21 | rules.list.forEach(function(item) {
22 | data[item.name] = item.data;
23 | });
24 | }
25 | res.json(data);
26 | };
27 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/move-to.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../../lib/rules/util').rules;
2 |
3 | module.exports = function(req, res) {
4 | var body = req.body;
5 | var result = rules.moveTo(body.from, body.to, body.clientId, body.group === 'true', body.toTop === 'true');
6 | res.json({ec: result ? 0 : 2, em: 'success'});
7 | };
8 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/recycle/list.js:
--------------------------------------------------------------------------------
1 | var recycleBin = require('../../../../../lib/rules/util').rules.recycleBin;
2 |
3 | module.exports = function(req, res) {
4 | res.json({
5 | ec: 0,
6 | list: recycleBin.list()
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/recycle/remove.js:
--------------------------------------------------------------------------------
1 | var recycleBin = require('../../../../../lib/rules/util').rules.recycleBin;
2 |
3 | module.exports = function(req, res) {
4 | recycleBin.remove(req.body.name);
5 | res.json({
6 | ec: 0,
7 | list: recycleBin.list()
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/recycle/view.js:
--------------------------------------------------------------------------------
1 | var recycleBin = require('../../../../../lib/rules/util').rules.recycleBin;
2 |
3 | module.exports = function(req, res) {
4 | var item = recycleBin.getFile(req.query.name);
5 | res.json({
6 | ec: item ? 0 : 3,
7 | data: item && item.data
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/remove.js:
--------------------------------------------------------------------------------
1 | var util = require('../../../../lib/rules/util');
2 |
3 | module.exports = function(req, res) {
4 | util.removeBatch(util.rules, req.body);
5 | res.json({ec: 0, em: 'success'});
6 | };
7 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/rename.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../../lib/rules/util').rules;
2 |
3 | module.exports = function(req, res) {
4 | var body = req.body;
5 | rules.rename(body.name, body.newName, body.clientId);
6 | res.json({ec: 0, em: 'success'});
7 | };
8 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/select.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../../lib/rules/util').rules;
2 |
3 | module.exports = function(req, res) {
4 | var body = req.body;
5 | var exists = rules.exists(body.name);
6 | var changed;
7 | if (rules.add(body.name, body.value, body.clientId) && !exists) {
8 | var group = rules.getFirstGroup();
9 | if (group) {
10 | rules.moveTo(body.name, group.name, body.clientId, null, true);
11 | changed = true;
12 | }
13 | }
14 | rules.select(req.body.name);
15 | res.json({ec: 0, em: 'success', defaultRulesIsDisabled: rules.defaultRulesIsDisabled(), list: rules.getSelectedList(), changed: changed});
16 | };
17 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/set-sys-hosts.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../../lib/rules/util').rules;
2 |
3 | module.exports = function(req, res) {
4 | rules.setSysHosts(req.body.hosts, function(err) {
5 | res.json({ec: err ? 2 : 0, em: err ? err.stack : 'success'});
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/rules/unselect.js:
--------------------------------------------------------------------------------
1 | var rules = require('../../../../lib/rules/util').rules;
2 |
3 | module.exports = function(req, res) {
4 | rules.add(req.body.name, req.body.value);
5 | rules.unselect(req.body.name);
6 | res.json({ec: 0, em: 'success', defaultRulesIsDisabled: rules.defaultRulesIsDisabled(), list: rules.getSelectedList()});
7 | };
8 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/server-info.js:
--------------------------------------------------------------------------------
1 | var util = require('./util');
2 |
3 | module.exports = function(req, res) {
4 | res.json({ec: 0, server: util.getServerInfo(req)});
5 | };
6 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/sessions/create-temp-file.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./expimp');
2 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/sessions/expimp.js:
--------------------------------------------------------------------------------
1 | var loadService = require('../../lib/proxy').loadService;
2 | var transformReq = require('../../../../lib/util').transformReq;
3 |
4 | module.exports = function(req, res) {
5 | loadService(function(err, options) {
6 | if (err) {
7 | res.type('text').status(500).send(err.stack || err);
8 | } else {
9 | transformReq(req, res, options.port);
10 | }
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/sessions/export.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./expimp');
2 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/sessions/get-temp-file.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./expimp');
2 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/sessions/import.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./expimp');
2 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/set-custom-column.js:
--------------------------------------------------------------------------------
1 | var util = require('../../../lib/util');
2 | var properties = require('../../../lib/rules/util').properties;
3 |
4 |
5 | function updateName(name, value, key) {
6 | properties.set(name, util.isString(value) ? value.trim().toString(0, 16) : name);
7 | properties.set(name + 'Key', util.isString(key) ? key.trim().substring(0, 72) : '');
8 | }
9 |
10 | module.exports = function(req, res) {
11 | var name = req.body.name;
12 | var value = req.body.value;
13 | if (name === 'Custom1' || name === 'Custom2') {
14 | updateName(name, value, req.body.key);
15 | }
16 | res.json({ ec: 0 });
17 | };
18 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/set-dns-order.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../lib/rules/util').properties;
2 | var config = require('../../../lib/config');
3 |
4 | module.exports = function(req, res) {
5 | properties.setDnsOrder(req.body.order);
6 | res.json({ec: 0, order: config.dnsOrder});
7 | };
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/set-ipv6-only.js:
--------------------------------------------------------------------------------
1 | var properties = require('../../../lib/rules/util').properties;
2 |
3 | module.exports = function(req, res) {
4 | properties.setIPv6Only(req.body.checked);
5 | res.json({ec: 0, ipv6Only: req.body.checked});
6 | };
7 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/socket/abort.js:
--------------------------------------------------------------------------------
1 | var proxy = require('../../lib/proxy');
2 |
3 | var socketMgr = proxy.socketMgr;
4 |
5 | module.exports = function(req, res) {
6 | var reqId = req.body.reqId;
7 | proxy.abortRequest(reqId);
8 | socketMgr.abort(req.body.reqId);
9 | res.json({ec: 0});
10 | };
11 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/socket/change-status.js:
--------------------------------------------------------------------------------
1 | var socketMgr = require('../../lib/proxy').socketMgr;
2 |
3 | module.exports = function(req, res) {
4 | socketMgr.changeStatus(req.body);
5 | res.json({ec: 0});
6 | };
7 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/socket/data.js:
--------------------------------------------------------------------------------
1 | var socketMgr = require('../../lib/proxy').socketMgr;
2 |
3 | module.exports = function(req, res) {
4 | var result = socketMgr.sendData(req.body);
5 | res.json({ec: result === false ? 3 : 0});
6 | };
7 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/status.js:
--------------------------------------------------------------------------------
1 | var config = require('../../../lib/config');
2 |
3 | module.exports = function(_, res) {
4 | res.json({
5 | storage: config.storage || '',
6 | client: config.client,
7 | whistleName: config.whistleName,
8 | name: config.name,
9 | version: config.version
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/top.js:
--------------------------------------------------------------------------------
1 | var proc = require('../../../lib/util/process');
2 |
3 | module.exports = function(req, res) {
4 | res.json(proc);
5 | };
6 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/add.js:
--------------------------------------------------------------------------------
1 | var values = require('../../../../lib/rules/util').values;
2 | var recycleBin = require('../../../../lib/rules/util').values.recycleBin;
3 | var isGroup = require('../../../../lib/util/common').isGroup;
4 |
5 | module.exports = function(req, res) {
6 | var body = req.body;
7 | var list;
8 | var exists = values.exists(body.name);
9 | if (values.add(body.name, body.value, body.clientId) != null) {
10 | if (isGroup(body.name)) {
11 | if (body.focusName) {
12 | values.moveTo(body.name, body.focusName, body.clientId);
13 | }
14 | } else if (body.groupName) {
15 | values.moveToGroup(body.name, body.groupName);
16 | } else if (!exists) {
17 | var group = values.getFirstGroup();
18 | group && values.moveTo(body.name, group.name, body.clientId, null, true);
19 | }
20 | }
21 | if (req.body.recycleFilename) {
22 | recycleBin.remove(req.body.recycleFilename);
23 | list = recycleBin.list();
24 | }
25 | res.json({
26 | ec: 0,
27 | list: list
28 | });
29 | };
30 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/download.js:
--------------------------------------------------------------------------------
1 | var values = require('../../../../lib/rules/util').values;
2 |
3 | module.exports = function(req, res) {
4 | values.download(req.query.name, res);
5 | };
6 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/export.js:
--------------------------------------------------------------------------------
1 | var values = require('../../../../lib/rules/util').values;
2 | var util = require('../util');
3 |
4 | module.exports = function(req, res) {
5 | var exportValues = req.query.values;
6 | try {
7 | exportValues = exportValues && JSON.parse(exportValues);
8 | } catch(e) {
9 | exportValues = null;
10 | }
11 | var result = {};
12 | values.list().forEach(function(file) {
13 | if (!exportValues || exportValues[file.name]) {
14 | result[file.name] = file.data;
15 | }
16 | });
17 | var filename = req.query.filename;
18 | if (filename && typeof filename === 'string') {
19 | if (!/\.(txt|json)/i.test(filename)) {
20 | filename += '.txt';
21 | }
22 | } else {
23 | filename = 'values_' + util.formatDate() + '.txt';
24 | }
25 | res.attachment(filename).send(JSON.stringify(result, null, ' '));
26 | };
27 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/get.js:
--------------------------------------------------------------------------------
1 | var values = require('../../../../lib/rules/util').values;
2 | var properties = require('../../../../lib/rules/util').properties;
3 |
4 | module.exports = function(req, res) {
5 | res.json({
6 | fontSize: properties.get('valuesFontSize'),
7 | theme: properties.get('valuesTheme'),
8 | showLineNumbers: properties.get('valuesShowLineNumbers'),
9 | values: values.list()
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/import.js:
--------------------------------------------------------------------------------
1 | var get = require('./index');
2 | var getReqData = require('../util').getReqData;
3 | var addValues = require('../../../../lib/rules/util').addValues;
4 |
5 | module.exports = function(req, res) {
6 | getReqData(req, function(err, result) {
7 | if (err) {
8 | res.status(200).json({ ec: 2, em: err.message });
9 | } else {
10 | addValues(result.data, result.replace, req.query.clientId);
11 | res.json(get());
12 | }
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/index.js:
--------------------------------------------------------------------------------
1 | var rulesUtil = require('../../../../lib/rules/util');
2 | var values = rulesUtil.values;
3 |
4 | module.exports = function get() {
5 | return {
6 | ec: 0,
7 | list: values.list()
8 | };
9 | };
10 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/list.js:
--------------------------------------------------------------------------------
1 | var get = require('./index');
2 |
3 | module.exports = function(req, res) {
4 | res.json(get());
5 | };
6 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/list2.js:
--------------------------------------------------------------------------------
1 | var get = require('./index');
2 |
3 | module.exports = function(req, res) {
4 | var data;
5 | if (req.query.order) {
6 | data = [];
7 | get().list.forEach(function(item) {
8 | data.push({
9 | name: item.name,
10 | value: item.data
11 | });
12 | });
13 | } else {
14 | data = {};
15 | get().list.forEach(function(item) {
16 | data[item.name] = item.data;
17 | });
18 | }
19 | res.json(data);
20 | };
21 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/move-to.js:
--------------------------------------------------------------------------------
1 | var values = require('../../../../lib/rules/util').values;
2 |
3 | module.exports = function(req, res) {
4 | var body = req.body;
5 | var result = values.moveTo(body.from, body.to, body.clientId, body.group === 'true');
6 | res.json({ec: result ? 0 : 2, em: 'success'});
7 | };
8 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/recycle/list.js:
--------------------------------------------------------------------------------
1 | var recycleBin = require('../../../../../lib/rules/util').values.recycleBin;
2 |
3 | module.exports = function(req, res) {
4 | res.json({
5 | ec: 0,
6 | list: recycleBin.list()
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/recycle/remove.js:
--------------------------------------------------------------------------------
1 | var recycleBin = require('../../../../../lib/rules/util').values.recycleBin;
2 |
3 | module.exports = function(req, res) {
4 | recycleBin.remove(req.body.name);
5 | res.json({
6 | ec: 0,
7 | list: recycleBin.list()
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/recycle/view.js:
--------------------------------------------------------------------------------
1 | var recycleBin = require('../../../../../lib/rules/util').values.recycleBin;
2 |
3 | module.exports = function(req, res) {
4 | var item = recycleBin.getFile(req.query.name);
5 | res.json({
6 | ec: item ? 0 : 3,
7 | data: item && item.data
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/remove.js:
--------------------------------------------------------------------------------
1 | var util = require('../../../../lib/rules/util');
2 |
3 | module.exports = function(req, res) {
4 | util.removeBatch(util.values, req.body);
5 | res.json({ec: 0, em: 'success'});
6 | };
7 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/rename.js:
--------------------------------------------------------------------------------
1 | var values = require('../../../../lib/rules/util').values;
2 |
3 | module.exports = function(req, res) {
4 | var body = req.body;
5 | values.rename(body.name, body.newName, body.clientId);
6 | res.json({ec: 0, em: 'success'});
7 | };
8 |
--------------------------------------------------------------------------------
/biz/webui/cgi-bin/values/value.js:
--------------------------------------------------------------------------------
1 | var values = require('../../../../lib/rules/util').values;
2 |
3 | module.exports = function(req, res) {
4 | res.json({ value: values.get(req.query.key) });
5 | };
6 |
--------------------------------------------------------------------------------
/biz/webui/htdocs.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var ROOT = path.join(__dirname, 'htdocs');
3 |
4 | function getHtmlFile(file) {
5 | return path.join(ROOT, file || '');
6 | }
7 |
8 | exports.getHtmlFile = getHtmlFile;
9 |
10 | function getImgFile(file) {
11 | return path.join(ROOT, 'img', file || '');
12 | }
13 |
14 | exports.getImgFile = getImgFile;
15 |
16 | function getJsFile(file) {
17 | return path.join(ROOT, 'js', file || '');
18 | }
19 |
20 | exports.getJsFile = getJsFile;
21 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/alipay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/alipay.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/amap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/amap.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/android.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/baidu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/baidu.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/brave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/brave.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/browser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/browser.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/cfnetwork.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/cfnetwork.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/chrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/chrome.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/cicc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/cicc.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/cronet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/cronet.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/dingtalk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/dingtalk.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/edge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/edge.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/electron.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/electron.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/firefox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/firefox.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/huawei.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/huawei.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/iphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/iphone.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/jd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/jd.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/mac.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/mac.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/opera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/opera.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/pdd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/pdd.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/qq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/qq.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/safari.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/safari.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/taobao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/taobao.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/tmall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/tmall.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/uc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/uc.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/wechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/wechat.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/weibo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/weibo.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/wework.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/wework.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/app/windows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/app/windows.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/favicon.ico
--------------------------------------------------------------------------------
/biz/webui/htdocs/img/whistle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/img/whistle.png
--------------------------------------------------------------------------------
/biz/webui/htdocs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Whistle Web Debugging Proxy
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/certs.css:
--------------------------------------------------------------------------------
1 | .w-certs-info-dialog {
2 | z-index: 1100;
3 | }
4 |
5 | .w-certs-info-dialog .modal-dialog {
6 | width: 1024px;
7 | }
8 |
9 | .w-certs-info-order {
10 | width: 50px;
11 | }
12 | .w-certs-info-validity {
13 | width: 330px;
14 | }
15 | .w-certs-info-status {
16 | width: 100px;
17 | }
18 | .w-cert-invalid th,
19 | .w-cert-invalid td {
20 | color: red;
21 | }
22 |
23 | .w-certs-info-filename a {
24 | font-size: 12px;
25 | cursor: pointer;
26 | }
27 |
28 | .w-certs-info-filename .glyphicon-lock {
29 | margin-right: 5px;
30 | }
31 |
32 | .w-certs-info-dialog td {
33 | overflow: hidden;
34 | text-overflow: ellipsis;
35 | }
36 |
37 | .w-certs-info-filename {
38 | width: 220px;
39 | }
40 |
41 | .w-certs-info-dialog th,
42 | .w-certs-info-dialog td {
43 | vertical-align: middle !important;
44 | }
45 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/dropdown.css:
--------------------------------------------------------------------------------
1 | .w-dropdown-text {
2 | max-width: 300px;
3 | overflow: hidden;
4 | text-overflow: ellipsis;
5 | white-space: nowrap;
6 | cursor: pointer;
7 | }
8 | .w-dropdown .dropdown-menu .divider {
9 | margin: 0 !important;
10 | }
11 | .w-dropdown .dropdown-menu {
12 | width: auto !important;
13 | max-width: 300px;
14 | white-space: nowrap;
15 | overflow: hidden;
16 | text-overflow: ellipsis;
17 | min-width: auto !important;
18 | display: none;
19 | max-height: 360px;
20 | overflow-x: hidden;
21 | overflow-y: auto;
22 | }
23 | .w-dropdown {
24 | display: inline-block;
25 | }
26 |
27 | .w-dropdown .dropdown-menu li {
28 | padding: 0 10px;
29 | cursor: pointer;
30 | text-overflow: ellipsis;
31 | overflow: hidden;
32 | white-space: nowrap;
33 | }
34 | .w-dropdown .dropdown-menu li:hover {
35 | background: #f5f5f5;
36 | }
37 | .w-dropdown .dropdown-menu a {
38 | padding: 0 10px;
39 | line-height: 20px;
40 | display: block;
41 | text-align: center;
42 | }
43 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/editor-settings.css:
--------------------------------------------------------------------------------
1 | .w-editor-settings label,
2 | .w-editor-settings-box label {
3 | font-weight: normal;
4 | white-space: nowrap;
5 | }
6 | .w-editor-settings label .w-label {
7 | display: inline-block;
8 | width: 60px;
9 | text-align: right;
10 | margin-right: 5px;
11 | }
12 | .w-editor-settings select {
13 | width: 186px;
14 | }
15 | .w-rules-settings-dialog .w-editor-settings select {
16 | width: 260px;
17 | }
18 | .w-editor-settings-box {
19 | padding-left: 65px;
20 | margin: 10px !important;
21 | }
22 | .w-editor-settings .form-control {
23 | display: inline-block;
24 | margin-left: 5px;
25 | }
26 | .w-editor-settings p {
27 | margin: 5px;
28 | }
29 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/editor.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-hints li.CodeMirror-hint-active:after {
2 | content: 'F1';
3 | position: absolute;
4 | right: 0;
5 | font-size: 12px;
6 | }
7 |
8 | .CodeMirror-hints .CodeMirror-hint {
9 | max-width: unset;
10 | position: relative;
11 | padding-right: 20px;
12 | font-family: consolas, monospace;
13 | font-size: 14px;
14 | }
15 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/export-dialog.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/biz/webui/htdocs/src/css/export-dialog.css
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/files-dialog.css:
--------------------------------------------------------------------------------
1 | .w-files-dialog .modal-dialog {
2 | width: 900px;
3 | }
4 |
5 | .w-files-order {
6 | width: 36px;
7 | }
8 | .w-files-date {
9 | width: 205px;
10 | }
11 | .w-files-path {
12 | word-break: break-all;
13 | word-wrap: break-word;
14 | }
15 | .w-files-operation {
16 | width: 240px;
17 | }
18 |
19 | .w-files-operation a {
20 | margin-right: 15px;
21 | display: inline-block;
22 | white-space: nowrap;
23 | }
24 |
25 | .w-files-operation a:last-child {
26 | color: #f66;
27 | }
28 |
29 | .w-files-operation a:last-child:hover {
30 | color: #f00;
31 | }
32 |
33 | .w-files-dialog thead th {
34 | padding: 8px;
35 | }
36 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/iframe-dialog.css:
--------------------------------------------------------------------------------
1 |
2 | .w-iframe-dialog .modal-dialog {
3 | width: max(calc(100% - 240px), 720px);
4 | }
5 |
6 | .w-iframe-dialog .modal-body {
7 | padding: 0;
8 | margin: 0;
9 | width: 100%;
10 | height: max(calc(100vh - 120px), 600px);
11 | }
12 |
13 | .w-iframe-dialog .modal-body iframe {
14 | width: 100%;
15 | height: 100%;
16 | display: block;
17 | border: none;
18 | outline: none;
19 | }
20 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/iframe.css:
--------------------------------------------------------------------------------
1 | .w-iframe {
2 | position: relative;
3 | min-width: 560px;
4 | }
5 |
6 | .w-iframe > iframe.fill {
7 | display: block;
8 | width: 100%;
9 | height: 100%;
10 | outline: none;
11 | border: none;
12 | margin: 0;
13 | padding: 0;
14 | }
15 |
16 | .w-iframe[allow-dragover="1"] > iframe.fill {
17 | pointer-events: none;
18 | }
19 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/image-view.css:
--------------------------------------------------------------------------------
1 | .w-image-view {
2 | font-size: 0;
3 | white-space: nowrap;
4 | overflow: auto;
5 | text-align: center;
6 | position: relative;
7 | }
8 | .w-image-bg {
9 | background: #0e0e0e;
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | }
14 | .w-image-view.w-image-webview {
15 | padding: 0;
16 | display: flex;
17 | }
18 | .w-image-view img {
19 | max-width: 100%;
20 | }
21 | .w-image-view .w-image-link {
22 | display: inline-block;
23 | width: 300px;
24 | line-height: 30px;
25 | position: absolute;
26 | top: 50%;
27 | left: 50%;
28 | margin: -15px 0 0 -150px;
29 | font-size: 14px;
30 | }
31 |
32 | .w-image-view:hover .w-textarea-bar {
33 | display: block;
34 | }
35 |
36 | .w-image-webview .fill {
37 | width: 100%;
38 | }
39 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/import-dialog.css:
--------------------------------------------------------------------------------
1 | .w-ie-dialog .modal-dialog {
2 | width: 600px;
3 | }
4 |
5 | .w-ie-dialog .modal-body {
6 | background-color: #fafafa;
7 | padding: 20px 10px;
8 | }
9 |
10 | .w-ie-dialog input {
11 | width: 578px;
12 | height: 36px;
13 | line-height: 36px;
14 | padding: 5px;
15 | border: 1px solid #ddd;
16 | }
17 |
18 | .w-ie-dialog .modal-footer {
19 | white-space: nowrap;
20 | }
21 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/json-viewer.css:
--------------------------------------------------------------------------------
1 | .w-properties-wrap:hover .w-textarea-bar {
2 | display: inline-block;
3 | }
4 | .w-textarea-bar:hover .w-download {
5 | display: inline-block;
6 | }
7 | .w-textarea-bar .w-properties-btn {
8 | position: static;
9 | }
10 | .w-json-viewer-str,
11 | .w-json-viewer-tree {
12 | padding: 5px;
13 | overflow: auto;
14 | }
15 | .w-json-viewer-tree > ul {
16 | background: none !important;
17 | font-size: 12px;
18 | margin: 0 !important;
19 | }
20 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/kv.css:
--------------------------------------------------------------------------------
1 | .w-kv-dialog {
2 | z-index: 1100;
3 | }
4 |
5 | .w-kv-dialog .modal-dialog {
6 | width: 720px;
7 | }
8 | .w-kv-name {
9 | width: 330px;
10 | white-space: normal;
11 | word-wrap: break-word;
12 | word-break: break-all;
13 | }
14 | .w-kv-dialog .w-kv-box {
15 | width: 36px;
16 | }
17 |
18 | .w-kv-operation pre {
19 | max-height: 70px;
20 | }
21 | .w-kv-operation a {
22 | display: block;
23 | width: 50px;
24 | margin-top: 3px;
25 | }
26 | .w-kv-name strong {
27 | color: #f66;
28 | margin-left: 5px;
29 | cursor: pointer;
30 | }
31 |
32 | .w-kv-dialog thead th, .w-kv-dialog thead td {
33 | padding: 8px;
34 | }
35 |
36 | .w-kv-check-all {
37 | float: left;
38 | margin: 0 0 0 9px;
39 | display: flex;
40 | align-items: center;
41 | }
42 |
43 | .w-kv-check-all input {
44 | margin-right: 8px;
45 | }
46 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/message.css:
--------------------------------------------------------------------------------
1 | .w-message {
2 | position: fixed;
3 | top: 30px;
4 | left: 50%;
5 | z-index: 999999999;
6 | padding: 8px 20px !important;
7 | max-width: 410px;
8 | }
9 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/modal.css:
--------------------------------------------------------------------------------
1 | .w-dialog-for-plguin .modal-header {
2 | display: none;
3 | }
4 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/plugins-mgr.css:
--------------------------------------------------------------------------------
1 | .w-plugins-mgr-dialog {
2 | z-index: 1060;
3 | }
4 |
5 | .w-plugins-mgr-dialog .modal-content {
6 | width: 380px;
7 | }
8 |
9 | .w-plugins-mgr-dialog .plugin-mgr-btn {
10 | display: block;
11 | line-height: 1.5;
12 | width: 320px;
13 | margin: 20px auto;
14 | padding: 15px 10px;
15 | text-align: center;
16 | cursor: pointer;
17 | font-size: 15px;
18 | overflow: hidden;
19 | text-overflow: ellipsis;
20 | font-weight: 500;
21 | }
22 |
23 | .w-plugins-mgr-dialog .plugin-mgr-btn span {
24 | opacity: 0.66;
25 | font-weight: 400;
26 | }
27 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/record-btn.css:
--------------------------------------------------------------------------------
1 | .w-refresh-menu-list .glyphicon-minus-sign,
2 | .w-refresh-menu-list .w-menu-item .glyphicon-stop {
3 | color: #ccc !important;
4 | }
5 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/res-detail.css:
--------------------------------------------------------------------------------
1 | .w-detail-response textarea {
2 | padding: 5px;
3 | border: none;
4 | }
5 | .w-detail-response-headers,
6 | .w-detail-response-cookies {
7 | overflow: auto;
8 | }
9 | .w-detail-response-cookies table {
10 | table-layout: auto;
11 | }
12 | .w-detail-response-cookies thead > th {
13 | white-space: nowrap;
14 | background: #fafafa;
15 | }
16 | .w-detail-response-cookies tbody > tr > td:nth-child(7),
17 | .w-detail-response-cookies tbody > tr > td:nth-child(8),
18 | .w-detail-response-cookies tbody > tr > td:nth-child(10) {
19 | text-align: center;
20 | vertical-align: middle;
21 | }
22 | .w-show-history .w-btn-group-sm {
23 | height: 22px;
24 | overflow: hidden;
25 | }
26 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/service.css:
--------------------------------------------------------------------------------
1 | .w-service-btn {
2 | font-weight: bold;
3 | }
4 |
5 | @media screen and (max-width: 1135px) {
6 | .w-has-token.w-show-rules .w-help-name {
7 | display: none;
8 | }
9 | }
10 |
11 | @media screen and (max-width: 1110px) {
12 | .w-has-token.w-show-rules .w-https-name {
13 | display: none;
14 | }
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/sync-dialog.css:
--------------------------------------------------------------------------------
1 | .w-sync-dialog .modal-dialog {
2 | width: 420px;
3 | }
4 |
5 | .w-sync-dialog .modal-body .btn {
6 | display: block;
7 | width: 398px;
8 | line-height: 40px;
9 | font-size: 18px;
10 | margin: 10px 0;
11 | }
12 |
13 | .w-sync-dialog .modal-body .btn span {
14 | margin-right: 10px;
15 | }
16 |
17 | .w-history-record-list {
18 | margin: 20px 0 15px 10px;
19 | width: 635px;
20 | display: inline-block;
21 | font-weight: normal;
22 | white-space: nowrap;
23 | }
24 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/css/table.css:
--------------------------------------------------------------------------------
1 | .w-table > thead > tr > th {
2 | background: #eee;
3 | font-weight: normal;
4 | border-bottom: 1px solid #ccc;
5 | vertical-align: top;
6 | }
7 |
8 | .w-table th,
9 | .w-table td {
10 | font-size: 12px;
11 | padding: 3px 5px !important;
12 | border-top: none;
13 | border-bottom: 1px solid #ccc;
14 | word-break: break-word;
15 | }
16 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/base-css.js:
--------------------------------------------------------------------------------
1 | require('bootstrap/dist/css/bootstrap.css');
2 | require('../css/base.css');
3 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/components/json/index.js:
--------------------------------------------------------------------------------
1 | exports.parse = require('./parse');
2 | exports.stringify = require('./stringify');
3 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/components/react-json-tree/objType.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.__esModule = true;
4 |
5 | var _iterator = require('babel-runtime/core-js/symbol/iterator');
6 |
7 | var _iterator2 = _interopRequireDefault(_iterator);
8 |
9 | exports['default'] = objType;
10 |
11 | function _interopRequireDefault(obj) {
12 | return obj && obj.__esModule ? obj : { default: obj };
13 | }
14 |
15 | function objType(obj) {
16 | var type = Object.prototype.toString.call(obj).slice(8, -1);
17 | if (type === 'Object' && typeof obj[_iterator2['default']] === 'function') {
18 | return 'Iterable';
19 | }
20 |
21 | if (type === 'String' && obj._$isNumber) {
22 | return 'BigNumber';
23 | }
24 |
25 | if (
26 | type === 'Custom' &&
27 | obj.constructor !== Object &&
28 | obj instanceof Object
29 | ) {
30 | // For projects implementing objects overriding `.prototype[Symbol.toStringTag]`
31 | return 'Object';
32 | }
33 |
34 | return type;
35 | }
36 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/components/react-json-tree/themes/solarized.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.__esModule = true;
4 | exports['default'] = {
5 | scheme: 'solarized',
6 | author: 'ethan schoonover (http://ethanschoonover.com/solarized)',
7 | base00: '#002b36',
8 | base01: '#073642',
9 | base02: '#586e75',
10 | base03: '#657b83',
11 | base04: '#839496',
12 | base05: '#93a1a1',
13 | base06: '#eee8d5',
14 | base07: '#fdf6e3',
15 | base08: '#dc322f',
16 | base09: '#cb4b16',
17 | base0A: '#b58900',
18 | base0B: '#859900',
19 | base0C: '#2aa198',
20 | base0D: '#268bd2',
21 | base0E: '#6c71c4',
22 | base0F: '#d33682'
23 | };
24 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/components/react-json-tree/utils/hexToRgb.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.__esModule = true;
4 |
5 | exports['default'] = function (hex) {
6 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
7 | return result
8 | ? {
9 | r: parseInt(result[1], 16),
10 | g: parseInt(result[2], 16),
11 | b: parseInt(result[3], 16)
12 | }
13 | : null;
14 | };
15 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/copy-btn.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var CopyBtn = React.createClass({
4 | getInitialState: function () {
5 | return {};
6 | },
7 | handleLeave: function () {
8 | this.setState({ copied: false });
9 | },
10 | handleCopy: function () {
11 | this.setState({ copied: true });
12 | },
13 | render: function () {
14 | var copied = this.state.copied;
15 | return (
16 |
24 | {(copied ? 'Copied' : 'Copy') + (this.props.name || '')}
25 |
26 | );
27 | }
28 | });
29 |
30 | module.exports = CopyBtn;
31 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/decode.js:
--------------------------------------------------------------------------------
1 | var toByteArray = require('base64-js').toByteArray;
2 | var base64Decode = require('js-base64').Base64.decode;
3 | var isUtf8 = require('./is-utf8');
4 |
5 | var gbkDecoder;
6 | if (self.TextDecoder) {
7 | try {
8 | gbkDecoder = new self.TextDecoder('GB18030');
9 | } catch (e) {}
10 | }
11 |
12 | function base64toBytes(base64) {
13 | try {
14 | return toByteArray(base64);
15 | } catch (e) {}
16 | }
17 |
18 | self.getText = function(base64) {
19 | var arr = base64 && base64toBytes(base64);
20 | if (!arr) {
21 | return '';
22 | }
23 | if (!isUtf8(arr)) {
24 | try {
25 | if (gbkDecoder) {
26 | return gbkDecoder.decode(arr);
27 | }
28 | } catch (e) {}
29 | }
30 | try {
31 | return base64Decode(base64);
32 | } catch (e) {}
33 | return '';
34 | };
35 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/enable-https-btn.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var dataCenter = require('./data-center');
3 | var events = require('./events');
4 |
5 | var EnableHttpsBtn = React.createClass({
6 | showHttpsSettingsDialog: function () {
7 | events.trigger('showHttpsSettingsDialog');
8 | },
9 | render: function () {
10 | if (dataCenter.isMultiEnv() || dataCenter.isCapture) {
11 | return null;
12 | }
13 | return ;
14 | }
15 | });
16 |
17 | module.exports = EnableHttpsBtn;
18 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/events.js:
--------------------------------------------------------------------------------
1 | var $ = require('jquery');
2 |
3 | module.exports = $({});
4 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/iframe.js:
--------------------------------------------------------------------------------
1 | require('../css/iframe.css');
2 | var React = require('react');
3 | var ReactDOM = require('react-dom');
4 |
5 | var IFrame = React.createClass({
6 | getWindow: function() {
7 | return ReactDOM.findDOMNode(this.refs.iframe).contentWindow;
8 | },
9 | render: function() {
10 | var props = this.props;
11 | var className = props.className;
12 | return (
13 |
14 |
15 |
16 | );
17 | }
18 | });
19 |
20 | module.exports = IFrame;
21 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/lazy-init.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var LazyInit = React.createClass({
4 | render: function () {
5 | if (!this.props.inited && !this._inited) {
6 | return null;
7 | }
8 | this._inited = true;
9 | return this.props.children;
10 | }
11 | });
12 |
13 | module.exports = LazyInit;
14 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/message.js:
--------------------------------------------------------------------------------
1 | var $ = require('jquery');
2 | require('../css/message.css');
3 |
4 | var cache = {};
5 |
6 | function showMessage(msg, level) {
7 | if (level === 'warn') {
8 | level = 'warning';
9 | } else if (level === 'error') {
10 | level = 'danger';
11 | }
12 | var elem = cache[level];
13 | if (!elem) {
14 | elem = $('');
15 | elem.appendTo(document.body);
16 | cache[level] = elem;
17 | }
18 | elem.text(msg);
19 | elem.stop(true, true).show();
20 | elem.css('marginLeft', -elem[0].offsetWidth / 2);
21 | elem.delay(2000).fadeOut(1600);
22 | return elem;
23 | }
24 |
25 | ['error', 'warn', 'info', 'success'].forEach(function (level) {
26 | exports[level] = function (msg) {
27 | return showMessage(msg, level);
28 | };
29 | });
30 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/storage.js:
--------------------------------------------------------------------------------
1 | var PREFIX = location.href
2 | .replace(/[?#].*$/, '')
3 | .replace(/\/index.html$/i, '/');
4 | var cache = {};
5 |
6 | function getKey(key) {
7 | return PREFIX + '?' + key;
8 | }
9 |
10 | exports.set = function (key, value) {
11 | key = getKey(key);
12 | if (value == null) {
13 | value = '';
14 | } else {
15 | value += '';
16 | }
17 | cache[key] = value;
18 | try {
19 | localStorage[key] = value;
20 | } catch (e) {}
21 | };
22 |
23 | exports.get = function (key, noCache) {
24 | key = getKey(key);
25 | try {
26 | return noCache ? localStorage[key] : cache[key] || localStorage[key];
27 | } catch (e) {}
28 | return cache[key];
29 | };
30 |
31 | exports.remove = function(key) {
32 | try {
33 | localStorage.removeItem(getKey(key));
34 | } catch (e) {}
35 | };
36 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/table.js:
--------------------------------------------------------------------------------
1 | require('./base-css.js');
2 | require('../css/table.css');
3 | var React = require('react');
4 |
5 | var Table = React.createClass({
6 | render: function () {
7 | var head = this.props.head;
8 | var hasHead = Array.isArray(head) && head.length;
9 | var modal = this.props.modal || [];
10 |
11 | return (
12 |
13 | {hasHead ? (
14 |
15 | {head.map(function (head) {
16 | return {head} | ;
17 | })}
18 |
19 | ) : (
20 | ''
21 | )}
22 |
23 | {modal.map(function (list, i) {
24 | return (
25 |
26 | {list.map(function (value, j) {
27 | return {value} | ;
28 | })}
29 |
30 | );
31 | })}
32 |
33 |
34 | );
35 | }
36 | });
37 |
38 | module.exports = Table;
39 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/tabs.js:
--------------------------------------------------------------------------------
1 | require('./base-css.js');
2 | var React = require('react');
3 |
4 | var Tabs = React.createClass({
5 | render: function() {
6 | var tabs = this.props.tabs || [];
7 | var onChange = this.props.onChange;
8 |
9 | return (
10 |
31 | );
32 | }
33 | });
34 |
35 | module.exports = Tabs;
36 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/js/update-all-btn.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var events = require('./events');
3 |
4 | var UpdateAllBtn = React.createClass({
5 | getInitialState: function () {
6 | return { disabled: true };
7 | },
8 | componentDidMount: function () {
9 | var self = this;
10 | events.on('setUpdateAllBtnState', function (_, hasNewPlugin) {
11 | self.setState({ disabled: !hasNewPlugin });
12 | });
13 | },
14 | updateAllPlugins: function () {
15 | !this.state.disabled && events.trigger('updateAllPlugins');
16 | },
17 | render: function () {
18 | var hide = this.state.disabled || this.props.hide;
19 | return (
20 |
25 |
26 | Update
27 |
28 | );
29 | }
30 | });
31 |
32 | module.exports = UpdateAllBtn;
33 |
--------------------------------------------------------------------------------
/biz/webui/htdocs/src/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 |
4 | module.exports = {
5 | entry: {
6 | index: path.join(__dirname, './js/index'),
7 | decode: path.join(__dirname, './js/decode')
8 | },
9 | output: {
10 | path: path.join(__dirname, '../js'),
11 | filename: '[name].js'
12 | },
13 | module: {
14 | loaders: [
15 | {
16 | test: /\.js$/,
17 | exclude: /node_modules/,
18 | loader: 'babel-loader'
19 | },
20 | {
21 | test: /\.css$/,
22 | loader: 'style-loader!css-loader'
23 | },
24 | {
25 | test: /\.(png|woff|woff2|eot|ttf|svg)$/,
26 | loader: 'url-loader?limit=1000000'
27 | }
28 | ]
29 | },
30 | plugins: [
31 | new webpack.DefinePlugin({
32 | 'process.env': {
33 | NODE_ENV: '"production"'
34 | }
35 | }),
36 | new webpack.optimize.UglifyJsPlugin({
37 | compress: {
38 | warnings: false
39 | }
40 | })
41 | ]
42 | };
43 |
--------------------------------------------------------------------------------
/biz/webui/lib/proxy.js:
--------------------------------------------------------------------------------
1 | module.exports = function(proxy) {
2 | module.exports = proxy;
3 | };
4 |
--------------------------------------------------------------------------------
/biz/weinre/index.js:
--------------------------------------------------------------------------------
1 | var fork = require('pfork').fork;
2 | var path = require('path');
3 | var util = require('../../lib/util');
4 | var config = require('../../lib/config');
5 |
6 | var options = {
7 | script: path.join(__dirname, 'server.js'),
8 | debugMode: config.debugMode
9 | };
10 |
11 | module.exports = function(req, res) {
12 | fork(options,
13 | function(err, options) {
14 | if (err) {
15 | res.type('text').status(500).send(err.stack || err);
16 | } else {
17 | util.transformReq(req, res, options.port);
18 | }
19 | }
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/biz/weinre/server.js:
--------------------------------------------------------------------------------
1 | var getServer = require('hagent').getServer;
2 | var startWeinre = require('weinre2').run;
3 |
4 | module.exports = function (_, callback) {
5 | getServer(function (server, port) {
6 | startWeinre({
7 | server: server,
8 | verbose: false,
9 | debug: false,
10 | readTimeout: 5,
11 | deathTimeout: 15
12 | });
13 | callback(null, { port: port });
14 | });
15 | };
16 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/assets/host01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/assets/host01.png
--------------------------------------------------------------------------------
/docs/assets/host02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/assets/host02.png
--------------------------------------------------------------------------------
/docs/assets/whistle-en_US.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/assets/whistle-en_US.png
--------------------------------------------------------------------------------
/docs/i18n/en/README.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/i18n/zh/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/about.md:
--------------------------------------------------------------------------------
1 | # Whistle
2 | 1. 代码仓库:https://github.com/avwo/whistle
3 | 2. Whistle 简介:https://github.com/avwo/whistle#readme
4 | 3. 帮助文档:[快速上手](./quickstart.md)
5 |
--------------------------------------------------------------------------------
/docs/i18n/zh/cli/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/cli/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/cli/add.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/cli/add.md
--------------------------------------------------------------------------------
/docs/i18n/zh/cli/ca.md:
--------------------------------------------------------------------------------
1 | # w2 ca
2 | 安装系统根证书命令,目前只支持 Mac 和 Windows 系统。
3 |
4 | # 用法
5 | 1. 安装本机默认 Whistle 实例的证书:
6 | ``` sh
7 | w2 ca
8 | ```
9 | > 安装本地运行的 Whistle 实例根证书(自动检测当前运行的默认实例,如果没有取默认取 `8899` 端口)
10 | 2. 安装指定端口的 Whistle 实例的证书:
11 | ``` sh
12 | w2 ca 8888
13 | ```
14 | > 安装本地 `8888` 端口的 Whistle 根证书
15 | 3. 安装运行在 `host` 和 `port` 的其它 Whistle 或 Nohost 的根证书:
16 | ``` sh
17 | w2 ca xxx.yyy.com:8080
18 | ```
19 | > 可以用来安装其它代理服务的证书
20 | 4. 下载指定 URL 的根证书并安装:
21 | ``` sh
22 | w2 ca url
23 | ```
24 | > 可以用来安装其它代理服务的证书
25 | 5. 下载指定本地路径的根证书并安装:
26 | ``` sh
27 | w2 ca filepath
28 | ```
29 | > 可以用来安装其它代理服务的证书
30 |
31 | 注意,Mac 系统需要指纹验证或输入开机密码:
32 |
33 |
34 |
35 | 如果上述命令系统不支持或安装失败,也可以:[手动安装](../manual/)
36 |
--------------------------------------------------------------------------------
/docs/i18n/zh/cli/env.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/cli/env.md
--------------------------------------------------------------------------------
/docs/i18n/zh/cli/exec.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/cli/exec.md
--------------------------------------------------------------------------------
/docs/i18n/zh/cli/install.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/cli/install.md
--------------------------------------------------------------------------------
/docs/i18n/zh/cli/status.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/cli/status.md
--------------------------------------------------------------------------------
/docs/i18n/zh/extensions/README.md:
--------------------------------------------------------------------------------
1 | # 扩展功能
2 | Whistle 支持两种方式:
3 | 1. 通过插件扩展(推荐)
4 | 2. 作为 npm 包使用
5 |
6 |
--------------------------------------------------------------------------------
/docs/i18n/zh/extensions/npm/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/extensions/npm/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/extensions/npm/api.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/extensions/npm/api.md
--------------------------------------------------------------------------------
/docs/i18n/zh/extensions/npm/dev.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/extensions/npm/dev.md
--------------------------------------------------------------------------------
/docs/i18n/zh/extensions/plugins/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/extensions/plugins/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/extensions/plugins/api.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/extensions/plugins/api.md
--------------------------------------------------------------------------------
/docs/i18n/zh/extensions/plugins/dev.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/extensions/plugins/dev.md
--------------------------------------------------------------------------------
/docs/i18n/zh/extensions/plugins/install.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/extensions/plugins/install.md
--------------------------------------------------------------------------------
/docs/i18n/zh/feedback.md:
--------------------------------------------------------------------------------
1 | # 用户反馈
2 | 遇到问题解决步骤:
3 | 1. 优先查文档:https://wproxy.org/docs/
4 | 2. 查常见问题:https://github.com/avwo/help
5 | 3. 查 Issue:https://github.com/avwo/whistle/issues
6 | 4. 提 Issue:https://github.com/avwo/whistle/issues/new
7 | 5. 提 PR:https://github.com/avwo/whistle/compare
8 | 6. 加 QQ 群:462558941
9 |
10 | # 支持项目
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/i18n/zh/mobile/README.md:
--------------------------------------------------------------------------------
1 | # 手机访问
2 | 手机访问 PC 的 Whistle 需要设置代理及安装根证书:
3 | 1. [iOS](./ios.md)
4 | 2. [Android](./android.md)
5 |
--------------------------------------------------------------------------------
/docs/i18n/zh/mobile/android.md:
--------------------------------------------------------------------------------
1 | # 设置代理
2 | 打开 系统设置 > 无线网络 > 点击你要设置代理的 WiFi > 高级设置 > 手动 > 输入 Whistle 的 `IP` 和 `PORT`
3 | > `IP` 和 `PORT` 可以从 Whistle 管理界面右上角的 Online 过去,如果不确定哪个可以用,每个都试一下,如果设置完所有 IP 还不能访问,看看是不是防火墙问题:https://github.com/avwo/whistle/issues/78
4 |
5 |
6 |
7 |
8 |
9 | # 安装根证书
10 | 1. **必须先按上面方法设置好代理**
11 | 2. 下载 Chrome 浏览器后在 Chrome 地址栏输入:**rootca.pro** 下载安装证书
12 | > 如果安装失败可以尝试输入:**rootca.pro/cer** 下载安装 cer 证书,其它情况参考:https://github.com/avwo/whistle/issues/79
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/i18n/zh/mobile/ios.md:
--------------------------------------------------------------------------------
1 | # 设置代理
2 | 打开 系统设置 > 无线局域网 > 点击 WiFi 右边图标 > 点击底部的配置代理项 > 选择手动代理 > 输入 Whistle 的 `IP` 和 `PORT`
3 | > `IP` 和 `PORT` 可以从 Whistle 管理界面右上角的 Online 过去,如果不确定哪个可以用,每个都试一下,如果设置完所有 IP 还不能访问,看看是不是防火墙问题:https://github.com/avwo/whistle/issues/78
4 |
5 |
6 |
7 |
8 |
9 | # 安装根证书
10 | 1. **必须先按上面方法设置好代理**
11 | 2. 打开 iOS 内置浏览器 Safari 并在地址栏输入:**rootca.pro** 下载证书并点击允许
12 | 3. 设置 > 通用 > VPN与设置管理 > 点击已下载的描述文件 > 点击右上角安装 > 输入锁屏密码 > 再次点击安装
13 | 4. 设置 > 通用 > 关于本机 > 滚动到底部打开证书信任设置 > 信任证书
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/i18n/zh/pc/README.md:
--------------------------------------------------------------------------------
1 | # PC 访问
2 | PC 访问需要设置代理及安装根证书,其中 Firefox 有自己的代理设置入口及根证书管理系统,需要独立设置。
3 | 1. [MAC](./mac.md)
4 | 2. [Windows](./windows.md)
5 | 3. [Firefox](./firefox.md)
6 | 4. [SwitchyOmega](./switchyomega.md)
7 | 5. [其它系统](./others.md)
8 |
--------------------------------------------------------------------------------
/docs/i18n/zh/pc/firefox.md:
--------------------------------------------------------------------------------
1 | # 设置 Firefox 代理
2 | 地址栏输入访问 about:preferences,找到 Network Proxy,选择 手动代理配置(Manual proxy configuration),输入代理服务器地址、端口,保存。
3 |
4 |
5 |
6 | # 安装 Firefox 根证书
7 | 1. 下载根证书,按上述方法设置好代理,在浏览器输入 **rootca.pro** 下载根证书到本地
8 | 2. 菜单 > 首选项 > 高级 > 证书 > 证书机构 > 导入 -> 选中所有checkbox -> 确定
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/i18n/zh/pc/mac.md:
--------------------------------------------------------------------------------
1 | # 设置代理
2 | 通过命令行设置系统代理:[w2 proxy](../cli/proxy.md)
3 |
4 | > Mac 如果不联网系统代理可能会失效,建议提前安装 Chrome 插件 [SwitchyOmega](./switchyomega.md) 备用。
5 |
6 | # 安装根证书
7 | 通过命令行安装根证书:[w2 ca](../cli/ca.md)
8 |
--------------------------------------------------------------------------------
/docs/i18n/zh/pc/others.md:
--------------------------------------------------------------------------------
1 | # 设置代理
2 | Linux: Settings > Network > VPN > Network Proxy > Manual
3 |
4 |
5 |
6 | # 安装根证书
7 | 1. 下载根证书,按上述方法设置好代理,在浏览器输入 **rootca.pro** 下载根证书到本地
8 | 2. Linux 安装较为复杂,根据发行版本的不同,安装位置可能略有变化,以下是一些常用发行版的安装方法:
9 | - ArchLinux: 将下载的 rootCA.crt 复制到 /etc/ca-certificates/trust-source/anchors/ 然后执行 trust extract-compat
10 | - Fedora: 将下载的 rootCA.crt 复制到 /etc/pki/ca-trust/source/anchors 然后执行 trust extract-compat
11 | - Ubuntu/Debian: 将下载的 rootCA.crt 复制到 /usr/share/ca-certificates/ 然后执行 echo "rootCA.crt" >> /etc/ca-certificates.conf && update-ca-certificates
12 | - 如果成功安装,命令 trust list | grep -i whistle 输出不为空。
13 | 3. 小米等支持 Magisk 模块的手机还可以尝试链接中的方式绕开 `ssl pinning`:https://blog.csdn.net/chiehfeng/article/details/134033846
14 |
--------------------------------------------------------------------------------
/docs/i18n/zh/pc/switchyomega.md:
--------------------------------------------------------------------------------
1 | # 通过 SwitchyOmega 设置代理
2 | 1. 设置 Whistle 代理
3 |
4 |
5 | 2. 选择 Whistle 代理
6 |
7 |
8 |
--------------------------------------------------------------------------------
/docs/i18n/zh/pc/windows.md:
--------------------------------------------------------------------------------
1 | # 设置代理
2 | 通过命令行设置系统代理:[w2 proxy](../cli/proxy.md)
3 |
4 | # 安装根证书
5 | 通过命令行安装根证书:[w2 ca](../cli/ca.md)
6 |
--------------------------------------------------------------------------------
/docs/i18n/zh/rules/filters/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/rules/filters/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/rules/modify/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/rules/modify/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/rules/modify/request/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/rules/modify/request/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/rules/modify/response/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/rules/modify/response/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/rules/pattern/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/rules/pattern/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/rules/values/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/rules/values/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/update.md:
--------------------------------------------------------------------------------
1 | # 更新 Whistle
2 | 更新即重新安装并重启:
3 | ``` sh
4 | npm i -g whistle && w2 restart
5 | ```
6 | > 如果安装速度慢可以改用:`npm i -g whistle --registry=https://registry.npmmirror.com && w2 restart`
7 |
8 | 如果出现权限问题导致安装失败,可以改用:
9 | ``` sh
10 | sudo npm i -g whistle
11 | w2 restart
12 | ```
13 |
14 | > 重启后看下命令行输出的版本是不是当前安装的版本,如果不是可能是更新了 Node 导致 PATH 路径更改(建议使用 [nvm](https://github.com/nvm-sh/nvm) 安装 Node),可以通过 `which w2` ( Windows 可以用 `git bash` 查看)路径,把该路径的 `w2` 文件删除,如果删除后找不到命令 `w2`,可以手动配下新 PATH 或者重新安装 Node。
15 |
--------------------------------------------------------------------------------
/docs/i18n/zh/webui/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/webui/README.md
--------------------------------------------------------------------------------
/docs/i18n/zh/webui/about.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/webui/about.md
--------------------------------------------------------------------------------
/docs/i18n/zh/webui/files.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/webui/files.md
--------------------------------------------------------------------------------
/docs/i18n/zh/webui/https.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/webui/https.md
--------------------------------------------------------------------------------
/docs/i18n/zh/webui/network.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/webui/network.md
--------------------------------------------------------------------------------
/docs/i18n/zh/webui/online.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/webui/online.md
--------------------------------------------------------------------------------
/docs/i18n/zh/webui/plugins.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/webui/plugins.md
--------------------------------------------------------------------------------
/docs/i18n/zh/webui/rules.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/webui/rules.md
--------------------------------------------------------------------------------
/docs/i18n/zh/webui/values.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/i18n/zh/webui/values.md
--------------------------------------------------------------------------------
/docs/zh/attention.md:
--------------------------------------------------------------------------------
1 | # 注意事项
2 |
3 | 1. 没有[开启https拦截][1]的https、websocket的请求或者通过https代理过来的socket请求,由于无法获取代理内容的协议或者本身代理内容没有协议,方便配置时区分,whistle把这些请求的协议看成`tunnel:`,所以这里请求只能支持[域名匹配、正则匹配](pattern.html)和形如下面的路径匹配:
4 |
5 | tunnel://host operatorURI
6 | tunnel://host/ operatorURI
7 | tunnel://host:port operatorURI
8 | tunnel://host:port/ operatorURI
9 | 2. https代理也可以代理socket请求,前提对该请求不能[开启https拦截][1],可以在代理头部新增`x-whistle-policy: tunnel`,这时whistle对该HTTPS代理的请求不会[开启https拦截][1],即使whistle本身[开启https拦截][1]。
10 | 3. 还有一些遇到过的问题可以查看:[常见问题](questions.html)
11 | 4. 用户反馈见:[用户反馈](fallback.html)
12 |
13 | [1]: webui/https.html "https拦截"
14 |
--------------------------------------------------------------------------------
/docs/zh/book.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["icp"],
3 | "pluginsConfig": {
4 | "icp": {
5 | "label": "",
6 | "number": "浙ICP备15019507号-2",
7 | "link": "https://beian.miit.gov.cn/"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/docs/zh/cases.md:
--------------------------------------------------------------------------------
1 | # 常见应用
2 |
3 | * [利用 whistle 调试移动端页面](http://imweb.io/topic/5981a34bf8b6c96352a59401)
4 | * [利用 whistle 调试 WebSocket 和 Socket 请求](http://imweb.io/topic/5a11b1b8ef79bc941c30d91a)
5 |
--------------------------------------------------------------------------------
/docs/zh/feedback.md:
--------------------------------------------------------------------------------
1 | # 用户反馈
2 | 遇到问题解决步骤:
3 | 1. 优先查文档:https://wproxy.org/whistle/
4 | 2. 查常见问题:https://github.com/avwo/help
5 | 3. 查 Issue:https://github.com/avwo/whistle/issues
6 | 4. 提 Issue:https://github.com/avwo/whistle/issues/new
7 | 5. 提 PR:https://github.com/avwo/whistle/compare
8 | 6. 加 QQ 群:462558941
9 |
10 | # 支持项目
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/zh/gitbook/images/apple-touch-icon-precomposed-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/gitbook/images/apple-touch-icon-precomposed-152.png
--------------------------------------------------------------------------------
/docs/zh/gitbook/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/gitbook/images/favicon.ico
--------------------------------------------------------------------------------
/docs/zh/img/Android_proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/Android_proxy.png
--------------------------------------------------------------------------------
/docs/zh/img/composer.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/composer.gif
--------------------------------------------------------------------------------
/docs/zh/img/firefox-proxy-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/firefox-proxy-1.jpg
--------------------------------------------------------------------------------
/docs/zh/img/firefox-proxy-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/firefox-proxy-2.jpg
--------------------------------------------------------------------------------
/docs/zh/img/host01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/host01.png
--------------------------------------------------------------------------------
/docs/zh/img/host02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/host02.png
--------------------------------------------------------------------------------
/docs/zh/img/http-request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/http-request.png
--------------------------------------------------------------------------------
/docs/zh/img/https.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/https.gif
--------------------------------------------------------------------------------
/docs/zh/img/iOS-proxy-all.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/iOS-proxy-all.jpg
--------------------------------------------------------------------------------
/docs/zh/img/iOS-proxy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/iOS-proxy.jpg
--------------------------------------------------------------------------------
/docs/zh/img/iOS_proxy.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/iOS_proxy.PNG
--------------------------------------------------------------------------------
/docs/zh/img/iOS_proxy_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/iOS_proxy_settings.png
--------------------------------------------------------------------------------
/docs/zh/img/ios10.3_ca.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/ios10.3_ca.PNG
--------------------------------------------------------------------------------
/docs/zh/img/linux-proxy-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/linux-proxy-1.jpg
--------------------------------------------------------------------------------
/docs/zh/img/linux-proxy-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/linux-proxy-2.jpg
--------------------------------------------------------------------------------
/docs/zh/img/log-basic.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/log-basic.gif
--------------------------------------------------------------------------------
/docs/zh/img/log-switch.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/log-switch.gif
--------------------------------------------------------------------------------
/docs/zh/img/mac-proxy-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/mac-proxy-1.jpg
--------------------------------------------------------------------------------
/docs/zh/img/mac-proxy-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/mac-proxy-2.jpg
--------------------------------------------------------------------------------
/docs/zh/img/network.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/network.gif
--------------------------------------------------------------------------------
/docs/zh/img/online.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/online.gif
--------------------------------------------------------------------------------
/docs/zh/img/plugin-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/plugin-list.png
--------------------------------------------------------------------------------
/docs/zh/img/plugin1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/plugin1.png
--------------------------------------------------------------------------------
/docs/zh/img/plugin2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/plugin2.png
--------------------------------------------------------------------------------
/docs/zh/img/plugin3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/plugin3.png
--------------------------------------------------------------------------------
/docs/zh/img/plugins.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/plugins.gif
--------------------------------------------------------------------------------
/docs/zh/img/rules.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/rules.gif
--------------------------------------------------------------------------------
/docs/zh/img/seq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/seq.png
--------------------------------------------------------------------------------
/docs/zh/img/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/settings.png
--------------------------------------------------------------------------------
/docs/zh/img/start_w2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/start_w2.jpg
--------------------------------------------------------------------------------
/docs/zh/img/switchyomega.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/switchyomega.jpg
--------------------------------------------------------------------------------
/docs/zh/img/tunnel-request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/tunnel-request.png
--------------------------------------------------------------------------------
/docs/zh/img/values.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/values.gif
--------------------------------------------------------------------------------
/docs/zh/img/weinre.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/weinre.gif
--------------------------------------------------------------------------------
/docs/zh/img/windows_rootca.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/docs/zh/img/windows_rootca.jpeg
--------------------------------------------------------------------------------
/docs/zh/mode-options.md:
--------------------------------------------------------------------------------
1 | # 启动参数 `-M m1|m2|mX` 的用途
2 |
3 | 可以通过启动参数 `-M m1|m2|mX` 设置或禁用 Whistle 的一些默认行为,其中 `m1`、`m2`、... 可以为以下参数的任意组合:
4 |
5 | ### disableForwardedProto
6 |
7 | ### disableForwardedHost
8 |
9 | ### network
10 |
11 | ### rules
12 |
13 | ### rulesOnly
14 |
15 | ### plugins
16 |
17 | ### pluginsOnly
18 |
19 | ### shadowRules
20 |
21 | ### shadowRulesOnly
22 |
23 | ### enableMultipleRules
24 |
25 | ### notAllowDisableRules
26 |
--------------------------------------------------------------------------------
/docs/zh/rules/@.md:
--------------------------------------------------------------------------------
1 | # @
2 | 这是一个特殊的符号,主要有一些功能:
3 |
4 | 1. 作为附加值带给插件或[reqScript.html](reqScript.html)、[resScript.html](resScript.html)
5 | ```
6 | pattern @value
7 | ```
8 | > 上述匹配pattern的请求,该请求如果还匹配了[reqScript.html](reqScript.html)、[resScript.html](resScript.html),均可以在里面直接通过全局的 `value` 变量获取该值,如果匹配了插件,可以在插件server的请求 `req.originalReq.globalValue` 获取该值
9 | 2. 可以通过如下配置从远程内联规则:
10 | ```
11 | @http://xxx.com/xxxx
12 | @https://yyy.com/yyyy
13 | ```
14 | > whistle会定时更新规则,远程规则有一些限制,每个远程规则最多配置64k的数据,且每个插件最多只能在 `rules.txt` 文件里面配置一条远程规则,通过界面配置的规则最多只能10条远程规则
15 | 3. 从本地或插件的接口获取规则并内联到现有规则里面(`>= v1.12.13`):
16 | ```
17 | @whistle.nohost/cgi-bin/global-rules
18 | @~/xxx/test.txt
19 | ```
20 | > 本地路径必须为绝对路径,如:`/User/xxx/test.txt`、`~/xxx/test.txt`、`e:/xxx/test.txt`、`e:\xxx\test.txt`,其中本地路径分割`/` 和 `\` 等价
21 | 4. 功能扩展,具体参见:[nohost](https://github.com/imweb/nohost)
22 |
--------------------------------------------------------------------------------
/docs/zh/rules/accept.md:
--------------------------------------------------------------------------------
1 | # accept
2 | 为尽可能缩减协议,减少复杂度,该协议已在最新版本的 whistle (`>=v1.12.3`) 中删除,请及时[更新whistle](../update.html),并用[reqHeaders](./reqHeaders.html)代替:
3 | ```
4 | pattern reqHeaders://accept=acceptType
5 | ```
6 |
7 |
--------------------------------------------------------------------------------
/docs/zh/rules/etag.md:
--------------------------------------------------------------------------------
1 | # etag
2 | 为尽可能缩减协议,减少复杂度,该协议已在最新版本的 whistle (`>=v1.12.3`) 中删除,请及时[更新whistle](../update.html),并用[reqHeaders](./reqHeaders.html)代替:
3 | ```
4 | pattern reqHeaders://etag=xxxxxxxx
5 | ```
6 |
7 | #### 过滤规则
8 | 需要确保whistle是最新版本:[更新whistle](../update.html)
9 |
10 | 如果要过滤指定请求或指定协议的规则匹配,可以用如下协议:
11 |
12 | 1. [ignore](./ignore.html):忽略指定规则
13 | 2. [filter](./filter.html):过滤指定pattern,支持根据请求方法、请求头、请求客户端IP过滤
14 |
15 | 例子:
16 |
17 | ```
18 | # 下面表示匹配pattern的同时不能为post请求且请求头里面的cookie字段必须包含test(忽略大小写)、url里面必须包含 cgi-bin 的请求
19 | # 即:过滤掉匹配filter里面的请求
20 | pattern operator1 operator2 excludeFilter://m:post includeFilter://h:cookie=test includeFilter:///cgi-bin/i
21 |
22 | # 下面表示匹配pattern1、pattern2的请求方法为post、或请求头里面的cookie字段不能包含类似 `uin=123123` 且url里面必须包含 cgi-bin 的请求
23 | operator pattern1 pattern2 includeFilter://m:post excludeFilter://h:cookie=/uin=o\d+/i excludeFilter:///cgi-bin/i
24 |
25 | # 下面表示匹配pattern的请求忽略除了host以外的所有规则
26 | pattern ignore://*|!host
27 |
28 | # 下面表示匹配pattern的请求忽略file和host协议的规则
29 | pattern ignore://file|host
30 | ```
31 |
--------------------------------------------------------------------------------
/docs/zh/rules/hostname.md:
--------------------------------------------------------------------------------
1 | # hostname
2 | 为尽可能缩减协议,减少复杂度,该协议已在最新版本的 whistle (`>=v1.12.3`) 中删除,请及时[更新whistle](../update.html),并用[reqHeaders](./reqHeaders.html)代替:
3 | ```
4 | pattern reqHeaders://host=www.qq.com
5 | ```
6 |
7 |
--------------------------------------------------------------------------------
/docs/zh/rules/http-proxy.md:
--------------------------------------------------------------------------------
1 | 同 [proxy](./proxy.html)。
2 |
--------------------------------------------------------------------------------
/docs/zh/rules/location.md:
--------------------------------------------------------------------------------
1 | # location
2 | 为尽可能缩减协议,减少复杂度,该协议已在最新版本的 whistle (`>=v1.12.3`) 中删除,请及时[更新whistle](../update.html),并用[resHeaders](./resHeaders.html)代替:
3 | ```
4 | pattern resHeaders://location=newUrl
5 | ```
6 |
7 | #### 过滤规则
8 | 需要确保whistle是最新版本:[更新whistle](../update.html)
9 |
10 | 如果要过滤指定请求或指定协议的规则匹配,可以用如下协议:
11 |
12 | 1. [ignore](./ignore.html):忽略指定规则
13 | 2. [filter](./filter.html):过滤指定pattern,支持根据请求方法、请求头、请求客户端IP过滤
14 |
15 | 例子:
16 |
17 | ```
18 | # 下面表示匹配pattern的同时不能为post请求且请求头里面的cookie字段必须包含test(忽略大小写)、url里面必须包含 cgi-bin 的请求
19 | # 即:过滤掉匹配filter里面的请求
20 | pattern operator1 operator2 excludeFilter://m:post includeFilter://h:cookie=test includeFilter:///cgi-bin/i
21 |
22 | # 下面表示匹配pattern1、pattern2的请求方法为post、或请求头里面的cookie字段不能包含类似 `uin=123123` 且url里面必须包含 cgi-bin 的请求
23 | operator pattern1 pattern2 includeFilter://m:post excludeFilter://h:cookie=/uin=o\d+/i excludeFilter:///cgi-bin/i
24 |
25 | # 下面表示匹配pattern的请求忽略除了host以外的所有规则
26 | pattern ignore://*|!host
27 |
28 | # 下面表示匹配pattern的请求忽略file和host协议的规则
29 | pattern ignore://file|host
30 | ```
31 |
--------------------------------------------------------------------------------
/docs/zh/rules/method.md:
--------------------------------------------------------------------------------
1 |
2 | # method
3 | 修改请求方法,配置方式:
4 |
5 | pattern method://newMethod
6 |
7 | pattern参见[匹配方式](../pattern.html),更多模式请参考[配置方式](../mode.html)。
8 |
9 | 例子:
10 |
11 |
12 | www.ifeng.com method://post
13 |
14 | #### 过滤规则
15 | 需要确保whistle是最新版本:[更新whistle](../update.html)
16 |
17 | 如果要过滤指定请求或指定协议的规则匹配,可以用如下协议:
18 |
19 | 1. [ignore](./ignore.html):忽略指定规则
20 | 2. [filter](./filter.html):过滤指定pattern,支持根据请求方法、请求头、请求客户端IP过滤
21 |
22 | 例子:
23 |
24 | ```
25 | # 下面表示匹配pattern的同时不能为post请求且请求头里面的cookie字段必须包含test(忽略大小写)、url里面必须包含 cgi-bin 的请求
26 | # 即:过滤掉匹配filter里面的请求
27 | pattern operator1 operator2 excludeFilter://m:post includeFilter://h:cookie=test includeFilter:///cgi-bin/i
28 |
29 | # 下面表示匹配pattern1、pattern2的请求方法为post、或请求头里面的cookie字段不能包含类似 `uin=123123` 且url里面必须包含 cgi-bin 的请求
30 | operator pattern1 pattern2 includeFilter://m:post excludeFilter://h:cookie=/uin=o\d+/i excludeFilter:///cgi-bin/i
31 |
32 | # 下面表示匹配pattern的请求忽略除了host以外的所有规则
33 | pattern ignore://*|!host
34 |
35 | # 下面表示匹配pattern的请求忽略file和host协议的规则
36 | pattern ignore://file|host
37 | ```
38 |
--------------------------------------------------------------------------------
/docs/zh/rules/params.md:
--------------------------------------------------------------------------------
1 | # params
2 | > 同[reqMerge](reqMerge.html)
3 |
--------------------------------------------------------------------------------
/docs/zh/rules/reqDelay.md:
--------------------------------------------------------------------------------
1 | # reqDelay
2 |
3 | 设置延迟请求的时间(单位:毫秒),配置方式:
4 |
5 | pattern reqDelay://timeMS
6 |
7 | pattern参见[匹配方式](../pattern.html),更多模式请参考[配置方式](../mode.html)。
8 |
9 | 例子:
10 |
11 | www.ifeng.com reqDelay://3000
12 |
13 | #### 过滤规则
14 | 需要确保whistle是最新版本:[更新whistle](../update.html)
15 |
16 | 如果要过滤指定请求或指定协议的规则匹配,可以用如下协议:
17 |
18 | 1. [ignore](./ignore.html):忽略指定规则
19 | 2. [filter](./filter.html):过滤指定pattern,支持根据请求方法、请求头、请求客户端IP过滤
20 |
21 | 例子:
22 |
23 | ```
24 | # 下面表示匹配pattern的同时不能为post请求且请求头里面的cookie字段必须包含test(忽略大小写)、url里面必须包含 cgi-bin 的请求
25 | # 即:过滤掉匹配filter里面的请求
26 | pattern operator1 operator2 excludeFilter://m:post includeFilter://h:cookie=test includeFilter:///cgi-bin/i
27 |
28 | # 下面表示匹配pattern1、pattern2的请求方法为post、或请求头里面的cookie字段不能包含类似 `uin=123123` 且url里面必须包含 cgi-bin 的请求
29 | operator pattern1 pattern2 includeFilter://m:post excludeFilter://h:cookie=/uin=o\d+/i excludeFilter:///cgi-bin/i
30 |
31 | # 下面表示匹配pattern的请求忽略除了host以外的所有规则
32 | pattern ignore://*|!host
33 |
34 | # 下面表示匹配pattern的请求忽略file和host协议的规则
35 | pattern ignore://file|host
36 | ```
37 |
--------------------------------------------------------------------------------
/docs/zh/rules/reqSpeed.md:
--------------------------------------------------------------------------------
1 | # reqSpeed
2 |
3 | 设置请求速度(单位:kb/s,千比特/每秒),配置方式:
4 |
5 | pattern reqSpeed://kbs
6 |
7 | pattern参见[匹配方式](../pattern.html),更多模式请参考[配置方式](../mode.html)。
8 |
9 | 例子:
10 |
11 | www.ifeng.com reqSpeed://3
12 |
13 | #### 过滤规则
14 | 需要确保whistle是最新版本:[更新whistle](../update.html)
15 |
16 | 如果要过滤指定请求或指定协议的规则匹配,可以用如下协议:
17 |
18 | 1. [ignore](./ignore.html):忽略指定规则
19 | 2. [filter](./filter.html):过滤指定pattern,支持根据请求方法、请求头、请求客户端IP过滤
20 |
21 | 例子:
22 |
23 | ```
24 | # 下面表示匹配pattern的同时不能为post请求且请求头里面的cookie字段必须包含test(忽略大小写)、url里面必须包含 cgi-bin 的请求
25 | # 即:过滤掉匹配filter里面的请求
26 | pattern operator1 operator2 excludeFilter://m:post includeFilter://h:cookie=test includeFilter:///cgi-bin/i
27 |
28 | # 下面表示匹配pattern1、pattern2的请求方法为post、或请求头里面的cookie字段不能包含类似 `uin=123123` 且url里面必须包含 cgi-bin 的请求
29 | operator pattern1 pattern2 includeFilter://m:post excludeFilter://h:cookie=/uin=o\d+/i excludeFilter:///cgi-bin/i
30 |
31 | # 下面表示匹配pattern的请求忽略除了host以外的所有规则
32 | pattern ignore://*|!host
33 |
34 | # 下面表示匹配pattern的请求忽略file和host协议的规则
35 | pattern ignore://file|host
36 | ```
37 |
--------------------------------------------------------------------------------
/docs/zh/rules/resDelay.md:
--------------------------------------------------------------------------------
1 | # resDelay
2 |
3 | 设置延迟响应的时间(单位:毫秒),配置方式:
4 |
5 | pattern resDelay://timeMS
6 |
7 | pattern参见[匹配方式](../pattern.html),更多模式请参考[配置方式](../mode.html)。
8 |
9 | 例子:
10 |
11 | www.ifeng.com resDelay://3000
12 |
13 | #### 过滤规则
14 | 需要确保whistle是最新版本:[更新whistle](../update.html)
15 |
16 | 如果要过滤指定请求或指定协议的规则匹配,可以用如下协议:
17 |
18 | 1. [ignore](./ignore.html):忽略指定规则
19 | 2. [filter](./filter.html):过滤指定pattern,支持根据请求方法、请求头、请求客户端IP过滤
20 |
21 | 例子:
22 |
23 | ```
24 | # 下面表示匹配pattern的同时不能为post请求且请求头里面的cookie字段必须包含test(忽略大小写)、url里面必须包含 cgi-bin 的请求
25 | # 即:过滤掉匹配filter里面的请求
26 | pattern operator1 operator2 excludeFilter://m:post includeFilter://h:cookie=test includeFilter:///cgi-bin/i
27 |
28 | # 下面表示匹配pattern1、pattern2的请求方法为post、或请求头里面的cookie字段不能包含类似 `uin=123123` 且url里面必须包含 cgi-bin 的请求
29 | operator pattern1 pattern2 includeFilter://m:post excludeFilter://h:cookie=/uin=o\d+/i excludeFilter:///cgi-bin/i
30 |
31 | # 下面表示匹配pattern的请求忽略除了host以外的所有规则
32 | pattern ignore://*|!host
33 |
34 | # 下面表示匹配pattern的请求忽略file和host协议的规则
35 | pattern ignore://file|host
36 | ```
37 |
--------------------------------------------------------------------------------
/docs/zh/rules/resSpeed.md:
--------------------------------------------------------------------------------
1 | # resSpeed
2 |
3 | 设置响应速度(单位:kb/s,千比特/每秒),配置方式:
4 |
5 | pattern resSpeed://kbs
6 |
7 | pattern参见[匹配方式](../pattern.html),更多模式请参考[配置方式](../mode.html)。
8 |
9 | 例子:
10 |
11 | www.ifeng.com resSpeed://3
12 |
13 | #### 过滤规则
14 | 需要确保whistle是最新版本:[更新whistle](../update.html)
15 |
16 | 如果要过滤指定请求或指定协议的规则匹配,可以用如下协议:
17 |
18 | 1. [ignore](./ignore.html):忽略指定规则
19 | 2. [filter](./filter.html):过滤指定pattern,支持根据请求方法、请求头、请求客户端IP过滤
20 |
21 | 例子:
22 |
23 | ```
24 | # 下面表示匹配pattern的同时不能为post请求且请求头里面的cookie字段必须包含test(忽略大小写)、url里面必须包含 cgi-bin 的请求
25 | # 即:过滤掉匹配filter里面的请求
26 | pattern operator1 operator2 excludeFilter://m:post includeFilter://h:cookie=test includeFilter:///cgi-bin/i
27 |
28 | # 下面表示匹配pattern1、pattern2的请求方法为post、或请求头里面的cookie字段不能包含类似 `uin=123123` 且url里面必须包含 cgi-bin 的请求
29 | operator pattern1 pattern2 includeFilter://m:post excludeFilter://h:cookie=/uin=o\d+/i excludeFilter:///cgi-bin/i
30 |
31 | # 下面表示匹配pattern的请求忽略除了host以外的所有规则
32 | pattern ignore://*|!host
33 |
34 | # 下面表示匹配pattern的请求忽略file和host协议的规则
35 | pattern ignore://file|host
36 | ```
37 |
--------------------------------------------------------------------------------
/docs/zh/rules/rule/README.md:
--------------------------------------------------------------------------------
1 | # 响应规则列表
2 |
3 | 1. [**请求替换**](replace.html)
4 | 1. [**file** (替换本地文件)](file.html)
5 | 1. [**xfile** (替换本地文件,如果本地文件不存在,则请求线上)](file.html)
6 | 1. [**rawfile** (替换本地http响应内容格式的文件)](rawfile.html)
7 | 1. [**xrawfile** (替换本地http响应内容格式的文件,如果本地文件不存在,则请求线上)](rawfile.html)
8 | 1. [**tpl** (替换本地目标文件,可用于模拟jsonp请求)](tpl.html)
9 | 1. [**xtpl** (同上,与xfile类似)](tpl.html)
10 | 1. [**redirect** (302 重定向)](redirect.html)
11 | 2. [**locationHref** (浏览器重定向)](locationHref.html)
12 | 3. [**statusCode** (设置响应状态码)](statusCode.html)
13 | 4. [**自定义**](custom.html)
14 |
--------------------------------------------------------------------------------
/docs/zh/rules/rule/custom.md:
--------------------------------------------------------------------------------
1 | # 自定义规则
2 |
3 | whistle提供了插件的方式扩展协议,具体参考:[插件开发](../../plugins.html)
--------------------------------------------------------------------------------
/docs/zh/rules/rule/xfile.md:
--------------------------------------------------------------------------------
1 |
2 | # xfile
3 |
4 | __xfile功能同file一样,xfile和file的唯一区别是file找不到对应文件返回404,而xfile则是继续请求线上资源。__
5 |
6 |
7 | 用法参考 [file](file.html)
8 |
9 | #### 过滤规则
10 | 需要确保whistle是最新版本:[更新whistle](../../update.html)
11 |
12 | 如果要过滤指定请求或指定协议的规则匹配,可以用如下协议:
13 |
14 | 1. [ignore](../ignore.html):忽略指定规则
15 | 2. [filter](../filter.html):过滤指定pattern,支持根据请求方法、请求头、请求客户端IP过滤
16 |
17 | 例子:
18 |
19 | ```
20 | # 下面表示匹配pattern的同时不能为post请求且请求头里面的cookie字段必须包含test(忽略大小写)、url里面必须包含 cgi-bin 的请求
21 | # 即:过滤掉匹配filter里面的请求
22 | pattern operator1 operator2 excludeFilter://m:post includeFilter://h:cookie=test includeFilter:///cgi-bin/i
23 |
24 | # 下面表示匹配pattern1、pattern2的请求方法为post、或请求头里面的cookie字段不能包含类似 `uin=123123` 且url里面必须包含 cgi-bin 的请求
25 | operator pattern1 pattern2 includeFilter://m:post excludeFilter://h:cookie=/uin=o\d+/i excludeFilter:///cgi-bin/i
26 |
27 | # 下面表示匹配pattern的请求忽略除了host以外的所有规则
28 | pattern ignore://*|!host
29 |
30 | # 下面表示匹配pattern的请求忽略file和host协议的规则
31 | pattern ignore://file|host
32 | ```
33 |
--------------------------------------------------------------------------------
/docs/zh/rules/rule/xrawfile.md:
--------------------------------------------------------------------------------
1 | # xrawfile
2 |
3 | __xrawfile功能同rawfile一样,和rawfile的唯一区别是rawfile找不到对应文件返回404,而xrawfile则是继续请求线上资源。__
4 |
5 | 用法参考 [rawfile](rawfile.html)
6 |
--------------------------------------------------------------------------------
/docs/zh/rules/rule/xtpl.md:
--------------------------------------------------------------------------------
1 | # xtpl
2 |
3 | __xtpl功能同tpl一样,和tpl的唯一区别是tpl找不到对应文件返回404,而xtpl则是继续请求线上资源。__
4 |
5 |
6 | 用法参考 [tpl](tpl.html)
7 |
--------------------------------------------------------------------------------
/docs/zh/rules/sniCallback.md:
--------------------------------------------------------------------------------
1 | # sniCallback
2 | 通过插件自定义请求的证书,实现参考:https://github.com/whistle-plugins/whistle.sni-callback
3 |
--------------------------------------------------------------------------------
/docs/zh/rules/statusCode.md:
--------------------------------------------------------------------------------
1 | [点击查看新文档](rule/statusCode.html)
2 |
--------------------------------------------------------------------------------
/docs/zh/update.md:
--------------------------------------------------------------------------------
1 | # 更新 Whistle
2 | > 以下是命令行版本的更新指引,有关 Whistle 客户端的安装与更新请参考:https://github.com/avwo/whistle-client
3 |
4 | 更新(即于重新安装并重启)命令:
5 | ``` sh
6 | npm i -g whistle && w2 restart
7 | ```
8 | > 如果安装速度慢可以改用:`npm i -g whistle --registry=https://registry.npmmirror.com && w2 restart`
9 |
10 | 如果出现权限问题导致安装失败,可以改用:
11 | ``` sh
12 | sudo npm i -g whistle
13 | w2 restart
14 | ```
15 |
16 | > 重启后看下命令行输出的版本是不是当前安装的版本,如果不是可能是更新了 Node 导致 PATH 路径更改(建议使用 [nvm](https://github.com/nvm-sh/nvm) 安装 Node),可以通过 `which w2`(Windows 可以用 `git bash` 查看)路径,把该路径的 `w2` 文件删除,如果删除后找不到命令 `w2`,可以手动配下新 PATH 或者重新安装 Node。
17 |
--------------------------------------------------------------------------------
/docs/zh/webui/README.md:
--------------------------------------------------------------------------------
1 | # 界面列表
2 |
3 | 1. [Network(请求列表页面)](network.md)
4 | 1. [Composer(构造请求)](composer.md)
5 | 1. [Log(日志平台)](log.md)
6 | 1. [Rules(操作规则配置界面)](rules.md)
7 | 1. [Values(存放KeyValue的系统)](values.md)
8 | 1. [Plugins(插件列表页面)](plugins.md)
9 | 1. [WebSocket(WebSocket抓包功能)](websocket.md)
10 | 1. [Filter(设置Network请求列表的过滤条件)](filter.md)
11 | 1. [Settings(设置对话框)](settings.md)
12 | 1. [Weinre(weinre列表)](weinre.md)
13 | 1. [HTTPS(设置HTTPS拦截及根证书)](https.md)
14 | 1. [Help(帮助文档)](help.md)
15 | 1. [About(whistle版本信息)](about.md)
16 | 1. [Online(在线状态及服务器信息)](online.md)
17 | 1. [Mock(快速设置规则)](mock.md)
18 |
--------------------------------------------------------------------------------
/docs/zh/webui/composer.md:
--------------------------------------------------------------------------------
1 | # Componser
2 |
3 | 用来重发请求、构造请求,可以自定义请求的url、请求方法、请求头、请求内容。
4 |
5 | 
--------------------------------------------------------------------------------
/docs/zh/webui/filter.md:
--------------------------------------------------------------------------------
1 | # Filter
2 | 
3 |
4 | ### Exclude Filter
5 | 表示只要匹配其中一个条件的请求就不会在当前页面的Network里面显示,多个条件用空格或换行分割,支持以下条件,/^(m|i|h|b|c|d|H):
6 |
7 | 1. `m:pattern`:pattern为字符串或正则表达式,匹配请求方法包含该字符串(不区分大小写)或匹配该正则的请求
8 | 2. `i:ip`:ip表示客户端ip或正则表达式,匹配客户端ip包含该字符串(不区分大小写)或匹配该正则的请求
9 | 3. `h:header`:header表示请求头rawData的某部分字符或正则表达式,匹配请求头包含该字符串(不区分大小写)或匹配该正则的请求
10 | 4. `H:host`:host表示Network里面的host字段,为请求的域名加端口,匹配请求host字段包含该字符串(不区分大小写)或匹配该正则的请求
11 | 5. `其它`:正则或普通字符串,匹配请求URL包含该字符串(不区分大小写)或匹配该正则的请求
12 |
13 | > 可以通过右键 `Filter -> This URL 或 This Host` 快速过滤当前URL或host的请求
14 |
15 | ### Include Filter
16 | 表示如果里面设置了条件,则要匹配该条件,且不匹配 `Exclude Filter` 的请求才会显示在当前页面的Network里面,可设置的条件及分割符同 `Exclude Filter`。
17 |
--------------------------------------------------------------------------------
/docs/zh/webui/log.md:
--------------------------------------------------------------------------------
1 | # Log
2 |
3 | > 主要用于调试远程页面特别是移动端页面,可以通过此功能把远程页面 `console` 打印的信息展示出来,使用方法参见 [log](../rules/log.html)。
4 |
5 | 
6 |
7 | 其中:
8 |
9 | 1. `Console` 显示页面抛出的异常或通过 `console` 打印的信息
10 | 2. `Server` 显示 whistle 内部发生的异常信息
11 | 3. `All Logs` 用于切换不同页面的 log 显示,这个功能详见 [log 高级使用](../rules/log.html)
--------------------------------------------------------------------------------
/docs/zh/webui/mock.md:
--------------------------------------------------------------------------------
1 | # Mock 对话框
2 |
3 |
4 |
5 |
6 |
7 |
8 | 1. URL Pattern:匹配请求 URL 的表达式,参见:(pattern)[../pattern.html]
9 | 2. Operation:操作指令
10 | - 操作协议:(协议列表)[../rules]
11 | - 操作值类型:Inline 或 Key-Value 模式
12 | - Inline:内嵌到 Rules 里面
13 | - Key-Value:设置 Key Name,选择默认值,编辑内容,最终存到 Values 里面
14 | - Rules:显示当前将生成的规则(可以删除或 Copy)
15 |
--------------------------------------------------------------------------------
/docs/zh/webui/online.md:
--------------------------------------------------------------------------------
1 | # Online
2 | 当前whistle是否在线及查看whistle服务的基本信息,包括:
3 |
4 | - 运行的Node版本
5 | - whistle的端口号及IP,方便移动端配置代理
6 |
7 | 
--------------------------------------------------------------------------------
/docs/zh/webui/plugins.md:
--------------------------------------------------------------------------------
1 | # Plugins
2 | > 如何开发插件参考:[插件开发](../plugins.html)
3 |
4 | 显示所有已安装的插件列表,开启关闭插件功能,打开插件的管理页面等。
5 |
6 | 
--------------------------------------------------------------------------------
/docs/zh/webui/values.md:
--------------------------------------------------------------------------------
1 | # Values
2 | 配置`key-value`的数据,在Rules里面配置可以通过`{key}`获取,如:`www.ifeng.com file://{key}`
3 |
4 | 
5 |
6 | 界面操作的一些快捷键:
7 |
8 | 1. `Ctrl + D`(Mac用`Command + D`):
9 | - 如果焦点在左侧的列表,可以删除列表项
10 | - 如果焦点在右侧的编辑框,可以删除光标所在行
11 | 2. `Ctrl + /`(Mac用`Command + /`): 注释编辑框中选中的行
12 | 3. `Ctrl + S`(Mac用`Command + S`): 保存当前编辑的内容
--------------------------------------------------------------------------------
/docs/zh/webui/weinre.md:
--------------------------------------------------------------------------------
1 | # Weinre
2 | 集成[weinre](http://people.apache.org/~pmuellr/weinre/docs/latest/)的功能,用户只需通过简单配置(`pattern weinre://id`)即可使用,具体参见[weinre](../rules/weinre.html),更多移动端调试方法可以参考:[利用whistle调试移动端页面](http://imweb.io/topic/5981a34bf8b6c96352a59401)。
3 |
4 | > 强制刷新 Elements:在 Elements 面板里面的元素可能存在与源页面不同步的情况,可以切换到 Remote 面板并再次点击当前选中的请求链接,再切换会 Elements 面板实现强制刷新
5 |
6 | 
--------------------------------------------------------------------------------
/lib/handlers/error-handler.js:
--------------------------------------------------------------------------------
1 | var util = require('../util');
2 |
3 | module.exports = function (err, req, res, _) {
4 | res.response(util.wrapGatewayError(util.getErrorStack(err)));
5 | };
6 |
--------------------------------------------------------------------------------
/lib/handlers/final-handler.js:
--------------------------------------------------------------------------------
1 | module.exports = function (req, res, next) {
2 | next(new Error('Unknown protocol ' + req.options.protocol));
3 | };
4 |
--------------------------------------------------------------------------------
/lib/handlers/http-proxy.js:
--------------------------------------------------------------------------------
1 | module.exports = function (req, res, next) {
2 | if (!req.isWebProtocol) {
3 | next();
4 | } else {
5 | req.request(req.options);
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/lib/handlers/index.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | './file-proxy',
3 | './plugin-handler',
4 | './http-proxy',
5 | './final-handler',
6 | './error-handler'
7 | ].map(function (mod) {
8 | return require(mod);
9 | });
10 |
--------------------------------------------------------------------------------
/lib/inspectors/index.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | './rules',
3 | './weinre',
4 | './log',
5 | './req',
6 | './data',
7 | './res'
8 | ].map(function (mod) {
9 | return require(mod);
10 | });
11 |
--------------------------------------------------------------------------------
/lib/service/installer.js:
--------------------------------------------------------------------------------
1 |
2 | var cp = require('child_process');
3 | var plugin = require('../../bin/plugin');
4 |
5 | var CMD_SUFFIX = process.platform === 'win32' ? '.cmd' : '';
6 |
7 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';
8 |
9 | function getVersion() {
10 | try {
11 | var result = cp.spawnSync('npm' + CMD_SUFFIX, ['-v'], plugin.formatCmdOpions({})).stdout;
12 | return result && result.toString().trim();
13 | } catch (e) {}
14 | }
15 |
16 | process.on('data', function (data) {
17 | if (!Array.isArray(data && data.pkgs)) {
18 | return;
19 | }
20 | var argv = data.pkgs.map(function(item) {
21 | return item.name + (item.version ? '@' + item.version : '');
22 | });
23 | if (data.whistleDir) {
24 | argv.push('--dir=' + data.whistleDir);
25 | }
26 | if (data.registry) {
27 | argv.push('--registry=' + data.registry);
28 | }
29 | plugin.install('npm', argv);
30 | });
31 |
32 | module.exports = function (_, callback) {
33 | var version = getVersion() || getVersion();
34 | callback(null, version);
35 | };
36 |
--------------------------------------------------------------------------------
/lib/service/plugin.js:
--------------------------------------------------------------------------------
1 | var fork = require('pfork').fork;
2 | var path = require('path');
3 |
4 | var debugMode;
5 | var script = path.join(__dirname, 'installer.js');
6 |
7 | function loadInstaller(callback) {
8 | fork(
9 | {
10 | script: script,
11 | debugMode: debugMode
12 | },
13 | callback
14 | );
15 | }
16 |
17 |
18 | module.exports = function(config) {
19 | debugMode = config.debugMode;
20 | loadInstaller(function(_, version, proc) {
21 | if (!version) {
22 | return proc && proc.kill();
23 | }
24 | config.epm = true;
25 | config.installPlugins = function(data) {
26 | loadInstaller(function(_, __, child) {
27 | child && child.sendData(data);
28 | });
29 | };
30 | });
31 | };
32 |
--------------------------------------------------------------------------------
/lib/util/buf-util.js:
--------------------------------------------------------------------------------
1 | exports.indexOf = function (buf, subBuf, start) {
2 | start = start || 0;
3 | var subLen = subBuf.length;
4 | if (!subLen) {
5 | return -1;
6 | }
7 | var len = buf.length - subLen;
8 | if (len < start) {
9 | return -1;
10 | }
11 | if (buf.indexOf) {
12 | return buf.indexOf(subBuf, start);
13 | }
14 |
15 | for (var i = start; i <= len; i++) {
16 | var j = 0;
17 | for (; j < subLen; j++) {
18 | if (subBuf[j] !== buf[i + j]) {
19 | break;
20 | }
21 | }
22 | if (j == subLen) {
23 | return i;
24 | }
25 | }
26 |
27 | return -1;
28 | };
29 |
--------------------------------------------------------------------------------
/lib/util/drain.js:
--------------------------------------------------------------------------------
1 | var createTransform = require('./common').createTransform;
2 |
3 | var noop = function () {};
4 |
5 | module.exports = function (stream, endHandler) {
6 | if (stream._hasAlreadyDrain || (!stream.noReqBody && stream.useH2)) {
7 | return typeof endHandler == 'function' && endHandler();
8 | }
9 | stream._hasAlreadyDrain = true;
10 | var emitEndStream = createTransform();
11 | emitEndStream.on('data', noop).on('error', noop);
12 | emitEndStream.on('end', endHandler);
13 | stream.pipe(emitEndStream);
14 | };
15 |
--------------------------------------------------------------------------------
/lib/util/parse-query.js:
--------------------------------------------------------------------------------
1 | var qs = require('querystring');
2 |
3 | var TOKEN_RE = /\r\u0000\n\u0003\r/g;
4 | var PLUS_RE = /\+/g;
5 | var TOKEN = '\r\u0000\n\u0003\r';
6 |
7 | var decoder = {
8 | decodeURIComponent: function (s) {
9 | s = s.replace(TOKEN_RE, '+');
10 | return qs.unescape(s);
11 | }
12 | };
13 | var rawDecoder = {
14 | decodeURIComponent: function (s) {
15 | return s.replace(TOKEN_RE, '+');
16 | }
17 | };
18 | var rawDecoder2 = {
19 | decodeURIComponent: function (s) {
20 | return s;
21 | }
22 | };
23 |
24 | function parse(str, sep, eq, escape) {
25 | try {
26 | if (str.indexOf('+') === -1 || str.indexOf(TOKEN) !== -1) {
27 | return qs.parse(str, sep, eq, escape ? rawDecoder2 : undefined);
28 | }
29 | str = str.replace(PLUS_RE, TOKEN);
30 | return qs.parse(str, sep, eq, escape ? rawDecoder : decoder);
31 | } catch (e) {}
32 | return '';
33 | }
34 |
35 | module.exports = parse;
36 |
--------------------------------------------------------------------------------
/lib/util/process.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./perf').procData;
2 |
--------------------------------------------------------------------------------
/lib/util/speed-transform.js:
--------------------------------------------------------------------------------
1 | var Transform = require('pipestream').Transform;
2 | var util = require('util');
3 |
4 | function SpeedTransform(options) {
5 | Transform.call(this);
6 | options = options || {};
7 | var value = parseInt((options.speed * 1000) / 8);
8 | if (value > 0) {
9 | this._speed = value;
10 | }
11 | if ((value = parseInt(options.delay)) > 0) {
12 | this._delay = value;
13 | }
14 | }
15 |
16 | util.inherits(SpeedTransform, Transform);
17 |
18 | SpeedTransform.prototype._transform = function (chunk, encoding, callback) {
19 | var self = this;
20 | var cb = function () {
21 | if (chunk && self._speed) {
22 | setTimeout(function () {
23 | callback(null, chunk);
24 | }, Math.round((chunk.length * 1000) / self._speed));
25 | } else {
26 | callback(null, chunk);
27 | }
28 | };
29 |
30 | if (self._delay) {
31 | var delay = self._delay;
32 | self._delay = null;
33 | return setTimeout(cb, delay);
34 | }
35 |
36 | cb();
37 | };
38 |
39 | module.exports = SpeedTransform;
40 |
--------------------------------------------------------------------------------
/require.js:
--------------------------------------------------------------------------------
1 | module.exports = require;
2 |
--------------------------------------------------------------------------------
/test/assets/certs/_.cert.w2.org.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIICXAIBAAKBgQCl/4gk7y8JzbSgNH71FoERR3XCBOZLvJ9L8XCe/83vF2Z/aTQL
3 | /abbVsAHkknjZqpyevf5qTA8UXdVmDWWHEhlaK0kaHC3ERMZP+c5n3GO5tQKxlS8
4 | M3ZEqM5iJWcpsXNiX3sgq4cH7vgmb3VX0knPmuzjqOMzpocnRzKfNz1MpwIDAQAB
5 | AoGAOBafadtniWh4H6mdPDLeaXg70dLV/cE+EesCorbMXn0JpQNnEqYiOvqU5/oF
6 | /VAzR3tFTpZcNgVQzRshABeOXilnQeVnNdxYV7rtPe7DpqM5Wvp6izUorJWqNGet
7 | sIrC/hlQupaYDXciYl9AP3yGs70CLMeorxTn0OSHy8e1sAECQQDlSiqFiTNVErEz
8 | j+47wsPrPbU/vnoPKK9HuZL93z1OmjzMekNWjBLh8l49VZfUTvNxxrD2LOp7n0EB
9 | X0AMBA53AkEAuVXlw1qfEan6UpKRWskuavCe6jj3mhWzu9LX04ektGEu3Y9uonPh
10 | o2fkSuE+jLTAvfuKoXJS0GAQTa3Rq/JPUQJATn3kLpB4PSBH/xG/iT+0V/xo5qhr
11 | GnNgBZq2gigA0b6lH46fLKqI8EZLEo4RisF4PzO4cp2Pq8ApvbGAuFxPIwJBAKAS
12 | E1bNfxOHhn8ovcf2eFO+rNJJD3kSg2CWcvfscJGmWg7cIcbHZTt3sJIHxrlKKCou
13 | Bgb4sZPtVEdy9+OVbXECQBN1jXBPaSVGPQeqjvEHymU6G2ulJqzXMDZciZLpHAwz
14 | GbjNIDkDzWdRLqmmRUqUXcA0mD2dxdWvkxBWRjntKsY=
15 | -----END RSA PRIVATE KEY-----
16 |
--------------------------------------------------------------------------------
/test/assets/certs/cert.w2.org.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIICXgIBAAKBgQCkl91qX33cnRX3gTTfUi72r8t/D1HavEm0McCaMVDQGJBX0VgV
3 | swLNIMGEyAcVmSMVleJAgu225M7rtpl9TKzSrOhdHAj7/AjZWOL5GJEuxu0LsuH8
4 | ZG9J6sS7HnVO//ZGJGjS5gGWk/gAfiII64+gurwasS7xiBHYYZOFTjRARwIDAQAB
5 | AoGBAIDuOVJfNQ+AublkrA8XqJQyxtxkGsGWZsHRi0b9xIkOBNvVsANnc5VNyGmD
6 | 6xC/IZ2CCHZyWVXATFqWcguV6XXouF9R8TN+HcEaiZ9epEOnwOSPz4DdEtB+TZp+
7 | Ih3l/NEzLRNxp7XVqI1k9OG5yguctyzfYcydFem/ZRWcMaxhAkEA0Rb+qGF7jb84
8 | xRBxFXxnKJVa6C2OSuDG1eecepMcYqNiUTimbk1/3qzJZqXmNBcIAfG/3a5dyM0O
9 | l1f2xeZ41wJBAMmFOPXkqS4gx8vItUJ36HSgXVOePbdmpBFRWD9R0uj83TuNc3V/
10 | pD9jKnU/ZQ0DacI57F5zvIxtVy9iAP1iVhECQEJ5sRUPiRyTwxTEGW/fUVzRv0k5
11 | 0pdzx0OSk2lVBB1IHKX+AMvoz9KX1KBR9lJxUBZuKbXtDdwddZogWVCp6ZkCQQC9
12 | kXcdyPZlEC0ixDHOzyF65Igmass/xWw9ZjoPhpdS2Nv8c3nTZDlL76s3FGWosjdA
13 | oGB8EX+i0hCb4CNyOJkhAkEADdZsXlSL7e0qy7iE1IP7uHrfse1ZZhIX48DSK+Yg
14 | nqZ8YdcUsS3RlVOgahqizD723klbKeGq8Pi9t0wHamjHjg==
15 | -----END RSA PRIVATE KEY-----
16 |
--------------------------------------------------------------------------------
/test/assets/certs/root.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIICXgIBAAKBgQCkl91qX33cnRX3gTTfUi72r8t/D1HavEm0McCaMVDQGJBX0VgV
3 | swLNIMGEyAcVmSMVleJAgu225M7rtpl9TKzSrOhdHAj7/AjZWOL5GJEuxu0LsuH8
4 | ZG9J6sS7HnVO//ZGJGjS5gGWk/gAfiII64+gurwasS7xiBHYYZOFTjRARwIDAQAB
5 | AoGBAIDuOVJfNQ+AublkrA8XqJQyxtxkGsGWZsHRi0b9xIkOBNvVsANnc5VNyGmD
6 | 6xC/IZ2CCHZyWVXATFqWcguV6XXouF9R8TN+HcEaiZ9epEOnwOSPz4DdEtB+TZp+
7 | Ih3l/NEzLRNxp7XVqI1k9OG5yguctyzfYcydFem/ZRWcMaxhAkEA0Rb+qGF7jb84
8 | xRBxFXxnKJVa6C2OSuDG1eecepMcYqNiUTimbk1/3qzJZqXmNBcIAfG/3a5dyM0O
9 | l1f2xeZ41wJBAMmFOPXkqS4gx8vItUJ36HSgXVOePbdmpBFRWD9R0uj83TuNc3V/
10 | pD9jKnU/ZQ0DacI57F5zvIxtVy9iAP1iVhECQEJ5sRUPiRyTwxTEGW/fUVzRv0k5
11 | 0pdzx0OSk2lVBB1IHKX+AMvoz9KX1KBR9lJxUBZuKbXtDdwddZogWVCp6ZkCQQC9
12 | kXcdyPZlEC0ixDHOzyF65Igmass/xWw9ZjoPhpdS2Nv8c3nTZDlL76s3FGWosjdA
13 | oGB8EX+i0hCb4CNyOJkhAkEADdZsXlSL7e0qy7iE1IP7uHrfse1ZZhIX48DSK+Yg
14 | nqZ8YdcUsS3RlVOgahqizD723klbKeGq8Pi9t0wHamjHjg==
15 | -----END RSA PRIVATE KEY-----
16 |
--------------------------------------------------------------------------------
/test/assets/files/1.txt:
--------------------------------------------------------------------------------
1 | 1
--------------------------------------------------------------------------------
/test/assets/files/2.txt:
--------------------------------------------------------------------------------
1 | 2
--------------------------------------------------------------------------------
/test/assets/files/3.txt:
--------------------------------------------------------------------------------
1 | 3
--------------------------------------------------------------------------------
/test/assets/files/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/test/assets/files/empty.txt
--------------------------------------------------------------------------------
/test/assets/files/gb2312.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/test/assets/files/gb2312.txt
--------------------------------------------------------------------------------
/test/assets/files/rules.txt:
--------------------------------------------------------------------------------
1 | str.w2.org/index.html file://`(${search.replace(a,b)})`
2 | str.w2.org/index2.html file://`(${query.replace(/a/g,b)})`
--------------------------------------------------------------------------------
/test/assets/files/storage/.backup/1.test1.tx:
--------------------------------------------------------------------------------
1 | 1
--------------------------------------------------------------------------------
/test/assets/files/storage/.backup/2.test2.tx:
--------------------------------------------------------------------------------
1 | 2
--------------------------------------------------------------------------------
/test/assets/files/storage/.backup/3.test3.tx:
--------------------------------------------------------------------------------
1 | 3
--------------------------------------------------------------------------------
/test/assets/files/storage/.backup/properties:
--------------------------------------------------------------------------------
1 | {"filesOrder":["test1.tx","test2.tx","test3.tx"]}
2 |
--------------------------------------------------------------------------------
/test/assets/files/storage/files/1.test1.tx:
--------------------------------------------------------------------------------
1 | 1
--------------------------------------------------------------------------------
/test/assets/files/storage/files/2.test2.tx:
--------------------------------------------------------------------------------
1 | 2
--------------------------------------------------------------------------------
/test/assets/files/storage/files/3.test3.tx:
--------------------------------------------------------------------------------
1 | 3
--------------------------------------------------------------------------------
/test/assets/files/storage/properties:
--------------------------------------------------------------------------------
1 | {"filesOrder":["test1.tx","test2.tx","test3.tx"]}
2 |
--------------------------------------------------------------------------------
/test/assets/files/test.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/test/assets/files/test.txt
--------------------------------------------------------------------------------
/test/assets/values/rawFile.html:
--------------------------------------------------------------------------------
1 | HTTP/1.1 500 OK
2 | content-type: text/plain
3 |
4 | test2
--------------------------------------------------------------------------------
/test/assets/values/rawFile2.js:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | content-type: application/javascript
3 | set-cookie: res_cookie_name=123; domain=.test.com; samesite=Lax; path=/; max-age=20000; expires=sxxxx; secure; httponly
4 |
5 |
--------------------------------------------------------------------------------
/test/assets/values/reqScript.js:
--------------------------------------------------------------------------------
1 | rules.push(headers.host + ' file://{test.html}');
2 | reqScriptData.test = body || 123;
3 | values['test.html'] = render('<%=test%>', {test: body || 123});
4 |
--------------------------------------------------------------------------------
/test/assets/values/resScript.js:
--------------------------------------------------------------------------------
1 | values.test = {'x-test': render('<%=test%>', {test: reqScriptData.test})};
2 | rules.push(headers.host + ' resHeaders://{test}');
3 |
--------------------------------------------------------------------------------
/test/assets/values/rulesFile.js:
--------------------------------------------------------------------------------
1 | if (isLocalAddress()) {
2 | rules.push('rf1.w2.org file://{test.json}');
3 | }
4 |
--------------------------------------------------------------------------------
/test/assets/values/rulesFile.txt:
--------------------------------------------------------------------------------
1 | # rules
2 | rf2.w2.org file://{test2.json}
--------------------------------------------------------------------------------
/test/assets/values/rulesFile2.js:
--------------------------------------------------------------------------------
1 | rules = null;
--------------------------------------------------------------------------------
/test/assets/values/test.json:
--------------------------------------------------------------------------------
1 | {
2 | "test": "values"
3 | }
--------------------------------------------------------------------------------
/test/assets/values/test2.json:
--------------------------------------------------------------------------------
1 | {
2 | "test": "values2"
3 | }
--------------------------------------------------------------------------------
/test/assets/values/test3.json:
--------------------------------------------------------------------------------
1 | {
2 | "test": "values3"
3 | }
--------------------------------------------------------------------------------
/test/assets/values/tps.rules:
--------------------------------------------------------------------------------
1 | # rules
2 | 2.tps.whistlejs.com jsAppend://`{${reqCookie.name}}`
--------------------------------------------------------------------------------
/test/assets/values/tps1.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "${url}",
3 | "search": "${url.search}",
4 | "query": "${url.query}",
5 | "queryValue": "${url.query.name}",
6 | "host": "${url.host}",
7 | "hostname": "${url.hostname}",
8 | "path": "${url.path}",
9 | "pathname": "${url.pathname}",
10 | "reqId": "${reqId}",
11 | "now": ${now},
12 | "method": "${method}",
13 | "xff": "${reqHeaders.x-test}",
14 | "other": "${reqHeaders.other}",
15 | "cookie": "${reqCookie}",
16 | "cookieValue": "${reqCookie.cookieName}",
17 | "clientIp": "${clientIp}"
18 | }
--------------------------------------------------------------------------------
/test/assets/values/tps2.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "${url}",
3 | "search": "${url.search}",
4 | "query": "${url.query}",
5 | "queryValue": "${url.query.name}",
6 | "host": "${url.host}",
7 | "hostname": "${url.hostname}",
8 | "path": "${url.path}",
9 | "pathname": "${url.pathname}",
10 | "reqId": "${reqId}",
11 | "now": ${now},
12 | "method": "${method}",
13 | "xff": "${reqHeaders.x-forwarded-for}",
14 | "other": "${reqHeaders.other}",
15 | "cookie": "${reqCookie}",
16 | "cookieValue": "${reqCookie.cookieName}",
17 | "clientIp": "${clientIp}",
18 | "statusCode": "${statusCode}",
19 | "serverIp": "${serverIp}",
20 | "resHeaderValue": "${resHeaders.x-res-header-name}",
21 | "resCookieValue": "${resCookie.res_cookie_name}"
22 | }
--------------------------------------------------------------------------------
/test/config.test.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | port: 6666,
4 | serverPort: 8080,
5 | wsPort: 8081,
6 | httpsPort: 5566,
7 | socksPort: 1080,
8 | authSocksPort: 1118,
9 | proxyPort: 7788,
10 | httpServerPort: 2080,
11 | httpsServerPort: 2081
12 | };
13 |
--------------------------------------------------------------------------------
/test/events.js:
--------------------------------------------------------------------------------
1 | var EventEmitter = require('events');
2 |
3 | module.exports = new EventEmitter();
--------------------------------------------------------------------------------
/test/plugins/@test/whistle.test3/index.js:
--------------------------------------------------------------------------------
1 | exports.reqRulesServer = function(server) {
2 | server.on('request', function(req, res) {
3 | res.end('tp.w2.org/index.html resType://html rulesFile://{rulesFile.js}\nths.w2.org file://{test.json}');
4 | });
5 | };
6 |
7 | exports.tunnelRulesServer = function(server) {
8 | server.on('request', function(req, res) {
9 | res.end('ths.w2.org filter://https');
10 | });
11 | };
--------------------------------------------------------------------------------
/test/plugins/@test/whistle.test3/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@test/whistle.test3",
3 | "version": "0.0.0",
4 | "description": "test3",
5 | "license": "MIT"
6 | }
7 |
--------------------------------------------------------------------------------
/test/plugins/@test/whistle.test3/test/abc/abc/index.html:
--------------------------------------------------------------------------------
1 | {
2 | "name": "https"
3 | }
4 |
--------------------------------------------------------------------------------
/test/plugins/@test/whistle.test3/test/abc/index.html:
--------------------------------------------------------------------------------
1 | {
2 | "name": "http"
3 | }
4 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-http/index.js:
--------------------------------------------------------------------------------
1 |
2 | exports.reqReadServer = require('./lib/reqReadServer');
3 | exports.reqWriteServer = require('./lib/reqWriteServer');
4 | exports.resReadServer = require('./lib/resReadServer');
5 | exports.resWriteServer = require('./lib/resWriteServer');
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-http/lib/reqReadServer.js:
--------------------------------------------------------------------------------
1 | module.exports = function(server) {
2 | server.on('request', function(req, res) {
3 | req.on('data', (data) => {
4 | return res.write(data);
5 | });
6 | req.on('end', () => res.end());
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-http/lib/reqWriteServer.js:
--------------------------------------------------------------------------------
1 | module.exports = function(server) {
2 | server.on('request', function(req, res) {
3 | req.pipe(res);
4 | });
5 | };
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-http/lib/resReadServer.js:
--------------------------------------------------------------------------------
1 | module.exports = function(server) {
2 | server.on('request', function(req, res) {
3 | var body;
4 | req.on('data', (data) => {
5 | body = body ? Buffer.concat([body, data]) : data;
6 | });
7 | req.on('end', () => res.end(body));
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-http/lib/resWriteServer.js:
--------------------------------------------------------------------------------
1 | module.exports = function(server) {
2 | server.on('request', function(req, res) {
3 | req.pipe(res);
4 | });
5 | };
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-http/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "whistle.pipe-http",
3 | "version": "1.0.0",
4 | "whistleConfig": {
5 | "hintList": [
6 | {
7 | "value": "123456",
8 | "label": "ssssssss",
9 | "help": "http://www.qq.com"
10 | },
11 | "sdfasfasfd"
12 | ],
13 | "hideShortProtocol": true,
14 | "hideLongProtocol": true,
15 | "hintUrl": "/",
16 | "rulesUrl": "/",
17 | "valuesUrl": "/"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-http/rules.txt:
--------------------------------------------------------------------------------
1 | http://* pipe://pipe-http
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-tunnel/index.js:
--------------------------------------------------------------------------------
1 |
2 | exports.tunnelReqRead = require('./lib/tunnelReqRead');
3 | exports.tunnelReqWrite = require('./lib/tunnelReqWrite');
4 | exports.tunnelResRead = require('./lib/tunnelResRead');
5 | exports.tunnelResWrite = require('./lib/tunnelResWrite');
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-tunnel/lib/tunnelReqRead.js:
--------------------------------------------------------------------------------
1 | module.exports = function(server) {
2 | server.on('connect', function(_, socket) {
3 | socket.pipe(socket);
4 | });
5 | };
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-tunnel/lib/tunnelReqWrite.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function(server) {
3 | server.on('connect', function(_, socket) {
4 | socket.on('data', (data) => {
5 | socket.write(data);
6 | });
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-tunnel/lib/tunnelResRead.js:
--------------------------------------------------------------------------------
1 | module.exports = function(server) {
2 | server.on('connect', function(_, socket) {
3 | socket.pipe(socket);
4 | });
5 | };
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-tunnel/lib/tunnelResWrite.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function(server) {
3 | server.on('connect', function(_, socket) {
4 | socket.on('data', (data) => {
5 | socket.write(data);
6 | });
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-tunnel/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "whistle.pipe-tunnel",
3 | "version": "1.1.1"
4 | }
5 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-tunnel/rules.txt:
--------------------------------------------------------------------------------
1 | tunnel://* pipe://pipe-tunnel
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-ws/index.js:
--------------------------------------------------------------------------------
1 |
2 | exports.wsReqRead = require('./lib/wsReqRead');
3 | exports.wsReqWrite = require('./lib/wsReqWrite');
4 | exports.wsResRead = require('./lib/wsResRead');
5 | exports.wsResWrite = require('./lib/wsResWrite');
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-ws/lib/wsReqRead.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function(server) {
3 | server.on('connect', function(_, socket) {
4 | socket.on('data', (data, opts) => {
5 | socket.write(data, opts);
6 | });
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-ws/lib/wsReqWrite.js:
--------------------------------------------------------------------------------
1 | module.exports = function(server) {
2 | server.on('connect', function(_, socket) {
3 | socket.pipe(socket);
4 | });
5 | };
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-ws/lib/wsResRead.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function(server) {
3 | server.on('connect', function(_, socket) {
4 | socket.on('data', (data, opts) => {
5 | socket.write(data, opts);
6 | });
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-ws/lib/wsResWrite.js:
--------------------------------------------------------------------------------
1 | module.exports = function(server) {
2 | server.on('connect', function(_, socket) {
3 | socket.pipe(socket);
4 | });
5 | };
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-ws/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "whistle.pipe-ws",
3 | "version": "1.1.1"
4 | }
5 |
--------------------------------------------------------------------------------
/test/plugins/whistle.pipe-ws/rules.txt:
--------------------------------------------------------------------------------
1 | ws://* pipe://pipe-ws
--------------------------------------------------------------------------------
/test/plugins/whistle.test-values/index.js:
--------------------------------------------------------------------------------
1 |
2 | exports.uiServer = function(server) {
3 | server.on('request', function(req, res) {
4 | var key = decodeURIComponent(req.url.substring(req.url.indexOf('=') + 1));
5 | res.end(key + '/' + req.headers['x-whistle-rule-proto']);
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/test/plugins/whistle.test-values/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "whistle.test-values",
3 | "version": "1.0.0",
4 | "description": "whistle的单元测试用例"
5 | }
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.test-values/rules.txt:
--------------------------------------------------------------------------------
1 |
2 | test-values.whistlejs.com reqHeaders://$test-values/x-test-req=123 resHeaders://$test-values/x-test-res=456 file://$test-values/x-test-body=测试789
3 |
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/dispatch.js:
--------------------------------------------------------------------------------
1 | params.dispatch='test';
2 | params.timestamp = Date.now();
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/append.txt:
--------------------------------------------------------------------------------
1 | append
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/bin/body.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/test/plugins/whistle.test/assets/files/bin/body.txt
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/bin/bottom.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avwo/whistle/44a83c877bb77b0de1122040161ce7339f8f4973/test/plugins/whistle.test/assets/files/bin/bottom.txt
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/bin/file.txt:
--------------------------------------------------------------------------------
1 | 我们是社会主义接班人!
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/bin/top.txt:
--------------------------------------------------------------------------------
1 | 我们是�
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/body.txt:
--------------------------------------------------------------------------------
1 | body
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/css.css:
--------------------------------------------------------------------------------
1 | css
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/html.html:
--------------------------------------------------------------------------------
1 | html
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/index.html:
--------------------------------------------------------------------------------
1 | {
2 | "body": "html"
3 | }
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/js.js:
--------------------------------------------------------------------------------
1 | js
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/log.js:
--------------------------------------------------------------------------------
1 | log
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/pac.js:
--------------------------------------------------------------------------------
1 | function FindProxyForURL(url, host) {
2 | // our local URLs from the domains below example.com don't need a proxy:
3 | if (shExpMatch(host, "*.example.com"))
4 | {
5 | return "DIRECT";
6 | }
7 |
8 | // URLs within this network are accessed through
9 | // port 8080 on fastproxy.example.com:
10 | if (isInNet(host, "10.0.0.0", "255.255.248.0"))
11 | {
12 | return "PROXY fastproxy.example.com:8080";
13 | }
14 |
15 | // All other requests go through port 8080 of proxy.example.com.
16 | // should that fail to respond, go directly to the WWW:
17 | return "PROXY 127.0.0.1:8080; DIRECT";
18 | }
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/prepend.txt:
--------------------------------------------------------------------------------
1 | prepend
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/rawfile.html:
--------------------------------------------------------------------------------
1 | HTTP/1.1 500 OK
2 | content-type: text/plain
3 |
4 | test
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/ssi-include.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Test ssi include
6 |
7 |
8 | Hello world~~~
9 | #include('assets/files/ssi1.html')
10 | Hello world~~~
11 | #include('assets/files/ssi2.html')
12 | Hello world~~~
13 | #include('assets/files/ssi3.html')
14 |
15 |
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/ssi1.html:
--------------------------------------------------------------------------------
1 | include1.html
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/ssi2.html:
--------------------------------------------------------------------------------
1 | include2.html
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/ssi3.html:
--------------------------------------------------------------------------------
1 | include3.html
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/files/tpl.js:
--------------------------------------------------------------------------------
1 | {callback}({ec: 0})
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/headers.json:
--------------------------------------------------------------------------------
1 | x-test1: value1
2 | x-test2: value2
3 | x-testN: valueN
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/replace.json:
--------------------------------------------------------------------------------
1 | test: abc
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/req.json:
--------------------------------------------------------------------------------
1 | {
2 | "method": "post",
3 | "headers": {
4 | "referer": "http://wproxy.org"
5 | },
6 | "top": "top",
7 | "body": "body",
8 | "bottom": "bottom"
9 | }
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/reqCookies.json:
--------------------------------------------------------------------------------
1 | test: abc
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/reqCors.json:
--------------------------------------------------------------------------------
1 | origin: *
2 | method: POST
3 | headers: x-test
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/res.json:
--------------------------------------------------------------------------------
1 | {
2 | "headers": {
3 | "Content-type": "text/plain"
4 | },
5 | "top": "top",
6 | "body": "body",
7 | "bottom": "bottom"
8 | }
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/resCookies.json:
--------------------------------------------------------------------------------
1 | {
2 | "key1": "value1",
3 | "key2": "value2",
4 | "keyN": {
5 | "value": "value1",
6 | "maxAge": 60,
7 | "httpOnly": true,
8 | "path": "/",
9 | "secure": true,
10 | "domain": ".example.com"
11 | }
12 | }
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/resCors.json:
--------------------------------------------------------------------------------
1 | origin: *
2 | methods: POST
3 | headers: x-test
4 | credentials: true
5 | maxAge: 300000
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/upload.json:
--------------------------------------------------------------------------------
1 | {
2 | "name1": "value1",
3 | "name2": "value2",
4 | "file1": {
5 | "filename": "text.txt",
6 | "content": "xxxxxxxxxxxxxxx"
7 | },
8 | "file2": {
9 | "value": "1234567890"
10 | }
11 | }
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/urlParams.json:
--------------------------------------------------------------------------------
1 | test: abc
--------------------------------------------------------------------------------
/test/plugins/whistle.test/assets/values/urlReplace.json:
--------------------------------------------------------------------------------
1 | /a/: e
2 | neme: user
3 | /a/g: tt
--------------------------------------------------------------------------------
/test/plugins/whistle.test/index.js:
--------------------------------------------------------------------------------
1 | exports.server = require('./lib/server');
2 | exports.uiServer = require('./lib/uiServer');
3 | exports.rulesServer = require('./lib/rulesServer');
4 | exports.resRulesServer = require('./lib/resRulesServer');
5 | exports.statusServer = require('./lib/statusServer');
6 | exports.tunnelRulesServer = require('./lib/tunnelRulesServer');
7 | exports.tunnelServer = require('./lib/tunnelServer');
--------------------------------------------------------------------------------
/test/plugins/whistle.test/lib/statusServer.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 | var util = require('./util');
4 |
5 | module.exports = function(server, options) {
6 | util.init(options);
7 | server.on('request', app);
8 | app.use(function(req, res, next) {
9 | req.on('error', next);
10 | res.on('error', next);
11 | req.setEncoding('utf8');
12 | var body = '';
13 | req.on('data', function(data) {
14 | body += data;
15 | });
16 |
17 | req.on('end', function() {
18 | res.end();
19 | });
20 | });
21 |
22 | app.use(function(err, req, res, next) {
23 | res.sendStatus(500);
24 | });
25 | };
--------------------------------------------------------------------------------
/test/plugins/whistle.test/lib/tunnelServer.js:
--------------------------------------------------------------------------------
1 | var net = require('net');
2 | var config = require('../package.json');
3 |
4 | function close() {
5 | this.destroy();
6 | }
7 |
8 | module.exports = function(server, options) {
9 | server.on('connect', function(req, socket) {
10 | socket.on('error', close);
11 | if (req.headers[options.RULE_VALUE_HEADER] != 'none') {
12 | throw new Error('wrong rule value');
13 | }
14 | var resSocket = net.connect({
15 | port: 8080,
16 | host: '127.0.0.1'
17 | }, function() {
18 | socket.write('HTTP/1.1 200 Connection Established\r\nProxy-Agent: ' + config.name + '\r\n\r\n');
19 | socket.pipe(resSocket).pipe(socket);
20 | resSocket.on('error', close);
21 | });
22 | });
23 | };
--------------------------------------------------------------------------------
/test/plugins/whistle.test/lib/uiServer.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 | var WebSocketServer = require('ws').Server;
4 | var util = require('./util');
5 |
6 | function startWebsocketServer(ws) {
7 | ws.on('connection', function(ws) {
8 | var req = ws.upgradeReq;
9 | ws.on('message', function(msg) {
10 | ws.send(JSON.stringify({
11 | headers: req.headers,
12 | body: msg
13 | }, null, '\t'));
14 | });
15 | });
16 | }
17 |
18 | module.exports = function(server, options) {
19 | util.init(options);
20 | server.on('request', app);
21 | startWebsocketServer(new WebSocketServer({ server: server }));
22 | app.use(function(req, res, next) {
23 | req.on('error', next);
24 | res.on('error', next);
25 |
26 | res.end('uiServer');
27 | });
28 |
29 | app.use(function(err, req, res, next) {
30 | res.sendStatus(500);
31 | });
32 | };
--------------------------------------------------------------------------------
/test/plugins/whistle.test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "whistle.test",
3 | "version": "1.0.0",
4 | "description": "whistle的单元测试用例"
5 | }
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.test1/_rules.txt:
--------------------------------------------------------------------------------
1 | delete.test.whistlejs.com delete://req.headers.x-delete-req|res.headers.x-delete-res|headers.x-delete-all
--------------------------------------------------------------------------------
/test/plugins/whistle.test1/index.js:
--------------------------------------------------------------------------------
1 | exports.rulesServer = require('./lib/rulesServer');
2 |
--------------------------------------------------------------------------------
/test/plugins/whistle.test1/lib/rulesServer.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function(server, options) {
3 | server.on('request', function(req, res) {
4 | if (req.headers.host === 'var1.wproxy.org') {
5 | return res.end(JSON.stringify({
6 | rules: '/./ file://(${json0}${json1},${json2},${json3}${jsonN})',
7 | values: {
8 | json0: '{',
9 | json1: '"json1": 1',
10 | json2: '"json2": 2',
11 | json3: '"json3": 3',
12 | jsonN: '}'
13 | }
14 | }));
15 | }
16 | res.end('mp1.w2.org/index.html resType://html\nhttps2.w2.org filter://https');
17 | });
18 | };
--------------------------------------------------------------------------------
/test/plugins/whistle.test1/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "whistle.test1",
3 | "version": "0.0.0",
4 | "whistleConfig": {
5 | "pluginVars": "http://www.test.com"
6 | },
7 | "description": "test1",
8 | "license": "MIT"
9 | }
10 |
--------------------------------------------------------------------------------
/test/plugins/whistle.test1/rules.txt:
--------------------------------------------------------------------------------
1 | /./ whistle.test1://test1 %test1=123
2 |
3 | %test1=abc
--------------------------------------------------------------------------------
/test/plugins/whistle.test2/_rules.txt:
--------------------------------------------------------------------------------
1 | mp1.w2.org/index.html resCharset://gbk
2 | enable3.w2.org test://abc
3 | enable4.w2.org test://123
4 |
5 | range2.whistlejs.com file://test.txt
6 |
--------------------------------------------------------------------------------
/test/plugins/whistle.test2/index.js:
--------------------------------------------------------------------------------
1 | exports.statsServer = function(server, options) {
2 | server.on('request', function(req, res) {
3 | res.end();
4 | });
5 | };
6 |
7 | exports.auth = function() {};
8 |
--------------------------------------------------------------------------------
/test/plugins/whistle.test2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "whistle.test2",
3 | "version": "0.0.0",
4 | "description": "test2",
5 | "license": "MIT"
6 | }
7 |
--------------------------------------------------------------------------------
/test/plugins/whistle.test2/rules.txt:
--------------------------------------------------------------------------------
1 | /./ whistle.test2://test2
2 | enable1.w2.org enable://intercept test://test proxy://test:123@127.0.0.1:7788
3 | enable2.w2.org enable://intercept test://test proxy://test:123@127.0.0.1:7788
4 | enable2.w2.org ignore://test
5 |
6 | enable3.w2.org enable://intercept proxy://test:123@127.0.0.1:7788 whistle.test2://
7 | enable4.w2.org enable://intercept proxy://test:123@127.0.0.1:7788 whistle.test2://
8 |
9 | enable4.w2.org ignore://whistle.test2
10 |
11 | var1.wproxy.org/index.html whistle.test1://
--------------------------------------------------------------------------------
/test/plugins/whistle.test2/test.txt:
--------------------------------------------------------------------------------
1 | 0123456789
--------------------------------------------------------------------------------
/test/proxy/disable.test.js:
--------------------------------------------------------------------------------
1 | var disableProxy = require('../../bin/proxy').disableProxy;
2 |
3 | console.log(disableProxy()); // eslint-disable-line
4 |
--------------------------------------------------------------------------------
/test/proxy/enable.test.js:
--------------------------------------------------------------------------------
1 | var enableProxy = require('../../bin/proxy').enableProxy;
2 |
3 | console.log(enableProxy({ // eslint-disable-line
4 | host: '127.0.0.1',
5 | port: 8899,
6 | bypass: ''
7 | }));
8 |
--------------------------------------------------------------------------------
/test/units/attachment.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://attachment.test.whistlejs.com/index.html', function(res, data) {
5 | res.headers.should.have.property('content-disposition', 'attachment; filename="index.html"');
6 | });
7 |
8 | util.request({
9 | method: 'put',
10 | url: 'https://attachment.test.whistlejs.com/index2.html'
11 | }, function(res, data) {
12 | res.headers.should.have.property('content-disposition', 'attachment; filename="index2.html"');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/auth.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://au2th.test.whistlejs.com/index.html', function(res, data) {
5 | data.headers.should.not.have.property('authorization');
6 | });
7 |
8 | util.request({
9 | method: 'put',
10 | url: 'https://auth.test.whistlejs.com/index2.html'
11 | }, function(res, data) {
12 | data.headers.should.have.property('authorization');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/cache.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://cache.test.whistlejs.com/index.html', function(res, data) {
5 | res.headers.should.have.property('cache-control', 'max-age=60000');
6 | });
7 |
8 | util.request({
9 | method: 'post',
10 | url: 'https://cache.test.whistlejs.com/index.html'
11 | }, function(res, data) {
12 | res.headers.should.have.property('cache-control', 'max-age=60000');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/common.test.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var fs = require('fs');
3 | var isUtf8 = require('../../lib/util/is-utf8');
4 | var createStorage = require('../../lib/rules/storage');
5 |
6 | var BASE_DIR = path.join(__dirname, '../assets/files/');
7 |
8 | module.exports = function() {
9 | var gb2312Buf = fs.readFileSync(path.join(BASE_DIR, 'gb2312.txt'));
10 | var utf8Buf = fs.readFileSync(path.join(BASE_DIR, '1.txt'));
11 | isUtf8(gb2312Buf).should.equal(false);
12 | isUtf8(utf8Buf).should.equal(true);
13 | createStorage(path.join(BASE_DIR, 'storage'));
14 | };
--------------------------------------------------------------------------------
/test/units/connect.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('ws://connect.whistlejs.com/index.html', function(data) {
5 | data.type.should.equal('server');
6 | });
7 |
8 | util.request('ws://connect.whistlejs.com/index.html', function(data) {
9 | data.type.should.equal('server');
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/test/units/css.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://css1.test.whistlejs.com/index.html?resBody=_', function(res, body) {
5 | body.should.equal('_');
6 | });
7 |
8 | util.request({
9 | method: 'post',
10 | url: 'https://css2.test.whistlejs.com/index.html?resBody=_'
11 | }, function(res, body) {
12 | body.should.equal('_css');
13 | });
14 |
15 | util.request({
16 | method: 'post',
17 | url: 'https://css3.test.whistlejs.com/index.html?resBody=_'
18 | }, function(res, body) {
19 | body.should.equal('_');
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/test/units/disable.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://disable.test.whistlejs.com/index.html', function(res, data) {
5 | res.headers.should.have.property('cache-control', 'no-cache');
6 | });
7 |
8 | util.request({
9 | method: 'post',
10 | url: 'https://disable.test.whistlejs.com/index.html'
11 | }, function(res, data) {
12 | res.headers.should.have.property('cache-control', 'no-cache');
13 | res.headers.should.not.have.property('set-cookie');
14 | });
15 | };
16 |
--------------------------------------------------------------------------------
/test/units/file.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://file.test.whistlejs.com/index.html', function(res, data) {
5 | data.should.have.property('body', 'html');
6 | });
7 |
8 | util.request({
9 | url: 'https://file.test.whistlejs.com/index.html',
10 | method: 'post',
11 | body: util.getTextBySize(3072)
12 | }, function(res, data) {
13 | data.should.have.property('body', 'html');
14 | });
15 | util.request({
16 | url: 'http://test-values.whistlejs.com/index.html?doNotParseJson',
17 | method: 'post',
18 | body: util.getTextBySize(3072)
19 | }, function(res, data) {
20 | res.headers['x-test-res'].should.be.equal('456/resHeaders');
21 | data.should.equal('x-test-body=测试789/file');
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/test/units/forward.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://forward.test.whistlejs.com/index.html', function(res, data) {
5 | data.should.have.property('type', 'server');
6 | });
7 |
8 | util.request({
9 | method: 'post',
10 | url: 'http://forward.test.whistlejs.com/index.html'
11 | }, function(res, data) {
12 | data.should.have.property('type', 'server');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/host.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://host.test.whistlejs.com/index.html', function(res, data) {
5 | data.should.have.property('type', 'server');
6 | });
7 | util.request('http://127.0.0.1:8080/xhost.html', function(res, data) {
8 | data.should.have.property('type', 'server');
9 | });
10 | };
11 |
--------------------------------------------------------------------------------
/test/units/html.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://html1.test.whistlejs.com/index.html?resBody=_', function(res, body) {
5 | body.should.equal('_html');
6 | });
7 | util.request('http://prependhtml.whistlejs.com/index.html?resBody=_', function(res, body) {
8 | body.should.equal(['', '-1', '-21', '23', '4'].join('\r\n'));
9 | });
10 |
11 | util.request({
12 | method: 'post',
13 | url: 'https://html2.test.whistlejs.com/index.html?resBody=_'
14 | }, function(res, body) {
15 | body.should.equal('_');
16 | });
17 |
18 | util.request({
19 | method: 'post',
20 | url: 'http://html3.test.whistlejs.com/index.html?resBody=_'
21 | }, function(res, body) {
22 | body.should.equal('_');
23 | });
24 | };
25 |
--------------------------------------------------------------------------------
/test/units/ignore.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('https://enable1.w2.org', function(res, data) {
5 | data.url.should.be.equal('https://enable1.w2.org/');
6 | });
7 | util.request('https://enable2.w2.org:5566', function(res, data) {
8 | data.body.should.be.equal('test');
9 | });
10 | util.request('https://enable3.w2.org:5566', function(res, data) {
11 | data.url.should.be.equal('https://enable3.w2.org:5566/');
12 | });
13 | util.request('https://enable4.w2.org:5566', function(res, data) {
14 | data.body.should.be.equal('test');
15 | });
16 | };
17 |
--------------------------------------------------------------------------------
/test/units/js.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://js1.test.whistlejs.com/index.html?resBody=_', function(res, body) {
5 | body.should.equal('_');
6 | });
7 |
8 | util.request({
9 | method: 'post',
10 | url: 'https://js2.test.whistlejs.com/index.html?resBody=_'
11 | }, function(res, body) {
12 | body.should.equal('_js');
13 | });
14 |
15 | util.request({
16 | method: 'post',
17 | url: 'https://js3.test.whistlejs.com/index.html?resBody=_'
18 | }, function(res, body) {
19 | body.should.equal('_');
20 | });
21 | util.request('http://jsbody2.whistlejs.com/index.html?resBody=_', function(res, body) {
22 | body.should.equal('\r\n0');
23 | });
24 | };
25 |
--------------------------------------------------------------------------------
/test/units/log.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://log1.test.whistlejs.com/index.html?resBody=_', function(res, body) {
5 | body.length.should.above(500);
6 | body.should.containEql('\r\n_');
7 | });
8 |
9 | util.request({
10 | method: 'post',
11 | url: 'https://log2.test.whistlejs.com/index.html?resBody=_'
12 | }, function(res, body) {
13 | body.length.should.above(500);
14 | body.should.containEql('_\r\nlog');
15 | });
16 |
17 | util.request({
18 | method: 'post',
19 | url: 'https://log3.test.whistlejs.com/index.html?resBody=_'
20 | }, function(res, body) {
21 | body.should.equal('_');
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/test/units/method.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://test.whistlejs.com/index.html', function(res, data) {
5 | data.method.should.equal('GET');
6 | });
7 |
8 | util.request({
9 | method: 'put',
10 | url: 'https://test.whistlejs.com/index.html'
11 | }, function(res, data) {
12 | data.method.should.equal('PUT');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/options.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://test.options.com/index.html', function(res, data) {
5 | data.method.should.equal('options');
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/test/units/others.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://unknownprotocol.w2.org/index.html?doNotParseJson', function(res, data) {
5 | res.statusCode.should.be.equal(502);
6 | });
7 | require('../../biz/webui/cgi-bin/util').formatDate();
8 | util.request('http://test.internal.path.com/...whistle-path.5b6af7b9884e1165...///whistle._abc/index.html', function(res, data) {
9 | data.url.should.be.equal('http://test.internal.path.com/...whistle-path.5b6af7b9884e1165...///whistle._abc/index.html');
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/test/units/pac.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://pac.test.com/index.html', function(res, data) {
5 | data.should.be.have.property('type', 'server');
6 | });
7 | util.request({
8 | url: 'http://pac.test.com/index.html',
9 | method: 'post'
10 | }, function(res, data) {
11 | data.should.be.have.property('type', 'server');
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/test/units/plugin.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'http://headerreplace.plugin.whistlejs.com:1234/index.html',
6 | headers: { test: 'abc' }
7 | }, function(res, data) {
8 | data.headers.host.should.equal('test.whistlejs.com:1234');
9 | res.headers['set-cookie'].join().should.equal('abc,abc222');
10 | });
11 |
12 | util.request('http://plugin.whistlejs.com:1234/index.html', function(res, data) {
13 | data.should.have.property('type', 'server');
14 | });
15 |
16 | util.request('wss://321.whistlejs.com/index.html', function(data) {
17 | data.ruleValue.should.equal('abc');
18 | });
19 |
20 | util.request('wss://321.ws1.whistlejs.com:2222/index.html', function(data) {
21 | data.host.should.equal('127.0.0.1:9999');
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/test/units/plugins.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://mp1.w2.org/index.html', function(res, data) {
5 | res.headers['content-type'].should.be.equal('text/html; charset=gbk');
6 | data.headers['x-whistle-rule-value'].should.be.equal('123');
7 | });
8 |
9 | util.request('https://ths.w2.org/index.html', function(res, data) {
10 | data.test.should.be.equal('values');
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/test/units/range.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | uri: 'http://range1.whistlejs.com/index.html',
6 | headers: {
7 | 'range': 'bytes=2-3,5-6'
8 | }
9 | }, function(res, body) {
10 | body.should.equal(23456);
11 | });
12 | util.request({
13 | url: 'http://range2.whistlejs.com/',
14 | headers: {
15 | 'range': 'bytes=2-3,1-8'
16 | }
17 | }, function(res, body) {
18 | body.should.equal(12345678);
19 | });
20 | };
21 |
--------------------------------------------------------------------------------
/test/units/rawfile.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 |
5 | util.request('http://raw.test.whistlejs.com/index.html?doNotParseJson', function(res, body) {
6 | res.statusCode.should.equal(500);
7 | body.should.equal('test');
8 | res.headers.should.have.property('content-type', 'text/plain');
9 | });
10 |
11 | util.request({
12 | method: 'post',
13 | url: 'https://raw.test.whistlejs.com/?doNotParseJson'
14 | }, function(res, body) {
15 | res.statusCode.should.equal(500);
16 | body.should.equal('test');
17 | res.headers.should.have.property('content-type', 'text/plain');
18 | });
19 |
20 | util.request('http://xraw.test.whistlejs.com/index2.html', function(res, data) {
21 | data.should.have.property('type', 'server');
22 | });
23 | util.request('http://rwf.w2.org/index.html?doNotParseJson', function(res, body) {
24 | res.statusCode.should.equal(500);
25 | body.should.equal('test2');
26 | });
27 | };
28 |
--------------------------------------------------------------------------------
/test/units/redirect.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('https://redirect.test.whistlejs.com/index.html', function(res, data) {
5 | data.should.have.property('url', 'http://test.whistlejs.com/');
6 | });
7 |
8 | util.request({
9 | method: 'post',
10 | url: 'http://redirect.test.whistlejs.com/index.html'
11 | }, function(res, data) {
12 | data.should.have.property('url', 'http://test.whistlejs.com/');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/referer.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://referer.test.whistlejs.com/index.html', function(res, data) {
5 | data.headers.should.have.property('referer', 'xxx');
6 | });
7 |
8 | util.request({
9 | url: 'https://referer.test.whistlejs.com/index.html',
10 | method: 'post'
11 | }, function(res, data) {
12 | data.headers.should.have.property('referer', 'xxx');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/replaceStatus.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://replacestatus.test.whistlejs.com/index.html', function(res, data) {
5 | res.statusCode.should.equal(500);
6 | });
7 |
8 | util.request({
9 | method: 'post',
10 | url: 'https://replacestatus.test.whistlejs.com/index.html'
11 | }, function(res, data) {
12 | res.statusCode.should.equal(500);
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/req.prepend.body.append.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'https://reqprepend.reqbody.reqappend.test.whistlejs.com/',
6 | method: 'post'
7 | }, function(res, data) {
8 | data.body.should.equal('prependbodyappend');
9 | });
10 |
11 | util.request({
12 | url: 'http://reqprepend.reqbody.reqappend.test.whistlejs.com/',
13 | method: 'post'
14 | }, function(res, data) {
15 | data.body.should.equal('prependbodyappend');
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/test/units/reqAppend.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'https://reqappend.test.whistlejs.com/',
6 | method: 'post'
7 | }, function(res, data) {
8 | data.body.should.equal('append\r\nappend');
9 | });
10 |
11 | util.request({
12 | url: 'http://reqappend.test.whistlejs.com/',
13 | method: 'post'
14 | }, function(res, data) {
15 | data.body.should.equal('append\r\nappend');
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/test/units/reqBody.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'https://reqbody.test.whistlejs.com/',
6 | method: 'post'
7 | }, function(res, data) {
8 | data.body.should.equal('body\r\nbody');
9 | });
10 |
11 | util.request({
12 | url: 'http://reqbody.test.whistlejs.com/',
13 | method: 'post'
14 | }, function(res, data) {
15 | data.body.should.equal('body\r\nbody');
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/test/units/reqCharset.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://reqcharset.test.whistlejs.com/index.html', function(res, data) {
5 | data.headers['content-type'].should.containEql('utf8');
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/test/units/reqCookies.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://reqcookies.test.whistlejs.com/', function(res, data) {
5 | data.headers.cookie.should.be.equal('test=abc');
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/test/units/reqCors.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://reqcors.test.whistlejs.com/index.html', function(res, data) {
5 | data.headers.should.have.property('origin', '*');
6 | data.headers.should.have.property('access-control-request-method', 'POST');
7 | data.headers.should.have.property('access-control-request-headers', 'x-test');
8 | });
9 |
10 | util.request({
11 | method: 'post',
12 | url: 'https://reqcors.test.whistlejs.com/index.html'
13 | }, function(res, data) {
14 | data.headers.should.have.property('origin', '*');
15 | data.headers.should.have.property('access-control-request-method', 'POST');
16 | data.headers.should.have.property('access-control-request-headers', 'x-test');
17 | });
18 | };
19 |
--------------------------------------------------------------------------------
/test/units/reqDelay.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | var now = Date.now();
5 | util.request('http://reqdelay.test.whistlejs.com/', function(res, data) {
6 | now = Date.now() - now;
7 | now.should.above(1000);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/test/units/reqHeaders.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://reqheaders.test.whistlejs.com/index.html', function(res, data) {
5 | data.headers.should.have.property('x-test1', 'value1');
6 | data.headers.should.have.property('x-test2', 'value2');
7 | data.headers.should.have.property('x-testn', 'valueN');
8 | });
9 |
10 | util.request({
11 | method: 'post',
12 | url: 'https://reqheaders.test.whistlejs.com/index.html'
13 | }, function(res, data) {
14 | data.headers.should.have.property('x-test1', 'value1');
15 | data.headers.should.have.property('x-test2', 'value2');
16 | data.headers.should.have.property('x-testn', 'valueN');
17 | });
18 | };
19 |
--------------------------------------------------------------------------------
/test/units/reqPrepend.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'https://reqprepend.test.whistlejs.com/',
6 | method: 'post'
7 | }, function(res, data) {
8 | data.body.should.equal('prepend');
9 | });
10 |
11 | util.request({
12 | url: 'http://reqprepend.test.whistlejs.com/',
13 | method: 'post'
14 | }, function(res, data) {
15 | data.body.should.equal('prepend');
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/test/units/reqReplace.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'https://reqreplace.test.whistlejs.com/',
6 | method: 'post',
7 | body: 'testxxx'
8 | }, function(res, data) {
9 | data.body.should.equal('abcxxx');
10 | });
11 |
12 | util.request({
13 | url: 'http://reqreplace.test.whistlejs.com/',
14 | method: 'post',
15 | body: 'test123'
16 | }, function(res, data) {
17 | data.body.should.equal('abc123');
18 | });
19 | };
20 |
--------------------------------------------------------------------------------
/test/units/reqSpeed.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | var now = Date.now();
5 | util.request({
6 | url: 'http://reqspeed.test.whistlejs.com/',
7 | method: 'post',
8 | body: util.getTextBySize(128 * 2 + 1)
9 | }, function(res, data) {
10 | now = Date.now() - now;
11 | now.should.above(2000);
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/test/units/reqType.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://restype.test.whistlejs.com/index.html', function(res, data) {
5 | res.headers.should.have.property('content-type', 'text/html');
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/test/units/res.prepend.body.append.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'https://resprepend.resbody.resappend.test.whistlejs.com/?resBody=',
6 | method: 'post'
7 | }, function(res, body) {
8 | body.should.equal('prependbodyappend');
9 | });
10 |
11 | util.request('http://resprepend.resbody.resappend.test.whistlejs.com/?resBody=', function(res, body) {
12 | body.should.equal('prependbodyappend');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/resAppend.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'https://resappend.test.whistlejs.com/?resBody=',
6 | method: 'post'
7 | }, function(res, body) {
8 | body.should.equal('append\r\nappend');
9 | });
10 |
11 | util.request('http://resappend.test.whistlejs.com/?resBody=', function(res, body) {
12 | body.should.equal('append\r\nappend');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/resBody.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('https://resbody.test.whistlejs.com/?resBody=', function(res, body) {
5 | body.should.equal('body\r\nbody');
6 | });
7 |
8 | util.request({
9 | url: 'https://resbody.test.whistlejs.com/?resBody=',
10 | method: 'post'
11 | }, function(res, body) {
12 | body.should.equal('body\r\nbody');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/resCharset.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://rescharset.test.whistlejs.com/index.html', function(res, data) {
5 | res.headers['content-type'].should.containEql('utf8');
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/test/units/resCookies.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://rescookies.test.whistlejs.com/', function(res, data) {
5 | res.headers['set-cookie'].should.containEql('key2=value2');
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/test/units/resDelay.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | var now = Date.now();
5 | util.request('http://resdelay.test.whistlejs.com/', function(res, data) {
6 | now = Date.now() - now;
7 | now.should.above(1000);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/test/units/resHeaders.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://resheaders.test.whistlejs.com/index.html', function(res, data) {
5 | res.headers.should.have.property('x-test1', 'value1');
6 | res.headers.should.have.property('x-test2', 'value2');
7 | res.headers.should.have.property('x-testn', 'valueN');
8 | });
9 |
10 | util.request({
11 | method: 'post',
12 | url: 'https://resheaders.test.whistlejs.com/index.html'
13 | }, function(res, data) {
14 | res.headers.should.have.property('x-test1', 'value1');
15 | res.headers.should.have.property('x-test2', 'value2');
16 | res.headers.should.have.property('x-testn', 'valueN');
17 | });
18 | };
19 |
--------------------------------------------------------------------------------
/test/units/resPrepend.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'http://resprepend.test.whistlejs.com/?resBody=',
6 | method: 'post'
7 | }, function(res, body) {
8 | body.should.equal('prepend');
9 | });
10 |
11 | util.request('https://resprepend.test.whistlejs.com/?resBody=', function(res, body) {
12 | body.should.equal('prepend');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/resReplace.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'https://resreplace.test.whistlejs.com/?resBody=123test',
6 | method: 'post'
7 | }, function(res, body) {
8 | body.should.equal('123abc');
9 | });
10 |
11 | util.request('http://resreplace.test.whistlejs.com/?resBody=test123', function(res, body) {
12 | body.should.equal('abc123');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/resSpeed.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | var now = Date.now();
5 | util.request({
6 | url: 'http://resspeed.test.whistlejs.com/',
7 | body: util.getTextBySize(128 * 2 + 1),
8 | method: 'post'
9 | }, function(res, data) {
10 | now = Date.now() - now;
11 | now.should.above(2000);
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/test/units/resType.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://reqtype.test.whistlejs.com/index.html', function(res, data) {
5 | data.headers.should.have.property('content-type', 'text/plain');
6 | });
7 | };
8 |
--------------------------------------------------------------------------------
/test/units/rulesFile.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://rf1.w2.org/index.html', function(res, data) {
5 | data.should.have.property('test', 'values');
6 | });
7 | util.request('http://rf2.w2.org/index.html', function(res, data) {
8 | data.should.have.property('test', 'values2');
9 | });
10 | util.request('http://rf3.w2.org/index.html', function(res, data) {
11 | data.should.have.property('test', 'values3');
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/test/units/script.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://reqscript.w2.org/index.html?doNotParseJson', function(res, data) {
5 | data.should.have.equal('123');
6 | res.headers['x-test'].should.have.equal('123');
7 | });
8 | util.request({
9 | url: 'http://reqscript.w2.org/index.html?doNotParseJson',
10 | method: 'POST',
11 | body: 'test'
12 | }, function(res, data) {
13 | data.should.have.equal('test');
14 | res.headers['x-test'].should.have.equal('test');
15 | });
16 | };
17 |
--------------------------------------------------------------------------------
/test/units/ssi-include.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://ssi-include.whistlejs.com/index.html?doNotParseJson', function(res, data) {
5 | data.should.be.containEql('include1.html');
6 | data.should.be.containEql('include2.html');
7 | data.should.be.containEql('include3.html');
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/test/units/statusCode.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'http://statuscode1.testx.whistlejs.com/index.html?resBody=',
6 | method: 'POST',
7 | body: 'xxxxxxxxxxxx'
8 | }, function(res) {
9 | res.statusCode.should.equal(999);
10 | });
11 |
12 | util.request('http://statuscode3.testx.whistlejs.com/index.html?resBody=', function(res) {
13 | res.statusCode.should.equal(500);
14 | });
15 |
16 | util.request({
17 | url: 'http://statuscode4.test.whistlejs.com/index.html?resBody=',
18 | method: 'POST',
19 | body: 'xxxxxxxxxxxx'
20 | }, function(res, body, err) {
21 | err.should.be.ok();
22 | });
23 |
24 | util.request('https://statuscode5.test.whistlejs.com/index.html?resBody=', function(res, body, err) {
25 | err.should.be.ok();
26 | });
27 | };
28 |
--------------------------------------------------------------------------------
/test/units/tpl.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://tpl.test.whistlejs.com/index.html?resBody=%7Bcallback%7D(%7Bec%3A%200%7D)&callback=test', function(res, body) {
5 | body.should.equal('test({ec: 0})');
6 | });
7 |
8 | util.request('http://tpl.test.whistlejs.com/index.html?doNotParseJson&callback=test', function(res, body) {
9 | body.should.equal('test({ec: 0})');
10 | });
11 |
12 | util.request({
13 | method: 'post',
14 | url: 'https://tpl2.test.whistlejs.com/?resBody=%7Bcallback%7D(%7Bec%3A%200%7D)&callback=test'
15 | }, function(res, body) {
16 | body.should.equal('test({ec: 0})');
17 | });
18 |
19 | util.request('http://xtpl.test.whistlejs.com/index2.html', function(res, data) {
20 | data.should.have.property('type', 'server');
21 | });
22 | };
23 |
--------------------------------------------------------------------------------
/test/units/tplStr.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://str.w2.org/index.html?doNotParseJson&a=1&a=2', function(res, body) {
5 | body.should.equal('?doNotPbrseJson&a=1&a=2');
6 | });
7 | util.request('http://str.w2.org/index2.html?doNotParseJson&a=1&a=2', function(res, body) {
8 | body.should.equal('doNotPbrseJson&b=1&b=2');
9 | });
10 | util.request('http://str2.w2.org/index.html?doNotParseJson&a=1&a=2', function(res, body) {
11 | body.should.equal('?doNotPbrseJson&a=1&a=2');
12 | });
13 |
14 | util.request('http://str2.w2.org/index2.html?doNotParseJson&a=1&a=2', function(res, body) {
15 | body.should.equal('doNotPbrseJson&b=1&b=2');
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/test/units/tps.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request({
5 | url: 'http://1.tps.whistlejs.com/index.html?name=tps1.json',
6 | headers: {
7 | 'x-test': 'test',
8 | cookie: 'cookieName=123; test=abc',
9 | other: 'otherhaha'
10 | }
11 | }, function(res, data) {
12 | data.cookieValue.should.equal('123');
13 | });
14 |
15 | util.request({
16 | method: 'post',
17 | headers: {
18 | 'x-test': 'test',
19 | cookie: 'cookieName=123; test=abc; name=tps2.json',
20 | other: 'otherhaha'
21 | },
22 | url: 'https://2.tps.whistlejs.com/?test=abc'
23 | }, function(res, data) {
24 | data.statusCode.should.equal('200');
25 | });
26 | };
27 |
--------------------------------------------------------------------------------
/test/units/tunnel.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.proxy('http://test.whistlejs.com');
5 | util.proxy('http://tnl1.whistlejs.com');
6 | util.proxy('http://tnl2.whistlejs.com');
7 | util.proxy('http://tnl3.whistlejs.com');
8 | util.request('http://tnl4.whistlejs.com', function(res) {
9 | var data = JSON.parse(res.body);
10 | data.type.should.equal('server');
11 | });
12 | util.proxy('http://8080.tnl5.whistlejs.com');
13 | util.proxy('http://8080.tnl6.whistlejs.com');
14 | util.proxy('http://break.whistlejs.com', function(err) {
15 | if (!err) {
16 | throw Error('error');
17 | }
18 | });
19 | util.proxy('http://ts.whistlejs.com/');
20 | };
21 |
--------------------------------------------------------------------------------
/test/units/tunnelPolicy.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('https://tp.w2.org/index.html', function(res, data, err) {
5 | data.ruleValue.should.be.equal('global');
6 | res.headers['content-type'].should.be.equal('text/html');
7 | });
8 |
9 | util.request({
10 | method: 'post',
11 | url: 'https://tp.w2.org/index.html',
12 | isTunnel: true
13 | }, function(res, data, err) {
14 | data.body.should.be.equal('test');
15 | (res.headers['content-type'] | '').should.not.be.equal('text/html');
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/test/units/ua.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://ua.test.whistlejs.com/index.html', function(res, data) {
5 | data.headers.should.have.property('user-agent', 'xxx');
6 | });
7 |
8 | util.request('https://ua.test.whistlejs.com/index.html', function(res, data) {
9 | data.headers.should.have.property('user-agent', 'xxx');
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/test/units/urlParams.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://urlparams.test.whistlejs.com/index.html', function(res, data) {
5 | // data.url.substring(data.url.indexOf('?') + 1).should.equal('test=abc');
6 | });
7 |
8 | util.request({
9 | method: 'post',
10 | url: 'http://urlparams.test.whistlejs.com/index.html'
11 | }, function(res, data) {
12 | // data.url.substring(data.url.indexOf('?') + 1).should.equal('test=abc');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/urlReplace.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://urlreplace.host.test.whistlejs.com/index.html?name=aven&test=abc', function(res, data) {
5 | data.url.should.equal('/index.html?user=ttven&test=ttbc');
6 | });
7 |
8 | util.request({
9 | method: 'post',
10 | url: 'http://urlreplace.host.test.whistlejs.com/index.html?name=aven&test=abc'
11 | }, function(res, data) {
12 | data.url.should.equal('/index.html?user=ttven&test=ttbc');
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/test/units/values.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://values1.avenwu.com/index.html', function(res, data) {
5 | res.headers.should.have.property('x-res-test', 'res');
6 | data.should.have.property('abc', 123);
7 | });
8 |
9 | util.request({
10 | method: 'post',
11 | url: 'http://values2.test.com/index.html',
12 | body: 'ssi1,ssi2,ssi3',
13 | headers: {
14 | 'content-type': 'text/plain'
15 | }
16 | }, function(res, data) {
17 | res.headers.should.have.property('x-res-test2', 'res');
18 | data.headers.should.have.property('x-req-test', 'req');
19 | data.body.should.be.equal('include1.html,include2.html,include3.html');
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/test/units/var.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://var1.wproxy.org/index.html', function(res, data) {
5 | data.should.have.property('json1', 1);
6 | data.should.have.property('json2', 2);
7 | data.should.have.property('json3', 3);
8 | });
9 | };
10 |
--------------------------------------------------------------------------------
/test/units/write.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://reqwrite.test.whistlejs.com/index.html');
5 | util.request({
6 | url: 'https://reqwrite.test.whistlejs.com/index.html',
7 | method: 'post',
8 | body: util.getTextBySize(32)
9 | });
10 |
11 | util.request('https://reswrite2.test.whistlejs.com/index.html');
12 | util.request({
13 | url: 'http://reswrite2.test.whistlejs.com/index.html',
14 | method: 'post',
15 | body: util.getTextBySize(128)
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/test/units/ws.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('ws://test.whistlejs.com/index.html', function(data) {
5 | data.host.should.equal('127.0.0.1:8080');
6 | });
7 |
8 | util.request('wss://ws1.test.whistlejs.com/index.html', function(data) {
9 | data.host.should.equal('127.0.0.1:9999');
10 | });
11 | util.request('wss://test.whistlejs.com/ups.html?abc=123', function(data) {
12 | // data.host.should.equal('127.0.0.1:9999');
13 | });
14 | util.request('wss://test.whistlejs.com/index2.html?abc=321', function(data) {
15 | data.host.should.equal('127.0.0.1:8080');
16 | });
17 | util.requestWS('ws://test.whistlejs.com/index2.html?abc=321', function(data) {
18 | data.host.should.equal('127.0.0.1:8080');
19 | });
20 | util.requestWS('ws://status.whistlejs.com/checkStatusCode.html', function(data) {
21 | data.should.equal('checkStatusCode');
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/test/units/xfile.test.js:
--------------------------------------------------------------------------------
1 | var util = require('../util.test');
2 |
3 | module.exports = function() {
4 | util.request('http://xfile.test.whistlejs.com/index2.html', function(res, data) {
5 | data.should.have.property('type', 'server');
6 | });
7 | };
8 |
--------------------------------------------------------------------------------