anyproxy/index.html

833 lines
49 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimal-ui">
<title>AnyProxy</title>
<link type="text/css" rel="stylesheet" href="assets/css/github-markdown.css">
<link type="text/css" rel="stylesheet" href="assets/css/pilcrow.css">
<link type="text/css" rel="stylesheet" href="assets/css/atom-one-light.css" />
<link type="text/css" rel="stylesheet" href="assets/css/custom.css" />
<meta name="description" content="A fully configurable proxy in NodeJS, which can handle HTTPS requests perfectly.">
<meta name="description" content="AnyProxy - 开放式的HTTP/HTTPS代理你可以灵活控制各种网络数据">
<meta name="keywords" content="代理服务器 Proxy HTTP HTTPS">
<script>
//redirect to Chinese version if in China
if (new Date().getTimezoneOffset() == "-480" && !(/(cn|en)/i.test(location.href))) {
location.href = "./cn.html";
} else {
var _hmt = _hmt || []; (function () { var hm = document.createElement("script"); hm.src = "//hm.baidu.com/hm.js?4e51565b7d471fd6623c163a8fd79e07"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })();
}
</script>
</head>
<body>
<a href="https://github.com/alibaba/anyproxy/tree/4.x" target="_blank">
<img style="position: fixed; top: 0; right: 0; border: 0;z-index: 1;" src="https://camo.githubusercontent.com/a6677b08c955af8400f44c6298f40e7d19cc5b2d/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677261795f3664366436642e706e67"
alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png">
</a>
<article class="markdown-body">
<div class="toc-container" id="j_toc">
<div class="toc-content"><ul class="nav nav-list">
<li class="sidebar-header-1"><a href="#anyproxy">AnyProxy</a></li>
<li class="sidebar-header-2"><a href="#quick-start">Quick start</a></li>
<li class="sidebar-header-3"><a href="#install">install</a></li>
<li class="sidebar-header-3"><a href="#launch">launch</a></li>
<li class="sidebar-header-3"><a href="#other-commands">other commands</a></li>
<li class="sidebar-header-2"><a href="#proxy-https-request">Proxy https request</a></li>
<li class="sidebar-header-2"><a href="#use-rule-module">Use rule module</a></li>
<li class="sidebar-header-3"><a href="#sample">sample</a></li>
<li class="sidebar-header-3"><a href="#the-entire-process">the entire process</a></li>
<li class="sidebar-header-3"><a href="#how-to-load-rule-module">how to load rule module</a></li>
<li class="sidebar-header-2"><a href="#rule-module-interface">Rule module interface</a></li>
<li class="sidebar-header-3"><a href="#summary">summary</a></li>
<li class="sidebar-header-4"><a href="#summary-1">summary</a></li>
<li class="sidebar-header-3"><a href="#beforesendrequest">beforeSendRequest</a></li>
<li class="sidebar-header-4"><a href="#beforesendrequest(requestdetail)">beforeSendRequest(requestDetail)</a></li>
<li class="sidebar-header-3"><a href="#beforesendresponse">beforeSendResponse</a></li>
<li class="sidebar-header-4"><a href="#beforesendresponse(requestdetail,-responsedetail)">beforeSendResponse(requestDetail, responseDetail)</a></li>
<li class="sidebar-header-3"><a href="#beforedealhttpsrequest">beforeDealHttpsRequest</a></li>
<li class="sidebar-header-4"><a href="#beforedealhttpsrequest(requestdetail)">beforeDealHttpsRequest(requestDetail)</a></li>
<li class="sidebar-header-3"><a href="#onerror">onError</a></li>
<li class="sidebar-header-4"><a href="#onerror(requestdetail,-error)">onError(requestDetail, error)</a></li>
<li class="sidebar-header-3"><a href="#onconnecterror">onConnectError</a></li>
<li class="sidebar-header-4"><a href="#onconnecterror(requestdetail,-error)">onConnectError(requestDetail, error)</a></li>
<li class="sidebar-header-3"><a href="#faq">FAQ</a></li>
<li class="sidebar-header-2"><a href="#rule-samples">Rule Samples</a></li>
<li class="sidebar-header-3"><a href="#use-local-response">use local response</a></li>
<li class="sidebar-header-3"><a href="#modify-request-header">modify request header</a></li>
<li class="sidebar-header-3"><a href="#modify-request-body">modify request body</a></li>
<li class="sidebar-header-3"><a href="#modify-the-request-target">modify the request target</a></li>
<li class="sidebar-header-3"><a href="#modify-request-protocol">modify request protocol</a></li>
<li class="sidebar-header-3"><a href="#modify-response-status-code">modify response status code</a></li>
<li class="sidebar-header-3"><a href="#modify-the-response-header">modify the response header</a></li>
<li class="sidebar-header-3"><a href="#modify-response-data-and-delay">modify response data and delay</a></li>
<li class="sidebar-header-2"><a href="#use-anyproxy-as-an-npm-module">Use AnyProxy as an npm module</a></li>
<li class="sidebar-header-2"><a href="#about-anyproxy">About AnyProxy</a></li>
<li class="sidebar-header-2"><a href="#appendix">Appendix</a></li>
<li class="sidebar-header-3"><a href="#config-root-ca-in-osx">Config root CA in OSX</a></li>
<li class="sidebar-header-3"><a href="#trust-root-ca-in-windows">trust root CA in windows</a></li>
<li class="sidebar-header-3"><a href="#config-osx-system-proxy">config OSX system proxy</a></li>
<li class="sidebar-header-3"><a href="#config-http-proxy-server">config http proxy server</a></li>
<li class="sidebar-header-3"><a href="#trust-root-ca-in-ios">trust root CA in iOS</a></li>
<li class="sidebar-header-3"><a href="#trust-root-ca-in-ios-&gt;&#x3D;-10.3">trust root CA in iOS &gt;&#x3D; 10.3</a></li>
<li class="sidebar-header-3"><a href="#config-ios/android-proxy-server">config iOS/Android proxy server</a></li>
</ul>
</div>
</div>
<div class="main-content"><h1 id="anyproxy"><a class="header-link" href="#anyproxy"></a>AnyProxy</h1>
<p>AnyProxy is a fully configurable http/https proxy in NodeJS. Version 4.0 is in beta now.</p>
<p>Ref: <a href="./cn.html">Chinese Doc 中文文档</a></p>
<p>Github: </p>
<ul class="list">
<li><a href="https://github.com/alibaba/anyproxy/tree/4.x">https://github.com/alibaba/anyproxy/tree/4.x</a></li>
</ul>
<p>Features:</p>
<ul class="list">
<li>Offer you the ablity to handle http traffic by invoking a js module</li>
<li>Intercept https</li>
<li>GUI webinterface</li>
</ul>
<p>Change Logs since 3.x:</p>
<ul class="list">
<li>Support Promise and Generator in rule module</li>
<li>Simplified interface in rule module</li>
<li>A newly designed web interface</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/SqVntpzmscXPbSzfcGcr.png" width="500" /></p>
<h2 id="quick-start"><a class="header-link" href="#quick-start"></a>Quick start</h2>
<h3 id="install"><a class="header-link" href="#install"></a>install</h3>
<pre class="hljs"><code>npm install -g anyproxy@beta <span class="hljs-comment"># 4.x is in beta now</span></code></pre><h3 id="launch"><a class="header-link" href="#launch"></a>launch</h3>
<ul class="list">
<li>start AnyProxy in command line, with default port 8001</li>
</ul>
<pre class="hljs"><code>anyproxy</code></pre><ul class="list">
<li>now you can use http proxy server by 127.0.0.1:8001</li>
<li>visit <a href="http://127.0.0.1:8002">http://127.0.0.1:8002</a> to see the http requests</li>
</ul>
<h3 id="other-commands"><a class="header-link" href="#other-commands"></a>other commands</h3>
<ul class="list">
<li>specify the port of http proxy</li>
</ul>
<pre class="hljs"><code>anyproxy --port 1080</code></pre><h2 id="proxy-https-request"><a class="header-link" href="#proxy-https-request"></a>Proxy https request</h2>
<ul class="list">
<li>AnyProxy does NOT intercept https requests by default. To view decrypted info, you have to config the CA certificate.</li>
</ul>
<blockquote>
<p>Under the hood, AnyProxy decryptes https requests by man-in-the-middle attack. Users have to trust the CA cert in advance. Otherwise, client side will issue errors about unsecure network.</p>
</blockquote>
<ul class="list">
<li>generate certifycates and intercept</li>
</ul>
<pre class="hljs"><code>anyproxy-ca <span class="hljs-comment">#generate root CA. manually trust it after that.</span>
anyproxy --intercept <span class="hljs-comment">#launch anyproxy and intercept all https traffic</span></code></pre><ul class="list">
<li><a href="#osx系统信任ca证书">Appendixhow to trust CA</a></li>
</ul>
<h2 id="use-rule-module"><a class="header-link" href="#use-rule-module"></a>Use rule module</h2>
<p>AnyProxy provides the ability to load your own rules written in javascript. With rule module, you could customize the logic to handle requests.</p>
<blockquote>
<p>Make sure your rule file is got from a trusted source. Otherwise, you may face some unknown security risk.</p>
</blockquote>
<p>Rule module could do the following stuff:</p>
<ul class="list">
<li>intercept and modify the request which is being sent<ul class="list">
<li>editable fields include request header, body, target address</li>
</ul>
</li>
<li>intercept and modify the response from server<ul class="list">
<li>editable fields include response status code, header, body</li>
</ul>
</li>
<li>intercept https requests, modify request and response</li>
</ul>
<h3 id="sample"><a class="header-link" href="#sample"></a>sample</h3>
<ul class="list">
<li><p>Target</p>
<ul class="list">
<li>write a rule module to append some text to the response of GET <a href="http://httpbin.org/user-agent">http://httpbin.org/user-agent</a>, and delay the response for 5 seconds</li>
</ul>
</li>
<li><p>Step 1Write the rule file, save as sample.js</p>
<pre class="hljs"><code><span class="hljs-comment">// file: sample.js</span>
<span class="hljs-built_in">module</span>.exports = {
<span class="hljs-attr">summary</span>: <span class="hljs-string">'a rule to modify response'</span>,
*beforeSendResponse(requestDetail, responseDetail) {
<span class="hljs-keyword">if</span> (requestDetail.url === <span class="hljs-string">'http://httpbin.org/user-agent'</span>) {
<span class="hljs-keyword">const</span> newResponse = responseDetail.response;
newResponse.body += <span class="hljs-string">'-- AnyProxy Hacked! --'</span>;
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> { <span class="hljs-comment">// delay</span>
resolve({ <span class="hljs-attr">response</span>: newResponse });
}, <span class="hljs-number">5000</span>);
});
}
},
};</code></pre></li>
<li><p>Step 2, start AnyProxy and load the rule file</p>
<ul class="list">
<li>run <code>anyproxy --rule sample.js</code></li>
</ul>
</li>
<li><p>Step 3, test</p>
<ul class="list">
<li><p>use curl </p>
<pre class="hljs"><code>curl http://httpbin.org/user-agent --proxy http://127.0.0.1:8001</code></pre></li>
<li><p>use browser. Point the http proxy of browser to 127.0.0.1:8001, then visit <a href="http://httpbin.org/user-agent">http://httpbin.org/user-agent</a> </p>
</li>
<li><p>the expected response from proxy is </p>
</li>
</ul>
<pre class="hljs"><code>{
<span class="hljs-string">"user-agent"</span>: <span class="hljs-string">"curl/7.43.0"</span>
}
- AnyProxy Hacked!</code></pre></li>
<li><p>Step 4, view the request log</p>
<ul class="list">
<li>visit <a href="http://127.0.0.1:8002">http://127.0.0.1:8002</a>, the request just sent should be listed here</li>
</ul>
</li>
</ul>
<h3 id="the-entire-process"><a class="header-link" href="#the-entire-process"></a>the entire process</h3>
<ul class="list">
<li>The flow chart is as follows</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/TWyNuSJtEZBdrdcOMRjE.png" width="550" /></p>
<ul class="list">
<li><p>When got an http request, the entire process of proxy server is</p>
<ul class="list">
<li>AnyProxy collects all the quest info, include method, header, body</li>
<li>AnyProxy calls <code>beforeSendRequest</code> of the rule module. Rule module deal the request, return new request param or response content</li>
<li>If <code>beforeSendRequest</code> returns the response content, AnyProxy will send the response to client without sending to target server. The process ends here.</li>
<li>Send request to target server, collect response</li>
<li>Call <code>beforeSendResponse</code> of the rule module. Rule module deal the response data</li>
<li>Send response to client</li>
</ul>
</li>
<li><p>When AnyProxy get https request, it could replace the certificate and decrypt the request data</p>
<ul class="list">
<li>AnyProxy calls <code>beforeDealHttpsRequest</code> of the rule module</li>
<li>If the function returns <code>true</code>, AnyProxy will do the man-in-the-middle attack to it. Otherwise, the request will not be dealed.</li>
</ul>
</li>
</ul>
<h3 id="how-to-load-rule-module"><a class="header-link" href="#how-to-load-rule-module"></a>how to load rule module</h3>
<ul class="list">
<li><p>use local file</p>
<pre class="hljs"><code>anyproxy --rule ./rule.js</code></pre></li>
<li><p>use an online rule file</p>
<pre class="hljs"><code>anyproxy --rule https://sample.com/rule.js</code></pre></li>
<li><p>use an npm module</p>
<ul class="list">
<li>AnyProxy uses <code>require()</code> to load rule module. You could either load a local npm module or a global-installed one.</li>
</ul>
<pre class="hljs"><code>anyproxy --rule ./myRulePkg/ <span class="hljs-comment">#local module</span>
npm i -g myRulePkg &amp;&amp; anyproxy --rule myRulePkg <span class="hljs-comment">#global-installed module</span></code></pre></li>
</ul>
<h2 id="rule-module-interface"><a class="header-link" href="#rule-module-interface"></a>Rule module interface</h2>
<p>A typical rule module is as follows. All the functions are optional, just write the part you are interested in.</p>
<pre class="hljs"><code><span class="hljs-built_in">module</span>.exports = {
<span class="hljs-comment">// introduction</span>
summary: <span class="hljs-string">'my customized rule for AnyProxy'</span>,
<span class="hljs-comment">// intercept before send request to server</span>
*beforeSendRequest(requestDetail) { <span class="hljs-comment">/* ... */</span> },
<span class="hljs-comment">// deal response before send to client </span>
*beforeSendResponse(requestDetail, responseDetail) { <span class="hljs-comment">/* ... */</span> },
<span class="hljs-comment">// if deal https request</span>
*beforeDealHttpsRequest(requestDetail) { <span class="hljs-comment">/* ... */</span> },
<span class="hljs-comment">// error happened when dealing requests</span>
*onError(requestDetail, error) { <span class="hljs-comment">/* ... */</span> },
<span class="hljs-comment">// error happened when connect to https server</span>
*onConnectError(requestDetail, error) { <span class="hljs-comment">/* ... */</span> }
};</code></pre><blockquote>
<p>All functions in your rule file, except summary, are all driven by <a href="https://www.npmjs.com/package/co">co</a> . They should be yieldable, i.e. return a promise or be a generator function.</p>
</blockquote>
<h3 id="summary"><a class="header-link" href="#summary"></a>summary</h3>
<h4 id="summary-1"><a class="header-link" href="#summary-1"></a>summary</h4>
<ul class="list">
<li>Introduction of this rule file. AnyProxy will read this field and give some tip to user.</li>
</ul>
<h3 id="beforesendrequest"><a class="header-link" href="#beforesendrequest"></a>beforeSendRequest</h3>
<h4 id="beforesendrequest(requestdetail)"><a class="header-link" href="#beforesendrequest(requestdetail)"></a>beforeSendRequest(requestDetail)</h4>
<ul class="list">
<li>Before sending request to server, AnyProxy will call <code>beforeSendRequest</code> with param <code>requestDetail</code></li>
<li><code>requestDetail</code> <ul class="list">
<li><code>protocol</code> {string} the protocol to use, http or https</li>
<li><code>requestOptions</code> {object} the options of the request-to-go, a param of require(&#39;http&#39;).request . ref: <a href="https://nodejs.org/api/http.html#http_http_request_options_callback">https://nodejs.org/api/http.html#http_http_request_options_callback</a></li>
<li><code>requestData</code> {object} request body</li>
<li><code>url</code> {string} request url</li>
<li><code>_req</code> {object} the native node.js request object</li>
</ul>
</li>
<li><p>e.g. When requesting <em>anyproxy.io</em>, <code>requestDetail</code> is something like the following</p>
<pre class="hljs"><code>{
<span class="hljs-attr">protocol</span>: <span class="hljs-string">'http'</span>,
<span class="hljs-attr">url</span>: <span class="hljs-string">'http://anyproxy.io/'</span>,
<span class="hljs-attr">requestOptions</span>: {
<span class="hljs-attr">hostname</span>: <span class="hljs-string">'anyproxy.io'</span>,
<span class="hljs-attr">port</span>: <span class="hljs-number">80</span>,
<span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>,
<span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span>,
<span class="hljs-attr">headers</span>: {
<span class="hljs-attr">Host</span>: <span class="hljs-string">'anyproxy.io'</span>,
<span class="hljs-string">'Proxy-Connection'</span>: <span class="hljs-string">'keep-alive'</span>,
<span class="hljs-string">'User-Agent'</span>: <span class="hljs-string">'...'</span>
}
},
<span class="hljs-attr">requestData</span>: <span class="hljs-string">'...'</span>,
<span class="hljs-attr">_req</span>: { <span class="hljs-comment">/* ... */</span>}
}</code></pre></li>
<li><p>Any of these return values are valid</p>
<ul class="list">
<li>do nothing, and return null</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;</code></pre><ul class="list">
<li>modify the request protocoli.e. force use https</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> {
<span class="hljs-attr">protocol</span>: <span class="hljs-string">'https'</span>
};</code></pre><ul class="list">
<li>modify request param</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">var</span> newOption = <span class="hljs-built_in">Object</span>.assign({}, requestDetail.requestOptions);
newOption.path = <span class="hljs-string">'/redirect/to/another/path'</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">requestOptions</span>: newOption
};</code></pre><ul class="list">
<li>modify request body</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> {
<span class="hljs-attr">requestData</span>: <span class="hljs-string">'my new request data'</span>
<span class="hljs-comment">// requestOptions can also be used here</span>
};</code></pre><ul class="list">
<li>give response to the client, not sending request any longer. <code>statusCode</code> <code>headers</code>are required is this situation.</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: {
<span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
<span class="hljs-attr">header</span>: { <span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span> },
<span class="hljs-attr">body</span>: <span class="hljs-string">'this could be a &lt;string&gt; or &lt;buffer&gt;'</span>
}
};</code></pre></li>
</ul>
<h3 id="beforesendresponse"><a class="header-link" href="#beforesendresponse"></a>beforeSendResponse</h3>
<h4 id="beforesendresponse(requestdetail,-responsedetail)"><a class="header-link" href="#beforesendresponse(requestdetail,-responsedetail)"></a>beforeSendResponse(requestDetail, responseDetail)</h4>
<ul class="list">
<li>Before sending response to client, AnyProxy will call <code>beforeSendResponse</code> with param <code>requestDetail</code> <code>responseDetail</code></li>
<li><code>requestDetail</code> is the same param as in <code>beforeSendRequest</code></li>
<li><code>responseDetail</code> <ul class="list">
<li><code>response</code> {object} the response from server, includes <code>statusCode</code> <code>header</code> <code>body</code></li>
<li><code>_res</code> {object} the native node.js response object</li>
</ul>
</li>
<li><p>e.g. When requesting <em>anyproxy.io</em>, <code>responseDetail</code> is something like the following</p>
<pre class="hljs"><code>{
<span class="hljs-attr">response</span>: {
<span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
<span class="hljs-attr">header</span>: {
<span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'image/gif'</span>,
<span class="hljs-attr">Connection</span>: <span class="hljs-string">'close'</span>,
<span class="hljs-string">'Cache-Control'</span>: <span class="hljs-string">'...'</span>
},
<span class="hljs-attr">body</span>: <span class="hljs-string">'...'</span>
},
<span class="hljs-attr">_res</span>: { <span class="hljs-comment">/* ... */</span> }
}</code></pre></li>
<li><p>Any of these return values are valid</p>
<ul class="list">
<li>do nothing, and return null</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;</code></pre><ul class="list">
<li>modify the response status code</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">var</span> newResponse = <span class="hljs-built_in">Object</span>.assign({}, responseDetail.response);
newResponse.statusCode = <span class="hljs-number">404</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: newResponse
};</code></pre><ul class="list">
<li>modify the response content</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">var</span> newResponse = <span class="hljs-built_in">Object</span>.assign({}, responseDetail.response);
newResponse.body += <span class="hljs-string">'--from anyproxy--'</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: newResponse
};</code></pre></li>
</ul>
<h3 id="beforedealhttpsrequest"><a class="header-link" href="#beforedealhttpsrequest"></a>beforeDealHttpsRequest</h3>
<h4 id="beforedealhttpsrequest(requestdetail)"><a class="header-link" href="#beforedealhttpsrequest(requestdetail)"></a>beforeDealHttpsRequest(requestDetail)</h4>
<ul class="list">
<li>When receiving https request, AnyProxy will call <code>beforeDealHttpsRequest</code> with param <code>requestDetail</code></li>
<li>If configed with <code>forceProxyHttps</code> in launching, AnyProxy will skip calling this method</li>
<li>Only by returning true, AnyProxy will try to replace the certificate and intercept the https request.</li>
<li><code>requestDetail</code><ul class="list">
<li><code>host</code> {string} the target host to request. Due to the request protocol, full url couldn&#39;t be got here</li>
<li><code>_req</code> {object} the native node.js request object. The <code>_req</code> here refers to the CONNECT request.</li>
</ul>
</li>
<li>return value<ul class="list">
<li><code>true</code> or <code>false</code>, whether AnyProxy should intercept the https request</li>
</ul>
</li>
</ul>
<h3 id="onerror"><a class="header-link" href="#onerror"></a>onError</h3>
<h4 id="onerror(requestdetail,-error)"><a class="header-link" href="#onerror(requestdetail,-error)"></a>onError(requestDetail, error)</h4>
<ul class="list">
<li>AnyProxy will call this method when an error happened in request handling.</li>
<li>Errors usually are issued during requesting, e.g. DNS failure, request timeout</li>
<li><code>requestDetail</code> is the same one as in <code>beforeSendRequest</code></li>
<li><p>Any of these return values are valid</p>
<ul class="list">
<li>do nothing, and AnyProxy will response a default error page</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;</code></pre><ul class="list">
<li>return a customized error page</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: {
<span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
<span class="hljs-attr">header</span>: { <span class="hljs-string">'content-type'</span>: <span class="hljs-string">'text/html'</span> },
<span class="hljs-attr">body</span>: <span class="hljs-string">'this could be a &lt;string&gt; or &lt;buffer&gt;'</span>
}
};</code></pre></li>
</ul>
<h3 id="onconnecterror"><a class="header-link" href="#onconnecterror"></a>onConnectError</h3>
<h4 id="onconnecterror(requestdetail,-error)"><a class="header-link" href="#onconnecterror(requestdetail,-error)"></a>onConnectError(requestDetail, error)</h4>
<ul class="list">
<li>AnyProxy will call this method when failed to connect target server in https request</li>
<li><code>requestDetail</code> is the same one as in <code>beforeDealHttpsRequest</code></li>
<li>no return value is required </li>
</ul>
<h3 id="faq"><a class="header-link" href="#faq"></a>FAQ</h3>
<ul class="list">
<li>Q: can not deal https request in rule module.</li>
<li><p>A: Any of these options could be used to change the way AnyProxy deall https requests </p>
<ol class="list">
<li>config <code>--intercept</code> when luanching AnyProxy via cli, or use <code>forceProxyHttps</code> when using as an npm module</li>
<li>place a <code>beforeDealHttpsRequest</code> function in your rule file and determine which request to intercept by your own.</li>
</ol>
</li>
<li><p>Q: get an error says <em>function is not yieldable</em></p>
</li>
<li>A: Rule module is driven by <a href="https://www.npmjs.com/package/co">co</a>. The functions inside should be yieldable, i.e. return a promise or be a generator function.</li>
</ul>
<h2 id="rule-samples"><a class="header-link" href="#rule-samples"></a>Rule Samples</h2>
<ul class="list">
<li>here are some samples about frequently used rule file</li>
<li>try these samples by <code>anyproxy --rule http://....js</code></li>
<li>how to test with curl:<ul class="list">
<li>request the server directly <code>curl http://httpbin.org/</code></li>
<li>request the server via proxy <code>curl http://httpbin.org/ --proxy http://127.0.0.1:8001</code></li>
</ul>
</li>
</ul>
<h3 id="use-local-response"><a class="header-link" href="#use-local-response"></a>use local response</h3>
<ul class="list">
<li>intercept the request towards <a href="http://httpbin.org">http://httpbin.org</a> , return the local-defined response</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_use_local_response.js</code></pre><pre class="hljs"><code><span class="hljs-comment">/*
sample:
intercept all requests toward httpbin.org, use a local response
test:
curl http://httpbin.org/user-agent --proxy http://127.0.0.1:8001
*/</span>
<span class="hljs-built_in">module</span>.exports = {
*beforeSendRequest(requestDetail) {
<span class="hljs-keyword">const</span> localResponse = {
<span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
<span class="hljs-attr">header</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
<span class="hljs-attr">body</span>: <span class="hljs-string">'{"hello": "this is local response"}'</span>
};
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org'</span>) === <span class="hljs-number">0</span>) {
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: localResponse
};
}
},
};</code></pre><h3 id="modify-request-header"><a class="header-link" href="#modify-request-header"></a>modify request header</h3>
<ul class="list">
<li>modify the user-agent sent to httpbin.org</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_request_header.js</code></pre><pre class="hljs"><code><span class="hljs-comment">/*
sample:
modify the user-agent in requests toward httpbin.org
test:
curl http://httpbin.org/user-agent --proxy http://127.0.0.1:8001
*/</span>
<span class="hljs-built_in">module</span>.exports = {
*beforeSendRequest(requestDetail) {
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org'</span>) === <span class="hljs-number">0</span>) {
<span class="hljs-keyword">const</span> newRequestOptions = requestDetail.requestOptions;
newRequestOptions.headers[<span class="hljs-string">'User-Agent'</span>] = <span class="hljs-string">'AnyProxy/0.0.0'</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">requestOptions</span>: newRequestOptions
};
}
},
};</code></pre><h3 id="modify-request-body"><a class="header-link" href="#modify-request-body"></a>modify request body</h3>
<ul class="list">
<li>modify the post body of <a href="http://httpbin.org/post">http://httpbin.org/post</a></li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_request_data.js</code></pre><pre class="hljs"><code><span class="hljs-comment">/*
sample:
modify the post data towards http://httpbin.org/post
test:
curl -H "Content-Type: text/plain" -X POST -d 'original post data' http://httpbin.org/post --proxy http://127.0.0.1:8001
expected response:
{ "data": "i-am-anyproxy-modified-post-data" }
*/</span>
<span class="hljs-built_in">module</span>.exports = {
<span class="hljs-attr">summary</span>: <span class="hljs-string">'Rule to modify request data'</span>,
*beforeSendRequest(requestDetail) {
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org/post'</span>) === <span class="hljs-number">0</span>) {
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">requestData</span>: <span class="hljs-string">'i-am-anyproxy-modified-post-data'</span>
};
}
},
};</code></pre><h3 id="modify-the-request-target"><a class="header-link" href="#modify-the-request-target"></a>modify the request target</h3>
<ul class="list">
<li>send all the request towards <a href="http://httpbin.org/">http://httpbin.org/</a> to <a href="http://httpbin.org/user-agent">http://httpbin.org/user-agent</a></li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_request_path.js</code></pre><pre class="hljs"><code><span class="hljs-comment">/*
sample:
redirect all httpbin.org requests to http://httpbin.org/user-agent
test:
curl http://httpbin.org/any-path --proxy http://127.0.0.1:8001
expected response:
{ "user-agent": "curl/7.43.0" }
*/</span>
<span class="hljs-built_in">module</span>.exports = {
*beforeSendRequest(requestDetail) {
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org'</span>) === <span class="hljs-number">0</span>) {
<span class="hljs-keyword">const</span> newRequestOptions = requestDetail.requestOptions;
newRequestOptions.path = <span class="hljs-string">'/user-agent'</span>;
newRequestOptions.method = <span class="hljs-string">'GET'</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">requestOptions</span>: newRequestOptions
};
}
},
};</code></pre><h3 id="modify-request-protocol"><a class="header-link" href="#modify-request-protocol"></a>modify request protocol</h3>
<ul class="list">
<li>modify the http request towards <a href="http://httpbin.org">http://httpbin.org</a> to https</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_request_protocol.js</code></pre><pre class="hljs"><code><span class="hljs-comment">/*
sample:
redirect all http requests of httpbin.org to https
test:
curl 'http://httpbin.org/get?show_env=1' --proxy http://127.0.0.1:8001
expected response:
{ "X-Forwarded-Protocol": "https" }
*/</span>
<span class="hljs-built_in">module</span>.exports = {
*beforeSendRequest(requestDetail) {
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org'</span>) === <span class="hljs-number">0</span>) {
<span class="hljs-keyword">const</span> newOption = requestDetail.requestOptions;
newOption.port = <span class="hljs-number">443</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">protocol</span>: <span class="hljs-string">'https'</span>,
<span class="hljs-attr">requestOptions</span>: newOption
};
}
}
};</code></pre><h3 id="modify-response-status-code"><a class="header-link" href="#modify-response-status-code"></a>modify response status code</h3>
<ul class="list">
<li>modify all status code from <a href="http://httpbin.org">http://httpbin.org</a> to 404</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_response_statuscode.js</code></pre><pre class="hljs"><code><span class="hljs-comment">/*
sample:
modify all status code of http://httpbin.org/ to 404
test:
curl -I 'http://httpbin.org/user-agent' --proxy http://127.0.0.1:8001
expected response:
HTTP/1.1 404 Not Found
*/</span>
<span class="hljs-built_in">module</span>.exports = {
*beforeSendResponse(requestDetail, responseDetail) {
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org'</span>) === <span class="hljs-number">0</span>) {
<span class="hljs-keyword">const</span> newResponse = responseDetail.response;
newResponse.statusCode = <span class="hljs-number">404</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: newResponse
};
}
}
};</code></pre><h3 id="modify-the-response-header"><a class="header-link" href="#modify-the-response-header"></a>modify the response header</h3>
<ul class="list">
<li>add X-Proxy-By:AnyProxy to the response header from <a href="http://httpbin.org/user-agent">http://httpbin.org/user-agent</a></li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_response_header.js</code></pre><pre class="hljs"><code><span class="hljs-comment">/*
sample:
modify response header of http://httpbin.org/user-agent
test:
curl -I 'http://httpbin.org/user-agent' --proxy http://127.0.0.1:8001
expected response:
X-Proxy-By: AnyProxy
*/</span>
<span class="hljs-built_in">module</span>.exports = {
*beforeSendResponse(requestDetail, responseDetail) {
<span class="hljs-keyword">if</span> (requestDetail.url.indexOf(<span class="hljs-string">'http://httpbin.org/user-agent'</span>) === <span class="hljs-number">0</span>) {
<span class="hljs-keyword">const</span> newResponse = responseDetail.response;
newResponse.header[<span class="hljs-string">'X-Proxy-By'</span>] = <span class="hljs-string">'AnyProxy'</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">response</span>: newResponse
};
}
}
};</code></pre><h3 id="modify-response-data-and-delay"><a class="header-link" href="#modify-response-data-and-delay"></a>modify response data and delay</h3>
<ul class="list">
<li>append some info to the response of <a href="http://httpbin.org/user-agent">http://httpbin.org/user-agent</a>, then delay the response for 5 seconds.</li>
</ul>
<pre class="hljs"><code>anyproxy --rule https://raw.githubusercontent.com/alibaba/anyproxy/4.x/rule_sample/sample_modify_response_data.js</code></pre><pre class="hljs"><code><span class="hljs-comment">/*
sample:
modify response data of http://httpbin.org/user-agent
test:
curl 'http://httpbin.org/user-agent' --proxy http://127.0.0.1:8001
expected response:
{ "user-agent": "curl/7.43.0" } -- AnyProxy Hacked! --
*/</span>
<span class="hljs-built_in">module</span>.exports = {
*beforeSendResponse(requestDetail, responseDetail) {
<span class="hljs-keyword">if</span> (requestDetail.url === <span class="hljs-string">'http://httpbin.org/user-agent'</span>) {
<span class="hljs-keyword">const</span> newResponse = responseDetail.response;
newResponse.body += <span class="hljs-string">'-- AnyProxy Hacked! --'</span>;
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> { <span class="hljs-comment">// delay the response for 5s</span>
resolve({ <span class="hljs-attr">response</span>: newResponse });
}, <span class="hljs-number">5000</span>);
});
}
},
};</code></pre><h2 id="use-anyproxy-as-an-npm-module"><a class="header-link" href="#use-anyproxy-as-an-npm-module"></a>Use AnyProxy as an npm module</h2>
<p>AnyProxy can be used as an npm module</p>
<blockquote>
<p>To enable https feature, please guide users to use <code>anyproxy-ca</code> in cli. Or use methods under <code>AnyProxy.utils.certMgr</code> to generate certificates.</p>
</blockquote>
<ul class="list">
<li>install</li>
</ul>
<pre class="hljs"><code>npm i anyproxy@beta --save <span class="hljs-comment"># 4.0 is in beta now</span></code></pre><ul class="list">
<li>sample</li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">const</span> AnyProxy = <span class="hljs-built_in">require</span>(<span class="hljs-string">'anyproxy'</span>);
<span class="hljs-keyword">const</span> options = {
<span class="hljs-attr">port</span>: <span class="hljs-number">8001</span>,
<span class="hljs-attr">rule</span>: <span class="hljs-built_in">require</span>(<span class="hljs-string">'myRuleModule'</span>),
<span class="hljs-attr">webInterface</span>: {
<span class="hljs-attr">enable</span>: <span class="hljs-literal">true</span>,
<span class="hljs-attr">webPort</span>: <span class="hljs-number">8002</span>,
<span class="hljs-attr">wsPort</span>: <span class="hljs-number">8003</span>,
},
<span class="hljs-attr">throttle</span>: <span class="hljs-number">10000</span>,
<span class="hljs-attr">forceProxyHttps</span>: <span class="hljs-literal">false</span>,
<span class="hljs-attr">silent</span>: <span class="hljs-literal">false</span>
};
<span class="hljs-keyword">const</span> proxyServer = <span class="hljs-keyword">new</span> AnyProxy.ProxyServer(options);
proxyServer.on(<span class="hljs-string">'ready'</span>, () =&gt; { <span class="hljs-comment">/* */</span> });
proxyServer.on(<span class="hljs-string">'error'</span>, (e) =&gt; { <span class="hljs-comment">/* */</span> });
proxyServer.start();
<span class="hljs-comment">//when finished</span>
proxyServer.close();</code></pre><ul class="list">
<li><p>Class: AnyProxy.proxyServer</p>
<ul class="list">
<li><p>create a proxy server</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> proxy = <span class="hljs-keyword">new</span> AnyProxy.proxyServer(options)</code></pre></li>
<li><p><code>options</code></p>
<ul class="list">
<li><code>port</code> {number} required, port number of proxy server</li>
<li><code>rule</code> {object} your rule module</li>
<li><code>throttle</code> {number} throttle in kb/s, unlimited for default</li>
<li><code>forceProxyHttps</code> {boolean} in force intercept all https request, false for default</li>
<li><code>silent</code> {boolean} if keep silent in console, false for default<code>false</code></li>
<li><code>dangerouslyIgnoreUnauthorized</code> {boolean} if ignore certificate error in request, false for default</li>
<li><code>webInterface</code> {object} config for web interface<ul class="list">
<li><code>enable</code> {boolean} if enable web interface, false for default</li>
<li><code>webPort</code> {number} port number for web interface</li>
</ul>
</li>
</ul>
</li>
<li><p>Event: <code>ready</code></p>
<ul class="list">
<li>emit when proxy server is ready</li>
<li>sample</li>
</ul>
<pre class="hljs"><code>proxy.on(<span class="hljs-string">'ready'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ })</code></pre></li>
<li><p>Event: <code>error</code></p>
<ul class="list">
<li>emit when error happened inside proxy server</li>
<li>sample</li>
</ul>
<pre class="hljs"><code>proxy.on(<span class="hljs-string">'error'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ })</code></pre></li>
<li><p>Method: <code>start</code></p>
<ul class="list">
<li>start proxy server</li>
<li>sample</li>
</ul>
<pre class="hljs"><code>proxy.start();</code></pre></li>
<li><p>Method: <code>close</code></p>
<ul class="list">
<li>close proxy server</li>
<li>sample</li>
</ul>
<pre class="hljs"><code>proxy.close();</code></pre></li>
</ul>
</li>
<li><p>AnyProxy.utils.systemProxyMgr</p>
<ul class="list">
<li>manage the system proxy config. sudo password may be required</li>
<li>sample</li>
</ul>
<pre class="hljs"><code><span class="hljs-comment">// set 127.0.0.1:8001 as system http server</span>
AnyProxy.utils.systemProxyMgr.enableGlobalProxy(<span class="hljs-string">'127.0.0.1'</span>, <span class="hljs-string">'8001'</span>);
<span class="hljs-comment">// disable global proxy server</span>
AnyProxy.utils.systemProxyMgr.disableGlobalProxy();</code></pre></li>
<li><p>AnyProxy.utils.certMgr</p>
<ul class="list">
<li>Manage certificates of AnyProxy</li>
<li><code>AnyProxy.utils.certMgr.ifRootCAFileExists()</code><ul class="list">
<li>detect if AnyProx rootCA exists</li>
</ul>
</li>
<li><code>AnyProxy.utils.certMgr.generateRootCA(callback)</code><ul class="list">
<li>generate a rootCA</li>
</ul>
</li>
<li>Sample</li>
</ul>
<pre class="hljs"><code> <span class="hljs-keyword">const</span> AnyProxy = <span class="hljs-built_in">require</span>(<span class="hljs-string">'AnyProxy'</span>);
<span class="hljs-keyword">const</span> exec = <span class="hljs-built_in">require</span>(<span class="hljs-string">'child_process'</span>).exec;
<span class="hljs-keyword">if</span> (!AnyProxy.utils.certMgr.ifRootCAFileExists()) {
AnyProxy.utils.certMgr.generateRootCA(<span class="hljs-function">(<span class="hljs-params">error, keyPath</span>) =&gt;</span> {
<span class="hljs-comment">// let users to trust this CA before using proxy</span>
<span class="hljs-keyword">if</span> (!error) {
<span class="hljs-keyword">const</span> certDir = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>).dirname(keyPath);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'The cert is generated at'</span>, certDir);
<span class="hljs-keyword">const</span> isWin = <span class="hljs-regexp">/^win/</span>.test(process.platform);
<span class="hljs-keyword">if</span> (isWin) {
exec(<span class="hljs-string">'start .'</span>, { <span class="hljs-attr">cwd</span>: certDir });
} <span class="hljs-keyword">else</span> {
exec(<span class="hljs-string">'open .'</span>, { <span class="hljs-attr">cwd</span>: certDir });
}
} <span class="hljs-keyword">else</span> {
<span class="hljs-built_in">console</span>.error(<span class="hljs-string">'error when generating rootCA'</span>, error);
}
});
}</code></pre></li>
</ul>
<h2 id="about-anyproxy"><a class="header-link" href="#about-anyproxy"></a>About AnyProxy</h2>
<ul class="list">
<li>Change Log: <a href="https://github.com/alibaba/anyproxy/blob/master/CHANGELOG">https://github.com/alibaba/anyproxy/blob/master/CHANGELOG</a></li>
<li>Github<a href="https://github.com/alibaba/anyproxy">https://github.com/alibaba/anyproxy</a></li>
<li>issue<a href="https://github.com/alibaba/anyproxy/issues">https://github.com/alibaba/anyproxy/issues</a></li>
</ul>
<h2 id="appendix"><a class="header-link" href="#appendix"></a>Appendix</h2>
<h3 id="config-root-ca-in-osx"><a class="header-link" href="#config-root-ca-in-osx"></a>Config root CA in OSX</h3>
<ul class="list">
<li>this kind of errors is usually caused by untrusted root CA</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/CBkLGYgvoHAYwNVAYkpk.png" width="450" /></p>
<blockquote>
<p>Warning: please keep your root CA safe since it may influence your system security.</p>
</blockquote>
<p>install </p>
<ul class="list">
<li><p>double click <em>rootCA.crt</em></p>
</li>
<li><p>add cert into login or system</p>
</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/bCwNUFFpvsmVuljQKrIk.png" width="350" /></p>
<ul class="list">
<li>find the newly imported AnyProxy certificates, configured as <strong>Always Trust</strong></li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/HOmEElNGdoZEWFMLsTNT.png" width="700" /></p>
<h3 id="trust-root-ca-in-windows"><a class="header-link" href="#trust-root-ca-in-windows"></a>trust root CA in windows</h3>
<p class="img-container"><img src="https://t.alipayobjects.com/tfscom/T1D3hfXeFtXXXXXXXX.jpg" width="700" /></p>
<h3 id="config-osx-system-proxy"><a class="header-link" href="#config-osx-system-proxy"></a>config OSX system proxy</h3>
<ul class="list">
<li>the config is in wifi - advanced</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/vduwhobSTypTfgniBvoa.png" width="500" /></p>
<h3 id="config-http-proxy-server"><a class="header-link" href="#config-http-proxy-server"></a>config http proxy server</h3>
<ul class="list">
<li>take Chrome extent [SwitchyOmega] as an example(<a href="https://chrome.google.com/webstore/detail/padekgcemlokbadohgkifijomclgjgif)为例">https://chrome.google.com/webstore/detail/padekgcemlokbadohgkifijomclgjgif)为例</a></li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/jIPZrKmqXRaSledQeJUJ.png" width="500" /></p>
<h3 id="trust-root-ca-in-ios"><a class="header-link" href="#trust-root-ca-in-ios"></a>trust root CA in iOS</h3>
<ul class="list">
<li>Click <em>Root CA</em> in web ui, and follow the instruction to install</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/BrugmMelGVysLDOIBblj.png" width="260" /></p>
<h3 id="trust-root-ca-in-ios->=-10.3"><a class="header-link" href="#trust-root-ca-in-ios->=-10.3"></a>trust root CA in iOS &gt;= 10.3</h3>
<ul class="list">
<li>Besides installing root CA, you have to &quot;turn on&quot; the certificate for web manually in <em>settings - general - about - Certificate Trust Settings</em>. Otherwire, safari will not trust the root CA generated by AnyProxy.</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/hVWkXHrzHmOKOtCKGUWx.png" width="500" /></p>
<h3 id="config-ios/android-proxy-server"><a class="header-link" href="#config-ios/android-proxy-server"></a>config iOS/Android proxy server</h3>
<ul class="list">
<li><p>proxy settings are placed in wifi setting</p>
</li>
<li><p>iOS</p>
</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/tLGqIozhffTccUgPakuw.png" width="260" /></p>
<ul class="list">
<li>Android</li>
</ul>
<p class="img-container"><img src="https://zos.alipayobjects.com/rmsportal/YQtbQYVNuOszZGdAOauU.png" width="260" /></p>
</div>
</article>
<script src="//cdn.bootcss.com/zepto/1.2.0/zepto.min.js"></script>
<script>
window.onload = function(){
var itemList = [];
var targetMap = {};
$("[id]", ".main-content").map(function (index, heading) {
targetMap[heading.getAttribute('id')] = heading;
});
$("#j_toc li").map(function (index, item) {
if (item.className.indexOf('sidebar-header-2') >= 0 || item.className.indexOf('sidebar-header-3') >= 0) {
var targetName = item.firstChild.getAttribute('href').replace('#', '');
var targetItem = targetMap[targetName];
itemList.push({ target: targetItem, tocItem: item, top: $(targetItem).position().top });
}
});
var updateTocActive = function (e) {
var windowHeight = window.innerHeight;
//find the first item to match
var scrollYThres = window.scrollY + 200;
var target;
if (scrollYThres < 100) {
target = itemList[0].tocItem;
} else {
itemList.forEach(function (item, index) {
if (target) return;
if (index > 0) {
if (item.top >= scrollYThres) {
target = itemList[index - 1].tocItem;
}
}
});
}
$('.toc-active').removeClass('toc-active');
$(target).addClass('toc-active');
};
window.onscroll = updateTocActive;
updateTocActive();
}
</script>
</body>
</html>