Compare commits

..

782 Commits

Author SHA1 Message Date
Jarrett Cruger
9b96cd7251 1.18.1 2020-05-17 17:26:59 -04:00
Jason
335aeeba2f
Skip sending the proxyReq event when the expect header is present (#1447)
* Skip sending the proxyReq event when the expect header is present

* Adjust padding to match advisory

Co-authored-by: Smylnycky, Jason M <jason.smylnycky@cengage.com>
2020-05-17 17:18:42 -04:00
Jason
dba39668ba
Remove node6 support, add node12 to build (#1397) 2020-05-17 17:16:55 -04:00
indexzero
9bbe486c5e [dist] Version bump. 1.18.0 2019-09-17 21:40:59 -04:00
Jason
6e4bef4d1c
Added in auto-changelog module set to keepachangelog format (#1373)
Removed last nodejitsu reference
2019-09-05 14:11:16 -04:00
Nick Gilligan
d05624167c fix 'Modify Response' readme section to avoid unnecessary array copying (#1300) 2019-08-22 02:40:15 -05:00
IdeaHunter
244303b994 Fix incorrect target name for reverse proxy example (#1135) 2019-08-22 02:39:14 -05:00
Ben Costolo
b4028ba78b Fix modify response middleware example (#1139)
* declare app variable to house middleware

* remove deprecated connect.createServer() function call

* specify middleware with app.use() and pass app middleware to an http
server
2019-08-22 02:38:28 -05:00
renovate[bot]
77a98159d2 [dist] Update dependency async to v3 (#1359) 2019-08-22 02:37:57 -05:00
Kristoffer Lundén
c662f9ebcd Fix path to local http-proxy in examples. (#1072) 2019-08-22 02:35:20 -05:00
Li Bin
806e4927c9 fix reverse-proxy example require path (#1067) 2019-08-22 02:34:29 -05:00
Subomi Oluwalana
c8fa599983 Update README.md (#970)
There were errors in the examples highlighted, check issue #969
2019-08-22 02:31:44 -05:00
renovate[bot]
0d9ed366b1 [dist] Update dependency request to ~2.88.0 [SECURITY] (#1357) 2019-08-22 02:30:06 -05:00
renovate[bot]
9d75b981a1 [dist] Update dependency eventemitter3 to v4 (#1365) 2019-08-22 02:29:37 -05:00
renovate[bot]
192b2b980b [dist] Update dependency colors to v1 (#1360) 2019-08-22 02:29:14 -05:00
renovate[bot]
4a657a7126 [dist] Update all non-major dependencies (#1356) 2019-08-22 02:24:41 -05:00
renovate[bot]
7a154f81d1 [dist] Update dependency agentkeepalive to v4 (#1358) 2019-08-22 02:24:25 -05:00
renovate[bot]
749eec65c3 [dist] Update dependency nyc to v14 (#1367) 2019-08-22 02:21:15 -05:00
renovate[bot]
e588213644 [dist] Update dependency concat-stream to v2 (#1363) 2019-08-22 02:16:50 -05:00
indexzero
59c4403e9d [fix] Latest versions. 2019-08-22 02:12:51 -05:00
indexzero
dd1d08b631 [fix test] Update tests. 2019-08-22 02:12:51 -05:00
indexzero
16d4f8a951 [dist] Regenerate package-lock.json. 2019-08-22 02:12:51 -05:00
indexzero
fc93520d74 [dist] .gitattributes all the things. 2019-08-22 02:12:51 -05:00
indexzero
7e4a0e511b [dist] New test fixtures. 2019-08-22 02:12:51 -05:00
indexzero
a9b09cce43 [dist] End of an era. 2019-08-22 02:12:51 -05:00
Renovate Bot
b00911c937 [dist] Update dependency ws to v3 [SECURITY] 2019-08-22 02:12:51 -05:00
Jaggernoth
36bfe566a7 x-forwarded-host overwrite for mutli level proxies (#1267)
With more than 1 proxy the original host was lost, now it will be passed down the proxy chain
2019-08-22 02:09:26 -05:00
Charlie Robbins
91fee3e943
[refactor doc] Complete rename to http-party org. (#1362) 2019-08-22 01:46:16 -05:00
Justin Russell
235f0aa047 Highlight correct lines for createProxyServer (#1117) 2019-08-22 01:41:47 -05:00
Stein Martin Hustad
acdbec09c6 Fix docs for rewrite options - 201 also handled (#1147)
Updates options documentation for location rewrite to include 201 responses. See #1024
2019-08-22 01:40:03 -05:00
Marcin K
569e2ac4fb Update .nyc_output (#1339)
Currently published version includes .nyc_output and coverage
2019-08-22 01:39:17 -05:00
renovate[bot]
cb3171abfa Configure Renovate (#1355)
* Add renovate.json

* [dist] Configure renovate more.
2019-08-22 01:38:48 -05:00
任侠
a3fe02d651 [examples] Restream body before proxying, support for Content-Type of application/x-www-form-urlencoded (#1264) 2018-06-06 12:39:50 -04:00
Jarrett Cruger
42e8e1e099 1.17.0 2018-04-20 11:42:55 -04:00
Jarrett Cruger
e94d52973a [dist] doc updates 2018-04-20 11:35:07 -04:00
Jarrett Cruger
4a37175a52 [test] add test for selfHandleRequest and remove modifyResponse as selfHandleRequest is the only way that functionality works 2018-04-20 11:35:07 -04:00
guoxiangyang
e5c02b8a8a add support for modify response 2018-04-20 11:35:07 -04:00
Jake Furler
2c44039a7c issue #953: stop using writeHead
object.keys in web-incoming.js results in a non-deterministic ordering of keys, which means that in web-outgoing writeHead might be called before setHeader, which throws an error
2018-04-20 11:35:07 -04:00
Thiago Bustamante
8097ae237e Fix "Can't set headers after they are sent" errors
This PR tries to fix "Can't set headers after they are sent" errors.
That are a lot of situations where this error can occurs. In my case, it is happening because I have others middlewares (in an expressjs application that tries to proxy requests). Some of those middlewares (like [passportjs](http://passportjs.org/), or [cors](https://www.npmjs.com/package/cors)) can run ```res.end()``` and when the proxy receive a response, it is already finished.
So, it is necessary to test if we can write on the user response when the proxy response is ready.
I think it could also fix #930, #1168, #908
2018-04-20 11:35:07 -04:00
Jarrett Cruger
abf882e03c [dist] update package-lock.json 2018-04-20 11:35:07 -04:00
Gustav Tiger
bab02e909e Include websocket non-upgrade response
When the server do not accept the upgrade request for websockets the
server's response was previously not included and sent back. Now the
proxy will include the response in these cases. Fixes #890.
2018-04-20 11:35:07 -04:00
n30n0v
c9a556cfa5 Add followRedirects option 2018-04-20 11:35:07 -04:00
Jon Hunter
6f88caf6e4 Add detail about "buffer" option 2018-04-20 11:35:07 -04:00
Radu Serbanescu
d2f9db8241 Add use case for proxy to HTTPS using a PKCS12 client certificate 2018-04-20 11:35:07 -04:00
carpsareokiguess
8231984fb0 fix small typos in README 2018-04-20 11:35:07 -04:00
Jarrett Cruger
81d58c531b [test] for override method feature 2018-04-20 11:35:07 -04:00
Jarrett Cruger
d533a1be43 [dist] document the feature 2018-04-20 11:35:07 -04:00
shaohui.tsh
89f9ef87e0 feat: 添加response自处理参数 2018-04-20 11:35:07 -04:00
Aydin
c5d8466483 Update common.js
Add method parameter to options for overriding the proxy-outgoing HTTP-method
2018-04-20 11:35:07 -04:00
jlaamanen
107c18720c Added timeout option to docs 2018-04-20 11:35:07 -04:00
Jarrett Cruger
de1b80851a [fix] slightly more tolerant 2018-04-20 11:35:07 -04:00
Sean Willis
bc6a23709c Removing unnecessary check since this is a private API 2018-04-20 11:35:07 -04:00
Sean Willis
f5c2381395 Updating docs and adding more tests. 2018-04-20 11:35:07 -04:00
Sean Willis
50f58b4cd9 Forgot 'i' flag when changing from regex shorthand to string. 2018-04-20 11:35:07 -04:00
Sean Willis
2c98416ac2 Adding ability to set cookie path 2018-04-20 11:35:07 -04:00
Jarrett Cruger
543636d0f6 [fix] move badges 2018-04-20 11:35:07 -04:00
Jarrett Cruger
a4bccc332d [dist][test] codecov config 2018-04-20 11:35:07 -04:00
Jarrett Cruger
f4ff1006b9 [wip] proper tests and reporting 2018-04-20 11:35:07 -04:00
Jarrett Cruger
09dcb98456 [dist] make tests work reliably, add package-lock.json 2018-04-20 11:35:07 -04:00
Georgi Yordanov
812757541d Fix overwriting of global options (#1074) 2018-01-02 19:48:17 -05:00
Elad Ben-Israel
c979ba9f2c Update README.md (#1131)
Update link to properties
2017-01-11 15:53:05 -05:00
Jarrett Cruger
e6f24ba617 [fix] rm newline 2016-12-24 17:03:33 -05:00
Ivan Nieto
d73f1ee873 Update README.md with CoC link (#1120)
* Add Code Of Conduct

* Update CODE_OF_CONDUCT.md

Fix placeholder

* Update REAME.md
2016-12-24 17:02:41 -05:00
Ivan Nieto
a539f3cbc1 Add Code Of Conduct (#1119)
* Add Code Of Conduct

* Update CODE_OF_CONDUCT.md

Fix placeholder
2016-12-24 13:27:54 -05:00
Luigi Pinca
d4d85ac5c4 [deps] Update eventemitter3 to version 2.0.x (#1109) 2016-12-16 12:28:52 -05:00
Jarrett Cruger
c1fb596b85 1.16.2 2016-12-06 10:49:02 -05:00
Yuta Shimizu
961f457622 [WIP] Revert default behavior of writeHeaders method (#1104)
* Replace header key only

* Add preserveHeaderKeyCase Option
2016-12-06 09:51:01 -05:00
Jarrett Cruger
ac1a01b1f3 [dist] Version bump. 1.16.1 2016-12-04 10:59:46 -05:00
Kris Williams
8cb451f20c Enable proxy response to have multiple Set-Cookie raw headers #1101 2016-12-04 10:58:49 -05:00
Jarrett Cruger
c252b32f6c 1.16.0 2016-12-02 09:13:10 -05:00
Maarten ter Horst
927357bedc Fix newly introduced error in error handler for ECONNREFUSED in forward proxy (#1100) 2016-12-02 09:09:11 -05:00
Yuta Shimizu
4edbb62cc5 Keep original letter case of response header keys (#1098)
* Keep original letter case of response header keys

* Support node older than v0.11.6

messege.rawHeaders was added in v0.11.6

* Extract duplicated logic to method
2016-12-01 20:03:13 -05:00
Maarten ter Horst
69cf892519 Handle errors for forward request, add test case (#1099) 2016-12-01 09:39:46 -05:00
purificant
2f7f03778c add node 6 to travis 2016-11-29 09:01:06 -05:00
Jarrett Cruger
d8223884f6 1.15.2 2016-10-22 11:47:23 -04:00
Jarrett Cruger
d0f1dfeb82 [fix] style nits 2016-10-22 11:45:16 -04:00
François Leurent
220f5fb795 Expose full callback names 2016-10-22 11:45:16 -04:00
François Leurent
d48f67eb90 Do not rely on func.name (no scope) 2016-10-22 11:45:16 -04:00
François Leurent
61c2889109 Do not rely on func.name (no scope) 2016-10-22 11:45:16 -04:00
François Leurent
fbc266809c With a comment 2016-10-22 11:45:16 -04:00
François Leurent
8eddf45f2a Fix browserification
Browserify fails to resolve the "./http-proxy/" as "./http-proxy/index.js" but as "./http-proxy.js" (so nothing works)
Beeing explicit here does not cost much for http-proxy, yet it's intrinsically complicated for browserify to fix (as trailing slash might be used as a pollyfill shim for native/non-natives addons i.e.  require('url/') vs require('url') )
2016-10-22 11:45:16 -04:00
Niranjan Ojha
f5217d6c20 test case added 2016-10-06 16:24:44 -04:00
Niranjan Ojha
2d01edc5a5 not setting connection header in case of http2 as it is deprecated 2016-10-06 16:24:44 -04:00
Ashish Dahiya
d0a1588639 Add proxy-timeout option to documentation (#1075)
http-proxy provides a [proxyTimeout option](https://github.com/nodejitsu/node-http-proxy/blob/master/lib/http-proxy/passes/web-incoming.js#L122) that allows us to set a timeout on the outgoing socket connection to the target. This timeout is very effective when the upstream target does not respond within an expected time.

I had wasted a few hours searching for this option. Documenting this option can save others a significant amount of time.
2016-10-04 09:54:52 -04:00
Jarrett Cruger
912cd3acae [dist] Version bump. 1.15.1 2016-09-14 17:12:30 -04:00
briman0094
84087208dd Properly write response header optionally including statusMessage (#1061) 2016-09-14 17:08:26 -04:00
Jarrett Cruger
b98c75b1ff [dist] Version bump. 1.15.0 2016-09-14 13:05:56 -04:00
Alex Indigo
b781af641a Made it not to crash with omited Host http header (#1050) 2016-09-14 07:03:48 -04:00
Michael Ira Krufky
cbd5777060 README.md: fix typo: 'ingoing' should be 'incoming' (#1060) 2016-09-14 07:02:30 -04:00
Cole Chamberlain
d8fb344715 Fix for Reason-Phrase being overwritten on proxy response. (#1051)
* Fix for Reason-Phrase being overwritten on proxy response.

Calling res.writeHead has the side effect of defaulting the Reason-Phrase to default ones.  I'm using Reason-Phrase codes to sub-route api responses and they were all being reset.  This change only sets the statusMessage (Reason-Phrase) if it exists on the proxyRes and is successfully passing it through in my tests.

* Fixed spaces and bracket formatting.
2016-09-13 18:19:33 -04:00
Jeremy Judeaux
1e52f660f0 cookieDomainRewrite option (#1009) 2016-08-12 13:42:18 -04:00
wuchangming
9d06ca99d3 Update ntlm-authentication.js (#1025) 2016-08-11 12:37:57 -04:00
Mati B. Terefe
d0e000e1f9 Restream body before proxying (#1027)
Support for bodyparser.json and bodyparser.urlencoded.

Fixes #955 #843 #791
2016-08-11 12:37:32 -04:00
Gabriel Boucher
183b5bb4fc Location rewriting for responses with status 201 (#1024)
Implement rewriting of the location header for responses with status code 201, according to RFC2616 section 10.2.2
2016-08-11 12:36:17 -04:00
Ken
3a347af543 #866 Copy CA from options into outbound proxy (#1042)
While using secure: true for proxy connections, there is no way to pass the trusted root CA(s) or intermediate CA(s). This change allows that to be passed in the httpProxy createServer options and used for the outgoing proxy connection.
2016-08-11 12:20:35 -04:00
Jarrett Cruger
fcfb0b37f6 [dist] Version bump. 1.14.0 2016-06-15 10:52:53 -04:00
Deividy Metheler
42df703830 Emit disconnected event instead of error when ECONNRESET (#966)
* Emit disconnected event instead of error when ECONNRESET

ECONNRESET means the other side of the TCP conversation abruptly
closed its end of the connection.

If we get an ECONNRESET error from the proxy request and the
socket is destroyed this means that the client has closed
his connection, and emit this as an error can lead to
confusion and hacks to filter that kind of message.

I think that the best we can do is abort and emit another event,
so if any caller wants to handle with that kind of error, he can
by listen the disconnected event.

https://github.com/nodejitsu/node-http-proxy/issues/813

* code standards, move econnreset check, change ev name
2016-06-03 13:39:40 -04:00
Jeremy Judeaux
3e966361bc fix test for node 0.10 + socket.io-client@1.4.6 (engine.io-client@1.6.9) (#1010) 2016-05-25 12:18:51 -04:00
Jarrett Cruger
5082acc067 [dist] Version bump. 1.13.3 2016-05-15 23:14:51 -04:00
idjem
433a7408cf fix browserify compatibility (#975) 2016-05-15 15:40:01 -04:00
Muromi Ukari
6baf1498cb alter message error (#998)
message error about port 9001 -> port 9002
2016-04-28 09:15:03 -07:00
Mihai Ene
284903d379 Sanitize header keys before setting them (#997)
Fixes #996.
2016-04-26 13:26:35 -07:00
Jarrett Cruger
b223275ebb Merge pull request #989 from aroder/patch-1
Update ntlm-authentication.js
2016-04-26 13:23:33 -07:00
Adam Roderick
ecdfff408f Update ntlm-authentication.js
missing bracket
2016-04-14 16:21:39 -05:00
Jarrett Cruger
28cecb5a96 Merge pull request #983 from deanshelton913/add-datatype-to-readme
Add expected datatype to readme
2016-03-23 18:36:21 -04:00
deanshelton913
bdb3492b21 Add expected datatype to readme
This confused me while attempting to use this feature
2016-03-23 15:19:50 -07:00
Jarrett Cruger
a4b2857216 Merge pull request #982 from kylehayes/patch-1
Update README
2016-03-22 15:13:09 -04:00
Kyle Hayes
820fc5987c Update README
For clarity
2016-03-22 08:47:14 -07:00
indexzero
f345a1ac2d [dist] Update LICENSE to reflect 2015 changes. 2016-03-12 00:05:21 -08:00
Jarrett Cruger
018352955e Merge pull request #974 from bmac/patch-1
Fix formatting of the `headers` option
2016-03-08 17:26:38 -08:00
Brendan McLoughlin
f8d605d53f Fix formatting of the headers option 2016-03-08 18:07:11 -05:00
Jarrett Cruger
c1440b58f1 Merge pull request #967 from jbacklund/patch-1
Set the x-forwarded-host flag when xfwd is enabled
2016-02-26 09:52:26 -08:00
Jakob Backlund
ef86b50427 Set the x-forwarded-host flag when xfwd is enabled
Reasoning: Rack's request class [makes use of](https://github.com/rack/rack/blob/master/lib/rack/request.rb#L243) this HTTP header. Certain edge-case scenarios (proxying from ember-cli to a Rails backend) can be problematic without this header being present.

/cc @perlun, @jesjos
2016-02-26 14:29:55 +02:00
Jarrett Cruger
e1b2f4c31b [dist] Version bump. 1.13.2 2016-02-17 11:00:08 -05:00
Jarrett Cruger
820f198729 Merge pull request #806 from chimurai/master
Fixed missing documentation: #options.headers
2016-02-16 18:05:28 -05:00
Jarrett Cruger
d2df053677 Merge pull request #950 from caioquirino/master
#949 Proxy example using req instead res on README
2016-02-15 10:36:24 -05:00
Jarrett Cruger
7357200334 Merge pull request #962 from Turbo87/default-mocha-reporter
mocha: Use default reporter
2016-02-15 10:35:41 -05:00
Jarrett Cruger
d19be83858 Merge pull request #961 from Turbo87/transfer-encoding-fix
Remove "transfer-encoding" header if "content-length" is set to zero
2016-02-15 10:35:32 -05:00
Tobias Bieniek
570cf3b4f9 mocha: Use default reporter
Unfortunately the "landing" reporter doesn't really look good on CI servers at all...
2016-02-15 15:47:46 +01:00
Tobias Bieniek
5c46e4b754 Remove "transfer-encoding" header if "content-length" is set to zero 2016-02-15 15:43:14 +01:00
Caio Quirino da Silva
25e56d0182 #949 Proxy example using req instead res on README
README example implies request instead of response parameter
2016-02-02 11:56:39 -02:00
Jarrett Cruger
9d9fa940cf [dist] Version bump. 1.13.1 2016-02-01 21:02:33 -08:00
Jarrett Cruger
2831d9a4f9 Merge pull request #932 from afriza/patch-1
README.md: summary to specify reverse proxy
2016-02-01 20:59:49 -08:00
Jarrett Cruger
a379d160f3 Merge pull request #947 from coderaiser/fix-urlJoin
fix(common) urlJoin replace: ":/" -> "http?s:/"
2016-02-01 20:59:18 -08:00
Jarrett Cruger
7aed1f4559 Merge pull request #948 from Alfredo-Delgado/patch-1
Update README.md
2016-02-01 20:58:45 -08:00
Alfredo Delgado
bfcab93d8d Update README.md
Fixed typo.
2016-01-30 12:26:26 -05:00
coderaiser
7bad3fbca4 fix(common) urlJoin replace: ":/" -> "http?s:/" 2016-01-29 02:47:12 -05:00
Jarrett Cruger
268994ea45 [dist] Version bump. 1.13.0 2016-01-26 17:11:50 -05:00
Jarrett Cruger
58c0fdc761 Merge pull request #934 from Torthu/master
Fix for #839 (Ignore path and the trailing slash)
2016-01-26 15:56:58 -05:00
Charlie Robbins
d73b0d312a Merge pull request #943 from pra85/patch-1
Update license year range to 2016
2016-01-26 01:02:52 -08:00
Prayag Verma
a76e226221 Update license year range to 2016 2016-01-26 14:12:24 +05:30
Jarrett Cruger
db576d75c1 Merge pull request #942 from merpnderp/patch-1
Bump version for npm publish
2016-01-24 15:19:54 -05:00
Kaleb Murphy
e017fa8189 Bump version for npm publish
Would be great to get the NTLM fix into npm.
2016-01-24 14:11:12 -06:00
Jarrett Cruger
646a7493a4 Merge pull request #940 from merpnderp/FixSetHeader
Added check to passes/web-outgoing.js to make sure the header being s…
2016-01-23 12:27:49 -05:00
merpnderp
3b39d2c3dc Added check to passes/web-outgoing.js to make sure the header being set is not undefined, which should be the only falsey value that could accidently show up and break that call. This fixes windows NTLM auth issues behind http-proxy. 2016-01-22 09:17:14 -06:00
Torstein Thune
0cb1d3c68e Added note for appending trailing / when using ignorePath 2016-01-13 15:27:51 +01:00
Torstein Thune
f9540de7b1 Fixed tests depending on ignorePath 2016-01-13 15:24:46 +01:00
Torstein Thune
f2093b5313 No longer appends / to path if ignorePath is set 2016-01-13 09:16:50 +01:00
Afriza N. Arief
41414a56a1 README.md: introduction to specify reverse proxy
clarify proxy type to be reverse proxy in the introduction
2016-01-04 12:40:05 +08:00
Charlie Robbins
6371231086 Merge pull request #825 from pose/patch-1
Created reverse-proxy.js example.
2015-12-29 23:53:21 -05:00
Jarrett Cruger
6c83980f29 Merge pull request #922 from aaronmaturen/sse
SSE example and test
2015-12-07 15:58:22 -05:00
Aaron T. Maturen
e4760727f1 SSE example and test 2015-12-06 19:34:42 -05:00
Charlie Robbins
222a4d0fa1 Merge pull request #912 from nodejitsu/more-structured-readme
More structured readme
2015-11-23 13:12:37 -05:00
donasaur
6106d4c32f Added back to top helpers 2015-11-23 09:46:15 -08:00
donasaur
cd1d7776e8 Organized README more 2015-11-23 09:30:05 -08:00
Jarrett Cruger
642e9cc2cb Merge pull request #910 from nodejitsu/proxy-table-readme
Updated markdown docs to mention proxy rules module
2015-11-22 14:19:09 -05:00
donasaur
eea79cab53 Updated markdown docs to mention proxy rules 2015-11-20 17:28:37 -08:00
Jarrett Cruger
f82ce18d2f [ci] use node 4.2 to test and do not allow failures 2015-11-09 19:43:18 -08:00
Jarrett Cruger
470475b896 Merge pull request #901 from jedverity/master
Add tests for forwarding of continuation frames
2015-11-09 14:53:05 -08:00
Jarrett Cruger
2a5e69d48c Merge pull request #904 from shinnn/deps
Bump requires-port, server and ws
2015-11-06 13:20:22 -08:00
Shinnosuke Watanabe
9ea1e89a2f [fix] bump requires-port, server and ws
npm v3 tries to dedupe the dependencies by default, and keeping
dependencies up-to-date helps better deduplication.

https://github.com/unshiftio/requires-port
https://github.com/npm/node-semver
https://github.com/websockets/ws
2015-11-05 17:49:45 +09:00
Jarrett Cruger
ab42124d54 Merge pull request #903 from nodejitsu/ntlm-authentication
[example] add an example for NTLM authentication
2015-10-30 14:16:10 -07:00
Jarrett Cruger
5d593e8ef1 [example] add an example for NTLM authentication 2015-10-30 14:14:03 -07:00
glortho
64fa520789 Add tests for testing forwarding of continuation frames
This adds two tests that send payloads below and at the threshold for continuation frames. Using node 0.12.7 both tests pass. Using node 4.1.2 the test below the threshold passes but the other fails.
2015-10-28 15:52:37 -04:00
Jarrett Cruger
b5a6d0e583 [dist] Version bump. 1.12.0 2015-10-22 19:27:24 -04:00
Jarrett Cruger
0bc4c783ca Merge pull request #897 from lbrucher/issue-896
Issue #896: provide a "proxyReq" event also for websocket connections.
2015-10-22 19:26:02 -04:00
Laurent Brucher
9752652e76 fixes after PR review 2015-10-22 18:38:58 +02:00
Laurent Brucher
a05fc2d169 Provide a "proxyReq" event also for websocket connections. 2015-10-22 15:56:34 +02:00
Jarrett Cruger
60baca5aed [dist] Version bump. 1.11.3 2015-10-19 09:30:18 -04:00
Charlie Robbins
6b65c428b3 Merge pull request #893 from donasaur/master
Removed unspecified trailing slash in proxy url
2015-10-18 16:15:53 -05:00
donasaur
eb97bf5423 Removed unspecified trailing slash in proxy url 2015-10-18 13:04:06 -07:00
Jarrett Cruger
ec64e4f597 Merge pull request #892 from donasaur/patch-1
Updating the upgrading doc
2015-10-18 10:45:45 -04:00
Don Mai
e666a4e07d Updating the upgrading doc
Recently ran into a case where I had to upgrade the `http-proxy` version for an app, and that app was using a proxy table.

I'm not sure how many users are still using the 0.x.x version of `http-proxy`, but the added link (found from one of the GH issues) may encourage them to switch over to 1.x.x if they were using the old version due to its proxy table support and the activation energy to upgrade was too high.

I might release a module for this eventually, lol, since there was some work involved in creating a proxy table to map paths to paths for the same hostname.
2015-10-18 01:12:19 -07:00
chimurai
c86ae51bb9 docs: options.headers 2015-09-26 23:46:11 +02:00
indexzero
302d981dd2 [dist] Update .travis.yml to be more modern. 2015-09-21 18:22:31 -07:00
Jarrett Cruger
30e3b371de [dist] Version bump. 1.11.2 2015-08-30 17:29:25 -04:00
Jarrett Cruger
cea0e8676b [fix] make more functional 2015-08-30 17:28:05 -04:00
Arttu Liimola
3d2350c54f Replaced Object.keys().map with for in loop. 2015-08-30 17:16:42 -04:00
Arttu Liimola
ca73208749 Websocket key was unnecessary long. 2015-08-30 17:16:36 -04:00
Arttu Liimola
da674ec4df Modify the set-cookie header fix to work with node 0.10.x. 2015-08-30 17:16:07 -04:00
Arttu Liimola
855cebdac4 Added websocket set-cookie headers test 2015-08-30 17:16:00 -04:00
Arttu Liimola
8bfd90c4d9 Use raw headers instead parsed.
Set-Cookie headers are parsed into single header with cookies in array.
This messes up the Set-Cookie headers, because browser receives multiple Set-Cookie headers as single with cookies separted with comma.
2015-08-30 17:15:54 -04:00
Charlie Robbins
931f73dc98 Merge pull request #870 from justsml/patch-1
Update gzip-middleware.js
2015-08-24 12:38:27 -07:00
Daniel Levy
349b843731 Update gzip-middleware.js
Punctuation
2015-08-24 13:23:53 -06:00
Charlie Robbins
2e3eb0950d Merge pull request #863 from stuartpb/patch-1
Fix broken option list indentation
2015-08-14 12:30:42 -07:00
Stuart P. Bentley
1f4fccd2c6 Fix broken option list indentation 2015-08-14 09:02:50 -07:00
Jarrett Cruger
ecbba1a008 Merge pull request #852 from jpatters/patch-1
Added missing configuration options
2015-07-09 09:55:36 -04:00
Jordan
fe3dd8363f Added missing configuration options
Added missing config options for httpProxy.createProxyServer. Updated to include all options listed in `lib/http-proxy.js`
Addresses nodejitsu/node-http-proxy#851
2015-07-09 08:03:23 -03:00
Alberto Pose
38864d0167 Created reverse-proxy.js example. 2015-05-18 20:30:43 -03:00
Jarrett Cruger
76051032e7 Merge pull request #823 from montogeek/patch-1
Added installation instructions
2015-05-13 10:24:09 -07:00
Fernando Montoya
7e82a04a16 Added installation instructions 2015-05-12 21:38:05 -05:00
Jarrett Cruger
1912b62ddb Merge pull request #817 from klammbueddel/master
fixes comment
2015-05-09 14:23:03 -07:00
klammbueddel
3f997b9289 fixes comment 2015-04-30 10:19:40 +02:00
Jarrett Cruger
7e6c66a7e4 [dist] Version bump. 1.11.1 2015-04-22 11:09:36 -04:00
Jarrett Cruger
d26ef56e1b [fix] dont use bind in the one case we do 2015-04-22 11:09:05 -04:00
Jarrett Cruger
607f96c00c [dist] update to new version of EE3 2015-04-22 11:07:24 -04:00
Jarrett Cruger
18c77cafc7 [fix] use the main export for EE3 2015-04-22 11:07:13 -04:00
Jarrett Cruger
934e6c4d54 [dist] Version bump. 1.11.0 2015-04-20 16:48:14 -04:00
Jarrett Cruger
0db8f195d7 Merge pull request #759 from nodejitsu/ignore-path
[api] add an ignorePath option if you want to disregard the path of the ...
2015-04-20 16:47:27 -04:00
Jarrett Cruger
0bd446c680 [dist] Version bump. 1.10.1 2015-04-02 12:41:02 -04:00
Jarrett Cruger
a6ae6c4997 [ci] add 0.12 and iojs to travis 2015-04-02 12:32:08 -04:00
Jarrett Cruger
1b89bc9a76 [dist] add semver and normalize package.json with --save-dev 2015-04-02 12:31:17 -04:00
Jarrett Cruger
c6dfb04a67 [fix] properly support iojs with test checking for HTTPS 2015-04-02 12:30:55 -04:00
Jarrett Cruger
6201ac76f7 Merge pull request #799 from F4-Group/fix_https
Fix default port detection with node 0.12.x
2015-04-02 12:05:03 -04:00
Jeremy Judeaux
5f14bcaa70 fix protocol and default port detection on node 0.12.x, compatible with 0.10.x 2015-04-02 14:23:58 +02:00
Jeremy Judeaux
0ee314c436 fix expected error message when node 0.12.x 2015-04-02 14:22:26 +02:00
Jeremy Judeaux
c33d1616cd force cipher AES128-GCM-SHA256 in https tests 2015-04-02 14:11:45 +02:00
Jarrett Cruger
1dabda241f [dist] Version bump. 1.10.0 2015-04-01 12:24:26 -04:00
Jarrett Cruger
5a969d077b Merge pull request #787 from mokafive/master
Fixes / additions to URL rewriting
2015-04-01 12:20:37 -04:00
Jarrett Cruger
21b30b754d [dist] Version bump. 1.9.1 2015-04-01 12:09:42 -04:00
Jarrett Cruger
aa8f3e9a6e Merge pull request #798 from damonmcminn/master
Fix #747
2015-04-01 11:07:42 -04:00
Damon McMinn
ab37a224aa Fix https://github.com/nodejitsu/node-http-proxy/issues/747 2015-04-01 13:19:03 +01:00
Damon McMinn
d145152655 Add test for https://github.com/nodejitsu/node-http-proxy/issues/747 2015-04-01 13:14:11 +01:00
Jarrett Cruger
87a92a7280 [dist] Version bump. 1.9.0 2015-03-12 18:59:32 -04:00
Jarrett Cruger
507f818df5 Merge pull request #792 from ashubham/master
Adding the nodejs0.12 auth option
2015-03-12 18:58:06 -04:00
ashubham
e907d7bb2a end of file line space 2015-03-12 15:17:26 -07:00
ashubham
7298510e91 space instead of tabs 2015-03-12 15:16:17 -07:00
ashubham
63c9262df5 space instead of tabs 2015-03-12 15:14:49 -07:00
ashubham
ff1626f071 added auth header test 2015-03-12 15:12:53 -07:00
ashubham
df158bfc53 added auth header test 2015-03-12 15:11:56 -07:00
ashubham
f55ffa356a auth header added tests 2015-03-12 13:40:49 -07:00
ashubham
ab5c3e5c81 auth header added 2015-03-12 13:15:06 -07:00
Jarrett Cruger
245d73ae6c Merge pull request #789 from feross/master
fix "x-forwarded-proto" in node 0.12 and iojs
2015-03-11 21:07:38 -04:00
Feross Aboukhadijeh
6d074eff47 fix "x-forwarded-proto" in node 0.12 and iojs
The way to detect TLSSockets in node 0.12 and iojs has changed. You can
just check `socket.encrypted` now :)

Fixes #772
2015-03-11 00:33:34 -07:00
Matt Hauck
26029ba7ac only rewrite redirect urls when it matches target
if functioning as a reverse proxy for host1.foo.com,
with a backend target of backend.foo.com:8080, the
node proxy should only rewrite the redirect if it is
a redirect to somewhere on backend.foo.com:8080
2015-03-09 13:17:52 -07:00
Matt Hauck
14415a5074 refactor some tests for greater readability 2015-03-09 11:49:28 -07:00
Matt Hauck
62e4b75101 Merge pull request #1 from matthauck/master
Add support for auto host rewriting and protocol rewriting
2015-02-05 12:33:10 -08:00
Matt Hauck
7f2f3ac35c Add support for auto host rewriting and protocol rewriting
auto host rewriting allows rewriting to work as expected in most
cases without extra cumbersome configuration

protocol rewriting allows node-http-proxy to be able to listen
over HTTPS and properly reverse-proxy to sites running over HTTP
(to avoid doing SSL twice)
2015-02-05 12:17:26 -08:00
Jarrett Cruger
9eefd4678e [api] add an ignorePath option if you want to disregard the path of the incoming request when proxying to the target server fixes #758 2014-12-23 13:22:49 -05:00
Jarrett Cruger
9ece52fac4 Merge pull request #756 from PanManAms/patch-1
changed highlighted part - very minor
2014-12-22 12:02:36 -05:00
PanManAms
32aa10dfe2 changed highlighted part - very minor 2014-12-20 15:40:46 +01:00
Charlie Robbins
c82c9ece8a Merge pull request #625 from bkochendorfer/master
Update README.md for benchmarks
2014-12-19 02:01:53 -07:00
Jarrett Cruger
3311106c2c [dist] Version bump. 1.8.1 2014-12-17 10:11:42 -07:00
Alistair Jones
402ab05734 Pass HTTPS client parameters.
For more detailed control over HTTPS client behaviour, pass through the
parameters listed here:
http://nodejs.org/api/https.html#https_https_request_options_callback

The `rejectUnauthorized` parameter is omitted, because it overlaps with
the existing `secure` parameter:
https://github.com/nodejitsu/node-http-proxy/blob/master/README.md#using-https

Conflicts:
	test/lib-http-proxy-common-test.js
2014-12-17 10:09:29 -07:00
Jarrett Cruger
f0db5b3f70 [dist] Version bump. 1.8.0 2014-12-17 00:58:17 -07:00
Jarrett Cruger
f30486195c [minor] grammar 2014-12-17 00:57:43 -07:00
Jarrett Cruger
ea0a4ded80 [fix] style spacing wtf 2014-12-17 00:53:51 -07:00
Jorge Leal
8a8a894092 Changed proxyServer and destiny to local variables. 2014-12-17 00:52:41 -07:00
Jorge Leal
c62610e8e4 Deprecated proxySocket event in favor to open event.
Maintained both proxySocket and open for backward compatibility.

Conflicts:
	test/lib-http-proxy-test.js
2014-12-17 00:52:19 -07:00
Jorge
05d18a4e1b Update README.md 2014-12-17 00:51:24 -07:00
Jorge Leal
8bff3ddc12 Added websocket close event test 2014-12-17 00:51:19 -07:00
Jorge
26537866b3 [api] add close event in ws-incoming.js 2014-12-17 00:51:06 -07:00
Charlie Robbins
f92a1b6839 Merge pull request #752 from ezhdan-sugarcrm/tests-fix
Fix variables scope in test
2014-12-13 14:34:45 -07:00
Eugene Zhdan
c1a94176a8 Fix variables scope in test 2014-12-13 21:45:14 +03:00
Arnout Kazemier
099eb86948 Merge pull request #751 from seanhussey/patch-1
Fix typo
2014-12-11 17:26:24 +01:00
Sean Hussey
4bd3c4671f Fix typo 2014-12-11 11:02:09 -05:00
Jarrett Cruger
6a330ff904 [dist] Version bump. 1.7.3 2014-12-08 23:05:01 -05:00
Jarrett Cruger
89f9ca1e89 [test] show that we support protocol without the colon 2014-12-08 23:04:41 -05:00
Jarrett Cruger
c04485671a [fix] use simple regex instead of indexOf to check the protocol to support without the colon fixes #711 2014-12-08 23:04:23 -05:00
Jarrett Cruger
2086e4917c [dist] Version bump. 1.7.2 2014-12-08 16:16:05 -05:00
Jarrett Cruger
71a06aab02 [test] add tests for the changeOrigin cases in properly setting the host header 2014-12-08 16:14:48 -05:00
Jarrett Cruger
501e8c2a9b [fix] properly include port in host header with changeOrigin in all cases fixes #750 2014-12-08 16:14:16 -05:00
Jarrett Cruger
81874f795b [dist] pin down deps and add requires-port 2014-12-08 16:11:28 -05:00
Charlie Robbins
75a9a2de61 Merge pull request #749 from kblanks/patch-1
Fix grammar in README.md
2014-12-03 04:51:11 -07:00
Kailan Blanks
aeb42a3614 Fix grammar in README.md 2014-12-03 11:49:19 +00:00
Jarrett Cruger
56a7b77645 [dist] Version bump. 1.7.1 2014-12-02 10:28:04 -07:00
Jarrett Cruger
9c0b8697bc [fix] fix #738 2014-12-02 10:25:46 -07:00
Jarrett Cruger
410a8ce94c [test] add proper failing test case for #738 2014-12-02 10:25:30 -07:00
Jarrett Cruger
d98d9516ea [fix] simple fixes #748 #744 #746 2014-12-02 09:58:06 -07:00
koolc
70ed1c4273 [Bugfix] Allow for multiple ? in outgoing urls.
Without this fix urls that had multiple ? in them would drop sections
of the url since before there was an assumption of there only being one.
2014-12-01 12:34:16 -05:00
Jarrett Cruger
361d4e3b00 Merge pull request #716 from No9/master
Adding harmon to the README
2014-11-28 12:02:39 -05:00
Jarrett Cruger
276f65a3b8 [dist] Version bump. 1.7.0 2014-11-25 17:31:28 -05:00
Jarrett Cruger
8d68ac0e0f [fix] be defensive and ensure location is in headers before running url.parse() 2014-11-25 17:22:23 -05:00
Jarrett Cruger
48ae5d828c [minor] style consistency 2014-11-25 17:21:24 -05:00
Jarrett Cruger
95a588706b Merge pull request #741 from samccone/sjs/redirect-host-rewrite
Allow optional redirect host rewriting.
2014-11-25 17:08:54 -05:00
Jarrett Cruger
3194d819b4 Merge pull request #742 from jugglinmike/option-content-length
Set `Content-Length` header for OPTIONS requests
2014-11-25 11:15:46 -05:00
Mike Pennisi
8a24a1e18f Set Content-Length header for OPTIONS requests
Web browsers automatically issue an OPTIONS request in advance of other
HTTP requests when the document's domain does not match the target in
order to facilitate Cross-Origin Resource Sharing. These requests are
forbidden from specifying a body and typically do not specify an
(unecessary) `Length` header.

Node.js automatically adds the `Content-Encoding: chunked` header value
to requests that do not specify a `Length` header. This makes proxied
OPTIONS requests from web browsers invalid.

Explicitly set the `Content-Length` header of all `OPTIONS` requests to
"0", disabling the default "chunked" encoding behavior [2].

[1] http://www.w3.org/TR/cors/
[2] http://nodejs.org/api/http.html
2014-11-24 17:14:48 -05:00
Sam Saccone
add81338a9 📝 Add host rewrite docs and specs. 2014-11-23 19:22:07 -05:00
Sam Saccone
daf66a7a88 Allow optional redirect host rewriting. 2014-11-23 19:22:07 -05:00
Jarrett Cruger
aba505d159 Merge pull request #736 from richardkazuomiller/copy-headers
copy headers instead of referencing them so they don't unexpectedly get overwritten
2014-11-12 16:46:51 -05:00
Ricky Miller
84036e9ddd style changes 2014-11-13 06:05:32 +09:00
Ricky Miller
daa2ce0ee3 copy headers instead of referencing them so they don't unexpectedly get overwritten 2014-11-13 04:37:45 +09:00
Jarrett Cruger
69a693034e Merge pull request #735 from jleal52/master
Updated to support error callback on proxy.web and start/proxyReq/end co...
2014-11-12 13:05:04 -05:00
jleal52
9ba8311343 Updated to support error callback on proxy.web and start/proxyReq/end continue working. 2014-11-12 14:41:46 +00:00
Jarrett Cruger
709b3e9656 [dist] Version bump. 1.6.2 2014-11-11 11:47:43 -05:00
Jarrett Cruger
3f19e6e178 [minor] this shouldnt be in var block 2014-11-11 11:47:15 -05:00
Jarrett Cruger
7c5e40a429 [fix] style changes 2014-11-10 23:02:43 -05:00
Jarrett Cruger
eb95660822 Merge pull request #733 from richardkazuomiller/double-slash-fix
do not modify the query string
2014-11-10 22:29:16 -05:00
Ricky Miller
4a2b870cc9 do not modify the query string 2014-11-09 08:44:22 +09:00
Jarrett Cruger
fa797fca90 [dist] Version bump. 1.6.1 2014-11-04 18:14:09 -05:00
Jarrett Cruger
57329b6327 Merge pull request #729 from lightblade/master
websocket needs to respect `options.secure` too
2014-11-04 18:13:26 -05:00
Ming Liu
d1eabccf93 websocket needs to respect options.secure too 2014-11-04 15:06:45 -08:00
Jarrett Cruger
60bd697051 Merge pull request #724 from whitecolor/change-origin-option
changeOrigin option docs fix
2014-10-29 10:52:10 -04:00
Alex Oshchepkov
1af8224cc1 changeOrigin option docs fix 2014-10-29 08:09:43 +05:00
Jarrett Cruger
43641b00b3 [dist] Version bump. 1.6.0 2014-10-28 22:53:54 -04:00
Jarrett Cruger
70fa8ad58c Merge pull request #723 from whitecolor/change-origin-option
Added changeOrigin option with test and docs
2014-10-28 22:52:50 -04:00
Alex Oshchepkov
796ab0bcc5 Added changeOrigin option with test and docs 2014-10-29 07:25:19 +05:00
Charlie Robbins
f70015f001 Merge pull request #717 from waded/patch-1
I presume you mean couchdb here
2014-10-15 01:35:41 -04:00
Wade Dorrell
f64954a08b I presume you mean couchdb here 2014-10-14 22:49:33 -06:00
no9
9f684d0439 harmon notes 2014-10-15 01:52:27 +01:00
Jarrett Cruger
3768cce4ca Merge pull request #712 from zhudan/master
update modify request body eg
2014-10-09 09:48:08 -04:00
dan
d46e876e27 update modify request body eg 2014-10-09 14:33:04 +08:00
dan
0378b03e53 update modify request body eg 2014-10-09 14:32:52 +08:00
dan
04c45a022c update modify request body eg 2014-10-09 14:30:11 +08:00
Jarrett Cruger
9577a0faf2 [dist] Version bump. 1.5.3 2014-10-01 07:10:51 -04:00
Jarrett Cruger
fcdbf46e4d Merge pull request #709 from minrk/close-on-error
close socket if upstream request fails
2014-10-01 07:10:22 -04:00
MinRK
c62766391e close socket if upstream request fails
adds socket.end() to on('error') handlers for proxyReq and proxySocket
2014-09-30 19:58:57 -07:00
Jarrett Cruger
43c6f0c7c0 [dist] Version bump. 1.5.2 2014-09-30 21:21:04 -04:00
Jarrett Cruger
b065d92908 Merge pull request #708 from minrk/close-closes
close websocket if proxyReq is closed before upgrade
2014-09-30 20:55:38 -04:00
MinRK
bcd8a564a8 close websocket if proxyReq is closed before upgrade
avoids leaving client sockets open when upstream
connections are rejected.
2014-09-30 17:01:20 -07:00
MinRK
77305489d9 test closing upstream socket prior to upgrade
should close the client socket with ECONNRESET,
but currently is left hanging.
2014-09-30 16:11:49 -07:00
Jarrett Cruger
f0bf741815 [dist] Version bump. 1.5.1 2014-09-30 15:23:02 -04:00
Jarrett Cruger
10a294af4d [fix] do a check to make sure the server exists before we try and emit 2014-09-30 15:22:52 -04:00
Jarrett Cruger
232258b6ec [dist] Version bump. 1.5.0 2014-09-29 22:38:47 -04:00
Jarrett Cruger
9210b56c9e Merge pull request #706 from thlorenz/expose-proxy-socket
exposing proxySocket on socket to support sniffing messages coming from proxy target
2014-09-29 22:34:06 -04:00
Thorsten Lorenz
000eb533de emitting proxySocket on proxyServer
- emitted once proxySocket was created and socket was piped into it
- needed to support sniffing messages coming from proxy target
2014-09-29 20:09:46 -04:00
Jarrett Cruger
2aa3b84d7b Merge pull request #705 from Jimbly/patch-1
Fixed misleading documentation
2014-09-26 00:01:36 -04:00
Jimb Esser
a4ca578b44 Fixed misleading documentation
options.xfwd definitely works fine without using the .listen method, and, AFAICT, .toProxy should as well.  Only .ssl and .ws are referenced in .listen.
2014-09-25 20:54:46 -07:00
Jarrett Cruger
e7d50b1a37 [minor] extra space 2014-09-25 22:11:12 -04:00
Jarrett Cruger
c0a796b3e3 [fix] perf optimization so we have a precompiled regexp 2014-09-17 07:53:18 -04:00
Jarrett Cruger
90d40d6a6a Merge pull request #702 from shebson/fix-readme-typo
Fix typo in README.md
2014-09-16 18:21:35 -04:00
Stephen Hebson
45cf95a82e Fix typo in README.md
"Is it then possible" -> "It is then possible"
2014-09-16 14:55:12 -07:00
Jarrett Cruger
42c35aedca Merge pull request #691 from minrk/firefox-ws-connection-close
handle 'upgrade' in comma-separated connection header
2014-09-16 15:42:41 -04:00
MinRK
ec683b924b test new detection of connection: upgrade 2014-09-16 12:09:26 -07:00
MinRK
65a21bce6d use regex to check for upgrade header
in websocket connections
2014-09-16 12:07:15 -07:00
MinRK
51eeebef68 handle 'upgrade' in comma-separated connection header
Firefox sends `keep-alive, upgrade`, not just `upgrade`,
which the proxy incorrectly turned into `close`
2014-09-16 11:15:17 -07:00
cronopio
554f59c518 Bump version v1.4.3 2014-09-12 12:31:28 -05:00
Arnout Kazemier
73e8a4cdd5 [minor] Added missing JSDoc comments 2014-09-12 19:21:12 +02:00
Arnout Kazemier
3ab6e9591e [minor] Code style adjustment. 2014-09-12 19:13:53 +02:00
Arnout Kazemier
a934cb6a46 [ignore] Ignore npm-debug.log 2014-09-12 19:11:49 +02:00
Arnout Kazemier
107b9da256 Merge pull request #699 from STRML/master
Urgent: Fix breaking bug on url joining resulting in paths like `///path`.
2014-09-12 19:10:30 +02:00
Samuel Reed
73d865bc9f Fix breaking bug on url joining resulting in paths like ///path.
Added OS-agnostic url join helper.
2014-09-12 13:08:10 -04:00
Jarrett Cruger
df12aeb12d [dist] Version bump. 1.4.2 2014-09-12 07:50:36 -04:00
Jarrett Cruger
ed73f06ed3 [fix] ensure path works on windows because path.join doesnt like URLs 2014-09-12 07:50:16 -04:00
Jarrett Cruger
d5c656bceb [dist] Version bump. 1.4.1 2014-09-11 18:52:13 -04:00
Jarrett Cruger
dceef407a1 [dist] Version bump. 1.4.0 2014-09-11 18:51:49 -04:00
Jarrett Cruger
e44fabe58a [test] add test for prependPath option 2014-09-11 18:51:49 -04:00
Jarrett Cruger
9a534c6ff6 [api] add prependPath option to go with path change 2014-09-11 18:51:49 -04:00
Arnout Kazemier
d1facd52c3 Merge pull request #644 from CaleyD/master
Trimming contents of distributed npm package.
2014-09-11 14:09:53 +02:00
Arnout Kazemier
5568cb5575 Merge pull request #669 from baer/remove-changelog
Remove changelog - it was not maintained
2014-09-11 14:08:50 +02:00
Arnout Kazemier
6ac05259ca Merge pull request #695 from outime/patch-1
Removed duplicated imported dependencies
2014-09-11 14:07:15 +02:00
Rubén Díaz
0e64568b4e Removed duplicated imported dependencies 2014-09-11 14:21:33 +03:00
Jarrett Cruger
fc73828035 [dist] Version bump. 1.3.1 2014-09-09 13:22:17 -04:00
Jarrett Cruger
814fbd254d Merge pull request #693 from EndangeredMassa/fix-path
Allow proxy to maintain the original target path
2014-09-08 18:23:42 -04:00
Sean Massa
a65021d52b fix tests for maintaining proxy path 2014-09-08 17:17:15 -05:00
Domi
511b7b3d47 Fix proxy path
This fix considers the actual target path again (which has been ignored).
2014-09-08 15:57:53 -05:00
Jarrett Cruger
6b83ae47bb [ci] remove 0.11.x to avoid failing builds caused by TLS errors 2014-09-08 16:28:51 -04:00
Jarrett Cruger
d16062bba2 Merge pull request #686 from joeyespo/master
Clarify usable parameters for 'proxyRes' event
2014-08-21 19:50:48 -04:00
Joe Esposito
49a0de1e7c Clarify usable parameters for proxyRes event. 2014-08-21 17:02:36 -04:00
Jarrett Cruger
05f0b891a6 [dist] Version bump. 1.3.0 2014-08-14 17:28:00 -04:00
Jarrett Cruger
261742a429 [fix] cleanup and stylize close function 2014-08-14 17:16:56 -04:00
Jarrett Cruger
f92f7aea9b Merge pull request #679 from RackspaceEmailAndApps/close_proxy
Added functionality to close proxy.
2014-08-14 17:12:42 -04:00
John Catron
8be9d945d0 updated close function for safety 2014-08-14 20:12:20 +00:00
Jarrett Cruger
0a6b424e2c [dist] Version bump. 1.2.1 2014-08-14 13:40:40 -04:00
Jarrett Cruger
37036dd325 [fix] emit an error if proper URL is not passed in as a target 2014-08-14 13:32:32 -04:00
John Catron
a3d02196c5 Added close method to proxy server.
Ensured server exists before closing.
Updated tests to use new close function.
Added documentation to README.
2014-08-14 17:30:38 +00:00
Jarrett Cruger
63c53a1772 [dist] Version bump. 1.2.0 2014-08-05 17:27:21 -04:00
Jarrett Cruger
3e8ee042fb Merge pull request #673 from digitalbazaar/mod-header-event
[api] Add event-based ability to modify pre-flight proxy requests.
2014-07-20 15:15:49 -04:00
Manu Sporny
db5f2954b2 [api] Add event-based ability to modify pre-flight proxy requests. 2014-07-18 11:46:04 -04:00
Jarrett Cruger
ed9e12b0ed [dist] Version bump. 1.1.6 2014-07-17 10:57:38 -04:00
Jarrett Cruger
5f838541cb do proper checking for a pass not existing. fixes #671 2014-07-17 10:56:53 -04:00
Eric Baer
e336b52629 Remove changelog - it was not maintained 2014-07-10 11:59:43 -04:00
Jarrett Cruger
7104a7c023 [dist] Version bump. 1.1.5 2014-07-09 23:27:35 -04:00
Jarrett Cruger
d1baa3684e [api] also emit the target on a proxy error 2014-07-08 16:12:57 -04:00
Jarrett Cruger
e50846b967 Merge pull request #666 from eiriklv/master
Fix simple-balancer example
2014-07-08 12:08:51 -04:00
Eirik Langholm Vullum
9df4bc1e12 fix balancer example 2014-07-04 23:37:23 +02:00
Jarrett Cruger
f6bac7b257 Merge pull request #658 from RushPL/master
Added proxyTimeout option and two tests for timeout
2014-06-10 13:11:13 -04:00
Damian Kaczmarek
48d46e6750 Merge branch 'master' of github.com:RushPL/node-http-proxy 2014-06-10 19:04:48 +02:00
Damian Kaczmarek
7b79a7409a Change name targetTimeout to proxyTimeout 2014-06-10 19:04:12 +02:00
Damian Kaczmarek
4193d3bd74 Fix #657 2014-06-10 01:50:59 +02:00
Damian Kaczmarek
159ca83652 Fix #657 2014-06-10 01:50:13 +02:00
Damian Kaczmarek
0f243516e1 Added targetTimeout option and two tests for timeout 2014-06-10 01:35:53 +02:00
unknown
431aba79d8 Trimming contents of distributed npm package.
https://www.npmjs.org/doc/developers.html#Keeping-files-out-of-your-package
Keep deployments as small as they can be.
2014-05-21 14:10:52 -07:00
Jarrett Cruger
7cb98a4e41 [dist] Version bump. 1.1.4 2014-05-11 19:03:07 -04:00
Jarrett Cruger
5ebf9833c8 Merge pull request #642 from bruce-one/proxyRes-req-res
`proxyRes` event, provide access to the req and res objects
2014-05-11 19:01:05 -04:00
Bryce Gibson
1385635e18 Add a test for the proxyRes event 2014-05-12 08:44:02 +10:00
Bryce Gibson
1213e46b1b Add the req and res objects to the proxyRes event 2014-05-12 08:22:54 +10:00
Jarrett Cruger
c472527ea6 [dist] Version bump. 1.1.3 2014-05-11 01:03:39 -04:00
Jarrett Cruger
ccad177954 [minor] style 2014-05-11 01:02:35 -04:00
Jarrett Cruger
896ee7c9c3 Merge pull request #640 from jayharris/master
Don't override connection header if Upgrading
2014-05-09 23:25:45 -04:00
Jay Harris
8aa7c519b1 Adding test cases on preventing upgrade override 2014-05-09 22:49:23 -04:00
Jay Harris
d637b96420 Don't override connection header if Upgrading 2014-05-09 20:48:30 -04:00
Brett Kochendorfer
4947484806 Update README.md for benchmarks
Remove number of requests flag from `wrk` as it no longer exists. Swapped out for 5 minute duration.
2014-04-20 20:34:08 -05:00
Jarrett Cruger
c54278bd3b [dist] Version bump. 1.1.2 2014-04-14 13:17:58 -04:00
Jarrett Cruger
61c8734e8b [fix test] handle proxy error since we are properly aborting the proxy Request 2014-04-14 13:17:18 -04:00
Jarrett Cruger
77a1cff9bc [fix] handle error on incoming request as well and properly abort proxy if client request is aborted 2014-04-14 13:08:10 -04:00
Jarrett Cruger
d908e2ad61 [dist] Version bump. 1.1.1 2014-04-10 20:03:06 -04:00
Jarrett Cruger
4f07dc220d [fix] let user make the decision on what to do with the buffer 2014-04-10 20:02:46 -04:00
Jarrett Cruger
97ceeb37d0 [dist] Version bump. 1.1.0 2014-04-09 13:38:40 -04:00
Jarrett Cruger
8b48a9fdab [api] emit a start an an end event 2014-04-09 13:38:13 -04:00
Jarrett Cruger
c6b7a7919f [fix] always be an eventemitter for consistency fixes #606 2014-04-09 13:37:27 -04:00
Jarrett Cruger
7e5feec34f Merge pull request #616 from hipstern/patch-1
Update UPGRADING.md
2014-04-06 02:41:27 -04:00
hipstern
d658c9fa39 Update UPGRADING.md
Fixing a typo
2014-04-05 11:05:17 -07:00
Jarrett Cruger
eca765a856 [minor] missing angle bracket 2014-03-26 22:48:35 -04:00
Jarrett Cruger
07fceb7c7a [dist] Version bump. 1.0.3 2014-03-26 22:41:51 -04:00
Jarrett Cruger
ece85b4e1b [doc] update docs with toProxy option 2014-03-26 22:36:59 -04:00
Jarrett Cruger
5251a238e7 Merge branch 'customizeOutgoingAddress' of github.com:sberan/node-http-proxy into sberan-customizeOutgoingAddress
Conflicts:
	lib/http-proxy.js
	lib/http-proxy/common.js
2014-03-26 22:30:11 -04:00
Jarrett Cruger
89a22bc003 [fix] set connection to CLOSE in cases where the agent is false. 2014-03-26 22:07:09 -04:00
Jarrett Cruger
a7b16eb136 [api] add toProxy method to allow absolute URLs to be sent when sending to another proxy fixes #603 2014-03-26 21:59:10 -04:00
Jarrett Cruger
c22610af75 Merge pull request #592 from SkeLLLa/patch-1
Fix for #591
2014-03-11 18:03:12 -04:00
Alexander
99f757251b Fix for #591
Fix for proxy crash if `HOST` header is not defined bug https://github.com/nodejitsu/node-http-proxy/issues/591.
2014-02-26 15:12:38 +02:00
Sam Beran
e633b0f7e4 Add support for localAddress
When we make outgoing requests, we may want to bind to a specific local
address. This change allows the localAddress property to be specified
via the options object.
2014-02-11 15:01:03 -06:00
Jarrett Cruger
10670540ac Merge pull request #578 from xtreme-topher-bullock/patch-1
Add Repository field to package.json
2014-02-10 23:47:47 -05:00
@xtreme-topher-bullock / @xtreme-todd-ritchie
68fa17bbca @xtreme-topher-bullock - update package.json to have proper repository key and formatting 2014-02-10 10:07:00 -05:00
Topher Bullock
7923cf3c6b Add Repository field to package.json
Seeing "npm WARN package.json http-proxy@1.0.2 No repository field." makes me anxious and its such an easy action to add a repo field to the package.json.
2014-02-07 16:49:45 -05:00
Jarrett Cruger
81daf26a43 Merge pull request #575 from ozh/patch-2
Fix doc: option lines
2014-02-05 09:42:51 -05:00
྅༻ Ǭɀħ ༄༆ཉ
80f645c7c0 Fix doc: option lines 2014-02-05 15:03:36 +01:00
Jarrett Cruger
4bdc3e4f45 [dist] Version bump. 1.0.2 2014-01-28 14:34:25 -05:00
David Glasser
4c3ba74c4e Close outgoing ws if incoming ws emits error
Fixes #559, which contains a full reproduction recipe.
2014-01-28 13:58:09 -05:00
Jarrett Cruger
daad4703f3 [fix] replicate node core behavior and throw an error if the user does not add their own error listener 2014-01-28 12:32:43 -05:00
yawnt
b60673522b Merge pull request #566 from Septembers/patch-1
Update README.md
2014-01-28 05:54:27 -08:00
Sep
4ecc6e26ce Update README.md
Syntax error correction
2014-01-28 21:51:59 +08:00
Arnout Kazemier
8004f4e5fc [doc] Fix broken image in npm by using an absolute link 2014-01-28 11:25:24 +01:00
yawnt
3b2178d1f7 Merge pull request #560 from meteor/fix-ws-arg-order
Fix argument order for ws stream pass
2014-01-27 23:04:09 -08:00
David Glasser
0b223abb65 Fix argument order for ws stream pass
head and error handling was broken before this commit.
2014-01-22 15:28:23 -08:00
Jarrett Cruger
7a53ec2fd6 Merge pull request #558 from p-a-c-o/master
Extend listen to enable IPv6 support.
2014-01-21 11:49:46 -08:00
p-a-c-o
96ea631fb6 Extend listen to enable IPv6 support. 2014-01-21 20:35:49 +01:00
yawnt
3e47c2485c Merge pull request #556 from alevicki/fix/before_and_after
Fix before and after type check
2014-01-20 09:55:28 -08:00
alevicki
c5ec1836b2 Fix before and after type check 2014-01-20 10:24:53 -06:00
yawnt
e936d186b6 [fix] closes #555 2014-01-19 11:49:26 +01:00
yawnt
68c5512303 [dist] bump v1.0.1 2014-01-17 22:19:42 +01:00
yawnt
689459fe46 typo 2014-01-17 22:18:54 +01:00
yawnt
53a2653b5e [fix] closes #553 2014-01-17 22:18:20 +01:00
yawnt
3330e125aa Merge pull request #552 from nodejitsu/caronte-merge
Http proxy 1.0
2014-01-16 07:34:37 -08:00
yawnt
d6d2d0c882 [fix] remove caronte 2014-01-16 16:28:08 +01:00
yawnt
d4942e52e7 Merge pull request #551 from nodejitsu/caronte
Caronte
2014-01-16 07:25:15 -08:00
yawnt
d23353d980 [fix] ee3 error handling 2014-01-16 15:05:52 +01:00
yawnt
4351ed1c86 [fix] closes #547 2014-01-16 15:03:44 +01:00
yawnt
0ba4fa8e5e Merge pull request #549 from mmoulton/caronte
Only emit response if a valid server is present
2014-01-14 01:23:28 -08:00
Mike Moulton
969a623542 Only emit response if a valid server is present 2014-01-14 00:45:42 -07:00
yawnt
0b642d4cf7 Merge remote-tracking branch 'origin/caronte' into caronte-merge 2014-01-08 10:19:11 +01:00
yawnt
a4ee8f9d82 [nuke] old files 2014-01-08 10:19:06 +01:00
yawnt
2c8edc170d Merge pull request #539 from nodejitsu/fix-before-after
[fix] add `type` to before and after to grab correct `passes`, fixes #537
2013-12-29 14:20:46 -08:00
Jarrett Cruger
c47adac391 [fix] add type to before and after to grab correct passes, fixes #537 2013-12-29 16:00:30 -05:00
yawnt
c17b591b7d Merge pull request #536 from nodejitsu/caronte-api
export the proxy itself from the main require
2013-12-28 10:58:28 -08:00
Jarrett Cruger
6fa23e11f6 [fix] comments 2013-12-27 19:04:44 -05:00
Jarrett Cruger
182c76cd23 [api] export the httpProxy.Server as the main export but preserve the createServer factory 2013-12-27 19:01:28 -05:00
yawnt
e5991519db [docs] upgrade UPGRADING.md 2013-12-27 23:38:48 +01:00
indexzero
840f6d8d29 [dist] Version bump. 0.10.4 2013-12-27 00:05:18 -08:00
indexzero
a81dd8d53e [dist] Bump dependencies. 2013-12-27 00:04:25 -08:00
vinodsr
8eb6780f87 added option for eventlistenerCount(max) 2013-12-27 00:01:15 -08:00
vinodsr
1333c0cc62 added unlimited listeners to the reverproxy event obj. 2013-12-27 00:01:07 -08:00
indexzero
2d42709c32 [fix] Optimize fix for x-forwarded-for-port. 2013-12-26 23:59:48 -08:00
blahed
d4e91ebc33 determine x-forwarded-port from host header
`req.remotePort' returns the ephemeral port, which is not useful.
node v0.10.0 added `req.localPort' which returns what we want, but
we want to maintain backwards compatibility. Fixes #341 & #227
2013-12-26 23:52:05 -08:00
indexzero
7e8041d2b6 [dist minor] 2 space indents next time @samalba 2013-12-26 23:50:19 -08:00
Sam Alba
8332e74420 Prevent headers to be sent twice 2013-12-26 23:48:06 -08:00
Phil Jackson
145798062e Put the arguments the right way around in the README. 2013-12-26 23:39:49 -08:00
Phil Jackson
7c8ecc8ea8 Put the arguments the right way around in emitter. 2013-12-26 23:39:44 -08:00
Phil Jackson
25bb3bfa70 Update the README to describe middleware err handler. 2013-12-26 23:39:40 -08:00
Phil Jackson
bc12ca3939 Emit middlewareError when on middleware error.
Now it's possible to pass an Error object to next() and have it handled
in a custom way that's suitable to your application.
2013-12-26 23:39:37 -08:00
Jan Jongboom
781c038f2b Fix for #458. Host header may cause some sites not to be proxyable with changeOrigin enabled 2013-12-26 23:35:47 -08:00
Charlie Robbins
d60f1a9353 Merge pull request #521 from derekdreery/patch-1
Update README.md
2013-12-26 23:10:25 -08:00
yawnt
162a42f58f [fix] legacy 2013-12-20 21:33:49 +01:00
yawnt
9243444ac0 fix docs 2013-12-20 20:24:49 +01:00
yawnt
db12f6c24e [docs] add UPGRADING.md 2013-12-20 20:22:40 +01:00
yawnt
16828a9915 Merge pull request #520 from nodejitsu/better-examples
Better examples
2013-12-18 10:03:46 -08:00
cronopio
e2a5d513ca Set travis to run npm test while we fix coveralss.io integration 2013-12-18 12:18:59 -05:00
cronopio
d83fdf69a1 [tests] disabled the examples-test by now 2013-12-18 12:18:59 -05:00
cronopio
bc236d7e95 [tests] Added a test case for run all the examples
* I changed all the ports across examples to be different and can run at same time
2013-12-18 12:18:58 -05:00
cronopio
c82ff2c3c0 [examples] updated bodyDecoder middleware example 2013-12-18 12:18:58 -05:00
cronopio
d7064f2e1e [examples] added error-handling using callbacks and HTTP-to-HTTPS examples 2013-12-18 12:18:58 -05:00
cronopio
de3ff11656 [examples] updated the modifyResponse-middleware example 2013-12-18 12:18:58 -05:00
cronopio
2142c506e0 [examples] add example of gzip using the connect.compress() middleware 2013-12-18 12:18:58 -05:00
cronopio
e592c53d1a [examples] fix the copyright header of example files 2013-12-18 12:18:58 -05:00
cronopio
d85ccdd333 [examples] added package.json with the dependencies needed by examples 2013-12-18 12:18:58 -05:00
cronopio
831a44b3c8 [examples] updated balancer examples 2013-12-18 12:18:58 -05:00
cronopio
ed8c9eeba9 [examples] updated websockets examples 2013-12-18 12:18:58 -05:00
cronopio
588327c2c4 [examples] updated old examples 2013-12-18 12:18:58 -05:00
cronopio
e02317ce86 [examples] updated old proxy examples 2013-12-18 12:18:58 -05:00
cronopio
b726116134 [examples] update forward and custom error examples 2013-12-18 12:18:58 -05:00
cronopio
7e44d3669b [examples] update old examples 2013-12-18 12:18:58 -05:00
cronopio
bdeabb767a [examples] deleted this examples 2013-12-18 12:18:58 -05:00
cronopio
cfd417de23 [tests] fix tests set correct host headers 2013-12-18 12:17:41 -05:00
cronopio
c4d56a5faf [tests] fix test using undefined url 2013-12-18 11:50:49 -05:00
yawnt
4d65280ea3 [fix] remove old reminescence 2013-12-18 13:30:02 +01:00
yawnt
36389384cb Merge pull request #416 from MiLk/req-path
Send path in req.path and not the url
2013-12-18 03:49:59 -08:00
yawnt
9e74a633a7 [fix] closes #529 2013-12-18 12:45:41 +01:00
yawnt
97e4600e94 [fix] fixes #341 2013-12-18 12:33:23 +01:00
cronopio
03880d8d06 [docs] typos, typos everywhere... 2013-12-13 13:06:19 -05:00
cronopio
0393b5da99 [docs] more short examples to the Readme 2013-12-13 12:58:37 -05:00
cronopio
ae0faef5aa [docs] Update readme with more how to 2013-12-09 12:33:16 -05:00
derekdreery
ef8150af95 Update README.md
I struggled to get the section about using https to http with two certificates to work, because I didn't understand where the myCert etc. came from. Once I realised they had to be created by the user I could get it working. I want to save someone else the time it took me.
2013-11-21 17:33:19 +00:00
cronopio
584ce76e75 [misc] add a LICENSE file 2013-11-19 20:03:23 -05:00
yawnt
10c0f11b68 [fix] remove duplicate 2013-11-19 20:05:46 +01:00
yawnt
83367e7e91 Merge pull request #518 from bfirsh/fix-ws-error-handling
Fix websocket error handing
2013-11-18 15:27:23 -08:00
Ben Firshman
cb7af4f4d7 Fix websocket error handing
Websockets have sockets, not responses.
2013-11-18 23:06:56 +00:00
yawnt
dcb873ad99 [doc] update README.md 2013-11-13 18:29:15 +01:00
cronopio
54eceb4a86 Merge branch 'caronte' of github.com:nodejitsu/node-http-proxy into caronte 2013-11-11 11:22:23 -05:00
cronopio
7a3f6dfbcc [examples] added forward example 2013-11-11 11:22:04 -05:00
cronopio
04c10113f7 [examples] added concurrent proxy example 2013-11-11 11:14:42 -05:00
yawnt
961d2f9400 [fix] support target and forward 2013-11-08 20:56:26 +01:00
cronopio
bbe3bfdf98 [tests] added test HTTPS to HTTP using own server 2013-11-07 21:27:50 -05:00
cronopio
31d919b0a3 [tests] added HTTPS to HTTPS test 2013-11-07 18:06:51 -05:00
cronopio
6a6dfbb79d [examples] fix styling and bad spaces 2013-11-07 18:06:12 -05:00
cronopio
a467b7b4a9 [examples] fixed https examples 2013-11-07 17:20:28 -05:00
cronopio
fd42dcef01 [tests] https test pass, fix #511. Exposed the rejectUnauthorized flag 2013-11-07 15:09:37 -05:00
cronopio
a2b1f0a4c9 [tests] disable test, by now is not throwing without options 2013-11-07 15:06:45 -05:00
yawnt
d0862aff0c [fix] merge #495, thanks @glasser 2013-11-07 19:13:09 +01:00
yawnt
cde08fb2ee [fix] closes number #487 2013-11-07 19:05:59 +01:00
yawnt
590bb604da [fix] _ because it is unused 2013-11-07 19:00:01 +01:00
Jarrett Cruger
b8c6397a94 [fix] pass proper options object that extend the global options and parse the per proxy args into options. fixes #510 2013-11-05 16:30:39 -05:00
yawnt
dda6f7a45a [feature] add emit proxyRes 2013-11-05 17:44:04 +01:00
cronopio
8085178dc2 [tests] Using target field, tests now pass. We are missing the tests using forward field 2013-10-29 16:46:27 -05:00
yawnt
1204a35e46 [fix] support buffer 2013-10-29 18:12:23 +01:00
cronopio
f720e36b42 Merge branch 'caronte' of github.com:nodejitsu/node-http-proxy into caronte 2013-10-28 13:19:35 -05:00
cronopio
33a2462d28 [wip] Initial HTTPS->HTTP test, updated https-secure example. Work in progress, need to add more https tests 2013-10-28 13:18:21 -05:00
yawnt
e3f8d5fdbe [feature] add buffer support 2013-10-26 17:20:30 +02:00
cronopio
a1b25a123b [examples] update the error-handling example using the new error handle way 2013-10-22 17:04:18 -05:00
cronopio
920f1e7707 [tests] this test is already in web-incoming tests 2013-10-22 16:09:11 -05:00
cronopio
c75d06c5f9 [tests] now each test use a different port to avoid some slow opening and closing ports 2013-10-22 15:57:52 -05:00
cronopio
d60353f80b [tests] tests fixed 2013-10-21 23:22:59 -05:00
cronopio
02df9a33c5 [fix] fix the correct order of arguments in ws-incoming passes 2013-10-21 23:22:32 -05:00
cronopio
881c7e62e0 [tests] this file is not necessary anymore 2013-10-21 21:22:39 -05:00
cronopio
cc09ae6a34 [fix] use the correct arguments order 2013-10-21 21:19:52 -05:00
cronopio
7c72f3b407 [tests] move contributions of @mmoulton to correct place 2013-10-21 21:11:19 -05:00
mmoulton
0bfb9be418 Fixed issue where error callback would not invoke, including new test cases. Added req/res values to error events.
Conflicts:
	lib/http-proxy/passes/web-incoming.js
2013-10-21 17:36:20 -05:00
cronopio
5d66ce11bb [fix] minor typo 2013-10-21 14:51:45 -05:00
cronopio
5e130de854 Revert "[fix] fixed passes functions, now 'this' can be used and options are stored on 'this.options'"
This reverts commit 9b3e1eb247df29d18ea299ff4ebb2f10eeb71269.
2013-10-21 14:49:39 -05:00
cronopio
babdf531fe Revert "[fix] fixed options and server reference to can access them from passes functions"
This reverts commit 90fb01d38ac5af7ef395547b24e985b6f63b4abc.
2013-10-21 14:45:03 -05:00
cronopio
2bf20d61d5 Revert "[tests] fix test to use the new way to pass options"
This reverts commit 52ecd52ee5aa78603e44ba8d5ff9187410351622.
2013-10-21 14:44:49 -05:00
cronopio
52ecd52ee5 [tests] fix test to use the new way to pass options 2013-10-21 03:59:14 -05:00
cronopio
9b3e1eb247 [fix] fixed passes functions, now 'this' can be used and options are stored on 'this.options' 2013-10-21 03:46:30 -05:00
cronopio
90fb01d38a [fix] fixed options and server reference to can access them from passes functions 2013-10-21 03:26:54 -05:00
cronopio
1d1ee88582 [tests] the options got a problem and this test probe that timeout is not being set 2013-10-21 03:25:47 -05:00
Jarrett Cruger
e4450132e2 Merge pull request #502 from jamesmanning/patch-1
attempting to fix links to 2 source locations in README.md
2013-10-20 02:19:58 -07:00
James Manning
bbe2b2788a attempting to fix link to valid options properties
Current link for 'valid properties are available here' goes to url:

https://github.com/nodejitsu/node-http-proxy/blob/caronte/tree/master/lib/http-proxy.js#L26-L39

The url works fine if 'tree/master/' is removed, so this is trying to remove that part of the relative path.

The same removal of 'tree/master/' is being made for the 'available here' link that is preceded by "When a request is proxied it follows two different pipelines" since it suffers the same issue.
2013-10-19 23:43:22 -04:00
cronopio
86750c7e59 [tests] throw error when no options, ALL TESTS PASSING! YAY 2013-10-10 11:04:17 -05:00
cronopio
c65ffbb976 [tests] fixed inherits problem and listen for the correct event 2013-10-09 12:40:05 -05:00
cronopio
a7042132c8 [tests] fixing tests, fixed some typos and changed how passes are stored 2013-10-09 12:00:42 -05:00
cronopio
b333e63648 [tests] fixing minor typos 2013-10-09 11:04:41 -05:00
cronopio
c9f5772fc1 [tests] remove caronte and use http-proxy for file names 2013-10-09 10:49:13 -05:00
yawnt
a9f9e21eda [fix] 2013-10-09 17:37:20 +02:00
yawnt
3d8e5383cd [fix] better code 2013-10-09 17:31:02 +02:00
yawnt
5a1504f076 [fix] minor typo 2013-10-09 17:28:39 +02:00
yawnt
c7924e01f9 [fix] callback as optional error handler 2013-10-09 17:23:44 +02:00
yawnt
601dbcbfe9 [fix] refactor error handling 2013-10-09 16:59:03 +02:00
yawnt
b79bd29d5e [feature] start working on the new server 2013-10-08 22:24:16 +02:00
3rd-Eden
a51b062278 [minor] Remove duplicate dependencies and cleanup of the scripts 2013-10-01 09:14:37 +02:00
yawnt
8269eca2bb [fix] tests 2013-09-26 11:13:16 +02:00
yawnt
1436b715ae Merge pull request #492 from nodejitsu/1.0.0-dev
[merge] rename codename to actual project name
2013-09-26 02:05:02 -07:00
indexzero
bb0d28c587 [refactor minor] s/caronte/http-proxy/ or s/caronte/httpProxy/ where appropriate. 2013-09-26 03:37:08 -04:00
indexzero
f7f5fa727e [dist doc] Added documentation for consistent benchmarking of node-http-proxy 2013-09-26 03:27:55 -04:00
yawnt
455f97e14c [fix] finished jshint fixes 2013-09-25 15:11:04 +02:00
yawnt
17399e7c3e [fix] more jshint intendation 2013-09-25 15:08:27 +02:00
yawnt
0aeaba7fe6 [fix] remove trailing whitespaces 2013-09-25 14:58:59 +02:00
yawnt
94ec6fa5ce Merge pull request #484 from srossross/error_handling
[merge] Added error handling example
2013-09-22 04:22:40 -07:00
srossross
32a40889ce DOC: Added error handling example 2013-09-21 13:15:34 -07:00
yawnt
32dcb0449c Merge pull request #482 from srossross/caronte
[merge] https & agent
2013-09-21 01:49:00 -07:00
cronopio
4a517fbe6e [readme] add links to badges on readme, fix #483 2013-09-20 20:47:02 -05:00
cronopio
5dcdf2b36c [doc] added some documentation to functions and comments to understand better the code 2013-09-20 19:28:53 -05:00
srossross
7ad5c0f993 DOC: updated readme
@yawnt I think it is good to go. If you have any other tests in mind let me know.
2013-09-18 09:07:56 -07:00
srossross
39b0c46a69 TEST: added agent and header tests 2013-09-17 15:29:48 -07:00
srossross
a350fadea6 FIX: tests. still need to add more tests tho 2013-09-17 15:06:22 -07:00
srossross
1b5fb1d8fc DOC: updated readme with options 2013-09-17 15:00:28 -07:00
srossross
12cda561af ENH: updated agent options in common.setupOutgoing 2013-09-17 14:52:53 -07:00
srossross
f566a42e51 ENH: updated examples 2013-09-17 14:51:56 -07:00
srossross
4ee96ddd66 Merge branch 'agent' into caronte 2013-09-17 11:51:17 -07:00
srossross
1c7ace26c5 ENH: updated example 2013-09-17 11:50:04 -07:00
srossross
7d840d3515 ENH: added 'headers' to available options, to add or overwrite existing headers 2013-09-17 11:45:41 -07:00
srossross
427d8d8536 ENH: added new https example, needs to be simplified before merge
updated existing example with log output
2013-09-17 11:44:09 -07:00
srossross
13741a823f ENH: updated https and agent option
Removed logic from createProxyServer and put it into setupOutgoing.

Conflicts:
	lib/caronte.js
2013-09-17 11:23:12 -07:00
yawnt
69f126b34c [fix] space 2013-09-17 20:15:34 +02:00
yawnt
72a89eab8b [fix] link 2013-09-17 20:14:16 +02:00
yawnt
1ceea3e5f9 [docs] test badge 2013-09-17 20:11:03 +02:00
yawnt
f36cb4d5a1 [fix] coveralls.. will it work? 2013-09-17 19:30:59 +02:00
yawnt
ca092635e7 [test] remove chunked on http1.0 2013-09-17 16:32:55 +02:00
yawnt
8663ac1c43 [fix] do not send chunked responses to http1.0 clients 2013-09-17 16:28:54 +02:00
yawnt
afc4d0931f [fix] pooled connections, closes #478 2013-09-17 12:14:52 +02:00
yawnt
6b61878759 [docs] add travis build status 2013-09-17 11:24:35 +02:00
yawnt
16a4d9da11 [test] added tests for web-outgoing.js 2013-09-17 11:20:18 +02:00
yawnt
2c10f256b6 [fix] write connection header 2013-09-17 10:59:45 +02:00
yawnt
611a1b1961 [fix] add 0.10 link, fixes #459 2013-09-17 10:38:25 +02:00
yawnt
031452e400 [fix] closes #473 2013-09-17 10:31:52 +02:00
yawnt
9efa40a9d2 Merge pull request #476 from nodejitsu/caronte-tests
[merge] caronte tests
2013-09-17 01:23:55 -07:00
cronopio
8eff1a1f26 [test][misc] remove node@0.8 to test on travis 2013-09-16 21:40:42 -05:00
cronopio
10a0db4f0d [tests] added test for socket.io proxying 2013-09-16 21:37:49 -05:00
cronopio
0602500230 [tests] added .travis.yml file 2013-09-16 21:00:34 -05:00
cronopio
02007ed0fb [tests] added tests for websockets 2013-09-16 20:59:10 -05:00
cronopio
40902506af [tests] fix code coverage, changed pattern on blanket options 2013-09-16 19:37:28 -05:00
cronopio
7e25bded27 [tests] removed unused tests 2013-09-16 19:04:49 -05:00
Jarrett Cruger
c01fd2c54e Merge pull request #475 from srossross/fix/ws_err_event
FIX: ws error event
2013-09-16 17:04:38 -07:00
cronopio
dc9d7e5452 [tests] drop the test of own streams, moved the usable tests 2013-09-16 18:59:48 -05:00
srossross
7b9169c8c5 FIX: ws error event 2013-09-16 16:42:53 -07:00
cronopio
1cb967b90a [tests] fixed according new refactor and added test to common.setupSocket() 2013-09-16 17:27:06 -05:00
cronopio
5bb83b967e [tests] make the tests run with the last refactor 2013-09-16 16:50:30 -05:00
cronopio
275a5192fa [fix] typo 2013-09-16 16:49:51 -05:00
cronopio
f1aeb0500c [misc] use the local mocha instead the global 2013-09-16 15:26:44 -05:00
yawnt
da9de7034a [docs] fix syntax highlighting 2013-09-16 22:12:52 +02:00
yawnt
38e6d7cd54 [merge] PR #470 2013-09-16 22:02:14 +02:00
yawnt
469b0d4e9f [fix] add 0.10 compatibily.. closes #474 2013-09-16 21:36:09 +02:00
Maciej Małecki
9f3508805a Merge pull request #472 from glasser/patch-1
Fix accidental write to global variable.
2013-09-16 12:01:27 -07:00
David Glasser
dfdedf23b7 Fix accidental write to global variable. 2013-09-16 11:33:57 -07:00
srossross
bd106d69f0 Updated readme 2013-09-16 11:24:00 -07:00
srossross
07091b5077 ENH: updated README and added examples file. 2013-09-16 11:21:20 -07:00
srossross
edd8e2f04e ENH: updated readme with an example 2013-09-16 11:01:34 -07:00
srossross
ef946a7697 ENH: updated target and forward options so that a string may be specified 2013-09-16 10:49:53 -07:00
srossross
268afe34bb ENH: updated ws and web functions to use the global options object as a base
even if request options is specified. request options will over write any global options in a conflict
2013-09-16 10:37:11 -07:00
srossross
1b867a7f59 ENH: added error events 2013-09-15 15:20:51 -07:00
yawnt
29afab4488 [fix] headers, closes #469 2013-09-15 22:07:35 +02:00
yawnt
e08d4edad3 [fix] write status 2013-09-15 18:02:00 +02:00
yawnt
60de543d04 [fix] headers, fixes #467 2013-09-15 17:55:41 +02:00
yawnt
adc5be020c [fix] opts 2013-09-15 17:19:07 +02:00
yawnt
0637322d96 [fix] url 2013-09-15 15:33:48 +02:00
yawnt
4d3a4e1ee7 [fix] readme 2013-09-15 15:30:05 +02:00
yawnt
dd0f7b8876 [docs] logo 2013-09-15 15:07:39 +02:00
yawnt
d7078e2fdd [fix] layout 2013-09-15 15:07:09 +02:00
yawnt
ee3cc38066 [fix] new logo 2013-09-15 15:05:22 +02:00
yawnt
aaff1966e4 [fix] move logo 2013-09-15 15:01:30 +02:00
yawnt
57abb7f26c [fix] move logo 2013-09-15 15:00:53 +02:00
yawnt
8b05626eed [docs] add logo 2013-09-15 14:59:55 +02:00
yawnt
98f29bdcfc [merge] text 2013-09-15 14:58:35 +02:00
yawnt
4c2f2f3b9a [logo] 2013-09-15 14:57:19 +02:00
yawnt
c9945dd370 Merge pull request #14 from sateffen/master
[fix] 2 spelling mistakes
2013-09-15 04:46:32 -07:00
sateffen
5823842194 [Fix] 2 spelling mistakes 2013-09-15 13:39:38 +02:00
yawnt
d1663549ec [fix] default port 2013-09-15 13:18:21 +02:00
yawnt
18341d5597 [fix] console 2013-09-15 13:07:24 +02:00
yawnt
26c4c43a06 [fix] proxying to https 2013-09-15 13:06:39 +02:00
yawnt
3c91ed3d26 [fix] proxy to http(s) 2013-09-15 13:03:51 +02:00
yawnt
46fe81e11a Merge pull request #11 from jcrugzz/https-req-ws
[fix] add ability to proxy websockets over HTTPS
2013-09-15 02:22:49 -07:00
Jarrett Cruger
92de6a6f95 [fix] add ability to proxy websockets over HTTPS 2013-09-14 20:46:05 -04:00
yawnt
6e77cd3909 [fix] do not call .end 2013-09-15 00:43:01 +02:00
yawnt
7599cee3fd [fix] minor 2013-09-14 22:52:45 +02:00
yawnt
dad211e71c keepalive sockets 2013-09-14 22:52:22 +02:00
yawnt
63b016c8ef [fix] yawnt baaaka .. fixes #8 2013-09-14 22:03:00 +02:00
yawnt
ec981c5b74 [fix] docs 2013-09-14 19:10:33 +02:00
yawnt
c4ddc4edd3 [fix] quote 2013-09-14 18:46:13 +02:00
yawnt
886a870707 [docs] readme 2013-09-14 18:44:39 +02:00
yawnt
8c8c455541 support forward 2013-09-14 14:00:31 +02:00
yawnt
031aa0fbf3 [fix] slimmer proxying 2013-09-14 13:33:38 +02:00
yawnt
07cfa6b981 [experiment] new api for proxying 2013-09-14 13:17:45 +02:00
yawnt
7d71a867a8 [fix] naming convention 2013-09-14 13:06:00 +02:00
yawnt
6a03e5f7cf [fix] remove stuff 2013-09-14 13:04:59 +02:00
yawnt
2a593664a5 [fix] naming 2013-09-14 13:02:28 +02:00
yawnt
893100972c [fix] naming 2013-09-14 13:01:53 +02:00
yawnt
79a14acfd2 [feature] websocket support 2013-09-14 12:48:53 +02:00
yawnt
f97c0c6167 write 2013-09-14 10:22:31 +02:00
yawnt
1a7bef0cda mm test file 2013-09-14 10:06:03 +02:00
yawnt
e45bfd66a2 stuff 2013-09-13 23:38:12 +02:00
yawnt
a74cd85c8a socket.io stuff 2013-09-13 20:49:52 +02:00
yawnt
4a4607d075 support websockets 2013-09-13 20:06:51 +02:00
yawnt
0fb33810f5 merge with @cronopio 2013-09-13 19:08:34 +02:00
yawnt
c9cd6d2ad3 [fix] make @mmalecki a happy camper 2013-09-13 19:07:34 +02:00
cronopio
8b3fe32f6a [tests] added the ws passes test and the streams webscokets test 2013-09-10 19:36:19 -05:00
cronopio
e0faaaf811 [fix] minor and short fixes 2013-09-10 19:31:47 -05:00
yawnt
1993faf8a4 new error propagation - follows 2013-09-05 17:45:03 +02:00
yawnt
3a39e444ff new error propagation 2013-09-05 17:44:23 +02:00
yawnt
07551c63e4 websocket draft 2013-09-05 17:28:25 +02:00
cronopio
79f7f99528 [lib] initial draft to websockets passes 2013-09-03 14:09:35 -05:00
yawnt
4480699d3a [fix] use some 2013-09-03 20:57:22 +02:00
yawnt
a6256cac1d [fix] short circuit 2013-09-03 20:56:18 +02:00
cronopio
b85aa16e75 [test] test onError part, proxying to no where 2013-08-28 14:01:55 -05:00
cronopio
27df8d72ad [test] testing the onResponse proxy method 2013-08-28 13:45:09 -05:00
yawnt
abf1d90fdf [fix] use agent pool 2013-08-28 15:22:04 +02:00
yawnt
c9612798f1 [test] proxystream test 2013-08-28 14:58:57 +02:00
yawnt
8fc3389367 [test] add test for forwardstream 2013-08-28 14:49:27 +02:00
yawnt
f4e9945856 Merge pull request #3 from yawnt/tests
Tests
2013-08-28 05:18:08 -07:00
cronopio
2fac7b9b00 [test] added the lib/caronte/streams/forward.js initial test, one test pending 2013-08-26 16:34:32 -05:00
cronopio
c02b721321 [test] passes/web.js XHeaders func 2013-08-26 00:21:30 -05:00
yawnt
d40e4beb62 [test] passes/web.js (first 2 funcs) 2013-08-21 17:37:38 +02:00
yawnt
356f43d719 [fix] ProxyStraem now works 2013-08-20 17:32:29 +02:00
yawnt
d4f0da898e [fix] some stuff start debugging proxystream 2013-08-20 16:09:37 +02:00
yawnt
9ab8749a9b [feature] started working on error propagation, kinda sucks, gotta think it over 2013-08-10 20:41:25 +02:00
yawnt
bd3df45010 [fix] woops 2013-08-09 20:52:55 +02:00
yawnt
2e7343d728 [fix] making @jcrugzz a happy camper 2013-08-09 20:52:21 +02:00
yawnt
6a4294cbdf [feature] implement _write and _read 2013-08-09 19:40:40 +02:00
yawnt
4f24664e8a [api] add draft for proxystream 2013-08-09 19:37:58 +02:00
yawnt
cedc5c4bd2 [tests] add more tests 2013-08-09 19:13:44 +02:00
yawnt
335af81d02 [minor] remove coverage 2013-08-09 18:59:20 +02:00
yawnt
a255f984fe [fix] tests 2013-08-09 18:58:56 +02:00
yawnt
16eacfa961 [test] started writing tests 2013-08-03 16:54:48 +02:00
yawnt
004a46c09d [test] COVERAGE 2013-08-03 16:44:23 +02:00
yawnt
34f16e7464 [fix] making @stoke a happy camper 2013-08-03 15:56:05 +02:00
yawnt
d05af4af60 [refactor docs] add descriptions 2013-08-03 15:45:07 +02:00
yawnt
8273cb6461 [refactor] move to leaner architecture 2013-08-03 08:47:07 +02:00
yawnt
4d13156721 [dist] first 2013-08-01 10:50:39 +02:00
Maciej Małecki
ebbba73eda [test] Test on newer version of node 2013-06-20 15:37:48 +02:00
Maciej Małecki
2fd748fb61 [dist] Bump version to 0.10.3 2013-06-20 15:29:14 +02:00
Maciej Małecki
e1d384e769 [fix] Respect maxSockets from target options in RoutingProxy 2013-06-20 15:28:47 +02:00
Charlie Robbins
5ff2b6e1a1 Merge pull request #419 from Raynos/patch-1
Pass default certs to SNICallback example
2013-06-14 19:20:24 -07:00
Raynos
f5e1844abd Pass default certs to SNICallback example
Using only SNICallback to create a HTTPS / TLS server is bad. It means all non SNI clients can't do anything because there are no certs.

in v0.10 of node TLS server was updated to throw if you forgot to supply certs.

Which means that every HTTPS server needs to supply certs as a fallback for when SNI is not available.

 - closes #399
2013-05-10 17:55:01 -06:00
Emilien Kenler
0c753234c0 Send path in req.path and not the url
Signed-off-by: Emilien Kenler <hello@emilienkenler.com>
2013-05-04 22:48:50 +02:00
indexzero
de0928f616 [dist] Version bump. 0.10.2 2013-04-21 17:06:54 -04:00
indexzero
7fc39d77f4 [minor] Strip trailing whitespace. 2013-04-21 17:02:18 -04:00
indexzero
59b71c033f [minor] Style compliance. Fixes #402. 2013-04-21 17:01:20 -04:00
Ivan Jaramillo
985025c90f Add headers on 'handshake'
The headers in the 'handshake' event were not written to the socket, the client received data but not the headers.
2013-04-21 16:59:08 -04:00
Charlie Robbins
98f5c462ea Merge pull request #407 from GUI/master
Correct keep-alive responses to HTTP 1.0 clients
2013-04-21 13:25:35 -07:00
Nick Muerdter
daf53bd753 Don't test raw HTTP 1.0 requests over HTTPS. 2013-04-18 18:11:58 -06:00
Nick Muerdter
a29b5e8e28 Correct keep-alive responses to HTTP 1.0 clients.
Since the proxy requests comes from NodeJS's HTTP 1.1 request client, a
backend server may default to setting Connection: keep-alive in its
response. However, the real HTTP 1.0 client may not be able to
handle that.

Force HTTP 1.0 client's to Connection: close, unless the client
explicitly supports keep-alive.
2013-04-18 16:33:10 -06:00
indexzero
9c13ad46e4 [dist] Version bump. 0.10.1 2013-04-12 04:55:26 -04:00
Charlie Robbins
3763dc935f Merge pull request #370 from jmatthewsr-ms/master
Fix for slab buffer retention, leading to large memory consumption
2013-04-09 11:02:56 -07:00
indexzero
71183bf30b [dist] Version bump. 0.10.0 2013-03-18 01:53:12 -04:00
indexzero
8665f3cc60 [dist] Update CHANGELOG.md 2013-03-18 01:53:03 -04:00
Charlie Robbins
4335f49b0e Merge pull request #385 from nodejitsu/breaking-proxy-response
Change the emitter of the `proxyResponse` event
2013-03-17 22:51:50 -07:00
Charlie Robbins
ea10bb22d9 Merge pull request #383 from thefosk/master
Fixing a bug that generates an unexpected TypeError
2013-03-17 22:50:17 -07:00
indexzero
2620f06e2d [fix breaking] Emit the proxyResponse event on the HttpProxy instance to reduce listener churn and reference counts. 2013-03-18 01:49:01 -04:00
Charlie Robbins
3ebc795c33 Merge pull request #384 from No9/master
Mention Harmon used for response modifications in the readme
2013-03-16 07:56:26 -07:00
No9
4e42354e77 Harmon messsage 2013-03-16 12:17:54 +00:00
No9
35ba0db554 Harmon messsage 2013-03-16 12:17:35 +00:00
thefosk
c9b6895c5e Fixing the if statement as it lead to 'TypeError: Parameter 'url' must be a string, not undefined' in certain cases 2013-03-14 19:09:03 -07:00
indexzero
701dc698e3 [dist] Version bump. 0.9.1 2013-03-09 05:09:18 -05:00
indexzero
ea5e214522 [dist doc] Updated CHANGELOG.md for v0.9.1 2013-03-09 05:09:10 -05:00
indexzero
c78356e9cf [breaking] Ensure that webSocketProxyError also receives the error to be consistent with proxyError events. 2013-03-09 05:08:55 -05:00
indexzero
c68e038912 [dist] Version bump. 0.9.0 2013-03-09 04:59:53 -05:00
indexzero
133115c976 [doc dist] Update CHANGELOG.md for v0.9.0. 2013-03-09 04:59:41 -05:00
indexzero
ad213106d0 [dist] Update devDependencies 2013-03-09 04:59:19 -05:00
indexzero
ea0587a8f9 [minor] Small whitespace compliance. 2013-03-09 04:42:07 -05:00
indexzero
5d515e4728 [api test] Manually merge #195 from @tglines since that fork was deleted. Update tests to use new macros. Fixes #195. Fixes #60. 2013-03-09 04:20:05 -05:00
Mikkel Garcia
5e6be6ccf5 [doc] added comments to pathnameOnly block. 2013-03-09 03:18:15 -05:00
Mikkel Garcia
a1607c1684 pathnameOnly option documented in the Readme.md 2013-03-09 03:18:11 -05:00
Mikkel Garcia
46b078a98d pathnameOnly flag added. Ignores hostname and applies routing table to the paths being requested. 2013-03-09 03:18:07 -05:00
Niall O'Higgins
10f6b05775 add support for loading CA bundles
fix loop

typo

another typo *sigh*

this wasn't doing what I thought it was doing.
2013-03-09 03:12:58 -05:00
Niall O'Higgins
2c3650746c problem: don't want to run my server as root to bind to privileged ports (e.g. 80, 443).
solution: support privilege drop after socket bind via new --user <username> parameter.
2013-03-09 03:12:52 -05:00
pdoran
89d43c20dd Added timeout option and test to test new timeout parameter, added requestFail assertion. 2013-03-09 03:04:29 -05:00
indexzero
476cbe741f [minor] Move private helper to end of file. 2013-03-09 02:44:46 -05:00
indexzero
9be0af3166 [fix] Set "content-length" header to "0" if it is not already set on DELETE requests. Fixes #338. 2013-03-09 02:44:28 -05:00
indexzero
a89e2f2688 [fix] Do not use "Transfer-Encoding: chunked" header for proxied DELETE requests with no "Content-Length" header. Fixes #373. 2013-03-09 02:40:09 -05:00
indexzero
6a278b3dd8 [fix] http-proxy should not modify the protocol in redirect request for external sites. Fixes #359. 2013-03-09 02:35:50 -05:00
indexzero
3130665d9f [fix] Emit notFound event when ProxyTable location does not exist. Fixes #355. Fixes #333. 2013-03-09 02:29:58 -05:00
indexzero
4c1a2c1416 [fix] Make options immutable in RoutingProxy. Fixes #248. 2013-03-09 02:21:31 -05:00
colinmollenhour
b1c4bd61e8 Remove data event that is not needed after-all. 2013-03-09 01:48:42 -05:00
Colin Mollenhour
3b86a7aae3 Add 'proxyResponse' event so observer can modify response headers or abort response. 2013-03-09 01:48:37 -05:00
Colin Mollenhour
4c130f5dac Allow event observers to access upstream response headers and data. 2013-03-09 01:48:29 -05:00
indexzero
9cecd97153 [minor] s/function(/function (/ s/){/) {/ 2013-03-09 01:43:25 -05:00
indexzero
440013c263 [fix doc] Fix bad variable reference in README.md. 2013-03-09 01:36:57 -05:00
jpetazzo
ba65a485fc Fix typo which slipped in during patch clean-up 2013-03-09 01:21:30 -05:00
jpetazzo
ef66833c4d Fix truncated chunked responses 2013-03-09 01:21:21 -05:00
Charlie Robbins
af9eb06e47 Merge pull request #298 from Kami/connection_keep_alive_on_1_1
If HTTP 1.1 is used and backend doesn't return 'Connection' header, expicitly  return Connection: keep-alive.
2013-03-08 22:11:37 -08:00
indexzero
28a3b0a6f0 [fix] Remove special case handling of 304 responses since it was fixed in 182dcd3. Fixes #322. 2013-03-09 01:10:02 -05:00
Gilad Oren
ecb547223f Add tests for headers bug fixes 2013-03-09 01:05:27 -05:00
Yosef Dinerstein
ffe74ed299 - support unix donain sockets and windows named pipes (socketPath) on node 0.8.x. On node 0.6.x the support was opaque via port, but on the new node, socketPath should be set explicitely.
- avoid adding multiple headers with the same name
- fix bug in setting connection
2013-03-09 01:05:22 -05:00
Charlie Robbins
eee6babc98 Merge pull request #332 from ramitos/patch-1
add "with custom server logic" to the "Proxying WebSockets" section of the readme
2013-03-08 21:45:30 -08:00
indexzero
c6da760ca9 Revert "[fix minor] Prevent crashes from attempting to remove listeners more than once when proxying websocket requests."
This reverts commit a681493371ae63f026e869bf58b6fea682dc5de3.
2013-03-09 00:43:25 -05:00
indexzero
a681493371 [fix minor] Prevent crashes from attempting to remove listeners more than once when proxying websocket requests. 2013-03-09 00:40:00 -05:00
unknown
2055d0c8ec memory leak fix in closing of the scokets 2013-03-09 00:36:19 -05:00
indexzero
013cb2e0c2 [fix] Ensure response.headers.location is defined. Fixes #276. 2013-03-09 00:28:50 -05:00
indexzero
deca7565c5 [doc fix] Add undefined var in example. 2013-03-09 00:24:04 -05:00
Oscar Östlund
64efa7f929 Added comments 2013-03-09 00:23:41 -05:00
Oscar Östlund
83fbd42506 Added simple round robin example with websocket support 2013-03-09 00:23:36 -05:00
Otávio Ribeiro
9672b99271 cleanning 2013-03-09 00:20:46 -05:00
Otávio Ribeiro
8d8739999f cleanning 2013-03-09 00:20:42 -05:00
Otávio Ribeiro
31fc94aa5e working on x-forwarded-for 2013-03-09 00:20:38 -05:00
Otávio Ribeiro
133240937d working on x-forwarded-for 2013-03-09 00:20:33 -05:00
Otávio Ribeiro
916d44e3d2 Routing Proxy was not sending x-forward-*. Fixing It... 2013-03-09 00:20:26 -05:00
Charlie Robbins
025adc2912 Merge pull request #365 from adjohnson916/master
routing proxy 'this' reference bug?
2013-03-08 21:14:14 -08:00
Charlie Robbins
8b38c994a9 Merge pull request #374 from erasmospunk/master
fixed issue #364 'proxyError' event emitted twice
2013-03-08 21:11:56 -08:00
Charlie Robbins
c686ac7b01 Merge pull request #349 from jamie-stackhouse/patch-1
Misleading documentation for Websockets via .createServer
2013-03-08 20:49:05 -08:00
jamie-stackhouse
603106a13d Re-added previous description 2013-02-22 10:31:44 -04:00
jamie-stackhouse
ee6bbe0024 Change wording for handling websocket proxy events 2013-02-22 09:59:16 -04:00
Giannis Dzegoutanis
3b84e27ab4 remove offending code, final fix for issue #364 2013-02-12 20:43:22 +01:00
Giannis Dzegoutanis
43e5f33320 fixed issue #364 'proxyError' event emitted twice 2013-02-10 23:07:40 +01:00
Justin Matthews
d2888c83f5 Fix for retaining large slab buffers in node core 2013-01-24 15:44:06 -08:00
Anders Johnson
15afc23a27 fix 'this' reference in routing proxy listener bindings 2013-01-12 21:55:46 -06:00
Maciej Małecki
26d3646ff2 [dist] Bump version to 0.8.7 2012-12-23 00:56:23 +01:00
Maciej Małecki
223eacda85 [fix] Don't remove error listener after response ends
In some rare cases, `error` event might still be emitted after the
response has ended. This is (most likely) a bug in the `node` core.
2012-12-23 00:44:21 +01:00
Maciej Małecki
edfe869159 [fix] Handle errors on request object
Sometimes a request emits `error` event with a `Parse Error`.
2012-12-21 20:56:01 +01:00
Maciej Małecki
6cd78f6af9 [dist] Bump version to 0.8.6 2012-12-21 16:51:47 +01:00
Maciej Małecki
2a61ec85bd [fix] Handle socket errors 2012-12-13 00:02:54 +01:00
Maciej Małecki
7bc1a628fe [bench] More exact size display 2012-11-30 13:54:36 +01:00
Maciej Małecki
b81d9b71da [dist] Update devDependencies 2012-11-30 03:25:53 +01:00
Maciej Małecki
6797a2705a [bench] Add a benchmark for websockets throughput 2012-11-30 03:25:53 +01:00
Maciej Małecki
2bd9cd9adb [bench] Remove silly "benchmarks" 2012-11-30 03:25:53 +01:00
Charlie Robbins
8b3cfdaaea Merge pull request #337 from indutny/feature-304-end
http-proxy: 304 responses should emit 'end' too
2012-11-29 03:51:42 -08:00
Fedor Indutny
0fd5884a0f http-proxy: 304 responses should emit 'end' too 2012-11-21 12:21:55 +04:00
Maciej Małecki
22639b3781 [dist] Bump version to 0.8.5 2012-11-16 06:19:31 +01:00
Sérgio Ramos
03dbe115c2 add "with custom server logic" to the "Proxying WebSockets" section of the readme.md 2012-11-08 09:47:44 +00:00
Colton Baker
8a88774ecf [fix] Convert strings to numbers if possible in .createServer
Fixes #321
2012-11-06 17:47:47 -05:00
Maciej Małecki
b8c27ed565 [fix] Correctly kill test processes 2012-10-29 12:59:04 +01:00
Maciej Małecki
886a395429 [test] Delete invalid core test 2012-10-29 12:50:41 +01:00
Maciej Małecki
9042665ea9 [test] Stop testing on node v0.9, tests timeout 2012-10-28 14:43:15 +01:00
Maciej Małecki
41c9a9caad [test] Run core tests on npm test 2012-10-28 14:42:18 +01:00
Maciej Małecki
74ec175715 [test] Kill child process when exiting test runner 2012-10-28 14:31:15 +01:00
Maciej Małecki
3531fd609a [test] Make global detection work with older node versions 2012-10-28 14:25:36 +01:00
Maciej Małecki
fefbf04ac0 [test] Upgrade common.js from node core 2012-10-28 13:56:53 +01:00
Maciej Małecki
3d618777ea Merge pull request #323 from indutny/fix-maciej-issue
lib: allow overriding maxSockets
2012-10-25 18:13:59 -07:00
Fedor Indutny
a487dc9b58 lib: allow overriding maxSockets 2012-10-26 01:39:13 +04:00
Maciej Małecki
4d7e8a808d [dist] Bump version to 0.8.4 2012-10-23 22:01:57 +02:00
Maciej Małecki
ebfdbede31 Merge pull request #320 from indutny/master
Events patch
2012-10-23 12:59:33 -07:00
Fedor Indutny
5df6e7bdb8 http-proxy: emit websocket:start
* routing-proxy: allow listening for websocket:* event
2012-10-23 23:54:23 +04:00
Farrin Reid
1df2b30e84 Merge pull request #315 from yawnt/options-doc
documentation for options
2012-10-15 12:19:26 -07:00
yawnt
213e03c998 [fix] function 2012-10-15 20:58:30 +02:00
yawnt
d4cb9dad6c [docs] more options 2012-10-14 20:25:19 +02:00
yawnt
4c8e1d96a3 [docs] options 2012-10-14 19:36:02 +02:00
Maciej Małecki
2e7d8a88f4 [fix] Partial fix for rejecting self-signed certs in tests
Since joyent/node@35607f3a2d, https and
tls modules validate server certificate by default. Turn this feature
off since we're using self-signed certificates in tests.

Currently wss tests are still failing, pending investigation.

Commited on a plane from Poznań to Munich.
2012-09-27 10:00:10 +02:00
Maciej Małecki
eafdc744b6 [refactor] Pass all options to Agent constructor 2012-09-27 10:00:10 +02:00
Maciej Małecki
e925e4928f Merge pull request #308 from peters/patch-1
Added travis build status
2012-09-24 16:20:16 -07:00
Bradley Meck
a89a5b8088 [dist] v0.8.3 2012-09-20 10:59:02 -05:00
Bradley Meck
698b01da8e [fix] spdy should look like https when forwarding (until we get a client) 2012-09-20 10:54:29 -05:00
Peter Rekdal
a64cec0be9 Added travis build status 2012-09-13 10:57:28 +03:00
Nuno Job
bf04bbde8f Merge pull request #302 from janl/patch-1
Fix installation instructions: s/http/https/
2012-08-27 08:48:41 -07:00
Jan Lehnardt
1db9542723 Fix installation instructions: s/http/https/ 2012-08-27 18:37:59 +03:00
Tomaz Muraus
850171cdc4 If HTTP 1.1 is used and backend doesn't return 'Connection' header, explicitly
return Connection: keep-alive.
2012-08-16 21:47:56 -07:00
Maciej Małecki
4f6387c17f [test] Add node v0.9 testing, test all branches 2012-08-10 21:46:58 +02:00
Maciej Małecki
cee27feedd [minor doc] Correct comment 2012-08-10 21:45:30 +02:00
Maciej Małecki
812868ddfc [minor] Remove setEncoding on incoming socket
This isn't needed as we don't do any string operations and `setEncoding`
results in a higher memory usage and is slower.
2012-08-10 21:43:55 +02:00
indexzero
1783ab0625 [fix] Dont use -i when running vows because it supresses --target= and --proxy= CLI arguments 2012-07-26 04:57:02 -04:00
indexzero
a454666e7a [fix] Ignore npm version errors when installing dependencies for examples 2012-07-26 04:53:48 -04:00
indexzero
c4a7b15843 [fix] Suppress EADDRINUSE errors from test/examples-test.js since we are just looking for require-time errors. Isolate tests to ensure idempotency of ports 2012-07-26 04:47:25 -04:00
indexzero
fd648a5290 [fix test] Fix examples to use newest version of socket.io and helpers. Added tests for ensuring that examples require as expected with no errors. 2012-07-26 04:29:47 -04:00
Charlie Robbins
82da8535c5 Merge pull request #285 from 1stvamp/pass-change-origin-from-routing-proxy
If supplied pass changeOrigin option through to HttpProxy instance if set in RoutingProxy
2012-07-26 00:51:10 -07:00
Wesley Mason
89459bfd32 If supplied pass changeOrigin option through to HttpProxy instance if set in RoutingProxy 2012-07-25 14:17:48 +01:00
Bert Belder
24b84068ea Fix socket leaks when FIN packet isn't responded to 2012-07-24 23:05:04 +02:00
Maciej Małecki
0d00b06af3 [fix] destroy() websockets in case of an error
Not doing so caused websockets in `CLOSE_WAIT` to pile up and cause
proxy to exceed open file descriptor limit.
2012-07-24 16:30:51 +02:00
109 changed files with 8858 additions and 6001 deletions

6
.auto-changelog Normal file
View File

@ -0,0 +1,6 @@
{
"output": "CHANGELOG.md",
"template": "keepachangelog",
"unreleased": true,
"commitLimit": false
}

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
package-lock.json binary

11
.gitignore vendored
View File

@ -1,3 +1,10 @@
config.json
node_modules/
node_modules
*.swp
cov
atest.js
notes
primus-proxy.js
tes.js
npm-debug.log
.nyc_output
coverage

9
.npmignore Normal file
View File

@ -0,0 +1,9 @@
test
examples
doc
benchmark
coverage
.nyc_output
.travis.yml
CHANGELOG.md
UPGRADING.md

View File

@ -1,11 +1,12 @@
sudo: false
language: node_js
node_js:
- 0.6
- 0.8
branches:
only:
- master
notifications:
email:
- travis@nodejitsu.com
irc: "irc.freenode.org#nodejitsu"
- "8"
- "10"
- "12"
script:
- npm test
after_success:
- bash <(curl -s https://codecov.io/bash)
matrix:
fast_finish: true

File diff suppressed because it is too large Load Diff

74
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,74 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at <https://github.com/http-party/node-http-proxy>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -1,7 +1,7 @@
node-http-proxy
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires
Copyright (c) 2010-2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -20,4 +20,4 @@
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

862
README.md
View File

@ -1,68 +1,107 @@
# node-http-proxy
<p align="center">
<img src="https://raw.github.com/http-party/node-http-proxy/master/doc/logo.png"/>
</p>
<img src="http://i.imgur.com/8fTt9.png" />
# node-http-proxy [![Build Status](https://travis-ci.org/http-party/node-http-proxy.svg?branch=master)](https://travis-ci.org/http-party/node-http-proxy) [![codecov](https://codecov.io/gh/http-party/node-http-proxy/branch/master/graph/badge.svg)](https://codecov.io/gh/http-party/node-http-proxy)
## Battle-hardened node.js http proxy
`node-http-proxy` is an HTTP programmable proxying library that supports
websockets. It is suitable for implementing components such as reverse
proxies and load balancers.
### Features
### Table of Contents
* [Installation](#installation)
* [Upgrading from 0.8.x ?](#upgrading-from-08x-)
* [Core Concept](#core-concept)
* [Use Cases](#use-cases)
* [Setup a basic stand-alone proxy server](#setup-a-basic-stand-alone-proxy-server)
* [Setup a stand-alone proxy server with custom server logic](#setup-a-stand-alone-proxy-server-with-custom-server-logic)
* [Setup a stand-alone proxy server with proxy request header re-writing](#setup-a-stand-alone-proxy-server-with-proxy-request-header-re-writing)
* [Modify a response from a proxied server](#modify-a-response-from-a-proxied-server)
* [Setup a stand-alone proxy server with latency](#setup-a-stand-alone-proxy-server-with-latency)
* [Using HTTPS](#using-https)
* [Proxying WebSockets](#proxying-websockets)
* [Options](#options)
* [Listening for proxy events](#listening-for-proxy-events)
* [Shutdown](#shutdown)
* [Miscellaneous](#miscellaneous)
* [Test](#test)
* [ProxyTable API](#proxytable-api)
* [Logo](#logo)
* [Contributing and Issues](#contributing-and-issues)
* [License](#license)
* Reverse proxies incoming http.ServerRequest streams
* Can be used as a CommonJS module in node.js
* Uses event buffering to support application latency in proxied requests
* Reverse or Forward Proxy based on simple JSON-based configuration
* Supports [WebSockets][1]
* Supports [HTTPS][2]
* Minimal request overhead and latency
* Full suite of functional tests
* Battled-hardened through __production usage__ @ [nodejitsu.com][0]
* Written entirely in Javascript
* Easy to use API
### Installation
### When to use node-http-proxy
`npm install http-proxy --save`
Let's suppose you were running multiple http application servers, but you only wanted to expose one machine to the internet. You could setup node-http-proxy on that one machine and then reverse-proxy the incoming http requests to locally running services which were not exposed to the outside network.
**[Back to top](#table-of-contents)**
### Installing npm (node package manager)
### Upgrading from 0.8.x ?
Click [here](UPGRADING.md)
**[Back to top](#table-of-contents)**
### Core Concept
A new proxy is created by calling `createProxyServer` and passing
an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L26-L42))
```javascript
var httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer(options); // See (†)
```
curl http://npmjs.org/install.sh | sh
†Unless listen(..) is invoked on the object, this does not create a webserver. See below.
An object will be returned with four methods:
* web `req, res, [options]` (used for proxying regular HTTP(S) requests)
* ws `req, socket, head, [options]` (used for proxying WS(S) requests)
* listen `port` (a function that wraps the object in a webserver, for your convenience)
* close `[callback]` (a function that closes the inner webserver and stops listening on given port)
It is then possible to proxy requests by calling these functions
```javascript
http.createServer(function(req, res) {
proxy.web(req, res, { target: 'http://mytarget.com:8080' });
});
```
### Installing node-http-proxy
Errors can be listened on either using the Event Emitter API
```
npm install http-proxy
```javascript
proxy.on('error', function(e) {
...
});
```
## Using node-http-proxy
or using the callback API
There are several ways to use node-http-proxy; the library is designed to be flexible so that it can be used by itself, or in conjunction with other node.js libraries / tools:
```javascript
proxy.web(req, res, { target: 'http://mytarget.com:8080' }, function(e) { ... });
```
1. Standalone HTTP Proxy server
2. Inside of another HTTP server (like Connect)
3. In conjunction with a Proxy Routing Table
4. As a forward-proxy with a reverse proxy
5. From the command-line as a long running process
6. customized with 3rd party middleware.
When a request is proxied it follows two different pipelines ([available here](lib/http-proxy/passes))
which apply transformations to both the `req` and `res` object.
The first pipeline (incoming) is responsible for the creation and manipulation of the stream that connects your client to the target.
The second pipeline (outgoing) is responsible for the creation and manipulation of the stream that, from your target, returns data
to the client.
In each of these scenarios node-http-proxy can handle any of these types of requests:
**[Back to top](#table-of-contents)**
1. HTTP Requests (http://)
2. HTTPS Requests (https://)
3. WebSocket Requests (ws://)
4. Secure WebSocket Requests (wss://)
### Use Cases
See the [examples][3] for more working sample code.
#### Setup a basic stand-alone proxy server
### Setup a basic stand-alone proxy server
``` js
```js
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create your proxy server
// Create your proxy server and set the target in the options.
//
httpProxy.createServer(9000, 'localhost').listen(8000);
httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); // See (†)
//
// Create your target server
@ -73,456 +112,457 @@ http.createServer(function (req, res) {
res.end();
}).listen(9000);
```
†Invoking listen(..) triggers the creation of a web server. Otherwise, just the proxy instance is created.
### Setup a stand-alone proxy server with custom server logic
**[Back to top](#table-of-contents)**
``` js
#### Setup a stand-alone proxy server with custom server logic
This example shows how you can proxy a request using your own HTTP server
and also you can put your own logic to handle the request.
```js
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a proxy server with custom application logic
//
httpProxy.createServer(function (req, res, proxy) {
//
// Put your custom server logic here
//
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
});
}).listen(8000);
var proxy = httpProxy.createProxyServer({});
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
//
// Create your custom server and just call `proxy.web()` to proxy
// a web request to the target passed in the options
// also you can use `proxy.ws()` to proxy a websockets request
//
var server = http.createServer(function(req, res) {
// You can define here your custom logic to handle the request
// and then proxy the request.
proxy.web(req, res, { target: 'http://127.0.0.1:5050' });
});
console.log("listening on port 5050")
server.listen(5050);
```
### Setup a stand-alone proxy server with latency (e.g. IO, etc)
**[Back to top](#table-of-contents)**
``` js
#### Setup a stand-alone proxy server with proxy request header re-writing
This example shows how you can proxy a request using your own HTTP server that
modifies the outgoing proxy request by adding a special header.
```js
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a proxy server with custom application logic
//
httpProxy.createServer(function (req, res, proxy) {
//
// Buffer the request so that `data` and `end` events
// are not lost during async operation(s).
//
var buffer = httpProxy.buffer(req);
//
// Wait for two seconds then respond: this simulates
// performing async actions before proxying a request
//
var proxy = httpProxy.createProxyServer({});
// To modify the proxy connection before data is sent, you can listen
// for the 'proxyReq' event. When the event is fired, you will receive
// the following arguments:
// (http.ClientRequest proxyReq, http.IncomingMessage req,
// http.ServerResponse res, Object options). This mechanism is useful when
// you need to modify the proxy request before the proxy connection
// is made to the target.
//
proxy.on('proxyReq', function(proxyReq, req, res, options) {
proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
});
var server = http.createServer(function(req, res) {
// You can define here your custom logic to handle the request
// and then proxy the request.
proxy.web(req, res, {
target: 'http://127.0.0.1:5050'
});
});
console.log("listening on port 5050")
server.listen(5050);
```
**[Back to top](#table-of-contents)**
#### Modify a response from a proxied server
Sometimes when you have received a HTML/XML document from the server of origin you would like to modify it before forwarding it on.
[Harmon](https://github.com/No9/harmon) allows you to do this in a streaming style so as to keep the pressure on the proxy to a minimum.
**[Back to top](#table-of-contents)**
#### Setup a stand-alone proxy server with latency
```js
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a proxy server with latency
//
var proxy = httpProxy.createProxyServer();
//
// Create your server that makes an operation that waits a while
// and then proxies the request
//
http.createServer(function (req, res) {
// This simulates an operation that takes 500ms to execute
setTimeout(function () {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000,
buffer: buffer
});
}, 2000);
}).listen(8000);
proxy.web(req, res, {
target: 'http://localhost:9008'
});
}, 500);
}).listen(8008);
//
// Create your target server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2));
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
}).listen(9008);
```
### Proxy requests within another http server
**[Back to top](#table-of-contents)**
``` js
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a new instance of HttProxy to use in your server
//
var proxy = new httpProxy.RoutingProxy();
#### Using HTTPS
You can activate the validation of a secure SSL certificate to the target connection (avoid self-signed certs), just set `secure: true` in the options.
##### HTTPS -> HTTP
```js
//
// Create a regular http server and proxy its handler
// Create the HTTPS proxy server in front of a HTTP server
//
http.createServer(function (req, res) {
//
// Put your custom server logic here, then proxy
//
proxy.proxyRequest(req, res, {
httpProxy.createServer({
target: {
host: 'localhost',
port: 9000
});
}).listen(8001);
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
```
### Proxy requests using a ProxyTable
A Proxy Table is a simple lookup table that maps incoming requests to proxy target locations. Take a look at an example of the options you need to pass to httpProxy.createServer:
``` js
var options = {
router: {
'foo.com/baz': '127.0.0.1:8001',
'foo.com/buz': '127.0.0.1:8002',
'bar.com/buz': '127.0.0.1:8003'
port: 9009
},
ssl: {
key: fs.readFileSync('valid-ssl-key.pem', 'utf8'),
cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8')
}
};
}).listen(8009);
```
The above route table will take incoming requests to 'foo.com/baz' and forward them to '127.0.0.1:8001'. Likewise it will take incoming requests to 'foo.com/buz' and forward them to '127.0.0.1:8002'. The routes themselves are later converted to regular expressions to enable more complex matching functionality. We can create a proxy server with these options by using the following code:
##### HTTPS -> HTTPS
``` js
var proxyServer = httpProxy.createServer(options);
proxyServer.listen(80);
```js
//
// Create the proxy server listening on port 443
//
httpProxy.createServer({
ssl: {
key: fs.readFileSync('valid-ssl-key.pem', 'utf8'),
cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8')
},
target: 'https://localhost:9010',
secure: true // Depends on your needs, could be false.
}).listen(443);
```
### Proxy requests using a 'Hostname Only' ProxyTable
As mentioned in the previous section, all routes passes to the ProxyTable are by default converted to regular expressions that are evaluated at proxy-time. This is good for complex URL rewriting of proxy requests, but less efficient when one simply wants to do pure hostname routing based on the HTTP 'Host' header. If you are only concerned with hostname routing, you change the lookup used by the internal ProxyTable:
##### HTTP -> HTTPS (using a PKCS12 client certificate)
``` js
var options = {
hostnameOnly: true,
router: {
'foo.com': '127.0.0.1:8001',
'bar.com': '127.0.0.1:8002'
}
}
```js
//
// Create an HTTP proxy server with an HTTPS target
//
httpProxy.createProxyServer({
target: {
protocol: 'https:',
host: 'my-domain-name',
port: 443,
pfx: fs.readFileSync('path/to/certificate.p12'),
passphrase: 'password',
},
changeOrigin: true,
}).listen(8000);
```
Notice here that I have not included paths on the individual domains because this is not possible when using only the HTTP 'Host' header. Care to learn more? See [RFC2616: HTTP/1.1, Section 14.23, "Host"][4].
**[Back to top](#table-of-contents)**
### Proxy requests with an additional forward proxy
Sometimes in addition to a reverse proxy, you may want your front-facing server to forward traffic to another location. For example, if you wanted to load test your staging environment. This is possible when using node-http-proxy using similar JSON-based configuration to a proxy table:
#### Proxying WebSockets
You can activate the websocket support for the proxy using `ws:true` in the options.
``` js
var proxyServerWithForwarding = httpProxy.createServer(9000, 'localhost', {
forward: {
port: 9000,
host: 'staging.com'
```js
//
// Create a proxy server for websockets
//
httpProxy.createServer({
target: 'ws://localhost:9014',
ws: true
}).listen(8014);
```
Also you can proxy the websocket requests just calling the `ws(req, socket, head)` method.
```js
//
// Setup our server to proxy standard HTTP requests
//
var proxy = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 9015
}
});
proxyServerWithForwarding.listen(80);
var proxyServer = http.createServer(function (req, res) {
proxy.web(req, res);
});
//
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
proxyServer.listen(8015);
```
The forwarding option can be used in conjunction with the proxy table options by simply including both the 'forward' and 'router' properties in the options passed to 'createServer'.
**[Back to top](#table-of-contents)**
### Options
`httpProxy.createProxyServer` supports the following options:
* **target**: url string to be parsed with the url module
* **forward**: url string to be parsed with the url module
* **agent**: object to be passed to http(s).request (see Node's [https agent](http://nodejs.org/api/https.html#https_class_https_agent) and [http agent](http://nodejs.org/api/http.html#http_class_http_agent) objects)
* **ssl**: object to be passed to https.createServer()
* **ws**: true/false, if you want to proxy websockets
* **xfwd**: true/false, adds x-forward headers
* **secure**: true/false, if you want to verify the SSL Certs
* **toProxy**: true/false, passes the absolute URL as the `path` (useful for proxying to proxies)
* **prependPath**: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path
* **ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required).
* **localAddress**: Local interface string to bind for outgoing connections
* **changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL
* **preserveHeaderKeyCase**: true/false, Default: false - specify whether you want to keep letter case of response header key
* **auth**: Basic authentication i.e. 'user:password' to compute an Authorization header.
* **hostRewrite**: rewrites the location hostname on (201/301/302/307/308) redirects.
* **autoRewrite**: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false.
* **protocolRewrite**: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null.
* **cookieDomainRewrite**: rewrites domain of `set-cookie` headers. Possible values:
* `false` (default): disable cookie rewriting
* String: new domain, for example `cookieDomainRewrite: "new.domain"`. To remove the domain, use `cookieDomainRewrite: ""`.
* Object: mapping of domains to new domains, use `"*"` to match all domains.
For example keep one domain unchanged, rewrite one domain and remove other domains:
```
cookieDomainRewrite: {
"unchanged.domain": "unchanged.domain",
"old.domain": "new.domain",
"*": ""
}
```
* **cookiePathRewrite**: rewrites path of `set-cookie` headers. Possible values:
* `false` (default): disable cookie rewriting
* String: new path, for example `cookiePathRewrite: "/newPath/"`. To remove the path, use `cookiePathRewrite: ""`. To set path to root use `cookiePathRewrite: "/"`.
* Object: mapping of paths to new paths, use `"*"` to match all paths.
For example, to keep one path unchanged, rewrite one path and remove other paths:
```
cookiePathRewrite: {
"/unchanged.path/": "/unchanged.path/",
"/old.path/": "/new.path/",
"*": ""
}
```
* **headers**: object with extra headers to be added to target requests.
* **proxyTimeout**: timeout (in millis) for outgoing proxy requests
* **timeout**: timeout (in millis) for incoming requests
* **followRedirects**: true/false, Default: false - specify whether you want to follow redirects
* **selfHandleResponse** true/false, if set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the `proxyRes` event
* **buffer**: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option:
```
'use strict';
const streamify = require('stream-array');
const HttpProxy = require('http-proxy');
const proxy = new HttpProxy();
module.exports = (req, res, next) => {
proxy.web(req, res, {
target: 'http://localhost:4003/',
buffer: streamify(req.rawBody)
}, next);
};
```
**NOTE:**
`options.ws` and `options.ssl` are optional.
`options.target` and `options.forward` cannot both be missing
If you are using the `proxyServer.listen` method, the following options are also applicable:
* **ssl**: object to be passed to https.createServer()
* **ws**: true/false, if you want to proxy websockets
**[Back to top](#table-of-contents)**
### Listening for proxy events
Sometimes you want to listen to an event on a proxy. For example, you may want to listen to the 'end' event, which represents when the proxy has finished proxying a request.
``` js
* `error`: The error event is emitted if the request to the target fail. **We do not do any error handling of messages passed between client and proxy, and messages passed between proxy and target, so it is recommended that you listen on errors and handle them.**
* `proxyReq`: This event is emitted before the data is sent. It gives you a chance to alter the proxyReq request object. Applies to "web" connections
* `proxyReqWs`: This event is emitted before the data is sent. It gives you a chance to alter the proxyReq request object. Applies to "websocket" connections
* `proxyRes`: This event is emitted if the request to the target got a response.
* `open`: This event is emitted once the proxy websocket was created and piped into the target websocket.
* `close`: This event is emitted once the proxy websocket was closed.
* (DEPRECATED) `proxySocket`: Deprecated in favor of `open`.
```js
var httpProxy = require('http-proxy');
// Error example
//
// Http Proxy Server with bad target
//
var proxy = httpProxy.createServer({
target:'http://localhost:9005'
});
var server = httpProxy.createServer(function (req, res, proxy) {
var buffer = httpProxy.buffer(req);
proxy.listen(8005);
proxy.proxyRequest(req, res, {
host: '127.0.0.1',
port: 9000,
buffer: buffer
//
// Listen for the `error` event on `proxy`.
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong. And we are reporting a custom error message.');
});
server.proxy.on('end', function() {
console.log("The request was proxied.");
//
// Listen for the `proxyRes` event on `proxy`.
//
proxy.on('proxyRes', function (proxyRes, req, res) {
console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2));
});
server.listen(8000);
```
It's important to remember not to listen for events on the proxy object in the function passed to `httpProxy.createServer`. Doing so would add a new listener on every request, which would end up being a disaster.
## Using HTTPS
You have all the full flexibility of node-http-proxy offers in HTTPS as well as HTTP. The two basic scenarios are: with a stand-alone proxy server or in conjunction with another HTTPS server.
### Proxying to HTTP from HTTPS
This is probably the most common use-case for proxying in conjunction with HTTPS. You have some front-facing HTTPS server, but all of your internal traffic is HTTP. In this way, you can reduce the number of servers to which your CA and other important security files are deployed and reduce the computational overhead from HTTPS traffic.
Using HTTPS in `node-http-proxy` is relatively straight-forward:
``` js
var fs = require('fs'),
http = require('http'),
https = require('https'),
httpProxy = require('http-proxy');
var options = {
https: {
key: fs.readFileSync('path/to/your/key.pem', 'utf8'),
cert: fs.readFileSync('path/to/your/cert.pem', 'utf8')
}
};
//
// Create a standalone HTTPS proxy server
// Listen for the `open` event on `proxy`.
//
httpProxy.createServer(8000, 'localhost', options).listen(8001);
//
// Create an instance of HttpProxy to use with another HTTPS server
//
var proxy = new httpProxy.HttpProxy({
target: {
host: 'localhost',
port: 8000
}
});
https.createServer(options.https, function (req, res) {
proxy.proxyRequest(req, res)
}).listen(8002);
//
// Create the target HTTPS server for both cases
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('hello https\n');
res.end();
}).listen(8000);
```
### Using two certificates
Suppose that your reverse proxy will handle HTTPS traffic for two different domains `fobar.com` and `barbaz.com`.
If you need to use two different certificates you can take advantage of [Server Name Indication](http://en.wikipedia.org/wiki/Server_Name_Indication).
``` js
var https = require('https'),
path = require("path"),
fs = require("fs"),
crypto = require("crypto");
//
// generic function to load the credentials context from disk
//
function getCredentialsContext (cer) {
return crypto.createCredentials({
key: fs.readFileSync(path.join(__dirname, 'certs', cer + '.key')),
cert: fs.readFileSync(path.join(__dirname, 'certs', cer + '.crt'))
}).context;
}
//
// A certificate per domain hash
//
var certs = {
"fobar.com": getCredentialsContext("foobar"),
"barbaz.com": getCredentialsContext("barbaz")
};
//
// Proxy options
//
var options = {
https: {
SNICallback: function(hostname){
return certs[hostname];
}
},
hostnameOnly: true,
router: {
'fobar.com': '127.0.0.1:8001',
'barbaz.com': '127.0.0.1:8002'
}
};
//
// Create a standalone HTTPS proxy server
//
httpProxy.createServer(options).listen(8001);
//
// Create the target HTTPS server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('hello https\n');
res.end();
}).listen(8000);
```
### Proxying to HTTPS from HTTPS
Proxying from HTTPS to HTTPS is essentially the same as proxying from HTTPS to HTTP, but you must include the `target` option in when calling `httpProxy.createServer` or instantiating a new instance of `HttpProxy`.
``` js
var fs = require('fs'),
https = require('https'),
httpProxy = require('http-proxy');
var options = {
https: {
key: fs.readFileSync('path/to/your/key.pem', 'utf8'),
cert: fs.readFileSync('path/to/your/cert.pem', 'utf8')
},
target: {
https: true // This could also be an Object with key and cert properties
}
};
//
// Create a standalone HTTPS proxy server
//
httpProxy.createServer(8000, 'localhost', options).listen(8001);
//
// Create an instance of HttpProxy to use with another HTTPS server
//
var proxy = new httpProxy.HttpProxy({
target: {
host: 'localhost',
port: 8000,
https: true
}
proxy.on('open', function (proxySocket) {
// listen for messages coming FROM the target here
proxySocket.on('data', hybiParseAndLogMessage);
});
https.createServer(options.https, function (req, res) {
proxy.proxyRequest(req, res);
}).listen(8002);
//
// Create the target HTTPS server for both cases
// Listen for the `close` event on `proxy`.
//
https.createServer(options.https, function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('hello https\n');
res.end();
}).listen(8000);
```
## Middleware
`node-http-proxy` now supports connect middleware. Add middleware functions to your createServer call:
``` js
httpProxy.createServer(
require('connect-gzip').gzip(),
9000, 'localhost'
).listen(8000);
proxy.on('close', function (res, socket, head) {
// view disconnected websocket connections
console.log('Client disconnected');
});
```
## Proxying WebSockets
Websockets are handled automatically when using `httpProxy.createServer()`, but if you want to use it in conjunction with a stand-alone HTTP + WebSocket (such as [socket.io][5]) server here's how:
**[Back to top](#table-of-contents)**
``` js
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create an instance of node-http-proxy
//
var proxy = new httpProxy.HttpProxy({
### Shutdown
* When testing or running server within another program it may be necessary to close the proxy.
* This will stop the proxy from accepting new connections.
```js
var proxy = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 8000
port: 1337
}
});
var server = http.createServer(function (req, res) {
//
// Proxy normal HTTP requests
//
proxy.proxyRequest(req, res);
});
server.on('upgrade', function(req, socket, head) {
//
// Proxy websocket requests too
//
proxy.proxyWebSocketRequest(req, socket, head);
});
server.listen(8080);
proxy.close();
```
### Configuring your Socket limits
**[Back to top](#table-of-contents)**
By default, `node-http-proxy` will set a 100 socket limit for all `host:port` proxy targets. You can change this in two ways:
### Miscellaneous
1. By passing the `maxSockets` option to `httpProxy.createServer()`
2. By calling `httpProxy.setMaxSockets(n)`, where `n` is the number of sockets you with to use.
If you want to handle your own response after receiving the `proxyRes`, you can do
so with `selfHandleResponse`. As you can see below, if you use this option, you
are able to intercept and read the `proxyRes` but you must also make sure to
reply to the `res` itself otherwise the original client will never receive any
data.
## POST requests and buffering
### Modify response
express.bodyParser will interfere with proxying of POST requests (and other methods that have a request
body). With bodyParser active, proxied requests will never send anything to the upstream server, and
the original client will just hang. See https://github.com/nodejitsu/node-http-proxy/issues/180 for options.
```js
## Using node-http-proxy from the command line
When you install this package with npm, a node-http-proxy binary will become available to you. Using this binary is easy with some simple options:
var option = {
target: target,
selfHandleResponse : true
};
proxy.on('proxyRes', function (proxyRes, req, res) {
var body = [];
proxyRes.on('data', function (chunk) {
body.push(chunk);
});
proxyRes.on('end', function () {
body = Buffer.concat(body).toString();
console.log("res from proxied server:", body);
res.end("my response to cli");
});
});
proxy.web(req, res, option);
``` js
usage: node-http-proxy [options]
All options should be set with the syntax --option=value
options:
--port PORT Port that the proxy server should run on
--target HOST:PORT Location of the server the proxy will target
--config OUTFILE Location of the configuration file for the proxy server
--silent Silence the log output from the proxy server
-h, --help You're staring at it
```
<br/>
## Why doesn't node-http-proxy have more advanced features like x, y, or z?
If you have a suggestion for a feature currently not supported, feel free to open a [support issue][6]. node-http-proxy is designed to just proxy http requests from one server to another, but we will be soon releasing many other complimentary projects that can be used in conjunction with node-http-proxy.
## Run Tests
The test suite is designed to fully cover the combinatoric possibilities of HTTP and HTTPS proxying:
1. HTTP --> HTTP
2. HTTPS --> HTTP
3. HTTPS --> HTTPS
4. HTTP --> HTTPS
```
vows test/*-test.js --spec
vows test/*-test.js --spec --https
vows test/*-test.js --spec --https --target=https
vows test/*-test.js --spec --target=https
#### ProxyTable API
A proxy table API is available through this add-on [module](https://github.com/donasaur/http-proxy-rules), which lets you define a set of rules to translate matching routes to target routes that the reverse proxy will talk to.
#### Test
```
$ npm test
```
<br/>
#### Logo
Logo created by [Diego Pasquali](http://dribbble.com/diegopq)
**[Back to top](#table-of-contents)**
### Contributing and Issues
* Read carefully our [Code Of Conduct](https://github.com/http-party/node-http-proxy/blob/master/CODE_OF_CONDUCT.md)
* Search on Google/Github
* If you can't find anything, open an issue
* If you feel comfortable about fixing the issue, fork the repo
* Commit to your local branch (which must be different from `master`)
* Submit your Pull Request (be sure to include tests and update documentation)
**[Back to top](#table-of-contents)**
### License
(The MIT License)
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[0]: http://nodejitsu.com
[1]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/websocket/websocket-proxy.js
[2]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/http/proxy-https-to-http.js
[3]: https://github.com/nodejitsu/node-http-proxy/tree/master/examples
[4]: http://www.ietf.org/rfc/rfc2616.txt
[5]: http://socket.io
[6]: http://github.com/nodejitsu/node-http-proxy/issues
>The MIT License (MIT)
>
>Copyright (c) 2010 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
>
>Permission is hereby granted, free of charge, to any person obtaining a copy
>of this software and associated documentation files (the "Software"), to deal
>in the Software without restriction, including without limitation the rights
>to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>copies of the Software, and to permit persons to whom the Software is
>furnished to do so, subject to the following conditions:
>
>The above copyright notice and this permission notice shall be included in
>all copies or substantial portions of the Software.
>
>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
>AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>THE SOFTWARE.

97
UPGRADING.md Normal file
View File

@ -0,0 +1,97 @@
Looking to upgrade from `http-proxy@0.x.x` to `http-proxy@1.0`? You've come to the right place!
`http-proxy@1.0` is a from-scratch implementation of `http-proxy` and, as such
brings some breaking changes to APIs.
## Server creation
Available through `.createServer()` or `.createProxyServer()`.
```javascript
httpProxy.createServer({
target:'http://localhost:9003'
}).listen(8003);
```
Check the [README.md](https://github.com/http-party/node-http-proxy/blob/caronte/README.md) for a more detailed explanation of the parameters.
## Proxying
Web proxying is done by calling the `.web()` method on a Proxy instance. You can check among some use cases in the [examples folder](https://github.com/http-party/node-http-proxy/tree/caronte/examples/http)
```javascript
//
// Create a HTTP Proxy server with a HTTPS target
//
httpProxy.createProxyServer({
target: 'https://google.com',
agent : https.globalAgent,
headers: {
host: 'google.com'
}
}).listen(8011);
```
Websockets are proxied by the `.ws()` method. The [examples folder](https://github.com/http-party/node-http-proxy/tree/caronte/examples/websocket) again provides a lot of useful snippets!
```javascript
var proxy = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 9015
}
});
var proxyServer = http.createServer(function (req, res) {
proxy.web(req, res);
});
//
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
```
## Error Handling
It is possible to listen globally on the `error` event on the server. In alternative, a
callback passed to `.web()` or `.ws()` as last parameter is also accepted.
```javascript
var proxy = httpProxy.createServer({
target:'http://localhost:9005'
});
//
// Tell the proxy to listen on port 8000
//
proxy.listen(8005);
//
// Listen for the `error` event on `proxy`.
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong. And we are reporting a custom error message.');
});
```
## Dropped
Since the API was rewritten to be extremely flexible we decided to drop some features
which were in the core and delegate them to eventual "userland" modules.
- Middleware API
- ProxyTable API
### Middleware API
The new API makes it really easy to implement code that behaves like the old Middleware API. You can check some examples [here](https://github.com/http-party/node-http-proxy/tree/caronte/examples/middleware)
### ProxyTable API
See this [link](https://github.com/donasaur/http-proxy-rules/) for an add-on proxy rules module that you can use to simulate the old ProxyTable API.

37
benchmark/README.md Normal file
View File

@ -0,0 +1,37 @@
# Benchmarking `node-http-proxy`
The long-term goal of these scripts and documentation is to provide a consistent and well understood benchmarking process for `node-http-proxy` so that performance does not degrade over time. They were initially created to compare the performance of `v0.10.3` and `v1.0.0` (which was a significant rewrite).
## Pre-requisites
All benchmarking shall be done with [wrk](https://github.com/wg/wrk) which _is the same tool used for performance testing by the node.js core team._ **Make sure you have `wrk` installed before continuing**.
```
$ wrk
Usage: wrk <options> <url>
Options:
-c, --connections <N> Connections to keep open
-d, --duration <T> Duration of test
-t, --threads <N> Number of threads to use
-s, --script <S> Load Lua script file
-H, --header <H> Add header to request
--latency Print latency statistics
--timeout <T> Socket/request timeout
-v, --version Print version details
Numeric arguments may include a SI unit (1k, 1M, 1G)
Time arguments may include a time unit (2s, 2m, 2h)
```
## Benchmarks
1. [Simple HTTP benchmark](#simple-http)
### Simple HTTP
_This benchmark requires three terminals running:_
1. **A proxy server:** `node benchmark/scripts/proxy.js`
2. **A target server:** `node benchmark/scripts/hello.js`
3. **A wrk process:** `wrk -c 20 -d5m -t 2 http://127.0.0.1:8000`

View File

@ -0,0 +1,3 @@
require('http').createServer(function(req, res) {
res.end('Hello world!');
}).listen(9000);

View File

@ -0,0 +1,6 @@
var http = require('http'),
httpProxy = require('../../');
//
// Create your proxy server
//
httpProxy.createProxyServer({ target: 'http://localhost:9000' }).listen(8000);

View File

@ -0,0 +1,88 @@
var crypto = require('crypto'),
WebSocket = require('ws'),
async = require('async'),
httpProxy = require('../../');
var SERVER_PORT = 8415,
PROXY_PORT = 8514;
var testSets = [
{
size: 1024 * 1024, // 1 MB
count: 128 // 128 MB
},
{
size: 1024, // 1 KB,
count: 1024 // 1 MB
},
{
size: 128, // 128 B
count: 1024 * 8 // 1 MB
}
];
testSets.forEach(function (set) {
set.buffer = new Buffer(crypto.randomBytes(set.size));
set.buffers = [];
for (var i = 0; i < set.count; i++) {
set.buffers.push(set.buffer);
}
});
function runSet(set, callback) {
function runAgainst(port, callback) {
function send(sock) {
sock.send(set.buffers[got++]);
if (got === set.count) {
t = new Date() - t;
server.close();
proxy.close();
callback(null, t);
}
}
var server = new WebSocket.Server({ port: SERVER_PORT }),
proxy = httpProxy.createServer(SERVER_PORT, 'localhost').listen(PROXY_PORT),
client = new WebSocket('ws://localhost:' + port),
got = 0,
t = new Date();
server.on('connection', function (ws) {
send(ws);
ws.on('message', function (msg) {
send(ws);
});
});
client.on('message', function () {
send(client);
});
}
async.series({
server: async.apply(runAgainst, SERVER_PORT),
proxy: async.apply(runAgainst, PROXY_PORT)
}, function (err, results) {
if (err) {
throw err;
}
var mb = (set.size * set.count) / (1024 * 1024);
console.log(set.size / (1024) + ' KB * ' + set.count + ' (' + mb + ' MB)');
Object.keys(results).forEach(function (key) {
var t = results[key],
throughput = mb / (t / 1000);
console.log(' ' + key + ' took ' + t + ' ms (' + throughput + ' MB/s)');
});
callback();
});
}
async.forEachLimit(testSets, 1, runSet);

View File

@ -1,3 +0,0 @@
Benchmarks are being run on a development laptop using apache ab (everything running locally, on one machine)
These benchmarks should not be considered very accurate, or indicative of actual results. There are numerous factors that could cause these numbers to be inaccurate. These benchmarks should only be considered a very basic baseline to determine changes in performance as we iterate on this project.

View File

@ -1,56 +0,0 @@
$ ab -c 50 -n 1000 -k http://127.0.0.1:9000/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software:
Server Hostname: 127.0.0.1
Server Port: 9000
Document Path: /
Document Length: 149 bytes
Concurrency Level: 50
Time taken for tests: 0.178 seconds
Complete requests: 1000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 0
Total transferred: 213213 bytes
HTML transferred: 149149 bytes
Requests per second: 5627.84 [#/sec] (mean)
Time per request: 8.884 [ms] (mean)
Time per request: 0.178 [ms] (mean, across all concurrent requests)
Transfer rate: 1171.81 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 0.9 1 5
Processing: 3 8 2.6 7 17
Waiting: 1 7 2.4 7 17
Total: 5 9 2.4 8 17
Percentage of the requests served within a certain time (ms)
50% 8
66% 9
75% 9
80% 10
90% 13
95% 14
98% 15
99% 16
100% 17 (longest request)

View File

@ -1,56 +0,0 @@
$ ab -c 5 -n 1000 http://127.0.0.1:8000/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software:
Server Hostname: 127.0.0.1
Server Port: 8000
Document Path: /
Document Length: 160 bytes
Concurrency Level: 5
Time taken for tests: 0.450 seconds
Complete requests: 1000
Failed requests: 1
(Connect: 0, Receive: 0, Length: 1, Exceptions: 0)
Write errors: 0
Total transferred: 252006 bytes
HTML transferred: 160006 bytes
Requests per second: 2219.97 [#/sec] (mean)
Time per request: 2.252 [ms] (mean)
Time per request: 0.450 [ms] (mean, across all concurrent requests)
Transfer rate: 546.33 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 1 2 0.9 2 10
Waiting: 1 2 0.9 2 10
Total: 1 2 0.9 2 10
Percentage of the requests served within a certain time (ms)
50% 2
66% 2
75% 3
80% 3
90% 3
95% 3
98% 3
99% 7
100% 10 (longest request)

View File

@ -1,93 +0,0 @@
#!/usr/bin/env node
var path = require('path'),
fs = require('fs'),
util = require('util'),
argv = require('optimist').argv,
httpProxy = require('../lib/node-http-proxy');
var help = [
"usage: node-http-proxy [options] ",
"",
"Starts a node-http-proxy server using the specified command-line options",
"",
"options:",
" --port PORT Port that the proxy server should run on",
" --host HOST Host that the proxy server should run on",
" --target HOST:PORT Location of the server the proxy will target",
" --config OUTFILE Location of the configuration file for the proxy server",
" --silent Silence the log output from the proxy server",
" -h, --help You're staring at it"
].join('\n');
if (argv.h || argv.help || Object.keys(argv).length === 2) {
return util.puts(help);
}
var location, config = {},
port = argv.port || 80,
host = argv.host || undefined,
target = argv.target;
//
// If we were passed a config, parse it
//
if (argv.config) {
try {
var data = fs.readFileSync(argv.config);
config = JSON.parse(data.toString());
} catch (ex) {
util.puts('Error starting node-http-proxy: ' + ex);
process.exit(1);
}
}
//
// If `config.https` is set, then load those files into the config options.
//
if (config.https) {
Object.keys(config.https).forEach(function (key) {
config.https[key] = fs.readFileSync(config.https[key], 'utf8');
});
}
//
// Check to see if we should silence the logs
//
config.silent = typeof argv.silent !== 'undefined' ? argv.silent : config.silent;
//
// If we were passed a target, parse the url string
//
if (typeof target === 'string') location = target.split(':');
//
// Create the server with the specified options
//
var server;
if (location) {
var targetPort = location.length === 1 ? 80 : parseInt(location[1]);
server = httpProxy.createServer(targetPort, location[0], config);
}
else if (config.router) {
server = httpProxy.createServer(config);
}
else {
return util.puts(help);
}
//
// Start the server
//
if (host) {
server.listen(port, host);
} else {
server.listen(port);
}
//
// Notify that the server is started
//
if (!config.silent) {
util.puts('node-http-proxy server now listening on port: ' + port);
}

10
codecov.yml Normal file
View File

@ -0,0 +1,10 @@
coverage:
parsers:
javascript:
enable_partials: yes
status:
project:
default:
target: "70%"
patch:
enabled: false

View File

@ -1,10 +0,0 @@
{
"silent": false,
"router": {
"localhost": "localhost:9000"
},
"forward": {
"port": 9001,
"host": "localhost"
}
}

BIN
doc/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -0,0 +1,83 @@
/*
simple-balancer.js: Example of a simple round robin balancer for websockets
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// A simple round-robin load balancing strategy.
//
// First, list the servers you want to use in your rotation.
//
var addresses = [
{
host: 'ws1.0.0.0',
port: 80
},
{
host: 'ws2.0.0.0',
port: 80
}
];
//
// Create a HttpProxy object for each target
//
var proxies = addresses.map(function (target) {
return new httpProxy.createProxyServer({
target: target
});
});
//
// Get the proxy at the front of the array, put it at the end and return it
// If you want a fancier balancer, put your code here
//
function nextProxy() {
var proxy = proxies.shift();
proxies.push(proxy);
return proxy;
}
//
// Get the 'next' proxy and send the http request
//
var server = http.createServer(function (req, res) {
nextProxy().web(req, res);
});
//
// Get the 'next' proxy and send the upgrade request
//
server.on('upgrade', function (req, socket, head) {
nextProxy().ws(req, socket, head);
});
server.listen(8001);

View File

@ -1,7 +1,34 @@
var httpProxy = require('../../lib/node-http-proxy');
/*
simple-balancer.js: Example of a simple round robin balancer
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// A simple round-robin load balancing strategy.
//
//
// First, list the servers you want to use in your rotation.
//
var addresses = [
@ -14,23 +41,24 @@ var addresses = [
port: 80
}
];
var proxy = httpProxy.createServer();
httpProxy.createServer(function (req, res, proxy) {
http.createServer(function (req, res) {
//
// On each request, get the first location from the list...
//
var target = addresses.shift();
var target = { target: addresses.shift() };
//
// ...then proxy to the server whose 'turn' it is...
//
console.log('balancing request to: ', target);
proxy.proxyRequest(req, res, target);
proxy.web(req, res, target);
//
// ...and then the server you just used becomes the last item in the list.
//
addresses.push(target);
}).listen(8000);
addresses.push(target.target);
}).listen(8021);
// Rinse; repeat; enjoy.

View File

@ -2,7 +2,7 @@
//
// just to make these example a little bit interesting,
// make a little key value store with an http interface
// (see couchbd for a grown-up version of this)
// (see couchdb for a grown-up version of this)
//
// API:
// GET /
@ -39,10 +39,10 @@ Store.prototype = {
res.end()
}
var url = req.url.split('?').shift()
if(url === '/') {
if (url === '/') {
console.log('get index')
return send(Object.keys(store.store))
} else if(req.method == 'GET') {
} else if (req.method == 'GET') {
var obj = store.get (url)
send(obj || {error: 'not_found', url: url}, obj ? 200 : 404)
} else {

View File

@ -1,7 +1,7 @@
/*
basic-proxy.js: Basic example of proxying over HTTP
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,14 +27,14 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
var welcome = [
'# # ##### ##### ##### ##### ##### #### # # # #',
'# # # # # # # # # # # # # # # # ',
'###### # # # # ##### # # # # # # ## # ',
'# # # # ##### ##### ##### # # ## # ',
'# # # # # # # # # # # # # ',
'# # # # # # # # # # # # # # # # ',
'###### # # # # ##### # # # # # # ## # ',
'# # # # ##### ##### ##### # # ## # ',
'# # # # # # # # # # # # # ',
'# # # # # # # # #### # # # '
].join('\n');
@ -43,7 +43,9 @@ util.puts(welcome.rainbow.bold);
//
// Basic Http Proxy Server
//
httpProxy.createServer(9000, 'localhost').listen(8000);
httpProxy.createServer({
target:'http://localhost:9003'
}).listen(8003);
//
// Target Http Server
@ -52,7 +54,7 @@ http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
}).listen(9003);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8003'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9003 '.yellow);

View File

@ -1,7 +1,7 @@
/*
concurrent-proxy.js: check levelof concurrency through proxy.
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,12 +27,14 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
//
// Basic Http Proxy Server
//
httpProxy.createServer(9000, 'localhost').listen(8000);
httpProxy.createServer({
target:'http://localhost:9004'
}).listen(8004);
//
// Target Http Server
@ -42,7 +44,7 @@ httpProxy.createServer(9000, 'localhost').listen(8000);
//
var connections = [],
var connections = [],
go;
http.createServer(function (req, res) {
@ -51,16 +53,16 @@ http.createServer(function (req, res) {
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
});
process.stdout.write(connections.length + ', ');
if (connections.length > 110 || go) {
go = true;
while (connections.length) {
connections.shift()();
}
}
}).listen(9000);
}).listen(9004);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8004'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9004 '.yellow);

View File

@ -1,7 +1,7 @@
/*
custom-proxy-error.js: Example of using the custom `proxyError` event.
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,28 +27,29 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
//
// Http Proxy Server with Latency
// Http Proxy Server with bad target
//
var server = httpProxy.createServer(9000, 'localhost');
var proxy = httpProxy.createServer({
target:'http://localhost:9005'
});
//
// Tell the server to listen on port 8002
// Tell the proxy to listen on port 8000
//
server.listen(8002);
proxy.listen(8005);
//
// Listen for the `proxyError` event on `server.proxy`. _It will not
// be raised on the server itself._
server.proxy.on('proxyError', function (err, req, res) {
// Listen for the `error` event on `proxy`.
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong. And we are reporting a custom error message.');
});
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8002 '.yellow + 'with custom error message'.magenta.underline);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8005 '.yellow + 'with custom error message'.magenta.underline);

View File

@ -1,7 +1,7 @@
/*
url-middleware.js: Example of a simple url routing middleware for node-http-proxy
error-handling.js: Example of handle erros for HTTP and WebSockets
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,32 +27,37 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
//
// Now we set up our proxy.
// HTTP Proxy Server
//
httpProxy.createServer(
//
// This is where our middlewares go, with any options desired - in this case,
// the list of routes/URLs and their destinations.
//
require('proxy-by-url')({
'/hello': { port: 9000, host: 'localhost' },
'/charlie': { port: 80, host: 'charlieistheman.com' },
'/google': { port: 80, host: 'google.com' }
var proxy = httpProxy.createProxyServer({target:'http://localhost:9000', ws:true});
//
// Example of error handling
//
function requestHandler(req, res) {
// Pass a callback to the web proxy method
// and catch the error there.
proxy.web(req, res, function (err) {
// Now you can get the err
// and handle it by your self
// if (err) throw err;
res.writeHead(502);
res.end("There was an error proxying your request");
});
// In a websocket request case
req.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head, function (err) {
// Now you can get the err
// and handle it by your self
// if (err) throw err;
socket.close();
})
})
).listen(8000);
}
//
// Target Http Server (to listen for requests on 'localhost')
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
// And finally, some colored startup output.
http.createServer(requestHandler).listen(8000);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);

View File

@ -1,7 +1,7 @@
/*
proxy-table.js: Example of proxying over HTTP with proxy table
forward-and-target-proxy.js: Example of proxying over HTTP with additional forward proxy
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,16 +27,21 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
//
// Http Proxy Server with Proxy Table
// Setup proxy server with forwarding
//
httpProxy.createServer({
router: {
'localhost': 'localhost:9000'
target: {
port: 9006,
host: 'localhost'
},
forward: {
port: 9007,
host: 'localhost'
}
}).listen(8001);
}).listen(8006);
//
// Target Http Server
@ -45,7 +50,18 @@ http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
}).listen(9006);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8001 '.yellow + 'with proxy table'.magenta.underline);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
//
// Target Http Forwarding Server
//
http.createServer(function (req, res) {
util.puts('Receiving forward for: ' + req.url);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully forwarded to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9007);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8006 '.yellow + 'with forward proxy'.magenta.underline);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9006 '.yellow);
util.puts('http forward server '.blue + 'started '.green.bold + 'on port '.blue + '9007 '.yellow);

View File

@ -1,7 +1,7 @@
/*
forward-proxy.js: Example of proxying over HTTP with additional forward proxy
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,26 +27,17 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
//
// Setup proxy server with forwarding
//
httpProxy.createServer(9000, 'localhost', {
httpProxy.createServer({
forward: {
port: 9001,
port: 9019,
host: 'localhost'
}
}).listen(8003);
//
// Target Http Server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
}).listen(8019);
//
// Target Http Forwarding Server
@ -56,8 +47,7 @@ http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully forwarded to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9001);
}).listen(9019);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8003 '.yellow + 'with forward proxy'.magenta.underline);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
util.puts('http forward server '.blue + 'started '.green.bold + 'on port '.blue + '9001 '.yellow);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8019 '.yellow + 'with forward proxy'.magenta.underline);
util.puts('http forward server '.blue + 'started '.green.bold + 'on port '.blue + '9019 '.yellow);

View File

@ -1,7 +1,7 @@
/*
latent-proxy.js: Example of proxying over HTTP with latency
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,21 +27,19 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
//
// Http Proxy Server with Latency
//
httpProxy.createServer(function (req, res, proxy) {
var buffer = httpProxy.buffer(req);
setTimeout(function() {
proxy.proxyRequest(req, res, {
port: 9000,
host: 'localhost',
buffer: buffer
var proxy = httpProxy.createProxyServer();
http.createServer(function (req, res) {
setTimeout(function () {
proxy.web(req, res, {
target: 'http://localhost:9008'
});
}, 200);
}).listen(8002);
}, 500);
}).listen(8008);
//
// Target Http Server
@ -50,7 +48,7 @@ http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
}).listen(9008);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8002 '.yellow + 'with latency'.magenta.underline);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8008 '.yellow + 'with latency'.magenta.underline);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9008 '.yellow);

View File

@ -0,0 +1,26 @@
var httpProxy = require('../../lib/http-proxy');
var Agent = require('agentkeepalive');
var agent = new Agent({
maxSockets: 100,
keepAlive: true,
maxFreeSockets: 10,
keepAliveMsecs:1000,
timeout: 60000,
keepAliveTimeout: 30000 // free socket keepalive for 30 seconds
});
var proxy = httpProxy.createProxy({ target: 'http://whatever.com', agent: agent });
//
// Modify headers of the response before it gets sent
// So that we handle the NLTM authentication response
//
proxy.on('proxyRes', function (proxyRes) {
var key = 'www-authenticate';
proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
});
require('http').createServer(function (req, res) {
proxy.web(req, res);
}).listen(3000);

View File

@ -1,7 +1,7 @@
/*
node-http-proxy-test.js: http proxy for node.js
proxy-http-to-https.js: Basic example of proxying over HTTP to a target HTTPS server
Copyright (c) 2010 Charlie Robbins, Marak Squires and Fedor Indutny
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -23,35 +23,24 @@
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var assert = require('assert'),
fs = require('fs'),
path = require('path'),
async = require('async'),
request = require('request'),
vows = require('vows'),
macros = require('../macros'),
helpers = require('../helpers');
var routeFile = path.join(__dirname, 'config.json');
var https = require('https'),
http = require('http'),
util = require('util'),
path = require('path'),
fs = require('fs'),
colors = require('colors'),
httpProxy = require('../../lib/http-proxy');
vows.describe(helpers.describe()).addBatch({
"With a valid target server": {
"and no latency": {
"and no headers": macros.http.assertProxied(),
"and headers": macros.http.assertProxied({
request: { headers: { host: 'unknown.com' } }
}),
"and forwarding enabled": macros.http.assertForwardProxied()
},
"and latency": macros.http.assertProxied({
latency: 2000
})
},
"With a no valid target server": {
"and no latency": macros.http.assertInvalidProxy(),
"and latency": macros.http.assertInvalidProxy({
latency: 2000
})
//
// Create a HTTP Proxy server with a HTTPS target
//
httpProxy.createProxyServer({
target: 'https://google.com',
agent : https.globalAgent,
headers: {
host: 'google.com'
}
}).export(module);
}).listen(8011);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8011'.yellow);

View File

@ -1,7 +1,7 @@
/*
proxy-https-to-http.js: Basic example of proxying over HTTPS to a target HTTP server
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -25,29 +25,36 @@
*/
var https = require('https'),
http = require('http'),
util = require('util'),
http = require('http'),
util = require('util'),
path = require('path'),
fs = require('fs'),
colors = require('colors'),
httpProxy = require('../../lib/node-http-proxy'),
helpers = require('../../test/helpers');
var opts = helpers.loadHttps();
httpProxy = require('../../lib/http-proxy'),
fixturesDir = path.join(__dirname, '..', '..', 'test', 'fixtures');
//
// Create the target HTTPS server
// Create the target HTTP server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('hello http over https\n');
res.end();
}).listen(8000);
res.end();
}).listen(9009);
//
// Create the proxy server listening on port 443
// Create the HTTPS proxy server listening on port 8000
//
httpProxy.createServer(8000, 'localhost', {
https: opts
}).listen(8080);
httpProxy.createServer({
target: {
host: 'localhost',
port: 9009
},
ssl: {
key: fs.readFileSync(path.join(fixturesDir, 'agent2-key.pem'), 'utf8'),
cert: fs.readFileSync(path.join(fixturesDir, 'agent2-cert.pem'), 'utf8')
}
}).listen(8009);
util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8080'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow);
util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8009'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9009 '.yellow);

View File

@ -1,7 +1,7 @@
/*
proxy-https-to-https.js: Basic example of proxying over HTTPS to a target HTTPS server
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,30 +27,33 @@
var https = require('https'),
http = require('http'),
util = require('util'),
fs = require('fs'),
path = require('path'),
colors = require('colors'),
httpProxy = require('../../lib/node-http-proxy'),
helpers = require('../../test/helpers');
var opts = helpers.loadHttps();
httpProxy = require('../../lib/http-proxy'),
fixturesDir = path.join(__dirname, '..', '..', 'test', 'fixtures'),
httpsOpts = {
key: fs.readFileSync(path.join(fixturesDir, 'agent2-key.pem'), 'utf8'),
cert: fs.readFileSync(path.join(fixturesDir, 'agent2-cert.pem'), 'utf8')
};
//
// Create the target HTTPS server
// Create the target HTTPS server
//
https.createServer(opts, function (req, res) {
https.createServer(httpsOpts, function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('hello https\n');
res.end();
}).listen(8000);
res.end();
}).listen(9010);
//
// Create the proxy server listening on port 443
// Create the proxy server listening on port 8010
//
httpProxy.createServer(8000, 'localhost', {
https: opts,
target: {
https: true
}
}).listen(8080);
httpProxy.createServer({
ssl: httpsOpts,
target: 'https://localhost:9010',
secure: false
}).listen(8010);
util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8080'.yellow);
util.puts('https server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow);
util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8010'.yellow);
util.puts('https server '.blue + 'started '.green.bold + 'on port '.blue + '9010 '.yellow);

View File

@ -0,0 +1,55 @@
/*
reverse-proxy.js: Example of reverse proxying (with HTTPS support)
Copyright (c) 2015 Alberto Pose <albertopose@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var http = require('http'),
net = require('net'),
httpProxy = require('../../lib/http-proxy'),
url = require('url'),
util = require('util');
var proxy = httpProxy.createServer();
var server = http.createServer(function (req, res) {
util.puts('Receiving reverse proxy request for:' + req.url);
var parsedUrl = url.parse(req.url);
var target = parsedUrl.protocol + '//' + parsedUrl.hostname;
proxy.web(req, res, {target: target, secure: false});
}).listen(8213);
server.on('connect', function (req, socket) {
util.puts('Receiving reverse proxy request for:' + req.url);
var serverUrl = url.parse('https://' + req.url);
var srvSocket = net.connect(serverUrl.port, serverUrl.hostname, function() {
socket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node-Proxy\r\n' +
'\r\n');
srvSocket.pipe(socket);
socket.pipe(srvSocket);
});
});
// Test with:
// curl -vv -x http://127.0.0.1:8213 https://www.google.com
// curl -vv -x http://127.0.0.1:8213 http://www.google.com

View File

@ -1,7 +1,7 @@
/*
gzip-middleware-proxytable.js: Basic example of `connect-gzip` middleware in node-http-proxy
sse.js: Basic example of proxying over HTTP
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, Marak Squires, & Dominic Tarr.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,28 +27,41 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy'),
SSE = require('sse');
//
// Basic Http Proxy Server
//
httpProxy.createServer(
require('connect-gzip').gzip({ matchType: /.?/ }),
{
router: {
"localhost/fun": "localhost:9000"
}
}
).listen(8000);
var proxy = new httpProxy.createProxyServer();
http.createServer(function (req, res) {
proxy.web(req, res, {
target: 'http://localhost:9003'
});
}).listen(8003);
//
// Target Http Server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
var server = http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
});
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
//
// Use SSE
//
var sse = new SSE(server, {path: '/'});
sse.on('connection', function(client) {
var count = 0;
setInterval(function(){
client.send('message #' + count++);
}, 1500);
});
server.listen(9003);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8003'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9003 '.yellow);

View File

@ -1,7 +1,7 @@
/*
standalone-proxy.js: Example of proxying over HTTP with a standalone HTTP server.
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,22 +27,19 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
//
// Http Server with proxyRequest Handler and Latency
//
var proxy = new httpProxy.RoutingProxy();
var proxy = new httpProxy.createProxyServer();
http.createServer(function (req, res) {
var buffer = httpProxy.buffer(req);
setTimeout(function() {
proxy.proxyRequest(req, res, {
port: 9000,
host: 'localhost',
buffer: buffer
setTimeout(function () {
proxy.web(req, res, {
target: 'http://localhost:9002'
});
}, 200);
}).listen(8004);
}).listen(8002);
//
// Target Http Server
@ -51,7 +48,7 @@ http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
}).listen(9002);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8004 '.yellow + 'with proxyRequest handler'.cyan.underline + ' and latency'.magenta);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8002 '.yellow + 'with proxy.web() handler'.cyan.underline + ' and latency'.magenta);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9002 '.yellow);

View File

@ -1,87 +1,108 @@
/*
bodyDecoder-middleware.js: Basic example of `connect.bodyParser()` middleware in node-http-proxy
var Store = require('../helpers/store')
, http = require('http')
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var http = require('http'),
connect = require('connect'),
request = require('request'),
colors = require('colors'),
util = require('util'),
queryString = require('querystring'),
bodyParser = require('body-parser'),
httpProxy = require('../../lib/http-proxy'),
proxy = httpProxy.createProxyServer({});
//restream parsed body before proxying
proxy.on('proxyReq', function(proxyReq, req, res, options) {
if (!req.body || !Object.keys(req.body).length) {
return;
}
var contentType = proxyReq.getHeader('Content-Type');
var bodyData;
if (contentType === 'application/json') {
bodyData = JSON.stringify(req.body);
}
if (contentType === 'application/x-www-form-urlencoded') {
bodyData = queryString.stringify(req.body);
}
if (bodyData) {
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
proxyReq.write(bodyData);
}
});
http.createServer(new Store().handler()).listen(7531, function () {
//try these commands:
// get index:
// curl localhost:7531
// []
//
// get a doc:
// curl localhost:7531/foo
// {"error":"not_found"}
//
// post an doc:
// curl -X POST localhost:7531/foo -d '{"content": "hello", "type": "greeting"}'
// {"ok":true}
//
// get index (now, not empty)
// curl localhost:7531
// ["/foo"]
//
// get doc
// curl localhost:7531/foo
// {"content": "hello", "type": "greeting"}
//
// now, suppose we wanted to direct all objects where type == "greeting" to a different store
// than where type == "insult"
// Basic Http Proxy Server
//
// we can use connect connect-bodyDecoder and some custom logic to send insults to another Store.
//insult server:
http.createServer(new Store().handler()).listen(2600, function () {
//greetings -> 7531, insults-> 2600
// now, start a proxy server.
var bodyParser = require('connect/lib/middleware/bodyParser')
//don't worry about incoming contont type
//bodyParser.parse[''] = JSON.parse
require('../../lib/node-http-proxy').createServer(
//refactor the body parser and re-streamer into a separate package
bodyParser(),
//body parser absorbs the data and end events before passing control to the next
// middleware. if we want to proxy it, we'll need to re-emit these events after
//passing control to the middleware.
require('connect-restreamer')(),
function (req, res, proxy) {
//if your posting an obect which contains type: "insult"
//it will get redirected to port 2600.
//normal get requests will go to 7531 nad will not return insults.
var port = (req.body && req.body.type === 'insult' ? 2600 : 7531)
proxy.proxyRequest(req, res, {host: 'localhost', port: port})
}
).listen(1337, function () {
var request = require('request')
//bodyParser needs content-type set to application/json
//if we use request, it will set automatically if we use the 'json:' field.
function post (greeting, type) {
request.post({
url: 'http://localhost:1337/' + greeting,
json: {content: greeting, type: type || "greeting"}
})
}
post("hello")
post("g'day")
post("kiora")
post("houdy")
post("java", "insult")
//now, the insult should have been proxied to 2600
//curl localhost:2600
//["/java"]
//but the greetings will be sent to 7531
//curl localhost:7531
//["/hello","/g%27day","/kiora","/houdy"]
var app = connect()
.use(bodyParser.json())//json parser
.use(bodyParser.urlencoded())//urlencoded parser
.use(function(req, res){
// modify body here,
// eg: req.body = {a: 1}.
console.log('proxy body:',req.body)
proxy.web(req, res, {
target: 'http://127.0.0.1:9013'
})
});
http.createServer(app).listen(8013, function(){
console.log('proxy linsten 8013');
});
//
// Target Http Server
//
var app1 = connect()
.use(bodyParser.json())
.use(function(req, res){
console.log('app1:',req.body)
res.end('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
});
http.createServer(app1).listen(9013, function(){
//request to 8013 to proxy
request.post({//
url: 'http://127.0.0.1:8013',
json: {content: 123, type: "greeting from json request"}
},function(err, res,data){
console.log('return for json request:' ,err, data)
})
})
// application/x-www-form-urlencoded request
request.post({//
url: 'http://127.0.0.1:8013',
form: {content: 123, type: "greeting from urlencoded request"}
},function(err, res,data){
console.log('return for urlencoded request:' ,err, data)
})
});

View File

@ -1,7 +1,7 @@
/*
gzip-middleware.js: Basic example of `connect-gzip` middleware in node-http-proxy
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, Marak Squires, & Dominic Tarr.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,15 +27,30 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
connect = require('connect'),
httpProxy = require('../../lib/http-proxy');
//
// Basic Connect App
//
connect.createServer(
connect.compress({
// Pass to connect.compress() the options
// that you need, just for show the example
// we use threshold to 1
threshold: 1
}),
function (req, res) {
proxy.web(req, res);
}
).listen(8012);
//
// Basic Http Proxy Server
//
httpProxy.createServer(
require('connect-gzip').gzip({ matchType: /.?/ }),
9000, 'localhost'
).listen(8000);
var proxy = httpProxy.createProxyServer({
target: 'http://localhost:9012'
});
//
// Target Http Server
@ -44,7 +59,7 @@ http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
}).listen(9012);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8012'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9012 '.yellow);

View File

@ -1,30 +0,0 @@
var Store = require('../helpers/store')
, http = require('http')
//
// jsonp is a handy technique for getting around the limitations of the same-origin policy.
// (http://en.wikipedia.org/wiki/Same_origin_policy)
//
// normally, to dynamically update a page you use an XmlHttpRequest. this has flakey support
// is some browsers and is restricted by the same origin policy. you cannot perform XHR requests to
// someone else's server. one way around this would be to proxy requests to all the servers you want
// to xhr to, and your core server - so that everything has the same port and host.
//
// another way, is to turn json into javascript. (which is exempt from the same origin policy)
// this is done by wrapping the json object in a function call, and then including a script tag.
//
// here we're proxing our own JSON returning server, but we could proxy any server on the internet,
// and our client side app would be slurping down JSONP from anywhere.
//
// curl localhost:1337/whatever?callback=alert
// alert([]) //which is valid javascript!
//
// also see http://en.wikipedia.org/wiki/JSONP#JSONP
//
http.createServer(new Store().handler()).listen(7531)
require('../../lib/node-http-proxy').createServer(
require('connect-jsonp')(true),
'localhost', 7531
).listen(1337)

View File

@ -1,7 +1,7 @@
/*
modifyBody-middleware.js: Example of middleware which modifies response
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, Marak Squires, & Dominic Tarr.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,31 +27,43 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
connect = require('connect'),
app = connect(),
httpProxy = require('../../lib/http-proxy');
//
// Basic Connect App
//
app.use(function (req, res, next) {
var _write = res.write;
res.write = function (data) {
_write.call(res, data.toString().replace("Ruby", "http-party"));
}
next();
});
app.use(function (req, res) {
proxy.web(req, res)
});
http.createServer(app).listen(8013);
//
// Basic Http Proxy Server
//
httpProxy.createServer(
function (req, res, next) {
var _write = res.write;
res.write = function (data) {
_write.call(res, data.toString().replace("Ruby", "nodejitsu"));
}
next();
},
9000, 'localhost'
).listen(8000);
var proxy = httpProxy.createProxyServer({
target: 'http://localhost:9013'
});
//
// Target Http Server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, I know Ruby\n');
}).listen(9000);
res.end('Hello, I love Ruby\n');
}).listen(9013);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8013'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9013 '.yellow);

View File

@ -1,30 +0,0 @@
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy'),
Store = require('../helpers/store')
http.createServer(new Store().handler()).listen(7531)
// Now we set up our proxy.
httpProxy.createServer(
// This is where our middlewares go, with any options desired - in this case,
// the list of routes/URLs and their destinations.
require('proxy-by-url')({
'/store': { port: 7531, host: 'localhost' },
'/': { port: 9000, host: 'localhost' }
})
).listen(8000);
//
// Target Http Server (to listen for requests on 'localhost')
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
// And finally, some colored startup output.
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);

View File

@ -1,12 +1,14 @@
{
"name": "http-proxy-examples",
"description": "packages required to run the examples",
"name": "http-proxy-examples",
"description": "packages required to run the examples",
"version": "0.0.0",
"dependencies": {
"connect": "1.6",
"connect-gzip": "0.1",
"connect-jsonp": "0.0.5",
"connect-restreamer": "1",
"proxy-by-url": ">= 0.0.1"
"agentkeepalive": "^4.0.0",
"colors": "~1.3.0",
"connect-restreamer": "~1.0.0",
"request": "~2.88.0",
"socket.io": "~0.9.16",
"socket.io-client": "~0.9.16",
"sse": "0.0.8"
}
}
}

View File

@ -1,7 +1,7 @@
/*
standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server.
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,79 +27,65 @@
var util = require('util'),
http = require('http'),
colors = require('colors'),
websocket = require('../../vendor/websocket'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
try {
var utils = require('socket.io/lib/socket.io/utils'),
io = require('socket.io');
var io = require('socket.io'),
client = require('socket.io-client');
}
catch (ex) {
console.error('Socket.io is required for this example:');
console.error('npm ' + 'install'.green + ' socket.io@0.6.18'.magenta);
console.error('npm ' + 'install'.green);
process.exit(1);
}
//
// Create the target HTTP server
// Create the target HTTP server and setup
// socket.io on it.
//
var server = http.createServer(function (req, res) {
res.writeHead(200);
res.end();
});
server.listen(8080);
//
// Setup socket.io on the target HTTP server
//
var socket = io.listen(server);
socket.on('connection', function (client) {
var server = io.listen(9016);
server.sockets.on('connection', function (client) {
util.debug('Got websocket connection');
client.on('message', function (msg) {
util.debug('Got message from client: ' + msg);
});
socket.broadcast('from server');
client.send('from server');
});
//
// Setup our server to proxy standard HTTP requests
//
var proxy = new httpProxy.HttpProxy({
var proxy = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 8080
host: 'localhost',
port: 9016
}
});
var proxyServer = http.createServer(function (req, res) {
proxy.proxyRequest(req, res);
proxy.web(req, res);
});
//
// Listen to the `upgrade` event and proxy the
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
var buffer = httpProxy.buffer(socket);
setTimeout(function () {
proxy.proxyWebSocketRequest(req, socket, head, buffer);
proxy.ws(req, socket, head);
}, 1000);
});
proxyServer.listen(8081);
proxyServer.listen(8016);
//
// Setup the web socket against our proxy
// Setup the socket.io client against our proxy
//
var ws = new websocket.WebSocket('ws://localhost:8081/socket.io/websocket/', 'borf');
ws.on('open', function () {
ws.send(utils.encode('from client'));
});
var ws = client.connect('ws://localhost:8016');
ws.on('message', function (msg) {
util.debug('Got message: ' + utils.decode(msg));
util.debug('Got message: ' + msg);
ws.send('I am the client');
});

View File

@ -1,7 +1,7 @@
/*
standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server.
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,75 +27,62 @@
var util = require('util'),
http = require('http'),
colors = require('colors'),
websocket = require('../../vendor/websocket'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
try {
var utils = require('socket.io/lib/socket.io/utils'),
io = require('socket.io');
var io = require('socket.io'),
client = require('socket.io-client');
}
catch (ex) {
console.error('Socket.io is required for this example:');
console.error('npm ' + 'install'.green + ' socket.io@0.6.18'.magenta);
console.error('npm ' + 'install'.green);
process.exit(1);
}
//
// Create the target HTTP server
// Create the target HTTP server and setup
// socket.io on it.
//
var server = http.createServer(function (req, res) {
res.writeHead(200);
res.end();
});
server.listen(8080);
//
// Setup socket.io on the target HTTP server
//
var socket = io.listen(server);
socket.on('connection', function (client) {
var server = io.listen(9015);
server.sockets.on('connection', function (client) {
util.debug('Got websocket connection');
client.on('message', function (msg) {
util.debug('Got message from client: ' + msg);
});
socket.broadcast('from server');
client.send('from server');
});
//
// Setup our server to proxy standard HTTP requests
//
var proxy = new httpProxy.HttpProxy({
var proxy = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 8080
host: 'localhost',
port: 9015
}
});
var proxyServer = http.createServer(function (req, res) {
proxy.proxyRequest(req, res);
proxy.web(req, res);
});
//
// Listen to the `upgrade` event and proxy the
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
proxy.proxyWebSocketRequest(req, socket, head);
proxy.ws(req, socket, head);
});
proxyServer.listen(8081);
proxyServer.listen(8015);
//
// Setup the web socket against our proxy
// Setup the socket.io client against our proxy
//
var ws = new websocket.WebSocket('ws://localhost:8081/socket.io/websocket/', 'borf');
ws.on('open', function () {
ws.send(utils.encode('from client'));
});
var ws = client.connect('ws://localhost:8015');
ws.on('message', function (msg) {
util.debug('Got message: ' + utils.decode(msg));
util.debug('Got message: ' + msg);
ws.send('I am the client');
});

View File

@ -1,7 +1,7 @@
/*
web-socket-proxy.js: Example of proxying over HTTP and WebSockets.
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires.
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,58 +27,44 @@
var util = require('util'),
http = require('http'),
colors = require('colors'),
websocket = require('../../vendor/websocket'),
httpProxy = require('../../lib/node-http-proxy');
httpProxy = require('../../lib/http-proxy');
try {
var utils = require('socket.io/lib/socket.io/utils'),
io = require('socket.io');
var io = require('socket.io'),
client = require('socket.io-client');
}
catch (ex) {
console.error('Socket.io is required for this example:');
console.error('npm ' + 'install'.green + ' socket.io@0.6.18'.magenta);
console.error('npm ' + 'install'.green);
process.exit(1);
}
//
// Create the target HTTP server
// Create the target HTTP server and setup
// socket.io on it.
//
var server = http.createServer(function (req, res) {
res.writeHead(200);
res.end();
});
server.listen(8080);
//
// Setup socket.io on the target HTTP server
//
var socket = io.listen(server);
socket.on('connection', function (client) {
var server = io.listen(9014);
server.sockets.on('connection', function (client) {
util.debug('Got websocket connection');
client.on('message', function (msg) {
util.debug('Got message from client: ' + msg);
});
socket.broadcast('from server');
client.send('from server');
});
//
// Create a proxy server with node-http-proxy
//
var proxy = httpProxy.createServer(8080, 'localhost');
proxy.listen(8081);
httpProxy.createServer({ target: 'ws://localhost:9014', ws: true }).listen(8014);
//
// Setup the web socket against our proxy
// Setup the socket.io client against our proxy
//
var ws = new websocket.WebSocket('ws://localhost:8081/socket.io/websocket/', 'borf');
ws.on('open', function () {
ws.send(utils.encode('from client'));
});
var ws = client.connect('ws://localhost:8014');
ws.on('message', function (msg) {
util.debug('Got message: ' + utils.decode(msg));
util.debug('Got message: ' + msg);
ws.send('I am the client');
});

13
index.js Normal file
View File

@ -0,0 +1,13 @@
/*!
* Caron dimonio, con occhi di bragia
* loro accennando, tutte le raccoglie;
* batte col remo qualunque sadagia
*
* Charon the demon, with the eyes of glede,
* Beckoning to them, collects them all together,
* Beats with his oar whoever lags behind
*
* Dante - The Divine Comedy (Canto III)
*/
module.exports = require('./lib/http-proxy');

66
lib/http-proxy.js Normal file
View File

@ -0,0 +1,66 @@
// Use explicit /index.js to help browserify negociation in require '/lib/http-proxy' (!)
var ProxyServer = require('./http-proxy/index.js').Server;
/**
* Creates the proxy server.
*
* Examples:
*
* httpProxy.createProxyServer({ .. }, 8000)
* // => '{ web: [Function], ws: [Function] ... }'
*
* @param {Object} Options Config object passed to the proxy
*
* @return {Object} Proxy Proxy object with handlers for `ws` and `web` requests
*
* @api public
*/
function createProxyServer(options) {
/*
* `options` is needed and it must have the following layout:
*
* {
* target : <url string to be parsed with the url module>
* forward: <url string to be parsed with the url module>
* agent : <object to be passed to http(s).request>
* ssl : <object to be passed to https.createServer()>
* ws : <true/false, if you want to proxy websockets>
* xfwd : <true/false, adds x-forward headers>
* secure : <true/false, verify SSL certificate>
* toProxy: <true/false, explicitly specify if we are proxying to another proxy>
* prependPath: <true/false, Default: true - specify whether you want to prepend the target's path to the proxy path>
* ignorePath: <true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request>
* localAddress : <Local interface string to bind for outgoing connections>
* changeOrigin: <true/false, Default: false - changes the origin of the host header to the target URL>
* preserveHeaderKeyCase: <true/false, Default: false - specify whether you want to keep letter case of response header key >
* auth : Basic authentication i.e. 'user:password' to compute an Authorization header.
* hostRewrite: rewrites the location hostname on (201/301/302/307/308) redirects, Default: null.
* autoRewrite: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false.
* protocolRewrite: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null.
* }
*
* NOTE: `options.ws` and `options.ssl` are optional.
* `options.target and `options.forward` cannot be
* both missing
* }
*/
return new ProxyServer(options);
}
ProxyServer.createProxyServer = createProxyServer;
ProxyServer.createServer = createProxyServer;
ProxyServer.createProxy = createProxyServer;
/**
* Export the proxy "Server" as the main export.
*/
module.exports = ProxyServer;

248
lib/http-proxy/common.js Normal file
View File

@ -0,0 +1,248 @@
var common = exports,
url = require('url'),
extend = require('util')._extend,
required = require('requires-port');
var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i,
isSSL = /^https|wss/;
/**
* Simple Regex for testing if protocol is https
*/
common.isSSL = isSSL;
/**
* Copies the right headers from `options` and `req` to
* `outgoing` which is then used to fire the proxied
* request.
*
* Examples:
*
* common.setupOutgoing(outgoing, options, req)
* // => { host: ..., hostname: ...}
*
* @param {Object} Outgoing Base object to be filled with required properties
* @param {Object} Options Config object passed to the proxy
* @param {ClientRequest} Req Request Object
* @param {String} Forward String to select forward or target
* 
* @return {Object} Outgoing Object with all required properties set
*
* @api private
*/
common.setupOutgoing = function(outgoing, options, req, forward) {
outgoing.port = options[forward || 'target'].port ||
(isSSL.test(options[forward || 'target'].protocol) ? 443 : 80);
['host', 'hostname', 'socketPath', 'pfx', 'key',
'passphrase', 'cert', 'ca', 'ciphers', 'secureProtocol'].forEach(
function(e) { outgoing[e] = options[forward || 'target'][e]; }
);
outgoing.method = options.method || req.method;
outgoing.headers = extend({}, req.headers);
if (options.headers){
extend(outgoing.headers, options.headers);
}
if (options.auth) {
outgoing.auth = options.auth;
}
if (options.ca) {
outgoing.ca = options.ca;
}
if (isSSL.test(options[forward || 'target'].protocol)) {
outgoing.rejectUnauthorized = (typeof options.secure === "undefined") ? true : options.secure;
}
outgoing.agent = options.agent || false;
outgoing.localAddress = options.localAddress;
//
// Remark: If we are false and not upgrading, set the connection: close. This is the right thing to do
// as node core doesn't handle this COMPLETELY properly yet.
//
if (!outgoing.agent) {
outgoing.headers = outgoing.headers || {};
if (typeof outgoing.headers.connection !== 'string'
|| !upgradeHeader.test(outgoing.headers.connection)
) { outgoing.headers.connection = 'close'; }
}
// the final path is target path + relative path requested by user:
var target = options[forward || 'target'];
var targetPath = target && options.prependPath !== false
? (target.path || '')
: '';
//
// Remark: Can we somehow not use url.parse as a perf optimization?
//
var outgoingPath = !options.toProxy
? (url.parse(req.url).path || '')
: req.url;
//
// Remark: ignorePath will just straight up ignore whatever the request's
// path is. This can be labeled as FOOT-GUN material if you do not know what
// you are doing and are using conflicting options.
//
outgoingPath = !options.ignorePath ? outgoingPath : '';
outgoing.path = common.urlJoin(targetPath, outgoingPath);
if (options.changeOrigin) {
outgoing.headers.host =
required(outgoing.port, options[forward || 'target'].protocol) && !hasPort(outgoing.host)
? outgoing.host + ':' + outgoing.port
: outgoing.host;
}
return outgoing;
};
/**
* Set the proper configuration for sockets,
* set no delay and set keep alive, also set
* the timeout to 0.
*
* Examples:
*
* common.setupSocket(socket)
* // => Socket
*
* @param {Socket} Socket instance to setup
* 
* @return {Socket} Return the configured socket.
*
* @api private
*/
common.setupSocket = function(socket) {
socket.setTimeout(0);
socket.setNoDelay(true);
socket.setKeepAlive(true, 0);
return socket;
};
/**
* Get the port number from the host. Or guess it based on the connection type.
*
* @param {Request} req Incoming HTTP request.
*
* @return {String} The port number.
*
* @api private
*/
common.getPort = function(req) {
var res = req.headers.host ? req.headers.host.match(/:(\d+)/) : '';
return res ?
res[1] :
common.hasEncryptedConnection(req) ? '443' : '80';
};
/**
* Check if the request has an encrypted connection.
*
* @param {Request} req Incoming HTTP request.
*
* @return {Boolean} Whether the connection is encrypted or not.
*
* @api private
*/
common.hasEncryptedConnection = function(req) {
return Boolean(req.connection.encrypted || req.connection.pair);
};
/**
* OS-agnostic join (doesn't break on URLs like path.join does on Windows)>
*
* @return {String} The generated path.
*
* @api private
*/
common.urlJoin = function() {
//
// We do not want to mess with the query string. All we want to touch is the path.
//
var args = Array.prototype.slice.call(arguments),
lastIndex = args.length - 1,
last = args[lastIndex],
lastSegs = last.split('?'),
retSegs;
args[lastIndex] = lastSegs.shift();
//
// Join all strings, but remove empty strings so we don't get extra slashes from
// joining e.g. ['', 'am']
//
retSegs = [
args.filter(Boolean).join('/')
.replace(/\/+/g, '/')
.replace('http:/', 'http://')
.replace('https:/', 'https://')
];
// Only join the query string if it exists so we don't have trailing a '?'
// on every request
// Handle case where there could be multiple ? in the URL.
retSegs.push.apply(retSegs, lastSegs);
return retSegs.join('?')
};
/**
* Rewrites or removes the domain of a cookie header
*
* @param {String|Array} Header
* @param {Object} Config, mapping of domain to rewritten domain.
* '*' key to match any domain, null value to remove the domain.
*
* @api private
*/
common.rewriteCookieProperty = function rewriteCookieProperty(header, config, property) {
if (Array.isArray(header)) {
return header.map(function (headerElement) {
return rewriteCookieProperty(headerElement, config, property);
});
}
return header.replace(new RegExp("(;\\s*" + property + "=)([^;]+)", 'i'), function(match, prefix, previousValue) {
var newValue;
if (previousValue in config) {
newValue = config[previousValue];
} else if ('*' in config) {
newValue = config['*'];
} else {
//no match, return previous value
return match;
}
if (newValue) {
//replace value
return prefix + newValue;
} else {
//remove value
return '';
}
});
};
/**
* Check the host and see if it potentially has a port in it (keep it simple)
*
* @returns {Boolean} Whether we have one or not
*
* @api private
*/
function hasPort(host) {
return !!~host.indexOf(':');
};

185
lib/http-proxy/index.js Normal file
View File

@ -0,0 +1,185 @@
var httpProxy = module.exports,
extend = require('util')._extend,
parse_url = require('url').parse,
EE3 = require('eventemitter3'),
http = require('http'),
https = require('https'),
web = require('./passes/web-incoming'),
ws = require('./passes/ws-incoming');
httpProxy.Server = ProxyServer;
/**
* Returns a function that creates the loader for
* either `ws` or `web`'s passes.
*
* Examples:
*
* httpProxy.createRightProxy('ws')
* // => [Function]
*
* @param {String} Type Either 'ws' or 'web'
* 
* @return {Function} Loader Function that when called returns an iterator for the right passes
*
* @api private
*/
function createRightProxy(type) {
return function(options) {
return function(req, res /*, [head], [opts] */) {
var passes = (type === 'ws') ? this.wsPasses : this.webPasses,
args = [].slice.call(arguments),
cntr = args.length - 1,
head, cbl;
/* optional args parse begin */
if(typeof args[cntr] === 'function') {
cbl = args[cntr];
cntr--;
}
var requestOptions = options;
if(
!(args[cntr] instanceof Buffer) &&
args[cntr] !== res
) {
//Copy global options
requestOptions = extend({}, options);
//Overwrite with request options
extend(requestOptions, args[cntr]);
cntr--;
}
if(args[cntr] instanceof Buffer) {
head = args[cntr];
}
/* optional args parse end */
['target', 'forward'].forEach(function(e) {
if (typeof requestOptions[e] === 'string')
requestOptions[e] = parse_url(requestOptions[e]);
});
if (!requestOptions.target && !requestOptions.forward) {
return this.emit('error', new Error('Must provide a proper URL as target'));
}
for(var i=0; i < passes.length; i++) {
/**
* Call of passes functions
* pass(req, res, options, head)
*
* In WebSockets case the `res` variable
* refer to the connection socket
* pass(req, socket, options, head)
*/
if(passes[i](req, res, requestOptions, head, this, cbl)) { // passes can return a truthy value to halt the loop
break;
}
}
};
};
}
httpProxy.createRightProxy = createRightProxy;
function ProxyServer(options) {
EE3.call(this);
options = options || {};
options.prependPath = options.prependPath === false ? false : true;
this.web = this.proxyRequest = createRightProxy('web')(options);
this.ws = this.proxyWebsocketRequest = createRightProxy('ws')(options);
this.options = options;
this.webPasses = Object.keys(web).map(function(pass) {
return web[pass];
});
this.wsPasses = Object.keys(ws).map(function(pass) {
return ws[pass];
});
this.on('error', this.onError, this);
}
require('util').inherits(ProxyServer, EE3);
ProxyServer.prototype.onError = function (err) {
//
// Remark: Replicate node core behavior using EE3
// so we force people to handle their own errors
//
if(this.listeners('error').length === 1) {
throw err;
}
};
ProxyServer.prototype.listen = function(port, hostname) {
var self = this,
closure = function(req, res) { self.web(req, res); };
this._server = this.options.ssl ?
https.createServer(this.options.ssl, closure) :
http.createServer(closure);
if(this.options.ws) {
this._server.on('upgrade', function(req, socket, head) { self.ws(req, socket, head); });
}
this._server.listen(port, hostname);
return this;
};
ProxyServer.prototype.close = function(callback) {
var self = this;
if (this._server) {
this._server.close(done);
}
// Wrap callback to nullify server after all open connections are closed.
function done() {
self._server = null;
if (callback) {
callback.apply(null, arguments);
}
};
};
ProxyServer.prototype.before = function(type, passName, callback) {
if (type !== 'ws' && type !== 'web') {
throw new Error('type must be `web` or `ws`');
}
var passes = (type === 'ws') ? this.wsPasses : this.webPasses,
i = false;
passes.forEach(function(v, idx) {
if(v.name === passName) i = idx;
})
if(i === false) throw new Error('No such pass');
passes.splice(i, 0, callback);
};
ProxyServer.prototype.after = function(type, passName, callback) {
if (type !== 'ws' && type !== 'web') {
throw new Error('type must be `web` or `ws`');
}
var passes = (type === 'ws') ? this.wsPasses : this.webPasses,
i = false;
passes.forEach(function(v, idx) {
if(v.name === passName) i = idx;
})
if(i === false) throw new Error('No such pass');
passes.splice(i++, 0, callback);
};

View File

@ -0,0 +1,194 @@
var httpNative = require('http'),
httpsNative = require('https'),
web_o = require('./web-outgoing'),
common = require('../common'),
followRedirects = require('follow-redirects');
web_o = Object.keys(web_o).map(function(pass) {
return web_o[pass];
});
var nativeAgents = { http: httpNative, https: httpsNative };
/*!
* Array of passes.
*
* A `pass` is just a function that is executed on `req, res, options`
* so that you can easily add new checks while still keeping the base
* flexible.
*/
module.exports = {
/**
* Sets `content-length` to '0' if request is of DELETE type.
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
deleteLength: function deleteLength(req, res, options) {
if((req.method === 'DELETE' || req.method === 'OPTIONS')
&& !req.headers['content-length']) {
req.headers['content-length'] = '0';
delete req.headers['transfer-encoding'];
}
},
/**
* Sets timeout in request socket if it was specified in options.
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
timeout: function timeout(req, res, options) {
if(options.timeout) {
req.socket.setTimeout(options.timeout);
}
},
/**
* Sets `x-forwarded-*` headers if specified in config.
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
XHeaders: function XHeaders(req, res, options) {
if(!options.xfwd) return;
var encrypted = req.isSpdy || common.hasEncryptedConnection(req);
var values = {
for : req.connection.remoteAddress || req.socket.remoteAddress,
port : common.getPort(req),
proto: encrypted ? 'https' : 'http'
};
['for', 'port', 'proto'].forEach(function(header) {
req.headers['x-forwarded-' + header] =
(req.headers['x-forwarded-' + header] || '') +
(req.headers['x-forwarded-' + header] ? ',' : '') +
values[header];
});
req.headers['x-forwarded-host'] = req.headers['x-forwarded-host'] || req.headers['host'] || '';
},
/**
* Does the actual proxying. If `forward` is enabled fires up
* a ForwardStream, same happens for ProxyStream. The request
* just dies otherwise.
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
stream: function stream(req, res, options, _, server, clb) {
// And we begin!
server.emit('start', req, res, options.target || options.forward);
var agents = options.followRedirects ? followRedirects : nativeAgents;
var http = agents.http;
var https = agents.https;
if(options.forward) {
// If forward enable, so just pipe the request
var forwardReq = (options.forward.protocol === 'https:' ? https : http).request(
common.setupOutgoing(options.ssl || {}, options, req, 'forward')
);
// error handler (e.g. ECONNRESET, ECONNREFUSED)
// Handle errors on incoming request as well as it makes sense to
var forwardError = createErrorHandler(forwardReq, options.forward);
req.on('error', forwardError);
forwardReq.on('error', forwardError);
(options.buffer || req).pipe(forwardReq);
if(!options.target) { return res.end(); }
}
// Request initalization
var proxyReq = (options.target.protocol === 'https:' ? https : http).request(
common.setupOutgoing(options.ssl || {}, options, req)
);
// Enable developers to modify the proxyReq before headers are sent
proxyReq.on('socket', function(socket) {
if(server && !proxyReq.getHeader('expect')) {
server.emit('proxyReq', proxyReq, req, res, options);
}
});
// allow outgoing socket to timeout so that we could
// show an error page at the initial request
if(options.proxyTimeout) {
proxyReq.setTimeout(options.proxyTimeout, function() {
proxyReq.abort();
});
}
// Ensure we abort proxy if request is aborted
req.on('aborted', function () {
proxyReq.abort();
});
// handle errors in proxy and incoming request, just like for forward proxy
var proxyError = createErrorHandler(proxyReq, options.target);
req.on('error', proxyError);
proxyReq.on('error', proxyError);
function createErrorHandler(proxyReq, url) {
return function proxyError(err) {
if (req.socket.destroyed && err.code === 'ECONNRESET') {
server.emit('econnreset', err, req, res, url);
return proxyReq.abort();
}
if (clb) {
clb(err, req, res, url);
} else {
server.emit('error', err, req, res, url);
}
}
}
(options.buffer || req).pipe(proxyReq);
proxyReq.on('response', function(proxyRes) {
if(server) { server.emit('proxyRes', proxyRes, req, res); }
if(!res.headersSent && !options.selfHandleResponse) {
for(var i=0; i < web_o.length; i++) {
if(web_o[i](req, res, proxyRes, options)) { break; }
}
}
if (!res.finished) {
// Allow us to listen when the proxy has completed
proxyRes.on('end', function () {
if (server) server.emit('end', req, res, proxyRes);
});
// We pipe to the response unless its expected to be handled by the user
if (!options.selfHandleResponse) proxyRes.pipe(res);
} else {
if (server) server.emit('end', req, res, proxyRes);
}
});
}
};

View File

@ -0,0 +1,147 @@
var url = require('url'),
common = require('../common');
var redirectRegex = /^201|30(1|2|7|8)$/;
/*!
* Array of passes.
*
* A `pass` is just a function that is executed on `req, res, options`
* so that you can easily add new checks while still keeping the base
* flexible.
*/
module.exports = { // <--
/**
* If is a HTTP 1.0 request, remove chunk headers
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {proxyResponse} Res Response object from the proxy request
*
* @api private
*/
removeChunked: function removeChunked(req, res, proxyRes) {
if (req.httpVersion === '1.0') {
delete proxyRes.headers['transfer-encoding'];
}
},
/**
* If is a HTTP 1.0 request, set the correct connection header
* or if connection header not present, then use `keep-alive`
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {proxyResponse} Res Response object from the proxy request
*
* @api private
*/
setConnection: function setConnection(req, res, proxyRes) {
if (req.httpVersion === '1.0') {
proxyRes.headers.connection = req.headers.connection || 'close';
} else if (req.httpVersion !== '2.0' && !proxyRes.headers.connection) {
proxyRes.headers.connection = req.headers.connection || 'keep-alive';
}
},
setRedirectHostRewrite: function setRedirectHostRewrite(req, res, proxyRes, options) {
if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite)
&& proxyRes.headers['location']
&& redirectRegex.test(proxyRes.statusCode)) {
var target = url.parse(options.target);
var u = url.parse(proxyRes.headers['location']);
// make sure the redirected host matches the target host before rewriting
if (target.host != u.host) {
return;
}
if (options.hostRewrite) {
u.host = options.hostRewrite;
} else if (options.autoRewrite) {
u.host = req.headers['host'];
}
if (options.protocolRewrite) {
u.protocol = options.protocolRewrite;
}
proxyRes.headers['location'] = u.format();
}
},
/**
* Copy headers from proxyResponse to response
* set each header in response object.
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {proxyResponse} Res Response object from the proxy request
* @param {Object} Options options.cookieDomainRewrite: Config to rewrite cookie domain
*
* @api private
*/
writeHeaders: function writeHeaders(req, res, proxyRes, options) {
var rewriteCookieDomainConfig = options.cookieDomainRewrite,
rewriteCookiePathConfig = options.cookiePathRewrite,
preserveHeaderKeyCase = options.preserveHeaderKeyCase,
rawHeaderKeyMap,
setHeader = function(key, header) {
if (header == undefined) return;
if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') {
header = common.rewriteCookieProperty(header, rewriteCookieDomainConfig, 'domain');
}
if (rewriteCookiePathConfig && key.toLowerCase() === 'set-cookie') {
header = common.rewriteCookieProperty(header, rewriteCookiePathConfig, 'path');
}
res.setHeader(String(key).trim(), header);
};
if (typeof rewriteCookieDomainConfig === 'string') { //also test for ''
rewriteCookieDomainConfig = { '*': rewriteCookieDomainConfig };
}
if (typeof rewriteCookiePathConfig === 'string') { //also test for ''
rewriteCookiePathConfig = { '*': rewriteCookiePathConfig };
}
// message.rawHeaders is added in: v0.11.6
// https://nodejs.org/api/http.html#http_message_rawheaders
if (preserveHeaderKeyCase && proxyRes.rawHeaders != undefined) {
rawHeaderKeyMap = {};
for (var i = 0; i < proxyRes.rawHeaders.length; i += 2) {
var key = proxyRes.rawHeaders[i];
rawHeaderKeyMap[key.toLowerCase()] = key;
}
}
Object.keys(proxyRes.headers).forEach(function(key) {
var header = proxyRes.headers[key];
if (preserveHeaderKeyCase && rawHeaderKeyMap) {
key = rawHeaderKeyMap[key] || key;
}
setHeader(key, header);
});
},
/**
* Set the statusCode from the proxyResponse
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {proxyResponse} Res Response object from the proxy request
*
* @api private
*/
writeStatusCode: function writeStatusCode(req, res, proxyRes) {
// From Node.js docs: response.writeHead(statusCode[, statusMessage][, headers])
if(proxyRes.statusMessage) {
res.statusCode = proxyRes.statusCode;
res.statusMessage = proxyRes.statusMessage;
} else {
res.statusCode = proxyRes.statusCode;
}
}
};

View File

@ -0,0 +1,162 @@
var http = require('http'),
https = require('https'),
common = require('../common');
/*!
* Array of passes.
*
* A `pass` is just a function that is executed on `req, socket, options`
* so that you can easily add new checks while still keeping the base
* flexible.
*/
/*
* Websockets Passes
*
*/
module.exports = {
/**
* WebSocket requests must have the `GET` method and
* the `upgrade:websocket` header
*
* @param {ClientRequest} Req Request object
* @param {Socket} Websocket
*
* @api private
*/
checkMethodAndHeader : function checkMethodAndHeader(req, socket) {
if (req.method !== 'GET' || !req.headers.upgrade) {
socket.destroy();
return true;
}
if (req.headers.upgrade.toLowerCase() !== 'websocket') {
socket.destroy();
return true;
}
},
/**
* Sets `x-forwarded-*` headers if specified in config.
*
* @param {ClientRequest} Req Request object
* @param {Socket} Websocket
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
XHeaders : function XHeaders(req, socket, options) {
if(!options.xfwd) return;
var values = {
for : req.connection.remoteAddress || req.socket.remoteAddress,
port : common.getPort(req),
proto: common.hasEncryptedConnection(req) ? 'wss' : 'ws'
};
['for', 'port', 'proto'].forEach(function(header) {
req.headers['x-forwarded-' + header] =
(req.headers['x-forwarded-' + header] || '') +
(req.headers['x-forwarded-' + header] ? ',' : '') +
values[header];
});
},
/**
* Does the actual proxying. Make the request and upgrade it
* send the Switching Protocols request and pipe the sockets.
*
* @param {ClientRequest} Req Request object
* @param {Socket} Websocket
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
stream : function stream(req, socket, options, head, server, clb) {
var createHttpHeader = function(line, headers) {
return Object.keys(headers).reduce(function (head, key) {
var value = headers[key];
if (!Array.isArray(value)) {
head.push(key + ': ' + value);
return head;
}
for (var i = 0; i < value.length; i++) {
head.push(key + ': ' + value[i]);
}
return head;
}, [line])
.join('\r\n') + '\r\n\r\n';
}
common.setupSocket(socket);
if (head && head.length) socket.unshift(head);
var proxyReq = (common.isSSL.test(options.target.protocol) ? https : http).request(
common.setupOutgoing(options.ssl || {}, options, req)
);
// Enable developers to modify the proxyReq before headers are sent
if (server) { server.emit('proxyReqWs', proxyReq, req, socket, options, head); }
// Error Handler
proxyReq.on('error', onOutgoingError);
proxyReq.on('response', function (res) {
// if upgrade event isn't going to happen, close the socket
if (!res.upgrade) {
socket.write(createHttpHeader('HTTP/' + res.httpVersion + ' ' + res.statusCode + ' ' + res.statusMessage, res.headers));
res.pipe(socket);
}
});
proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) {
proxySocket.on('error', onOutgoingError);
// Allow us to listen when the websocket has completed
proxySocket.on('end', function () {
server.emit('close', proxyRes, proxySocket, proxyHead);
});
// The pipe below will end proxySocket if socket closes cleanly, but not
// if it errors (eg, vanishes from the net and starts returning
// EHOSTUNREACH). We need to do that explicitly.
socket.on('error', function () {
proxySocket.end();
});
common.setupSocket(proxySocket);
if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead);
//
// Remark: Handle writing the headers to the socket when switching protocols
// Also handles when a header is an array
//
socket.write(createHttpHeader('HTTP/1.1 101 Switching Protocols', proxyRes.headers));
proxySocket.pipe(socket).pipe(proxySocket);
server.emit('open', proxySocket);
server.emit('proxySocket', proxySocket); //DEPRECATED.
});
return proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT
function onOutgoingError(err) {
if (clb) {
clb(err, req, socket);
} else {
server.emit('error', err, req, socket);
}
socket.end();
}
}
};

View File

@ -1,394 +0,0 @@
/*
node-http-proxy.js: http proxy for node.js
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Marak Squires, Fedor Indutny
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var util = require('util'),
http = require('http'),
https = require('https'),
events = require('events'),
maxSockets = 100;
//
// Expose version information through `pkginfo`.
//
require('pkginfo')(module, 'version');
//
// ### Export the relevant objects exposed by `node-http-proxy`
//
var HttpProxy = exports.HttpProxy = require('./node-http-proxy/http-proxy').HttpProxy,
ProxyTable = exports.ProxyTable = require('./node-http-proxy/proxy-table').ProxyTable,
RoutingProxy = exports.RoutingProxy = require('./node-http-proxy/routing-proxy').RoutingProxy;
//
// ### function createServer ([port, host, options, handler])
// #### @port {number} **Optional** Port to use on the proxy target host.
// #### @host {string} **Optional** Host of the proxy target.
// #### @options {Object} **Optional** Options for the HttpProxy instance used
// #### @handler {function} **Optional** Request handler for the server
// Returns a server that manages an instance of HttpProxy. Flexible arguments allow for:
//
// * `httpProxy.createServer(9000, 'localhost')`
// * `httpProxy.createServer(9000, 'localhost', options)
// * `httpPRoxy.createServer(function (req, res, proxy) { ... })`
//
exports.createServer = function () {
var args = Array.prototype.slice.call(arguments),
handlers = [],
callback,
options = {},
message,
handler,
server,
proxy,
host,
port;
//
// Liberally parse arguments of the form:
//
// httpProxy.createServer('localhost', 9000, callback);
// httpProxy.createServer({ host: 'localhost', port: 9000 }, callback);
// **NEED MORE HERE!!!**
//
args.forEach(function (arg) {
switch (typeof arg) {
case 'string': host = arg; break;
case 'number': port = arg; break;
case 'object': options = arg || {}; break;
case 'function': callback = arg; handlers.push(callback); break;
}
});
//
// Helper function to create intelligent error message(s)
// for the very liberal arguments parsing performed by
// `require('http-proxy').createServer()`.
//
function validArguments() {
var conditions = {
'port and host': function () {
return port && host;
},
'options.target or options.router': function () {
return options && (options.router ||
(options.target && options.target.host && options.target.port));
},
'or proxy handlers': function () {
return handlers && handlers.length;
}
};
var missing = Object.keys(conditions).filter(function (name) {
return !conditions[name]();
});
if (missing.length === 3) {
message = 'Cannot proxy without ' + missing.join(', ');
return false;
}
return true;
}
if (!validArguments()) {
//
// If `host`, `port` and `options` are all not passed (with valid
// options) then this server is improperly configured.
//
throw new Error(message);
}
//
// Hoist up any explicit `host` or `port` arguments
// that have been passed in to the options we will
// pass to the `httpProxy.HttpProxy` constructor.
//
options.target = options.target || {};
options.target.port = options.target.port || port;
options.target.host = options.target.host || host;
if (options.target && options.target.host && options.target.port) {
//
// If an explicit `host` and `port` combination has been passed
// to `.createServer()` then instantiate a hot-path optimized
// `HttpProxy` object and add the "proxy" middleware layer.
//
proxy = new HttpProxy(options);
handlers.push(function (req, res) {
proxy.proxyRequest(req, res);
});
}
else {
//
// If no explicit `host` or `port` combination has been passed then
// we have to assume that this is a "go-anywhere" Proxy (i.e. a `RoutingProxy`).
//
proxy = new RoutingProxy(options);
if (options.router) {
//
// If a routing table has been supplied than we assume
// the user intends us to add the "proxy" middleware layer
// for them
//
handlers.push(function (req, res) {
proxy.proxyRequest(req, res);
});
proxy.on('routes', function (routes) {
server.emit('routes', routes);
});
}
}
//
// Create the `http[s].Server` instance which will use
// an instance of `httpProxy.HttpProxy`.
//
handler = handlers.length > 1
? exports.stack(handlers, proxy)
: function (req, res) { handlers[0](req, res, proxy) };
server = options.https
? https.createServer(options.https, handler)
: http.createServer(handler);
server.on('close', function () {
proxy.close();
});
if (!callback) {
//
// If an explicit callback has not been supplied then
// automagically proxy the request using the `HttpProxy`
// instance we have created.
//
server.on('upgrade', function (req, socket, head) {
proxy.proxyWebSocketRequest(req, socket, head);
});
}
//
// Set the proxy on the server so it is available
// to the consumer of the server
//
server.proxy = proxy;
return server;
};
//
// ### function buffer (obj)
// #### @obj {Object} Object to pause events from
// Buffer `data` and `end` events from the given `obj`.
// Consumers of HttpProxy performing async tasks
// __must__ utilize this utility, to re-emit data once
// the async operation has completed, otherwise these
// __events will be lost.__
//
// var buffer = httpProxy.buffer(req);
// fs.readFile(path, function(){
// httpProxy.proxyRequest(req, res, host, port, buffer);
// });
//
// __Attribution:__ This approach is based heavily on
// [Connect](https://github.com/senchalabs/connect/blob/master/lib/utils.js#L157).
// However, this is not a big leap from the implementation in node-http-proxy < 0.4.0.
// This simply chooses to manage the scope of the events on a new Object literal as opposed to
// [on the HttpProxy instance](https://github.com/nodejitsu/node-http-proxy/blob/v0.3.1/lib/node-http-proxy.js#L154).
//
exports.buffer = function (obj) {
var events = [],
onData,
onEnd;
obj.on('data', onData = function (data, encoding) {
events.push(['data', data, encoding]);
});
obj.on('end', onEnd = function (data, encoding) {
events.push(['end', data, encoding]);
});
return {
end: function () {
obj.removeListener('data', onData);
obj.removeListener('end', onEnd);
},
destroy: function () {
this.end();
this.resume = function () {
console.error("Cannot resume buffer after destroying it.");
};
onData = onEnd = events = obj = null;
},
resume: function () {
this.end();
for (var i = 0, len = events.length; i < len; ++i) {
obj.emit.apply(obj, events[i]);
}
}
};
};
//
// ### function getMaxSockets ()
// Returns the maximum number of sockets
// allowed on __every__ outgoing request
// made by __all__ instances of `HttpProxy`
//
exports.getMaxSockets = function () {
return maxSockets;
};
//
// ### function setMaxSockets ()
// Sets the maximum number of sockets
// allowed on __every__ outgoing request
// made by __all__ instances of `HttpProxy`
//
exports.setMaxSockets = function (value) {
maxSockets = value;
};
//
// ### function stack (middlewares, proxy)
// #### @middlewares {Array} Array of functions to stack.
// #### @proxy {HttpProxy|RoutingProxy} Proxy instance to
// Iteratively build up a single handler to the `http.Server`
// `request` event (i.e. `function (req, res)`) by wrapping
// each middleware `layer` into a `child` middleware which
// is in invoked by the parent (i.e. predecessor in the Array).
//
// adapted from https://github.com/creationix/stack
//
exports.stack = function stack (middlewares, proxy) {
var handle;
middlewares.reverse().forEach(function (layer) {
var child = handle;
handle = function (req, res) {
var next = function (err) {
if (err) {
if (res._headerSent) {
res.destroy();
}
else {
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end('Internal Server Error');
}
console.error('Error in middleware(s): %s', err.stack);
return;
}
if (child) {
child(req, res);
}
};
//
// Set the prototype of the `next` function to the instance
// of the `proxy` so that in can be used interchangably from
// a `connect` style callback and a true `HttpProxy` object.
//
// e.g. `function (req, res, next)` vs. `function (req, res, proxy)`
//
next.__proto__ = proxy;
layer(req, res, next);
};
});
return handle;
};
//
// ### function _getAgent (host, port, secure)
// #### @options {Object} Options to use when creating the agent.
//
// {
// host: 'localhost',
// port: 9000,
// https: true,
// maxSockets: 100
// }
//
// Createsan agent from the `http` or `https` module
// and sets the `maxSockets` property appropriately.
//
exports._getAgent = function _getAgent (options) {
if (!options || !options.host) {
throw new Error('`options.host` is required to create an Agent.');
}
if (!options.port) {
options.port = options.https ? 443 : 80;
}
var Agent = options.https ? https.Agent : http.Agent,
agent;
agent = new Agent({
host: options.host,
port: options.port
});
agent.maxSockets = options.maxSockets || maxSockets;
return agent;
};
//
// ### function _getProtocol (options)
// #### @options {Object} Options for the proxy target.
// Returns the appropriate node.js core protocol module (i.e. `http` or `https`)
// based on the `options` supplied.
//
exports._getProtocol = function _getProtocol (options) {
return options.https ? https : http;
};
//
// ### function _getBase (options)
// #### @options {Object} Options for the proxy target.
// Returns the relevate base object to create on outgoing proxy request.
// If `options.https` are supplied, this function respond with an object
// containing the relevant `ca`, `key`, and `cert` properties.
//
exports._getBase = function _getBase (options) {
var result = function () {};
if (options.https && typeof options.https === 'object') {
['ca', 'cert', 'key'].forEach(function (key) {
if (options.https[key]) {
result.prototype[key] = options.https[key];
}
});
}
return result;
};

View File

@ -1,840 +0,0 @@
/*
node-http-proxy.js: http proxy for node.js
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Marak Squires, Fedor Indutny
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var events = require('events'),
http = require('http'),
util = require('util'),
httpProxy = require('../node-http-proxy');
//
// ### function HttpProxy (options)
// #### @options {Object} Options for this instance.
// Constructor function for new instances of HttpProxy responsible
// for managing the life-cycle of streaming reverse proxyied HTTP requests.
//
// Example options:
//
// {
// target: {
// host: 'localhost',
// port: 9000
// },
// forward: {
// host: 'localhost',
// port: 9001
// }
// }
//
var HttpProxy = exports.HttpProxy = function (options) {
if (!options || !options.target) {
throw new Error('Both `options` and `options.target` are required.');
}
events.EventEmitter.call(this);
var self = this;
//
// Setup basic proxying options:
//
// * forward {Object} Options for a forward-proxy (if-any)
// * target {Object} Options for the **sole** proxy target of this instance
//
this.forward = options.forward;
this.target = options.target;
//
// Setup the necessary instances instance variables for
// the `target` and `forward` `host:port` combinations
// used by this instance.
//
// * agent {http[s].Agent} Agent to be used by this instance.
// * protocol {http|https} Core node.js module to make requests with.
// * base {Object} Base object to create when proxying containing any https settings.
//
function setupProxy (key) {
self[key].agent = httpProxy._getAgent(self[key]);
self[key].protocol = httpProxy._getProtocol(self[key]);
self[key].base = httpProxy._getBase(self[key]);
}
setupProxy('target');
if (this.forward) {
setupProxy('forward');
}
//
// Setup opt-in features
//
this.enable = options.enable || {};
this.enable.xforward = typeof this.enable.xforward === 'boolean'
? this.enable.xforward
: true;
//
// Setup additional options for WebSocket proxying. When forcing
// the WebSocket handshake to change the `sec-websocket-location`
// and `sec-websocket-origin` headers `options.source` **MUST**
// be provided or the operation will fail with an `origin mismatch`
// by definition.
//
this.source = options.source || { host: 'localhost', port: 8000 };
this.source.https = this.source.https || options.https;
this.changeOrigin = options.changeOrigin || false;
};
// Inherit from events.EventEmitter
util.inherits(HttpProxy, events.EventEmitter);
//
// ### function proxyRequest (req, res, [port, host, paused])
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
// #### @res {ServerResponse} Outgoing HTTP Request to write proxied data to.
// #### @buffer {Object} Result from `httpProxy.buffer(req)`
//
HttpProxy.prototype.proxyRequest = function (req, res, buffer) {
var self = this,
errState = false,
outgoing = new(this.target.base),
reverseProxy;
//
// Add common proxy headers to the request so that they can
// be availible to the proxy target server. If the proxy is
// part of proxy chain it will append the address:
//
// * `x-forwarded-for`: IP Address of the original request
// * `x-forwarded-proto`: Protocol of the original request
// * `x-forwarded-port`: Port of the original request.
//
if (this.enable.xforward && req.connection && req.socket) {
if (req.headers['x-forwarded-for']){
var addressToAppend = "," + req.connection.remoteAddress || req.socket.remoteAddress;
req.headers['x-forwarded-for'] += addressToAppend;
}
else {
req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.socket.remoteAddress;
}
if (req.headers['x-forwarded-port']){
var portToAppend = "," + req.connection.remotePort || req.socket.remotePort;
req.headers['x-forwarded-port'] += portToAppend;
}
else {
req.headers['x-forwarded-port'] = req.connection.remotePort || req.socket.remotePort;
}
if (req.headers['x-forwarded-proto']){
var protoToAppend = "," + (req.connection.pair ? 'https' : 'http');
req.headers['x-forwarded-proto'] += protoToAppend;
}
else {
req.headers['x-forwarded-proto'] = req.connection.pair ? 'https' : 'http';
}
}
//
// Emit the `start` event indicating that we have begun the proxy operation.
//
this.emit('start', req, res, this.target);
//
// If forwarding is enabled for this instance, foward proxy the
// specified request to the address provided in `this.forward`
//
if (this.forward) {
this.emit('forward', req, res, this.forward);
this._forwardRequest(req);
}
//
// #### function proxyError (err)
// #### @err {Error} Error contacting the proxy target
// Short-circuits `res` in the event of any error when
// contacting the proxy target at `host` / `port`.
//
function proxyError(err) {
errState = true;
//
// Emit an `error` event, allowing the application to use custom
// error handling. The error handler should end the response.
//
if (self.emit('proxyError', err, req, res)) {
return;
}
res.writeHead(500, { 'Content-Type': 'text/plain' });
if (req.method !== 'HEAD') {
//
// This NODE_ENV=production behavior is mimics Express and
// Connect.
//
if (process.env.NODE_ENV === 'production') {
res.write('Internal Server Error');
}
else {
res.write('An error has occurred: ' + JSON.stringify(err));
}
}
try { res.end() }
catch (ex) { console.error("res.end error: %s", ex.message) }
}
//
// Setup outgoing proxy with relevant properties.
//
outgoing.host = this.target.host;
outgoing.hostname = this.target.hostname;
outgoing.port = this.target.port;
outgoing.agent = this.target.agent;
outgoing.method = req.method;
outgoing.path = req.url;
outgoing.headers = req.headers;
//
// If the changeOrigin option is specified, change the
// origin of the host header to the target URL! Please
// don't revert this without documenting it!
//
if (this.changeOrigin) {
outgoing.headers.host = this.target.host + ':' + this.target.port;
}
//
// Open new HTTP request to internal resource with will act
// as a reverse proxy pass
//
reverseProxy = this.target.protocol.request(outgoing, function (response) {
//
// Process the `reverseProxy` `response` when it's received.
//
if (response.headers.connection) {
if (req.headers.connection) { response.headers.connection = req.headers.connection }
else { response.headers.connection = 'close' }
}
// Remove `Transfer-Encoding` header if client's protocol is HTTP/1.0
if (req.httpVersion === '1.0') {
delete response.headers['transfer-encoding'];
}
if ((response.statusCode === 301) || (response.statusCode === 302)) {
if (self.source.https && !self.target.https) {
response.headers.location = response.headers.location.replace(/^http\:/, 'https:');
}
if (self.target.https && !self.source.https) {
response.headers.location = response.headers.location.replace(/^https\:/, 'http:');
}
}
// Set the headers of the client response
res.writeHead(response.statusCode, response.headers);
// If `response.statusCode === 304`: No 'data' event and no 'end'
if (response.statusCode === 304) {
try { res.end() }
catch (ex) { console.error("res.end error: %s", ex.message) }
return;
}
function ondata(chunk) {
if (res.writable) {
if (false === res.write(chunk) && response.pause) {
response.pause();
}
}
}
response.on('data', ondata);
function ondrain() {
if (response.readable && response.resume) {
response.resume();
}
}
res.on('drain', ondrain);
//
// When the `reverseProxy` `response` ends, end the
// corresponding outgoing `res` unless we have entered
// an error state. In which case, assume `res.end()` has
// already been called and the 'error' event listener
// removed.
//
var ended = false;
response.on('close', function () {
if (!ended) { response.emit('end') }
});
response.on('end', function () {
ended = true;
if (!errState) {
reverseProxy.removeListener('error', proxyError);
try { res.end() }
catch (ex) { console.error("res.end error: %s", ex.message) }
// Emit the `end` event now that we have completed proxying
self.emit('end', req, res);
}
});
});
//
// Handle 'error' events from the `reverseProxy`.
//
reverseProxy.once('error', proxyError);
//
// If `req` is aborted, we abort our `reverseProxy` request as well.
//
req.on('aborted', function () {
reverseProxy.abort();
});
//
// For each data `chunk` received from the incoming
// `req` write it to the `reverseProxy` request.
//
req.on('data', function (chunk) {
if (!errState) {
var flushed = reverseProxy.write(chunk);
if (!flushed) {
req.pause();
reverseProxy.once('drain', function () {
try { req.resume() }
catch (er) { console.error("req.resume error: %s", er.message) }
});
//
// Force the `drain` event in 100ms if it hasn't
// happened on its own.
//
setTimeout(function () {
reverseProxy.emit('drain');
}, 100);
}
}
});
//
// When the incoming `req` ends, end the corresponding `reverseProxy`
// request unless we have entered an error state.
//
req.on('end', function () {
if (!errState) {
reverseProxy.end();
}
});
//Aborts reverseProxy if client aborts the connection.
req.on('close', function () {
if (!errState) {
reverseProxy.abort();
}
});
//
// If we have been passed buffered data, resume it.
//
if (buffer) {
return !errState
? buffer.resume()
: buffer.destroy();
}
};
//
// ### function proxyWebSocketRequest (req, socket, head, buffer)
// #### @req {ServerRequest} Websocket request to proxy.
// #### @socket {net.Socket} Socket for the underlying HTTP request
// #### @head {string} Headers for the Websocket request.
// #### @buffer {Object} Result from `httpProxy.buffer(req)`
// Performs a WebSocket proxy operation to the location specified by
// `this.target`.
//
HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) {
var self = this,
outgoing = new(this.target.base),
listeners = {},
errState = false,
CRLF = '\r\n';
//
// WebSocket requests must have the `GET` method and
// the `upgrade:websocket` header
//
if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') {
//
// This request is not WebSocket request
//
return socket.destroy();
}
//
// Add common proxy headers to the request so that they can
// be availible to the proxy target server. If the proxy is
// part of proxy chain it will append the address:
//
// * `x-forwarded-for`: IP Address of the original request
// * `x-forwarded-proto`: Protocol of the original request
// * `x-forwarded-port`: Port of the original request.
//
if (this.enable.xforward && req.connection && req.connection.socket) {
if (req.headers['x-forwarded-for']){
var addressToAppend = "," + req.connection.remoteAddress || req.connection.socket.remoteAddress;
req.headers['x-forwarded-for'] += addressToAppend;
}
else {
req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.connection.socket.remoteAddress;
}
if (req.headers['x-forwarded-port']){
var portToAppend = "," + req.connection.remotePort || req.connection.socket.remotePort;
req.headers['x-forwarded-port'] += portToAppend;
}
else {
req.headers['x-forwarded-port'] = req.connection.remotePort || req.connection.socket.remotePort;
}
if (req.headers['x-forwarded-proto']){
var protoToAppend = "," + (req.connection.pair ? 'wss' : 'ws');
req.headers['x-forwarded-proto'] += protoToAppend;
}
else {
req.headers['x-forwarded-proto'] = req.connection.pair ? 'wss' : 'ws';
}
}
//
// Helper function for setting appropriate socket values:
// 1. Turn of all bufferings
// 2. For server set KeepAlive
// 3. For client set encoding
//
function _socket(socket, keepAlive) {
socket.setTimeout(0);
socket.setNoDelay(true);
if (keepAlive) {
if (socket.setKeepAlive) {
socket.setKeepAlive(true, 0);
}
else if (socket.pair.cleartext.socket.setKeepAlive) {
socket.pair.cleartext.socket.setKeepAlive(true, 0);
}
}
else {
socket.setEncoding('utf8');
}
}
//
// Setup the incoming client socket.
//
_socket(socket, true);
//
// On `upgrade` from the Agent socket, listen to
// the appropriate events.
//
function onUpgrade (reverseProxy, proxySocket) {
if (!reverseProxy) {
proxySocket.end();
socket.end();
return;
}
//
// Any incoming data on this WebSocket to the proxy target
// will be written to the `reverseProxy` socket.
//
proxySocket.on('data', listeners.onIncoming = function (data) {
if (reverseProxy.incoming.socket.writable) {
try {
self.emit('websocket:outgoing', req, socket, head, data);
var flushed = reverseProxy.incoming.socket.write(data);
if (!flushed) {
proxySocket.pause();
reverseProxy.incoming.socket.once('drain', function () {
try { proxySocket.resume() }
catch (er) { console.error("proxySocket.resume error: %s", er.message) }
});
//
// Force the `drain` event in 100ms if it hasn't
// happened on its own.
//
setTimeout(function () {
reverseProxy.incoming.socket.emit('drain');
}, 100);
}
}
catch (ex) {
detach();
reverseProxy.incoming.socket.end();
proxySocket.end();
}
}
});
//
// Any outgoing data on this Websocket from the proxy target
// will be written to the `proxySocket` socket.
//
reverseProxy.incoming.socket.on('data', listeners.onOutgoing = function (data) {
try {
self.emit('websocket:incoming', reverseProxy, reverseProxy.incoming, head, data);
var flushed = proxySocket.write(data);
if (!flushed) {
reverseProxy.incoming.socket.pause();
proxySocket.once('drain', function () {
try { reverseProxy.incoming.socket.resume() }
catch (er) { console.error("reverseProxy.incoming.socket.resume error: %s", er.message) }
});
//
// Force the `drain` event in 100ms if it hasn't
// happened on its own.
//
setTimeout(function () {
proxySocket.emit('drain');
}, 100);
}
}
catch (ex) {
detach();
proxySocket.end();
socket.end();
}
});
//
// Helper function to detach all event listeners
// from `reverseProxy` and `proxySocket`.
//
function detach() {
proxySocket.removeListener('end', listeners.onIncomingClose);
proxySocket.removeListener('data', listeners.onIncoming);
reverseProxy.incoming.socket.removeListener('end', listeners.onOutgoingClose);
reverseProxy.incoming.socket.removeListener('data', listeners.onOutgoing);
}
//
// If the incoming `proxySocket` socket closes, then
// detach all event listeners.
//
proxySocket.on('end', listeners.onIncomingClose = function() {
reverseProxy.incoming.socket.end();
detach();
// Emit the `end` event now that we have completed proxying
self.emit('websocket:end', req, socket, head);
});
//
// If the `reverseProxy` socket closes, then detach all
// event listeners.
//
reverseProxy.incoming.socket.on('end', listeners.onOutgoingClose = function() {
proxySocket.end();
detach();
});
}
function getPort (port) {
port = port || 80;
return port - 80 === 0 ? '' : ':' + port;
}
//
// Get the protocol, and host for this request and create an instance
// of `http.Agent` or `https.Agent` from the pool managed by `node-http-proxy`.
//
var agent = this.target.agent,
protocolName = this.target.https ? 'https' : 'http',
portUri = getPort(this.source.port),
remoteHost = this.target.host + portUri;
//
// Change headers (if requested).
//
if (this.changeOrigin) {
req.headers.host = remoteHost;
req.headers.origin = protocolName + '://' + remoteHost;
}
//
// Make the outgoing WebSocket request
//
outgoing.host = this.target.host;
outgoing.port = this.target.port;
outgoing.agent = agent;
outgoing.method = 'GET';
outgoing.path = req.url;
outgoing.headers = req.headers;
outgoing.agent = agent;
var reverseProxy = this.target.protocol.request(outgoing);
//
// On any errors from the `reverseProxy` emit the
// `webSocketProxyError` and close the appropriate
// connections.
//
function proxyError (err) {
reverseProxy.end();
if (self.emit('webSocketProxyError', req, socket, head)) {
return;
}
socket.end();
}
//
// Here we set the incoming `req`, `socket` and `head` data to the outgoing
// request so that we can reuse this data later on in the closure scope
// available to the `upgrade` event. This bookkeeping is not tracked anywhere
// in nodejs core and is **very** specific to proxying WebSockets.
//
reverseProxy.incoming = {
request: req,
socket: socket,
head: head
};
//
// If the agent for this particular `host` and `port` combination
// is not already listening for the `upgrade` event, then do so once.
// This will force us not to disconnect.
//
// In addition, it's important to note the closure scope here. Since
// there is no mapping of the socket to the request bound to it.
//
reverseProxy.on('upgrade', function (_, remoteSocket, head) {
//
// Prepare the socket for the reverseProxy request and begin to
// stream data between the two sockets. Here it is important to
// note that `remoteSocket._httpMessage === reverseProxy`.
//
_socket(remoteSocket, true);
onUpgrade(remoteSocket._httpMessage, remoteSocket);
});
//
// If the reverseProxy connection has an underlying socket,
// then execute the WebSocket handshake.
//
reverseProxy.once('socket', function (revSocket) {
revSocket.on('data', function handshake (data) {
//
// Ok, kind of harmfull part of code. Socket.IO sends a hash
// at the end of handshake if protocol === 76, but we need
// to replace 'host' and 'origin' in response so we split
// data to printable data and to non-printable. (Non-printable
// will come after double-CRLF).
//
var sdata = data.toString();
// Get the Printable data
sdata = sdata.substr(0, sdata.search(CRLF + CRLF));
// Get the Non-Printable data
data = data.slice(Buffer.byteLength(sdata), data.length);
if (self.source.https && !self.target.https) {
//
// If the proxy server is running HTTPS but the client is running
// HTTP then replace `ws` with `wss` in the data sent back to the client.
//
sdata = sdata.replace('ws:', 'wss:');
}
try {
//
// Write the printable and non-printable data to the socket
// from the original incoming request.
//
self.emit('websocket:handshake', req, socket, head, sdata, data);
socket.write(sdata);
var flushed = socket.write(data);
if (!flushed) {
revSocket.pause();
socket.once('drain', function () {
try { revSocket.resume() }
catch (er) { console.error("reverseProxy.socket.resume error: %s", er.message) }
});
//
// Force the `drain` event in 100ms if it hasn't
// happened on its own.
//
setTimeout(function () {
socket.emit('drain');
}, 100);
}
}
catch (ex) {
//
// Remove data listener on socket error because the
// 'handshake' has failed.
//
revSocket.removeListener('data', handshake);
return proxyError(ex);
}
// Catch socket errors
socket.on('error', proxyError);
//
// Remove data listener now that the 'handshake' is complete
//
revSocket.removeListener('data', handshake);
});
});
reverseProxy.on('error', proxyError);
try {
//
// Attempt to write the upgrade-head to the reverseProxy
// request. This is small, and there's only ever one of
// it; no need for pause/resume.
//
// XXX This is very wrong and should be fixed in node's core
//
reverseProxy.write(head);
if (head && head.length === 0) {
reverseProxy._send('');
}
}
catch (ex) {
return proxyError(ex);
}
//
// If we have been passed buffered data, resume it.
//
if (buffer) {
return !errState
? buffer.resume()
: buffer.destroy();
}
};
//
// ### function close()
// Closes all sockets associated with the Agents
// belonging to this instance.
//
HttpProxy.prototype.close = function () {
[this.forward, this.target].forEach(function (proxy) {
if (proxy && proxy.agent) {
for (var host in proxy.agent.sockets) {
proxy.agent.sockets[host].forEach(function (socket) {
socket.end();
});
}
}
});
};
//
// ### @private function _forwardRequest (req)
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
// Forwards the specified `req` to the location specified
// by `this.forward` ignoring errors and the subsequent response.
//
HttpProxy.prototype._forwardRequest = function (req) {
var self = this,
outgoing = new(this.forward.base),
forwardProxy;
//
// Setup outgoing proxy with relevant properties.
//
outgoing.host = this.forward.host;
outgoing.port = this.forward.port,
outgoing.agent = this.forward.agent;
outgoing.method = req.method;
outgoing.path = req.url;
outgoing.headers = req.headers;
//
// Open new HTTP request to internal resource with will
// act as a reverse proxy pass.
//
forwardProxy = this.forward.protocol.request(outgoing, function (response) {
//
// Ignore the response from the forward proxy since this is a 'fire-and-forget' proxy.
// Remark (indexzero): We will eventually emit a 'forward' event here for performance tuning.
//
});
//
// Add a listener for the connection timeout event.
//
// Remark: Ignoring this error in the event
// forward target doesn't exist.
//
forwardProxy.once('error', function (err) { });
//
// Chunk the client request body as chunks from
// the proxied request come in
//
req.on('data', function (chunk) {
var flushed = forwardProxy.write(chunk);
if (!flushed) {
req.pause();
forwardProxy.once('drain', function () {
try { req.resume() }
catch (er) { console.error("req.resume error: %s", er.message) }
});
//
// Force the `drain` event in 100ms if it hasn't
// happened on its own.
//
setTimeout(function () {
forwardProxy.emit('drain');
}, 100);
}
});
//
// At the end of the client request, we are going to
// stop the proxied request
//
req.on('end', function () {
forwardProxy.end();
});
};

View File

@ -1,225 +0,0 @@
/*
node-http-proxy.js: Lookup table for proxy targets in node.js
Copyright (c) 2010 Charlie Robbins
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var util = require('util'),
events = require('events'),
fs = require('fs'),
url = require('url');
//
// ### function ProxyTable (router, silent)
// #### @router {Object} Object containing the host based routes
// #### @silent {Boolean} Value indicating whether we should suppress logs
// #### @hostnameOnly {Boolean} Value indicating if we should route based on __hostname string only__
// Constructor function for the ProxyTable responsible for getting
// locations of proxy targets based on ServerRequest headers; specifically
// the HTTP host header.
//
var ProxyTable = exports.ProxyTable = function (options) {
events.EventEmitter.call(this);
this.silent = options.silent || options.silent !== true;
this.target = options.target || {};
this.hostnameOnly = options.hostnameOnly === true;
if (typeof options.router === 'object') {
//
// If we are passed an object literal setup
// the routes with RegExps from the router
//
this.setRoutes(options.router);
}
else if (typeof options.router === 'string') {
//
// If we are passed a string then assume it is a
// file path, parse that file and watch it for changes
//
var self = this;
this.routeFile = options.router;
this.setRoutes(JSON.parse(fs.readFileSync(options.router)).router);
fs.watchFile(this.routeFile, function () {
fs.readFile(self.routeFile, function (err, data) {
if (err) {
self.emit('error', err);
}
self.setRoutes(JSON.parse(data).router);
self.emit('routes', self.hostnameOnly === false ? self.routes : self.router);
});
});
}
else {
throw new Error('Cannot parse router with unknown type: ' + typeof router);
}
};
//
// Inherit from `events.EventEmitter`
//
util.inherits(ProxyTable, events.EventEmitter);
//
// ### function setRoutes (router)
// #### @router {Object} Object containing the host based routes
// Sets the host-based routes to be used by this instance.
//
ProxyTable.prototype.setRoutes = function (router) {
if (!router) {
throw new Error('Cannot update ProxyTable routes without router.');
}
var self = this;
this.router = router;
if (this.hostnameOnly === false) {
this.routes = [];
Object.keys(router).forEach(function (path) {
if (!/http[s]?/.test(router[path])) {
router[path] = (self.target.https ? 'https://' : 'http://')
+ router[path];
}
var target = url.parse(router[path]),
defaultPort = self.target.https ? 443 : 80;
//
// Setup a robust lookup table for the route:
//
// {
// source: {
// regexp: /^foo.com/i,
// sref: 'foo.com',
// url: {
// protocol: 'http:',
// slashes: true,
// host: 'foo.com',
// hostname: 'foo.com',
// href: 'http://foo.com/',
// pathname: '/',
// path: '/'
// }
// },
// {
// target: {
// sref: '127.0.0.1:8000/',
// url: {
// protocol: 'http:',
// slashes: true,
// host: '127.0.0.1:8000',
// hostname: '127.0.0.1',
// href: 'http://127.0.0.1:8000/',
// pathname: '/',
// path: '/'
// }
// },
//
self.routes.push({
source: {
regexp: new RegExp('^' + path, 'i'),
sref: path,
url: url.parse('http://' + path)
},
target: {
sref: target.hostname + ':' + (target.port || defaultPort) + target.path,
url: target
}
});
});
}
};
//
// ### function getProxyLocation (req)
// #### @req {ServerRequest} The incoming server request to get proxy information about.
// Returns the proxy location based on the HTTP Headers in the ServerRequest `req`
// available to this instance.
//
ProxyTable.prototype.getProxyLocation = function (req) {
if (!req || !req.headers || !req.headers.host) {
return null;
}
var target = req.headers.host.split(':')[0];
if (this.hostnameOnly === true) {
if (this.router.hasOwnProperty(target)) {
var location = this.router[target].split(':'),
host = location[0],
port = location.length === 1 ? 80 : location[1];
return {
port: port,
host: host
};
}
}
else {
target += req.url;
for (var i in this.routes) {
var route = this.routes[i];
if (target.match(route.source.regexp)) {
//
// Attempt to perform any path replacement for differences
// between the source path and the target path. This replaces the
// path's part of the URL to the target's part of the URL.
//
// 1. Parse the request URL
// 2. Replace any portions of the source path with the target path
// 3. Set the request URL to the formatted URL with replacements.
//
var parsed = url.parse(req.url);
parsed.pathname = parsed.pathname.replace(
route.source.url.pathname,
route.target.url.pathname
);
req.url = url.format(parsed);
return {
protocol: route.target.url.protocol.replace(':', ''),
host: route.target.url.hostname,
port: route.target.url.port
|| (this.target.https ? 443 : 80)
};
}
}
}
return null;
};
//
// ### close function ()
// Cleans up the event listeneners maintained
// by this instance.
//
ProxyTable.prototype.close = function () {
if (typeof this.routeFile === 'string') {
fs.unwatchFile(this.routeFile);
}
};

View File

@ -1,284 +0,0 @@
/*
* routing-proxy.js: A routing proxy consuming a RoutingTable and multiple HttpProxy instances
*
* (C) 2011 Nodejitsu Inc.
* MIT LICENCE
*
*/
var events = require('events'),
util = require('util'),
HttpProxy = require('./http-proxy').HttpProxy,
ProxyTable = require('./proxy-table').ProxyTable;
//
// ### function RoutingProxy (options)
// #### @options {Object} Options for this instance
// Constructor function for the RoutingProxy object, a higher level
// reverse proxy Object which can proxy to multiple hosts and also interface
// easily with a RoutingTable instance.
//
var RoutingProxy = exports.RoutingProxy = function (options) {
events.EventEmitter.call(this);
var self = this;
options = options || {};
if (options.router) {
this.proxyTable = new ProxyTable(options);
this.proxyTable.on('routes', function (routes) {
self.emit('routes', routes);
});
}
//
// Create a set of `HttpProxy` objects to be used later on calls
// to `.proxyRequest()` and `.proxyWebSocketRequest()`.
//
this.proxies = {};
//
// Setup default target options (such as `https`).
//
this.target = {};
this.target.https = options.target && options.target.https;
//
// Setup other default options to be used for instances of
// `HttpProxy` created by this `RoutingProxy` instance.
//
this.source = options.source || { host: 'localhost', port: 8000 };
this.https = this.source.https || options.https;
this.enable = options.enable;
this.forward = options.forward;
//
// Listen for 'newListener' events so that we can bind 'proxyError'
// listeners to each HttpProxy's 'proxyError' event.
//
this.on('newListener', function (evt) {
if (evt === 'proxyError' || evt === 'webSocketProxyError') {
Object.keys(self.proxies).forEach(function (key) {
self.proxies[key].on(evt, this.emit.bind(this, evt));
});
}
});
};
//
// Inherit from `events.EventEmitter`.
//
util.inherits(RoutingProxy, events.EventEmitter);
//
// ### function add (options)
// #### @options {Object} Options for the `HttpProxy` to add.
// Adds a new instance of `HttpProxy` to this `RoutingProxy` instance
// for the specified `options.host` and `options.port`.
//
RoutingProxy.prototype.add = function (options) {
var self = this,
key = this._getKey(options);
//
// TODO: Consume properties in `options` related to the `ProxyTable`.
//
options.target = options.target || {};
options.target.host = options.target.host || options.host;
options.target.port = options.target.port || options.port;
options.target.https = this.target && this.target.https ||
options.target && options.target.https;
//
// Setup options to pass-thru to the new `HttpProxy` instance
// for the specified `options.host` and `options.port` pair.
//
['https', 'enable', 'forward'].forEach(function (key) {
if (options[key] !== false && self[key]) {
options[key] = self[key];
}
});
this.proxies[key] = new HttpProxy(options);
if (this.listeners('proxyError').length > 0) {
this.proxies[key].on('proxyError', this.emit.bind(this, 'proxyError'));
}
if (this.listeners('webSocketProxyError').length > 0) {
this.proxies[key].on('webSocketProxyError', this.emit.bind(this, 'webSocketProxyError'));
}
this.proxies[key].on('start', this.emit.bind(this, 'start'));
this.proxies[key].on('forward', this.emit.bind(this, 'forward'));
this.proxies[key].on('end', this.emit.bind(this, 'end'));
};
//
// ### function remove (options)
// #### @options {Object} Options mapping to the `HttpProxy` to remove.
// Removes an instance of `HttpProxy` from this `RoutingProxy` instance
// for the specified `options.host` and `options.port` (if they exist).
//
RoutingProxy.prototype.remove = function (options) {
var key = this._getKey(options),
proxy = this.proxies[key];
delete this.proxies[key];
return proxy;
};
//
// ### function close()
// Cleans up any state left behind (sockets, timeouts, etc)
// associated with this instance.
//
RoutingProxy.prototype.close = function () {
var self = this;
if (this.proxyTable) {
//
// Close the `RoutingTable` associated with
// this instance (if any).
//
this.proxyTable.close();
}
//
// Close all sockets for all `HttpProxy` object(s)
// associated with this instance.
//
Object.keys(this.proxies).forEach(function (key) {
self.proxies[key].close();
});
};
//
// ### function proxyRequest (req, res, [port, host, paused])
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
// #### @res {ServerResponse} Outgoing HTTP Request to write proxied data to.
// #### @options {Object} Options for the outgoing proxy request.
//
// options.port {number} Port to use on the proxy target host.
// options.host {string} Host of the proxy target.
// options.buffer {Object} Result from `httpProxy.buffer(req)`
// options.https {Object|boolean} Settings for https.
//
RoutingProxy.prototype.proxyRequest = function (req, res, options) {
options = options || {};
var location;
//
// Check the proxy table for this instance to see if we need
// to get the proxy location for the request supplied. We will
// always ignore the proxyTable if an explicit `port` and `host`
// arguments are supplied to `proxyRequest`.
//
if (this.proxyTable && !options.host) {
location = this.proxyTable.getProxyLocation(req);
//
// If no location is returned from the ProxyTable instance
// then respond with `404` since we do not have a valid proxy target.
//
if (!location) {
try {
res.writeHead(404);
res.end();
}
catch (er) {
console.error("res.writeHead/res.end error: %s", er.message);
}
return;
}
//
// When using the ProxyTable in conjunction with an HttpProxy instance
// only the following arguments are valid:
//
// * `proxy.proxyRequest(req, res, { host: 'localhost' })`: This will be skipped
// * `proxy.proxyRequest(req, res, { buffer: buffer })`: Buffer will get updated appropriately
// * `proxy.proxyRequest(req, res)`: Options will be assigned appropriately.
//
options.port = location.port;
options.host = location.host;
}
var key = this._getKey(options),
proxy;
if ((this.target && this.target.https)
|| (location && location.protocol === 'https')) {
options.target = options.target || {};
options.target.https = true;
}
if (!this.proxies[key]) {
this.add(options);
}
proxy = this.proxies[key];
proxy.proxyRequest(req, res, options.buffer);
};
//
// ### function proxyWebSocketRequest (req, socket, head, options)
// #### @req {ServerRequest} Websocket request to proxy.
// #### @socket {net.Socket} Socket for the underlying HTTP request
// #### @head {string} Headers for the Websocket request.
// #### @options {Object} Options to use when proxying this request.
//
// options.port {number} Port to use on the proxy target host.
// options.host {string} Host of the proxy target.
// options.buffer {Object} Result from `httpProxy.buffer(req)`
// options.https {Object|boolean} Settings for https.
//
RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options) {
options = options || {};
var location,
proxy,
key;
if (this.proxyTable && !options.host) {
location = this.proxyTable.getProxyLocation(req);
if (!location) {
return socket.destroy();
}
options.port = location.port;
options.host = location.host;
}
key = this._getKey(options);
if (!this.proxies[key]) {
this.add(options);
}
proxy = this.proxies[key];
proxy.proxyWebSocketRequest(req, socket, head, options.buffer);
};
//
// ### @private function _getKey (options)
// #### @options {Object} Options to extract the key from
// Ensures that the appropriate options are present in the `options`
// provided and responds with a string key representing the `host`, `port`
// combination contained within.
//
RoutingProxy.prototype._getKey = function (options) {
if (!options || ((!options.host || !options.port)
&& (!options.target || !options.target.host || !options.target.port))) {
throw new Error('options.host and options.port or options.target are required.');
}
return [
options.host || options.target.host,
options.port || options.target.port
].join(':');
};

2028
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +1,41 @@
{
"name": "http-proxy",
"version": "0.8.2",
"description": "A full-featured http reverse proxy for node.js",
"author": "Nodejitsu Inc. <info@nodejitsu.com>",
"maintainers": [
"indexzero <charlie@nodejitsu.com>",
"AvianFlu <avianflu@nodejitsu.com>"
],
"version": "1.18.1",
"repository": {
"type": "git",
"url": "http://github.com/nodejitsu/node-http-proxy.git"
"url": "https://github.com/http-party/node-http-proxy.git"
},
"keywords": [
"reverse",
"proxy",
"http"
"description": "HTTP proxying for the masses",
"author": "Charlie Robbins <charlie.robbins@gmail.com>",
"maintainers": [
"jcrugzz <jcrugzz@gmail.com>"
],
"main": "index.js",
"dependencies": {
"colors": "0.x.x",
"optimist": "0.3.x",
"pkginfo": "0.2.x"
"eventemitter3": "^4.0.0",
"requires-port": "^1.0.0",
"follow-redirects": "^1.0.0"
},
"devDependencies": {
"request": "1.9.x",
"vows": "0.6.x",
"async": "0.1.x",
"socket.io": "0.9.6",
"socket.io-client": "0.9.6",
"ws": "0.4.21"
},
"main": "./lib/node-http-proxy",
"bin": {
"node-http-proxy": "./bin/node-http-proxy"
"async": "^3.0.0",
"auto-changelog": "^1.15.0",
"concat-stream": "^2.0.0",
"expect.js": "~0.3.1",
"mocha": "^3.5.3",
"nyc": "^14.0.0",
"semver": "^5.0.3",
"socket.io": "^2.1.0",
"socket.io-client": "^2.1.0",
"sse": "0.0.8",
"ws": "^3.0.0"
},
"scripts": {
"test": "npm run-script test-http && npm run-script test-https",
"test-http": "vows --spec && vows --spec --target=https",
"test-https": "vows --spec --proxy=https && vows --spec --proxy=https --target=https",
"test-core": "test/core/run"
"mocha": "mocha test/*-test.js",
"test": "nyc --reporter=text --reporter=lcov npm run mocha",
"version": "auto-changelog -p && git add CHANGELOG.md"
},
"engines": {
"node": ">= 0.6.6"
}
"node": ">=8.0.0"
},
"license": "MIT"
}

19
renovate.json Normal file
View File

@ -0,0 +1,19 @@
{
"platform": "github",
"autodiscover": false,
"requireConfig": true,
"ignoreNpmrcFile": true,
"rangeStrategy": "replace",
"packageRules": [
{
"packagePatterns": [
"*"
],
"minor": {
"groupName": "all non-major dependencies",
"groupSlug": "all-minor-patch"
}
}
],
"commitMessagePrefix": "[dist]"
}

View File

@ -1,10 +0,0 @@
# `test/core`
`test/core` directory is a place where tests from node.js core go. They are
here to ensure that node-http-proxy works just fine with all kinds of
different situations, which are covered in core tests, but are not covered in
our tests.
All these tests require little modifications to make them test node-http-proxy,
but we try to keep them as vanilla as possible.

View File

@ -1,145 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var path = require('path');
var assert = require('assert');
exports.testDir = path.dirname(__filename);
exports.fixturesDir = path.join(exports.testDir, 'fixtures');
exports.libDir = path.join(exports.testDir, '../lib');
exports.tmpDir = path.join(exports.testDir, 'tmp');
exports.PORT = 12346;
exports.PROXY_PORT = 1234567;
if (process.platform == 'win32') {
exports.PIPE = '\\\\.\\pipe\\libuv-test';
} else {
exports.PIPE = exports.tmpDir + '/test.sock';
}
var util = require('util');
for (var i in util) exports[i] = util[i];
//for (var i in exports) global[i] = exports[i];
function protoCtrChain(o) {
var result = [];
for (; o; o = o.__proto__) { result.push(o.constructor); }
return result.join();
}
exports.indirectInstanceOf = function(obj, cls) {
if (obj instanceof cls) { return true; }
var clsChain = protoCtrChain(cls.prototype);
var objChain = protoCtrChain(obj);
return objChain.slice(-clsChain.length) === clsChain;
};
exports.ddCommand = function(filename, kilobytes) {
if (process.platform == 'win32') {
return '"' + process.argv[0] + '" "' + path.resolve(exports.fixturesDir,
'create-file.js') + '" "' + filename + '" ' + (kilobytes * 1024);
} else {
return 'dd if=/dev/zero of="' + filename + '" bs=1024 count=' + kilobytes;
}
};
exports.spawnPwd = function(options) {
var spawn = require('child_process').spawn;
if (process.platform == 'win32') {
return spawn('cmd.exe', ['/c', 'cd'], options);
} else {
return spawn('pwd', [], options);
}
};
// Turn this off if the test should not check for global leaks.
exports.globalCheck = true;
process.on('exit', function() {
if (!exports.globalCheck) return;
var knownGlobals = [setTimeout,
setInterval,
clearTimeout,
clearInterval,
console,
Buffer,
process,
global];
if (global.errno) {
knownGlobals.push(errno);
}
if (global.gc) {
knownGlobals.push(gc);
}
if (global.DTRACE_HTTP_SERVER_RESPONSE) {
knownGlobals.push(DTRACE_HTTP_SERVER_RESPONSE);
knownGlobals.push(DTRACE_HTTP_SERVER_REQUEST);
knownGlobals.push(DTRACE_HTTP_CLIENT_RESPONSE);
knownGlobals.push(DTRACE_HTTP_CLIENT_REQUEST);
knownGlobals.push(DTRACE_NET_STREAM_END);
knownGlobals.push(DTRACE_NET_SERVER_CONNECTION);
knownGlobals.push(DTRACE_NET_SOCKET_READ);
knownGlobals.push(DTRACE_NET_SOCKET_WRITE);
}
if (global.ArrayBuffer) {
knownGlobals.push(ArrayBuffer);
knownGlobals.push(Int8Array);
knownGlobals.push(Uint8Array);
knownGlobals.push(Int16Array);
knownGlobals.push(Uint16Array);
knownGlobals.push(Int32Array);
knownGlobals.push(Uint32Array);
knownGlobals.push(Float32Array);
knownGlobals.push(Float64Array);
knownGlobals.push(DataView);
}
for (var x in global) {
var found = false;
for (var y in knownGlobals) {
if (global[x] === knownGlobals[y]) {
found = true;
break;
}
}
if (!found) {
console.error('Unknown global: %s', x);
assert.ok(false, 'Unknown global found');
}
}
});
// This function allows one two run an HTTP test agaist both HTTPS and
// normal HTTP modules. This ensures they fit the same API.
exports.httpTest = function httpTest(cb) {
};

View File

@ -1,69 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// This tests setTimeout() by having multiple clients connecting and sending
// data in random intervals. Clients are also randomly disconnecting until there
// are no more clients left. If no false timeout occurs, this test has passed.
var common = require('../common'),
assert = require('assert'),
http = require('http'),
server = http.createServer(),
connections = 0;
server.on('request', function(req, res) {
req.socket.setTimeout(1000);
req.socket.on('timeout', function() {
throw new Error('Unexpected timeout');
});
req.on('end', function() {
connections--;
res.writeHead(200);
res.end('done\n');
if (connections == 0) {
server.close();
}
});
});
server.listen(common.PORT, '127.0.0.1', function() {
for (var i = 0; i < 10; i++) {
connections++;
setTimeout(function() {
var request = http.request({
port: common.PROXY_PORT,
method: 'POST',
path: '/'
});
function ping() {
var nextPing = (Math.random() * 900).toFixed();
if (nextPing > 600) {
request.end();
return;
}
request.write('ping');
setTimeout(ping, nextPing);
}
ping();
}, i * 50);
}
});

View File

@ -1,90 +0,0 @@
#!/usr/bin/env node
/*
run.js: test runner for core tests
Copyright (c) 2011 Nodejitsu
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var fs = require('fs'),
path = require('path'),
spawn = require('child_process').spawn,
async = require('async'),
colors = require('colors'),
optimist = require('optimist');
optimist.argv.color && (colors.mode = optimist.argv.color);
var testTimeout = 15000;
var results = {};
function runTest(test, callback) {
var child = spawn(path.join(__dirname, 'run-single'), [ test ]);
var killTimeout = setTimeout(function () {
child.kill();
console.log(' ' + path.basename(test).yellow + ' timed out'.red);
}, testTimeout);
child.on('exit', function (exitCode) {
clearTimeout(killTimeout);
console.log(' ' + ((exitCode) ? '✘'.red : '✔'.green) + ' ' +
path.basename(test) +
(exitCode ? (' (exit code: ' + exitCode + ')') : ''));
results[test] = { exitCode: exitCode };
callback();
//
// We don't want tests to be stopped after first failure, and that's what
// async does when it receives truthy value in callback.
//
});
};
var tests = process.argv.slice(2).filter(function (test) {
return test.substr(0, 2) != '--';
});
if (!tests.length) {
var pathPrefix = path.join(__dirname, 'simple');
tests = fs.readdirSync(pathPrefix).map(function (test) {
return path.join(pathPrefix, test);
});
//
// We only run simple tests by default.
//
}
console.log('Running tests:'.bold);
async.forEachSeries(tests, runTest, function () {
var failed = [], ok = [];
for (var test in results) {
(results[test].exitCode != 0 ? failed : ok).push(test);
}
console.log('\nSummary:'.bold);
console.log((' ' + ok.length + '\tpassed tests').green);
console.log((' ' + failed.length + '\tfailed tests').red);
});
// vim:filetype=javascript

View File

@ -1,62 +0,0 @@
#!/usr/bin/env node
/*
run-single.js: test runner for core tests
Copyright (c) 2011 Nodejitsu
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
//
// Basic idea behind core test runner is to modify core tests as little as
// possible. That's why we start up node-http-proxy here instead of embeeding
// this code in tests.
//
// In most cases only modification to core tests you'll need is changing port
// of http client to common.PROXY_PORT.
//
var path = require('path'),
spawn = require('child_process').spawn,
httpProxy = require('../../'),
common = require('./common');
var test = process.argv[2];
if (!test) {
return console.error('Need test to run');
}
console.log('Running test ' + test);
var proxy = httpProxy.createServer(common.PORT, 'localhost');
proxy.listen(common.PROXY_PORT);
proxy.on('listening', function () {
console.log('Proxy server listening on ' + common.PROXY_PORT);
var testProcess = spawn(process.argv[0], [ process.argv[2] ]);
testProcess.stdout.pipe(process.stdout);
testProcess.stderr.pipe(process.stderr);
testProcess.on('exit', process.exit);
});
// vim:filetype=javascript

View File

@ -1,63 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var UTF8_STRING = '南越国是前203年至前111年存在于岭南地区的一个国家' +
'国都位于番禺,疆域包括今天中国的广东、广西两省区的大部份地区,福建省、湖南、' +
'贵州、云南的一小部份地区和越南的北部。南越国是秦朝灭亡后,' +
'由南海郡尉赵佗于前203年起兵兼并桂林郡和象郡后建立。前196年和前179年' +
'南越国曾先后两次名义上臣属于西汉成为西汉的“外臣”。前112年' +
'南越国末代君主赵建德与西汉发生战争被汉武帝于前111年所灭。' +
'南越国共存在93年历经五代君主。南越国是岭南地区的第一个有记载的政权国家' +
'采用封建制和郡县制并存的制度,它的建立保证了秦末乱世岭南地区社会秩序的稳定,' +
'有效的改善了岭南地区落后的政治、经济现状。';
var server = http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain; charset=utf8'});
res.end(UTF8_STRING, 'utf8');
});
server.listen(common.PORT, function() {
var data = '';
var get = http.get({
path: '/',
host: 'localhost',
port: common.PROXY_PORT
}, function(x) {
x.setEncoding('utf8');
x.on('data', function(c) {data += c});
x.on('error', function(e) {
throw e;
});
x.on('end', function() {
assert.equal('string', typeof data);
console.log('here is the response:');
assert.equal(UTF8_STRING, data);
console.log(data);
server.close();
});
});
get.on('error', function(e) {throw e});
get.end();
});

View File

@ -1,80 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var clientAborts = 0;
var server = http.Server(function(req, res) {
console.log('Got connection');
res.writeHead(200);
res.write('Working on it...');
// I would expect an error event from req or res that the client aborted
// before completing the HTTP request / response cycle, or maybe a new
// event like "aborted" or something.
req.on('aborted', function() {
clientAborts++;
console.log('Got abort ' + clientAborts);
if (clientAborts === N) {
console.log('All aborts detected, you win.');
server.close();
}
});
// since there is already clientError, maybe that would be appropriate,
// since "error" is magical
req.on('clientError', function() {
console.log('Got clientError');
});
});
var responses = 0;
var N = http.Agent.defaultMaxSockets - 1;
var requests = [];
server.listen(common.PORT, function() {
console.log('Server listening.');
for (var i = 0; i < N; i++) {
console.log('Making client ' + i);
var options = { port: common.PROXY_PORT, path: '/?id=' + i };
var req = http.get(options, function(res) {
console.log('Client response code ' + res.statusCode);
if (++responses == N) {
console.log('All clients connected, destroying.');
requests.forEach(function(outReq) {
console.log('abort');
outReq.abort();
});
}
});
requests.push(req);
}
});
process.on('exit', function() {
assert.equal(N, clientAborts);
});

View File

@ -1,41 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// libuv-broken
var common = require('../common');
var assert = require('assert');
var http = require('http');
var server = http.createServer(function(req, res) {
res.end('Hello');
});
server.listen(common.PORT, function() {
var req = http.get({port: common.PROXY_PORT}, function(res) {
res.on('data', function(data) {
req.abort();
server.close();
});
});
});

View File

@ -1,74 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var N = 1024;
var bytesRecieved = 0;
var server_req_complete = false;
var client_res_complete = false;
var server = http.createServer(function(req, res) {
assert.equal('POST', req.method);
req.on('data', function(chunk) {
bytesRecieved += chunk.length;
});
req.on('end', function() {
server_req_complete = true;
console.log('request complete from server');
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('hello\n');
res.end();
});
});
server.listen(common.PORT);
server.on('listening', function() {
var req = http.request({
port: common.PROXY_PORT,
method: 'POST',
path: '/'
}, function(res) {
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log(chunk);
});
res.on('end', function() {
client_res_complete = true;
server.close();
});
});
req.write(new Buffer(N));
req.end();
common.error('client finished sending request');
});
process.on('exit', function() {
assert.equal(N, bytesRecieved);
assert.equal(true, server_req_complete);
assert.equal(true, client_res_complete);
});

View File

@ -1,77 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var sent_body = '';
var server_req_complete = false;
var client_res_complete = false;
var server = http.createServer(function(req, res) {
assert.equal('POST', req.method);
req.setEncoding('utf8');
req.on('data', function(chunk) {
console.log('server got: ' + JSON.stringify(chunk));
sent_body += chunk;
});
req.on('end', function() {
server_req_complete = true;
console.log('request complete from server');
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('hello\n');
res.end();
});
});
server.listen(common.PORT);
server.on('listening', function() {
var req = http.request({
port: common.PROXY_PORT,
method: 'POST',
path: '/'
}, function(res) {
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log(chunk);
});
res.on('end', function() {
client_res_complete = true;
server.close();
});
});
req.write('1\n');
req.write('2\n');
req.write('3\n');
req.end();
common.error('client finished sending request');
});
process.on('exit', function() {
assert.equal('1\n2\n3\n', sent_body);
assert.equal(true, server_req_complete);
assert.equal(true, client_res_complete);
});

View File

@ -1,42 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var http = require('http');
// Simple test of Node's HTTP Client choking on a response
// with a 'Content-Length: 0 ' response header.
// I.E. a space character after the 'Content-Length' throws an `error` event.
var s = http.createServer(function(req, res) {
res.writeHead(200, {'Content-Length': '0 '});
res.end();
});
s.listen(common.PORT, function() {
var request = http.request({ port: common.PROXY_PORT }, function(response) {
console.log('STATUS: ' + response.statusCode);
s.close();
});
request.end();
});

View File

@ -1,40 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var net = require('net');
var http = require('http');
// This is a regression test for http://github.com/ry/node/issues/#issue/44
// It is separate from test-http-malformed-request.js because it is only
// reproduceable on the first packet on the first connection to a server.
var server = http.createServer(function(req, res) {});
server.listen(common.PORT);
server.on('listening', function() {
net.createConnection(common.PROXY_PORT).on('connect', function() {
this.destroy();
}).on('close', function() {
server.close();
});
});

View File

@ -1,86 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var net = require('net');
// If an HTTP server is broken and sends data after the end of the response,
// node should ignore it and drop the connection.
// Demos this bug: https://github.com/ry/node/issues/680
var body = 'hello world\r\n';
var fullResponse =
'HTTP/1.1 500 Internal Server Error\r\n' +
'Content-Length: ' + body.length + '\r\n' +
'Content-Type: text/plain\r\n' +
'Date: Fri + 18 Feb 2011 06:22:45 GMT\r\n' +
'Host: 10.20.149.2\r\n' +
'Access-Control-Allow-Credentials: true\r\n' +
'Server: badly broken/0.1 (OS NAME)\r\n' +
'\r\n' +
body;
var gotResponse = false;
var server = net.createServer(function(socket) {
var postBody = '';
socket.setEncoding('utf8');
socket.on('data', function(chunk) {
postBody += chunk;
if (postBody.indexOf('\r\n') > -1) {
socket.write(fullResponse);
// omg, I wrote the response twice, what a terrible HTTP server I am.
socket.end(fullResponse);
}
});
});
server.listen(common.PORT, function() {
http.get({ port: common.PROXY_PORT }, function(res) {
var buffer = '';
console.log('Got res code: ' + res.statusCode);
res.setEncoding('utf8');
res.on('data', function(chunk) {
buffer += chunk;
});
res.on('end', function() {
console.log('Response ended, read ' + buffer.length + ' bytes');
assert.equal(body, buffer);
server.close();
gotResponse = true;
});
});
});
process.on('exit', function() {
assert.ok(gotResponse);
});

View File

@ -1,56 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var util = require('util');
var body = 'hello world\n';
var server = http.createServer(function(req, res) {
common.error('req: ' + req.method);
res.writeHead(200, {'Content-Length': body.length});
res.end();
server.close();
});
var gotEnd = false;
server.listen(common.PORT, function() {
var request = http.request({
port: common.PROXY_PORT,
method: 'HEAD',
path: '/'
}, function(response) {
common.error('response start');
response.on('end', function() {
common.error('response end');
gotEnd = true;
});
});
request.end();
});
process.on('exit', function() {
assert.ok(gotEnd);
});

View File

@ -1,61 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// libuv-broken
var common = require('../common');
var assert = require('assert');
var http = require('http');
// This test is to make sure that when the HTTP server
// responds to a HEAD request with data to res.end,
// it does not send any body.
var server = http.createServer(function(req, res) {
res.writeHead(200);
res.end('FAIL'); // broken: sends FAIL from hot path.
});
server.listen(common.PORT);
var responseComplete = false;
server.on('listening', function() {
var req = http.request({
port: common.PROXY_PORT,
method: 'HEAD',
path: '/'
}, function(res) {
common.error('response');
res.on('end', function() {
common.error('response end');
server.close();
responseComplete = true;
});
});
common.error('req');
req.end();
});
process.on('exit', function() {
assert.ok(responseComplete);
});

View File

@ -1,58 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
// This test is to make sure that when the HTTP server
// responds to a HEAD request, it does not send any body.
// In this case it was sending '0\r\n\r\n'
var server = http.createServer(function(req, res) {
res.writeHead(200); // broken: defaults to TE chunked
res.end();
});
server.listen(common.PORT);
var responseComplete = false;
server.on('listening', function() {
var req = http.request({
port: common.PROXY_PORT,
method: 'HEAD',
path: '/'
}, function(res) {
common.error('response');
res.on('end', function() {
common.error('response end');
server.close();
responseComplete = true;
});
});
common.error('req');
req.end();
});
process.on('exit', function() {
assert.ok(responseComplete);
});

View File

@ -1,101 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// libuv-broken
var http = require('http'),
common = require('../common'),
assert = require('assert'),
httpServer = http.createServer(reqHandler);
function reqHandler(req, res) {
console.log('Got request: ' + req.headers.host + ' ' + req.url);
if (req.url === '/setHostFalse5') {
assert.equal(req.headers.host, undefined);
} else {
assert.equal(req.headers.host, 'localhost:' + common.PROXY_PORT,
'Wrong host header for req[' + req.url + ']: ' +
req.headers.host);
}
res.writeHead(200, {});
//process.nextTick(function() { res.end('ok'); });
res.end('ok');
}
function thrower(er) {
throw er;
}
testHttp();
function testHttp() {
console.log('testing http on port ' + common.PROXY_PORT + ' (proxied to ' +
common.PORT + ')');
var counter = 0;
function cb() {
counter--;
console.log('back from http request. counter = ' + counter);
if (counter === 0) {
httpServer.close();
}
}
httpServer.listen(common.PORT, function(er) {
console.error('listening on ' + common.PORT);
if (er) throw er;
http.get({ method: 'GET',
path: '/' + (counter++),
host: 'localhost',
//agent: false,
port: common.PROXY_PORT }, cb).on('error', thrower);
http.request({ method: 'GET',
path: '/' + (counter++),
host: 'localhost',
//agent: false,
port: common.PROXY_PORT }, cb).on('error', thrower).end();
http.request({ method: 'POST',
path: '/' + (counter++),
host: 'localhost',
//agent: false,
port: common.PROXY_PORT }, cb).on('error', thrower).end();
http.request({ method: 'PUT',
path: '/' + (counter++),
host: 'localhost',
//agent: false,
port: common.PROXY_PORT }, cb).on('error', thrower).end();
http.request({ method: 'DELETE',
path: '/' + (counter++),
host: 'localhost',
//agent: false,
port: common.PROXY_PORT }, cb).on('error', thrower).end();
});
}

View File

@ -1,57 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var net = require('net');
var http = require('http');
var url = require('url');
// Make sure no exceptions are thrown when receiving malformed HTTP
// requests.
var nrequests_completed = 0;
var nrequests_expected = 1;
var server = http.createServer(function(req, res) {
console.log('req: ' + JSON.stringify(url.parse(req.url)));
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello World');
res.end();
if (++nrequests_completed == nrequests_expected) server.close();
});
server.listen(common.PORT);
server.on('listening', function() {
var c = net.createConnection(common.PROXY_PORT);
c.on('connect', function() {
c.write('GET /hello?foo=%99bar HTTP/1.1\r\n\r\n');
c.end();
});
// TODO add more!
});
process.on('exit', function() {
assert.equal(nrequests_expected, nrequests_completed);
});

View File

@ -1,68 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var expected = 10000;
var responses = 0;
var requests = 0;
var connection;
var server = http.Server(function(req, res) {
requests++;
assert.equal(req.connection, connection);
res.writeHead(200);
res.end('hello world\n');
});
server.once('connection', function(c) {
connection = c;
});
server.listen(common.PORT, function() {
var callee = arguments.callee;
var request = http.get({
port: common.PROXY_PORT,
path: '/',
headers: {
'Connection': 'Keep-alive'
}
}, function(res) {
res.on('end', function() {
if (++responses < expected) {
callee();
} else {
process.exit();
}
});
}).on('error', function(e) {
console.log(e.message);
process.exit(1);
});
request.agent.maxSockets = 1;
});
process.on('exit', function() {
assert.equal(expected, responses);
assert.equal(expected, requests);
});

View File

@ -1,59 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var net = require('net');
var gotResponse = false;
var server = net.createServer(function(conn) {
var body = 'Yet another node.js server.';
var response =
'HTTP/1.1 200 OK\r\n' +
'Connection: close\r\n' +
'Content-Length: ' + body.length + '\r\n' +
'Content-Type: text/plain;\r\n' +
' x-unix-mode=0600;\r\n' +
' name=\"hello.txt\"\r\n' +
'\r\n' +
body;
conn.write(response, function() {
conn.destroy();
server.close();
});
});
server.listen(common.PORT, function() {
http.get({host: '127.0.0.1', port: common.PROXY_PORT}, function(res) {
assert.equal(res.headers['content-type'],
'text/plain;x-unix-mode=0600;name="hello.txt"');
gotResponse = true;
});
});
process.on('exit', function() {
assert.ok(gotResponse);
});

View File

@ -1,109 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var url = require('url');
var PROXY_PORT = common.PORT;
var BACKEND_PORT = common.PORT + 1;
var cookies = [
'session_token=; path=/; expires=Sun, 15-Sep-2030 13:48:52 GMT',
'prefers_open_id=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT'
];
var headers = {'content-type': 'text/plain',
'set-cookie': cookies,
'hello': 'world' };
var backend = http.createServer(function(req, res) {
common.debug('backend request');
res.writeHead(200, headers);
res.write('hello world\n');
res.end();
});
var proxy = http.createServer(function(req, res) {
common.debug('proxy req headers: ' + JSON.stringify(req.headers));
var proxy_req = http.get({
port: BACKEND_PORT,
path: url.parse(req.url).pathname
}, function(proxy_res) {
common.debug('proxy res headers: ' + JSON.stringify(proxy_res.headers));
assert.equal('world', proxy_res.headers['hello']);
assert.equal('text/plain', proxy_res.headers['content-type']);
assert.deepEqual(cookies, proxy_res.headers['set-cookie']);
res.writeHead(proxy_res.statusCode, proxy_res.headers);
proxy_res.on('data', function(chunk) {
res.write(chunk);
});
proxy_res.on('end', function() {
res.end();
common.debug('proxy res');
});
});
});
var body = '';
var nlistening = 0;
function startReq() {
nlistening++;
if (nlistening < 2) return;
var client = http.get({
port: common.PROXY_PORT,
path: '/test'
}, function(res) {
common.debug('got res');
assert.equal(200, res.statusCode);
assert.equal('world', res.headers['hello']);
assert.equal('text/plain', res.headers['content-type']);
assert.deepEqual(cookies, res.headers['set-cookie']);
res.setEncoding('utf8');
res.on('data', function(chunk) { body += chunk; });
res.on('end', function() {
proxy.close();
backend.close();
common.debug('closed both');
});
});
common.debug('client req');
}
common.debug('listen proxy');
proxy.listen(PROXY_PORT, startReq);
common.debug('listen backend');
backend.listen(BACKEND_PORT, startReq);
process.on('exit', function() {
assert.equal(body, 'hello world\n');
});

View File

@ -1,55 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var gotEnd = false;
var server = http.createServer(function(req, res) {
res.writeHead(200);
res.write('a');
req.on('close', function() {
console.error('aborted');
gotEnd = true;
});
});
server.listen(common.PORT);
server.on('listening', function() {
console.error('make req');
http.get({
port: common.PROXY_PORT
}, function(res) {
console.error('got res');
res.on('data', function(data) {
console.error('destroy res');
res.destroy();
server.close();
});
});
});
process.on('exit', function() {
assert.ok(gotEnd);
});

View File

@ -1,59 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// Verify that the HTTP server implementation handles multiple instances
// of the same header as per RFC2616: joining the handful of fields by ', '
// that support it, and dropping duplicates for other fields.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var srv = http.createServer(function(req, res) {
assert.equal(req.headers.accept, 'abc, def, ghijklmnopqrst');
assert.equal(req.headers.host, 'foo');
assert.equal(req.headers['x-foo'], 'bingo');
assert.equal(req.headers['x-bar'], 'banjo, bango');
res.writeHead(200, {'Content-Type' : 'text/plain'});
res.end('EOF');
srv.close();
});
srv.listen(common.PORT, function() {
http.get({
host: 'localhost',
port: common.PROXY_PORT,
path: '/',
headers: [
['accept', 'abc'],
['accept', 'def'],
['Accept', 'ghijklmnopqrst'],
['host', 'foo'],
['Host', 'bar'],
['hOst', 'baz'],
['x-foo', 'bingo'],
['x-bar', 'banjo'],
['x-bar', 'bango']
]
});
});

View File

@ -1,84 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var nresponses = 0;
var server = http.createServer(function(req, res) {
if (req.url == '/one') {
res.writeHead(200, [['set-cookie', 'A'],
['content-type', 'text/plain']]);
res.end('one\n');
} else {
res.writeHead(200, [['set-cookie', 'A'],
['set-cookie', 'B'],
['content-type', 'text/plain']]);
res.end('two\n');
}
});
server.listen(common.PORT);
server.on('listening', function() {
//
// one set-cookie header
//
http.get({ port: common.PROXY_PORT, path: '/one' }, function(res) {
// set-cookie headers are always return in an array.
// even if there is only one.
assert.deepEqual(['A'], res.headers['set-cookie']);
assert.equal('text/plain', res.headers['content-type']);
res.on('data', function(chunk) {
console.log(chunk.toString());
});
res.on('end', function() {
if (++nresponses == 2) {
server.close();
}
});
});
// two set-cookie headers
http.get({ port: common.PROXY_PORT, path: '/two' }, function(res) {
assert.deepEqual(['A', 'B'], res.headers['set-cookie']);
assert.equal('text/plain', res.headers['content-type']);
res.on('data', function(chunk) {
console.log(chunk.toString());
});
res.on('end', function() {
if (++nresponses == 2) {
server.close();
}
});
});
});
process.on('exit', function() {
assert.equal(2, nresponses);
});

View File

@ -1,69 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// libuv-broken
var common = require('../common');
var assert = require('assert');
var http = require('http');
// Simple test of Node's HTTP ServerResponse.statusCode
// ServerResponse.prototype.statusCode
var testsComplete = 0;
var tests = [200, 202, 300, 404, 500];
var testIdx = 0;
var s = http.createServer(function(req, res) {
var t = tests[testIdx];
res.writeHead(t, {'Content-Type': 'text/plain'});
console.log('--\nserver: statusCode after writeHead: ' + res.statusCode);
assert.equal(res.statusCode, t);
res.end('hello world\n');
});
s.listen(common.PORT, nextTest);
function nextTest() {
if (testIdx + 1 === tests.length) {
return s.close();
}
var test = tests[testIdx];
http.get({ port: common.PROXY_PORT }, function(response) {
console.log('client: expected status: ' + test);
console.log('client: statusCode: ' + response.statusCode);
assert.equal(response.statusCode, test);
response.on('end', function() {
testsComplete++;
testIdx += 1;
nextTest();
});
});
}
process.on('exit', function() {
assert.equal(4, testsComplete);
});

View File

@ -1,72 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var net = require('net');
var server = http.createServer(function(req, res) {
common.error('got req');
throw new Error('This shouldn\'t happen.');
});
server.on('upgrade', function(req, socket, upgradeHead) {
common.error('got upgrade event');
// test that throwing an error from upgrade gets
// is uncaught
throw new Error('upgrade error');
});
var gotError = false;
process.on('uncaughtException', function(e) {
common.error('got \'clientError\' event');
assert.equal('upgrade error', e.message);
gotError = true;
process.exit(0);
});
server.listen(common.PORT, function() {
var c = net.createConnection(common.PROXY_PORT);
c.on('connect', function() {
common.error('client wrote message');
c.write('GET /blah HTTP/1.1\r\n' +
'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' +
'\r\n\r\nhello world');
});
c.on('end', function() {
c.end();
});
c.on('close', function() {
common.error('client close');
server.close();
});
});
process.on('exit', function() {
assert.ok(gotError);
});

View File

@ -1,108 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var url = require('url');
function p(x) {
common.error(common.inspect(x));
}
var responses_sent = 0;
var responses_recvd = 0;
var body0 = '';
var body1 = '';
var server = http.Server(function(req, res) {
if (responses_sent == 0) {
assert.equal('GET', req.method);
assert.equal('/hello', url.parse(req.url).pathname);
console.dir(req.headers);
assert.equal(true, 'accept' in req.headers);
assert.equal('*/*', req.headers['accept']);
assert.equal(true, 'foo' in req.headers);
assert.equal('bar', req.headers['foo']);
}
if (responses_sent == 1) {
assert.equal('POST', req.method);
assert.equal('/world', url.parse(req.url).pathname);
this.close();
}
req.on('end', function() {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('The path was ' + url.parse(req.url).pathname);
res.end();
responses_sent += 1;
});
//assert.equal('127.0.0.1', res.connection.remoteAddress);
});
server.listen(common.PORT);
server.on('listening', function() {
var agent = new http.Agent({ port: common.PROXY_PORT, maxSockets: 1 });
http.get({
port: common.PROXY_PORT,
path: '/hello',
headers: {'Accept': '*/*', 'Foo': 'bar'},
agent: agent
}, function(res) {
assert.equal(200, res.statusCode);
responses_recvd += 1;
res.setEncoding('utf8');
res.on('data', function(chunk) { body0 += chunk; });
common.debug('Got /hello response');
});
setTimeout(function() {
var req = http.request({
port: common.PROXY_PORT,
method: 'POST',
path: '/world',
agent: agent
}, function(res) {
assert.equal(200, res.statusCode);
responses_recvd += 1;
res.setEncoding('utf8');
res.on('data', function(chunk) { body1 += chunk; });
common.debug('Got /world response');
});
req.end();
}, 1);
});
process.on('exit', function() {
common.debug('responses_recvd: ' + responses_recvd);
assert.equal(2, responses_recvd);
common.debug('responses_sent: ' + responses_sent);
assert.equal(2, responses_sent);
assert.equal('The path was /hello', body0);
assert.equal('The path was /world', body1);
});

71
test/examples-test.js Normal file
View File

@ -0,0 +1,71 @@
/*
examples-test.js: Test to run all the examples
Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
*/
var path = require('path'),
fs = require('fs'),
spawn = require('child_process').spawn,
expect = require('expect.js'),
async = require('async');
var rootDir = path.join(__dirname, '..'),
examplesDir = path.join(rootDir, 'examples');
describe.skip('http-proxy examples', function () {
describe('Before testing examples', function () {
// Set a timeout to avoid this error
this.timeout(30 * 1000);
it('should have installed dependencies', function (done) {
async.waterfall([
//
// 1. Read files in examples dir
//
async.apply(fs.readdir, examplesDir),
//
// 2. If node_modules exists, continue. Otherwise
// exec `npm` to install them
//
function checkNodeModules(files, next) {
if (files.indexOf('node_modules') !== -1) {
return next();
}
console.log('Warning: installing dependencies, this operation could take a while');
var child = spawn('npm', ['install', '-f'], {
cwd: examplesDir
});
child.on('exit', function (code) {
return code
? next(new Error('npm install exited with non-zero exit code'))
: next();
});
},
//
// 3. Read files in examples dir again to ensure the install
// worked as expected.
//
async.apply(fs.readdir, examplesDir),
], done);
})
});
describe('Requiring all the examples', function () {
it('should have no errors', function (done) {
async.each(['balancer', 'http', 'middleware', 'websocket'], function (dir, cb) {
var name = 'examples/' + dir,
files = fs.readdirSync(path.join(rootDir, 'examples', dir));
async.each(files, function (file, callback) {
var example;
expect(function () { example = require(path.join(examplesDir, dir, file)); }).to.not.throwException();
expect(example).to.be.an('object');
callback();
}, cb);
}, done);
})
})
})

View File

@ -1,13 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIB7DCCAZYCCQC7gs0MDNn6MTANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJV
UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO
BgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEgMB4GCSqGSIb3DQEJARYR
cnlAdGlueWNsb3Vkcy5vcmcwHhcNMTEwMzE0MTgyOTEyWhcNMzgwNzI5MTgyOTEy
WjB9MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYD
VQQKEwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEg
MB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwXDANBgkqhkiG9w0BAQEF
AANLADBIAkEAyXb8FrRdKbhrKLgLSsn61i1C7w7fVVVd7OQsmV/7p9WB2lWFiDlC
WKGU9SiIz/A6wNZDUAuc2E+VwtpCT561AQIDAQABMA0GCSqGSIb3DQEBBQUAA0EA
C8HzpuNhFLCI3A5KkBS5zHAQax6TFUOhbpBCR0aTDbJ6F1liDTK1lmU/BjvPoj+9
1LHwrmh29rK8kBPEjmymCQ==
MIIEIDCCAggCCQChRDh/XiBF+zANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJ1
czETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEeMBwGA1UE
AwwVRHVtbXkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDYyMjIwMzEwNFoXDTMyMDIy
OTIwMzEwNFowUDELMAkGA1UEBhMCdXMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAO
BgNVBAcMB1NlYXR0bGUxGjAYBgNVBAMMEWR1bW15LmV4YW1wbGUuY29tMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvSQq3d8AeZMTvtqZ13jWCckikyXJ
SACvkGCQUCJqOceESbg6IHdRzQdoccE4P3sbvNsf9BlbdJKM+neCxabqKaU1PPje
4P0tHT57t6yJrMuUh9NxEz3Bgh1srNHVS7saKvwHmcKm79jc+wxlioPmEQvQagjn
y7oTkyLt0sn4LGxBjrcv2JoHOC9f1pxX7l47MaiN0/ctRau7Nr3PFn+pkB4Yf6Z0
VyicVJbaUSz39Qo4HQWl1L2hiBP3CS1oKs2Yk0O1aOCMExWrhZQan+ZgHqL1rhgm
kPpw2/zwwPt5Vf9CSakvHwg198EXuTTXtkzYduuIJAm8yp969iEIiG2xTwIDAQAB
MA0GCSqGSIb3DQEBCwUAA4ICAQBnMSIo+kujkeXPh+iErFBmNtu/7EA+i/QnFPbN
lSLngclYYBJAGQI+DhirJI8ghDi6vmlHB2THewDaOJXEKvC1czE8064wioIcA9HJ
l3QJ3YYOFRctYdSHBU4TWdJbPgkLWDzYP5smjOfw8nDdr4WO/5jh9qRFcFpTFmQf
DyU3xgWLsQnNK3qXLdJjWG75pEhHR+7TGo+Ob/RUho/1RX/P89Ux7/oVbzdKqqFu
SErXAsjEIEFzWOM2uDOt6hrxDF6q+8/zudwQNEo422poEcTT9tDEFxMQ391CzZRi
nozBm4igRn1f5S3YZzLI6VEUns0s76BNy2CzvFWn40DziTqNBExAMfFFj76wiMsX
6fTIdcvkaTBa0S9SZB0vN99qahBdcG17rt4RssMHVRH1Wn7NXMwe476L0yXZ6gO7
Z4uNAPxgaI3BRP75EPfslLutCLZ+BC4Zzu6MY0Salbpfl0Go462EhsKCxvYhE2Dg
T477pICLfETZfA499Fd1tOaIsoLCrILAia/+Yd76uf94MuXUIqykDng/4H7xCc47
BZhNFJiPC6XHaXzN7NYSEUNX9VOwY8ncxKwtP6TXga96PdMUy/p98KIM8RZlDoxB
Xy9dcZBFNn/zrqjW7R0CCWCUriDIFSmEP0wDZ91YYa6BVuJMb5uL/USkTLpjZS4/
HNGvug==
-----END CERTIFICATE-----

View File

@ -1,10 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBXTCCAQcCAQAwfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQH
EwJTRjEPMA0GA1UEChMGSm95ZW50MRAwDgYDVQQLEwdOb2RlLmpzMQ8wDQYDVQQD
EwZhZ2VudDIxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMFwwDQYJ
KoZIhvcNAQEBBQADSwAwSAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf
+6fVgdpVhYg5QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAaAlMCMGCSqG
SIb3DQEJBzEWExRBIGNoYWxsZW5nZSBwYXNzd29yZDANBgkqhkiG9w0BAQUFAANB
AJnll2pt5l0pzskQSpjjLVTlFDFmJr/AZ3UK8v0WxBjYjCe5Jx4YehkChpxIyDUm
U3J9q9MDUf0+Y2+EGkssFfk=
-----END CERTIFICATE REQUEST-----

View File

@ -1,9 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf+6fVgdpVhYg5
QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAQJBAMT6Bf34+UHKY1ObpsbH
9u2jsVblFq1rWvs8GPMY6oertzvwm3DpuSUp7PTgOB1nLTLYtCERbQ4ovtN8tn3p
OHUCIQDzIEGsoCr5vlxXvy2zJwu+fxYuhTZWMVuo1397L0VyhwIhANQh+yzqUgaf
WRtSB4T2W7ADtJI35ET61jKBty3CqJY3AiAIwju7dVW3A5WeD6Qc1SZGKZvp9yCb
AFI2BfVwwaY11wIgXF3PeGcvACMyMWsuSv7aPXHfliswAbkWuzcwA4TW01ECIGWa
cgsDvVFxmfM5NPSuT/UDTa6R5BFISB5ea0N0AR3I
MIIEpQIBAAKCAQEAvSQq3d8AeZMTvtqZ13jWCckikyXJSACvkGCQUCJqOceESbg6
IHdRzQdoccE4P3sbvNsf9BlbdJKM+neCxabqKaU1PPje4P0tHT57t6yJrMuUh9Nx
Ez3Bgh1srNHVS7saKvwHmcKm79jc+wxlioPmEQvQagjny7oTkyLt0sn4LGxBjrcv
2JoHOC9f1pxX7l47MaiN0/ctRau7Nr3PFn+pkB4Yf6Z0VyicVJbaUSz39Qo4HQWl
1L2hiBP3CS1oKs2Yk0O1aOCMExWrhZQan+ZgHqL1rhgmkPpw2/zwwPt5Vf9CSakv
Hwg198EXuTTXtkzYduuIJAm8yp969iEIiG2xTwIDAQABAoIBAGPIw/C/qJF7HYyv
6T+7GTiaa2o0IiehbP3/Y8NTFLWc49a8obXlHTvMr7Zr2I/tE+ojtIzkH9K1SjkN
eelqsNj9tsOPDI6oIvftsflpxkxqLtclnt8m0oMhoObf4OaONDT/N8dP4SBiSdsM
ZDmacnMFx5NZVWiup4sVf2CYexx7qks9FhyN2K5PArCQ4S9LHjFhSJVH4DSEpv7E
Ykbp30rhpqV7wSwjgUsm8ZYvI2NOlmffzLSiPdt3vy2K5Q25S/MVEAicg83rfDgK
6EluHjeygRI1xU6DJ0hU7tnU7zE9KURoHPUycO3BKzZnzUH26AA36I58Pu4fXWw/
Cgmbv2ECgYEA+og9E4ziKCEi3p8gqjIfwTRgWZxDLjEzooB/K0UhEearn/xiX29A
FiSzEHKfCB4uSrw5OENg2ckDs8uy08Qmxx7xFXL7AtufAl5fIYaWa0sNSqCaIk7p
ebbUmPcaYhKiLzIEd1EYEL38sXVZ62wvSVMRSWvEMq44g1qnoRlDa/8CgYEAwUTt
talYNwVmR9ZdkVEWm9ZxirdzoM6NaM6u4Tf34ygptpapdmIFSUhfq4iOiEnRGNg/
tuNqhNCIb3LNpJbhRPEzqN7E7qiF/mp7AcJgbuxLZBm12QuLuJdG3nrisKPFXcY1
lA4A7CFmNgH3E4THFfgwzyDXsBOxVLXleTqn+rECgYEA9up1P6J3dtOJuV2d5P/3
ugRz/X173LfTSxJXw36jZDAy8D/feG19/RT4gnplcKvGNhQiVOhbOOnbw0U8n2fQ
TCmbs+cZqyxnH/+AxNsPvvk+RVHZ93xMsY/XIldP4l65B8jFDA+Zp06IESI2mEeM
pzi+bd1Phh+dRSCA2865W2MCgYEAlxYsgmQ1WyX0dFpHYU+zzfXRYzDQyrhOYc2Z
duVK+yCto1iad7pfCY/zgmRJkI+sT7DV9kJIRjXDQuTLkEyHJF8vFGe6KhxCS8aw
DIsI2g4NTd6vg1J8UryoIUqNpqsQoqNNxUVBQVdG0ReuMGsPO8R/W50AIFz0txVP
o/rP0LECgYEA7e/mOwCnR+ovmS/CAksmos3oIqvkRkXNKpKe513FVmp3TpTU38ex
cBkFNU3hEO31FyrX1hGIKp3N5mHYSQ1lyODHM6teHW0OLWWTwIe8rIGvR2jfRLe0
bbkdj40atYVkfeFmpz9uHHG24CUYxJdPc360jbXTVp4i3q8zqgL5aMY=
-----END RSA PRIVATE KEY-----

View File

@ -1,19 +0,0 @@
[ req ]
default_bits = 1024
days = 999
distinguished_name = req_distinguished_name
attributes = req_attributes
prompt = no
[ req_distinguished_name ]
C = US
ST = CA
L = SF
O = Joyent
OU = Node.js
CN = agent2
emailAddress = ry@tinyclouds.org
[ req_attributes ]
challengePassword = A challenge password

View File

@ -1,168 +0,0 @@
/*
* http.js: Top level include for node-http-proxy http helpers
*
* (C) 2010 Nodejitsu Inc.
* MIT LICENCE
*
*/
var assert = require('assert'),
http = require('http'),
https = require('https'),
url = require('url'),
async = require('async'),
helpers = require('./index'),
protocols = helpers.protocols,
httpProxy = require('../../lib/node-http-proxy');
//
// ### function createServerPair (options, callback)
// #### @options {Object} Options to create target and proxy server.
// #### @callback {function} Continuation to respond to when complete.
//
// Creates http target and proxy servers
//
exports.createServerPair = function (options, callback) {
async.series([
//
// 1. Create the target server
//
function createTarget(next) {
exports.createServer(options.target, next);
},
//
// 2. Create the proxy server
//
function createTarget(next) {
exports.createProxyServer(options.proxy, next);
}
], callback);
};
//
// ### function createServer (options, callback)
// #### @options {Object} Options for creatig an http server.
// #### @port {number} Port to listen on
// #### @output {string} String to write to each HTTP response
// #### @headers {Object} Headers to assert are sent by `node-http-proxy`.
// #### @callback {function} Continuation to respond to when complete.
//
// Creates a target server that the tests will proxy to.
//
exports.createServer = function (options, callback) {
//
// Request handler to use in either `http`
// or `https` server.
//
function requestHandler(req, res) {
if (options.headers) {
Object.keys(options.headers).forEach(function (key) {
assert.equal(req.headers[key], options.headers[key]);
});
}
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write(options.output || 'hello proxy');
res.end();
}
var server = protocols.target === 'https'
? https.createServer(helpers.https, requestHandler)
: http.createServer(requestHandler);
server.listen(options.port, function () {
callback(null, this);
});
};
//
// ### function createProxyServer (options, callback)
// #### @options {Object} Options for creatig an http server.
// #### @port {number} Port to listen on
// #### @latency {number} Latency of this server in milliseconds
// #### @proxy {Object} Options to pass to the HttpProxy.
// #### @routing {boolean} Enables `httpProxy.RoutingProxy`
// #### @callback {function} Continuation to respond to when complete.
//
// Creates a proxy server that the tests will request against.
//
exports.createProxyServer = function (options, callback) {
if (!options.latency) {
if (protocols.proxy === 'https') {
options.proxy.https = helpers.https;
}
return httpProxy
.createServer(options.proxy)
.listen(options.port, function () {
callback(null, this);
});
}
var server,
proxy;
proxy = options.routing
? new httpProxy.RoutingProxy(options.proxy)
: new httpProxy.HttpProxy(options.proxy);
//
// Request handler to use in either `http`
// or `https` server.
//
function requestHandler(req, res) {
var buffer = httpProxy.buffer(req);
setTimeout(function () {
//
// Setup options dynamically for `RoutingProxy.prototype.proxyRequest`
// or `HttpProxy.prototype.proxyRequest`.
//
buffer = options.routing ? { buffer: buffer } : buffer;
proxy.proxyRequest(req, res, buffer);
}, options.latency);
}
server = protocols.proxy === 'https'
? https.createServer(helpers.https, requestHandler)
: http.createServer(requestHandler);
server.listen(options.port, function () {
callback(null, this);
});
};
//
// ### function assignPortsToRoutes (routes)
// #### @routes {Object} Routing table to assign ports to
//
// Assigns dynamic ports to the `routes` for runtime testing.
//
exports.assignPortsToRoutes = function (routes) {
Object.keys(routes).forEach(function (source) {
routes[source] = routes[source].replace('{PORT}', helpers.nextPort);
});
return routes;
};
//
// ### function parseRoutes (options)
// #### @options {Object} Options to use when parsing routes
// #### @protocol {string} Protocol to use in the routes
// #### @routes {Object} Routes to parse.
//
// Returns an Array of fully-parsed URLs for the source and
// target of `options.routes`.
//
exports.parseRoutes = function (options) {
var protocol = options.protocol || 'http',
routes = options.routes;
return Object.keys(routes).map(function (source) {
return {
source: url.parse(protocol + '://' + source),
target: url.parse(protocol + '://' + routes[source])
};
});
};

View File

@ -1,105 +0,0 @@
/*
* index.js: Top level include for node-http-proxy helpers
*
* (C) 2010 Nodejitsu Inc.
* MIT LICENCE
*
*/
var fs = require('fs'),
path = require('path');
var fixturesDir = path.join(__dirname, '..', 'fixtures');
//
// @https {Object}
// Returns the necessary `https` credentials.
//
Object.defineProperty(exports, 'https', {
get: function () {
delete this.https;
return this.https = {
key: fs.readFileSync(path.join(fixturesDir, 'agent2-key.pem'), 'utf8'),
cert: fs.readFileSync(path.join(fixturesDir, 'agent2-cert.pem'), 'utf8')
};
}
});
//
// @protocols {Object}
// Returns an object representing the desired protocols
// for the `proxy` and `target` server.
//
Object.defineProperty(exports, 'protocols', {
get: function () {
delete this.protocols;
return this.protocols = {
target: exports.argv.target || 'http',
proxy: exports.argv.proxy || 'http'
};
}
});
//
// @nextPort {number}
// Returns an auto-incrementing port for tests.
//
Object.defineProperty(exports, 'nextPort', {
get: function () {
var current = this.port || 8000;
this.port = current + 1;
return current;
}
});
//
// @nextPortPair {Object}
// Returns an auto-incrementing pair of ports for tests.
//
Object.defineProperty(exports, 'nextPortPair', {
get: function () {
return {
target: this.nextPort,
proxy: this.nextPort
};
}
});
//
// ### function describe(prefix)
// #### @prefix {string} Prefix to use before the description
//
// Returns a string representing the protocols that this suite
// is testing based on CLI arguments.
//
exports.describe = function (prefix, base) {
prefix = prefix || '';
base = base || 'http';
function protocol(endpoint) {
return exports.protocols[endpoint] === 'https'
? base + 's'
: base;
}
return [
'node-http-proxy',
prefix,
[
protocol('proxy'),
'-to-',
protocol('target')
].join('')
].filter(Boolean).join('/');
};
//
// Expose the CLI arguments
//
exports.argv = require('optimist').argv;
//
// Export additional helpers for `http` and `websockets`.
//
exports.http = require('./http');
exports.ws = require('./ws');

View File

@ -1,112 +0,0 @@
/*
* ws.js: Top level include for node-http-proxy websocket helpers
*
* (C) 2010 Nodejitsu Inc.
* MIT LICENCE
*
*/
var assert = require('assert'),
https = require('https'),
async = require('async'),
io = require('socket.io'),
ws = require('ws'),
helpers = require('./index'),
protocols = helpers.protocols,
http = require('./http');
//
// ### function createServerPair (options, callback)
// #### @options {Object} Options to create target and proxy server.
// #### @target {Object} Options for the target server.
// #### @proxy {Object} Options for the proxy server.
// #### @callback {function} Continuation to respond to when complete.
//
// Creates http target and proxy servers
//
exports.createServerPair = function (options, callback) {
async.series([
//
// 1. Create the target server
//
function createTarget(next) {
exports.createServer(options.target, next);
},
//
// 2. Create the proxy server
//
function createTarget(next) {
http.createProxyServer(options.proxy, next);
}
], callback);
};
//
// ### function createServer (options, callback)
// #### @options {Object} Options for creating the socket.io or ws server.
// #### @raw {boolean} Enables ws.Websocket server.
//
// Creates a socket.io or ws server using the specified `options`.
//
exports.createServer = function (options, callback) {
return options.raw
? exports.createWsServer(options, callback)
: exports.createSocketIoServer(options, callback);
};
//
// ### function createSocketIoServer (options, callback)
// #### @options {Object} Options for creating the socket.io server
// #### @port {number} Port to listen on
// #### @input {string} Input to expect from the only socket
// #### @output {string} Output to send the only socket
//
// Creates a socket.io server on the specified `options.port` which
// will expect `options.input` and then send `options.output`.
//
exports.createSocketIoServer = function (options, callback) {
var server = protocols.target === 'https'
? io.listen(options.port, helpers.https, callback)
: io.listen(options.port, callback);
server.sockets.on('connection', function (socket) {
socket.on('incoming', function (data) {
assert.equal(data, options.input);
socket.emit('outgoing', options.output);
});
});
};
//
// ### function createWsServer (options, callback)
// #### @options {Object} Options for creating the ws.Server instance
// #### @port {number} Port to listen on
// #### @input {string} Input to expect from the only socket
// #### @output {string} Output to send the only socket
//
// Creates a ws.Server instance on the specified `options.port` which
// will expect `options.input` and then send `options.output`.
//
exports.createWsServer = function (options, callback) {
var server,
wss;
if (protocols.target === 'https') {
server = https.createServer(helpers.https, function (req, res) {
req.writeHead(200);
req.end();
}).listen(options.port, callback);
wss = new ws.Server({ server: server });
}
else {
wss = new ws.Server({ port: options.port }, callback);
}
wss.on('connection', function (socket) {
socket.on('message', function (data) {
assert.equal(data, options.input);
socket.send(options.output);
});
});
};

View File

@ -1,89 +0,0 @@
/*
* routing-table-test.js: Tests for the proxying using the ProxyTable object.
*
* (C) 2010, Charlie Robbins
*
*/
var assert = require('assert'),
fs = require('fs'),
path = require('path'),
async = require('async'),
request = require('request'),
vows = require('vows'),
macros = require('../macros'),
helpers = require('../helpers/index');
var routeFile = path.join(__dirname, 'config.json');
vows.describe(helpers.describe('routing-table')).addBatch({
"With a routing table": {
"with latency": macros.http.assertProxiedToRoutes({
latency: 2000,
routes: {
"icanhaz.com": "127.0.0.1:{PORT}",
"latency.com": "127.0.0.1:{PORT}"
}
}),
"using RegExp": macros.http.assertProxiedToRoutes({
routes: {
"foo.com": "127.0.0.1:{PORT}",
"bar.com": "127.0.0.1:{PORT}",
"baz.com/taco": "127.0.0.1:{PORT}",
"pizza.com/taco/muffins": "127.0.0.1:{PORT}",
"blah.com/me": "127.0.0.1:{PORT}/remapped",
"bleh.com/remap/this": "127.0.0.1:{PORT}/remap/remapped",
"test.com/double/tap": "127.0.0.1:{PORT}/remap"
}
}),
"using hostnameOnly": macros.http.assertProxiedToRoutes({
hostnameOnly: true,
routes: {
"foo.com": "127.0.0.1:{PORT}",
"bar.com": "127.0.0.1:{PORT}"
}
}),
"using a routing file": macros.http.assertProxiedToRoutes({
filename: routeFile,
routes: {
"foo.com": "127.0.0.1:{PORT}",
"bar.com": "127.0.0.1:{PORT}"
}
}, {
"after the file has been modified": {
topic: function () {
var config = JSON.parse(fs.readFileSync(routeFile, 'utf8')),
protocol = helpers.protocols.proxy,
port = helpers.nextPort,
that = this;
config.router['dynamic.com'] = "127.0.0.1:" + port;
fs.writeFileSync(routeFile, JSON.stringify(config));
async.parallel([
function waitForRoutes(next) {
that.proxyServer.on('routes', next);
},
async.apply(
helpers.http.createServer,
{
port: port,
output: 'hello from dynamic.com'
}
)
], function () {
request({
uri: protocol + '://127.0.0.1:' + that.port,
headers: {
host: 'dynamic.com'
}
}, that.callback);
});
},
"should receive 'hello from dynamic.com'": function (err, res, body) {
assert.equal(body, 'hello from dynamic.com');
}
}
})
}
}).export(module);

View File

@ -0,0 +1,397 @@
var common = require('../lib/http-proxy/common'),
url = require('url'),
expect = require('expect.js');
describe('lib/http-proxy/common.js', function () {
describe('#setupOutgoing', function () {
it('should setup the correct headers', function () {
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent : '?',
target: {
host : 'hey',
hostname : 'how',
socketPath: 'are',
port : 'you',
},
headers: {'fizz': 'bang', 'overwritten':true},
localAddress: 'local.address',
auth:'username:pass'
},
{
method : 'i',
url : 'am',
headers : {'pro':'xy','overwritten':false}
});
expect(outgoing.host).to.eql('hey');
expect(outgoing.hostname).to.eql('how');
expect(outgoing.socketPath).to.eql('are');
expect(outgoing.port).to.eql('you');
expect(outgoing.agent).to.eql('?');
expect(outgoing.method).to.eql('i');
expect(outgoing.path).to.eql('am');
expect(outgoing.headers.pro).to.eql('xy');
expect(outgoing.headers.fizz).to.eql('bang');
expect(outgoing.headers.overwritten).to.eql(true);
expect(outgoing.localAddress).to.eql('local.address');
expect(outgoing.auth).to.eql('username:pass');
});
it('should not override agentless upgrade header', function () {
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent: undefined,
target: {
host : 'hey',
hostname : 'how',
socketPath: 'are',
port : 'you',
},
headers: {'connection': 'upgrade'},
},
{
method : 'i',
url : 'am',
headers : {'pro':'xy','overwritten':false}
});
expect(outgoing.headers.connection).to.eql('upgrade');
});
it('should not override agentless connection: contains upgrade', function () {
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent: undefined,
target: {
host : 'hey',
hostname : 'how',
socketPath: 'are',
port : 'you',
},
headers: {'connection': 'keep-alive, upgrade'}, // this is what Firefox sets
},
{
method : 'i',
url : 'am',
headers : {'pro':'xy','overwritten':false}
});
expect(outgoing.headers.connection).to.eql('keep-alive, upgrade');
});
it('should override agentless connection: contains improper upgrade', function () {
// sanity check on upgrade regex
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent: undefined,
target: {
host : 'hey',
hostname : 'how',
socketPath: 'are',
port : 'you',
},
headers: {'connection': 'keep-alive, not upgrade'},
},
{
method : 'i',
url : 'am',
headers : {'pro':'xy','overwritten':false}
});
expect(outgoing.headers.connection).to.eql('close');
});
it('should override agentless non-upgrade header to close', function () {
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent: undefined,
target: {
host : 'hey',
hostname : 'how',
socketPath: 'are',
port : 'you',
},
headers: {'connection': 'xyz'},
},
{
method : 'i',
url : 'am',
headers : {'pro':'xy','overwritten':false}
});
expect(outgoing.headers.connection).to.eql('close');
});
it('should set the agent to false if none is given', function () {
var outgoing = {};
common.setupOutgoing(outgoing, {target:
'http://localhost'
}, { url: '/' });
expect(outgoing.agent).to.eql(false);
});
it('set the port according to the protocol', function () {
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent : '?',
target: {
host : 'how',
hostname : 'are',
socketPath: 'you',
protocol: 'https:'
}
},
{
method : 'i',
url : 'am',
headers : {pro:'xy'}
});
expect(outgoing.host).to.eql('how');
expect(outgoing.hostname).to.eql('are');
expect(outgoing.socketPath).to.eql('you');
expect(outgoing.agent).to.eql('?');
expect(outgoing.method).to.eql('i');
expect(outgoing.path).to.eql('am');
expect(outgoing.headers.pro).to.eql('xy');
expect(outgoing.port).to.eql(443);
});
it('should keep the original target path in the outgoing path', function(){
var outgoing = {};
common.setupOutgoing(outgoing, {target:
{ path: 'some-path' }
}, { url : 'am' });
expect(outgoing.path).to.eql('some-path/am');
});
it('should keep the original forward path in the outgoing path', function(){
var outgoing = {};
common.setupOutgoing(outgoing, {
target: {},
forward: {
path: 'some-path'
}
}, {
url : 'am'
}, 'forward');
expect(outgoing.path).to.eql('some-path/am');
});
it('should properly detect https/wss protocol without the colon', function () {
var outgoing = {};
common.setupOutgoing(outgoing, {
target: {
protocol: 'https',
host: 'whatever.com'
}
}, { url: '/' });
expect(outgoing.port).to.eql(443);
});
it('should not prepend the target path to the outgoing path with prependPath = false', function () {
var outgoing = {};
common.setupOutgoing(outgoing, {
target: { path: 'hellothere' },
prependPath: false
}, { url: 'hi' });
expect(outgoing.path).to.eql('hi');
})
it('should properly join paths', function () {
var outgoing = {};
common.setupOutgoing(outgoing, {
target: { path: '/forward' },
}, { url: '/static/path' });
expect(outgoing.path).to.eql('/forward/static/path');
})
it('should not modify the query string', function () {
var outgoing = {};
common.setupOutgoing(outgoing, {
target: { path: '/forward' },
}, { url: '/?foo=bar//&target=http://foobar.com/?a=1%26b=2&other=2' });
expect(outgoing.path).to.eql('/forward/?foo=bar//&target=http://foobar.com/?a=1%26b=2&other=2');
})
//
// This is the proper failing test case for the common.join problem
//
it('should correctly format the toProxy URL', function () {
var outgoing = {};
var google = 'https://google.com'
common.setupOutgoing(outgoing, {
target: url.parse('http://sometarget.com:80'),
toProxy: true,
}, { url: google });
expect(outgoing.path).to.eql('/' + google);
});
it('should not replace :\ to :\\ when no https word before', function () {
var outgoing = {};
var google = 'https://google.com:/join/join.js'
common.setupOutgoing(outgoing, {
target: url.parse('http://sometarget.com:80'),
toProxy: true,
}, { url: google });
expect(outgoing.path).to.eql('/' + google);
});
it('should not replace :\ to :\\ when no http word before', function () {
var outgoing = {};
var google = 'http://google.com:/join/join.js'
common.setupOutgoing(outgoing, {
target: url.parse('http://sometarget.com:80'),
toProxy: true,
}, { url: google });
expect(outgoing.path).to.eql('/' + google);
});
describe('when using ignorePath', function () {
it('should ignore the path of the `req.url` passed in but use the target path', function () {
var outgoing = {};
var myEndpoint = 'https://whatever.com/some/crazy/path/whoooo';
common.setupOutgoing(outgoing, {
target: url.parse(myEndpoint),
ignorePath: true
}, { url: '/more/crazy/pathness' });
expect(outgoing.path).to.eql('/some/crazy/path/whoooo');
});
it('and prependPath: false, it should ignore path of target and incoming request', function () {
var outgoing = {};
var myEndpoint = 'https://whatever.com/some/crazy/path/whoooo';
common.setupOutgoing(outgoing, {
target: url.parse(myEndpoint),
ignorePath: true,
prependPath: false
}, { url: '/more/crazy/pathness' });
expect(outgoing.path).to.eql('');
});
});
describe('when using changeOrigin', function () {
it('should correctly set the port to the host when it is a non-standard port using url.parse', function () {
var outgoing = {};
var myEndpoint = 'https://myCouch.com:6984';
common.setupOutgoing(outgoing, {
target: url.parse(myEndpoint),
changeOrigin: true
}, { url: '/' });
expect(outgoing.headers.host).to.eql('mycouch.com:6984');
});
it('should correctly set the port to the host when it is a non-standard port when setting host and port manually (which ignores port)', function () {
var outgoing = {};
common.setupOutgoing(outgoing, {
target: {
protocol: 'https:',
host: 'mycouch.com',
port: 6984
},
changeOrigin: true
}, { url: '/' });
expect(outgoing.headers.host).to.eql('mycouch.com:6984');
})
});
it('should pass through https client parameters', function () {
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent : '?',
target: {
host : 'how',
hostname : 'are',
socketPath: 'you',
protocol: 'https:',
pfx: 'my-pfx',
key: 'my-key',
passphrase: 'my-passphrase',
cert: 'my-cert',
ca: 'my-ca',
ciphers: 'my-ciphers',
secureProtocol: 'my-secure-protocol'
}
},
{
method : 'i',
url : 'am'
});
expect(outgoing.pfx).eql('my-pfx');
expect(outgoing.key).eql('my-key');
expect(outgoing.passphrase).eql('my-passphrase');
expect(outgoing.cert).eql('my-cert');
expect(outgoing.ca).eql('my-ca');
expect(outgoing.ciphers).eql('my-ciphers');
expect(outgoing.secureProtocol).eql('my-secure-protocol');
});
it('should handle overriding the `method` of the http request', function () {
var outgoing = {};
common.setupOutgoing(outgoing, {
target: url.parse('https://whooooo.com'),
method: 'POST' ,
}, { method: 'GET', url: '' });
expect(outgoing.method).eql('POST');
});
// url.parse('').path => null
it('should not pass null as last arg to #urlJoin', function(){
var outgoing = {};
common.setupOutgoing(outgoing, {target:
{ path: '' }
}, { url : '' });
expect(outgoing.path).to.be('');
});
});
describe('#setupSocket', function () {
it('should setup a socket', function () {
var socketConfig = {
timeout: null,
nodelay: false,
keepalive: false
},
stubSocket = {
setTimeout: function (num) {
socketConfig.timeout = num;
},
setNoDelay: function (bol) {
socketConfig.nodelay = bol;
},
setKeepAlive: function (bol) {
socketConfig.keepalive = bol;
}
}
returnValue = common.setupSocket(stubSocket);
expect(socketConfig.timeout).to.eql(0);
expect(socketConfig.nodelay).to.eql(true);
expect(socketConfig.keepalive).to.eql(true);
});
});
});

View File

@ -0,0 +1,536 @@
var webPasses = require('../lib/http-proxy/passes/web-incoming'),
httpProxy = require('../lib/http-proxy'),
expect = require('expect.js'),
concat = require('concat-stream'),
async = require('async'),
url = require('url'),
http = require('http');
describe('lib/http-proxy/passes/web.js', function() {
describe('#deleteLength', function() {
it('should change `content-length` for DELETE requests', function() {
var stubRequest = {
method: 'DELETE',
headers: {}
};
webPasses.deleteLength(stubRequest, {}, {});
expect(stubRequest.headers['content-length']).to.eql('0');
});
it('should change `content-length` for OPTIONS requests', function() {
var stubRequest = {
method: 'OPTIONS',
headers: {}
};
webPasses.deleteLength(stubRequest, {}, {});
expect(stubRequest.headers['content-length']).to.eql('0');
});
it('should remove `transfer-encoding` from empty DELETE requests', function() {
var stubRequest = {
method: 'DELETE',
headers: {
'transfer-encoding': 'chunked'
}
};
webPasses.deleteLength(stubRequest, {}, {});
expect(stubRequest.headers['content-length']).to.eql('0');
expect(stubRequest.headers).to.not.have.key('transfer-encoding');
});
});
describe('#timeout', function() {
it('should set timeout on the socket', function() {
var done = false, stubRequest = {
socket: {
setTimeout: function(value) { done = value; }
}
}
webPasses.timeout(stubRequest, {}, { timeout: 5000});
expect(done).to.eql(5000);
});
});
describe('#XHeaders', function () {
var stubRequest = {
connection: {
remoteAddress: '192.168.1.2',
remotePort: '8080'
},
headers: {
host: '192.168.1.2:8080'
}
}
it('set the correct x-forwarded-* headers', function () {
webPasses.XHeaders(stubRequest, {}, { xfwd: true });
expect(stubRequest.headers['x-forwarded-for']).to.be('192.168.1.2');
expect(stubRequest.headers['x-forwarded-port']).to.be('8080');
expect(stubRequest.headers['x-forwarded-proto']).to.be('http');
});
});
});
describe('#createProxyServer.web() using own http server', function () {
it('should proxy the request using the web proxy handler', function (done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080'
});
function requestHandler(req, res) {
proxy.web(req, res);
}
var proxyServer = http.createServer(requestHandler);
var source = http.createServer(function(req, res) {
source.close();
proxyServer.close();
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql('8081');
done();
});
proxyServer.listen('8081');
source.listen('8080');
http.request('http://127.0.0.1:8081', function() {}).end();
});
it('should detect a proxyReq event and modify headers', function (done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080',
});
proxy.on('proxyReq', function(proxyReq, req, res, options) {
proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
});
function requestHandler(req, res) {
proxy.web(req, res);
}
var proxyServer = http.createServer(requestHandler);
var source = http.createServer(function(req, res) {
source.close();
proxyServer.close();
expect(req.headers['x-special-proxy-header']).to.eql('foobar');
done();
});
proxyServer.listen('8081');
source.listen('8080');
http.request('http://127.0.0.1:8081', function() {}).end();
});
it('should skip proxyReq event when handling a request with header "expect: 100-continue" [https://www.npmjs.com/advisories/1486]', function (done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080',
});
proxy.on('proxyReq', function(proxyReq, req, res, options) {
proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
});
function requestHandler(req, res) {
proxy.web(req, res);
}
var proxyServer = http.createServer(requestHandler);
var source = http.createServer(function(req, res) {
source.close();
proxyServer.close();
expect(req.headers['x-special-proxy-header']).to.not.eql('foobar');
done();
});
proxyServer.listen('8081');
source.listen('8080');
const postData = ''.padStart(1025, 'x');
const postOptions = {
hostname: '127.0.0.1',
port: 8081,
path: '/',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData),
'expect': '100-continue'
}
};
const req = http.request(postOptions, function() {});
req.write(postData);
req.end();
});
it('should proxy the request and handle error via callback', function(done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080'
});
var proxyServer = http.createServer(requestHandler);
function requestHandler(req, res) {
proxy.web(req, res, function (err) {
proxyServer.close();
expect(err).to.be.an(Error);
expect(err.code).to.be('ECONNREFUSED');
done();
});
}
proxyServer.listen('8082');
http.request({
hostname: '127.0.0.1',
port: '8082',
method: 'GET',
}, function() {}).end();
});
it('should proxy the request and handle error via event listener', function(done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080'
});
var proxyServer = http.createServer(requestHandler);
function requestHandler(req, res) {
proxy.once('error', function (err, errReq, errRes) {
proxyServer.close();
expect(err).to.be.an(Error);
expect(errReq).to.be.equal(req);
expect(errRes).to.be.equal(res);
expect(err.code).to.be('ECONNREFUSED');
done();
});
proxy.web(req, res);
}
proxyServer.listen('8083');
http.request({
hostname: '127.0.0.1',
port: '8083',
method: 'GET',
}, function() {}).end();
});
it('should forward the request and handle error via event listener', function(done) {
var proxy = httpProxy.createProxyServer({
forward: 'http://127.0.0.1:8080'
});
var proxyServer = http.createServer(requestHandler);
function requestHandler(req, res) {
proxy.once('error', function (err, errReq, errRes) {
proxyServer.close();
expect(err).to.be.an(Error);
expect(errReq).to.be.equal(req);
expect(errRes).to.be.equal(res);
expect(err.code).to.be('ECONNREFUSED');
done();
});
proxy.web(req, res);
}
proxyServer.listen('8083');
http.request({
hostname: '127.0.0.1',
port: '8083',
method: 'GET',
}, function() {}).end();
});
it('should proxy the request and handle timeout error (proxyTimeout)', function(done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:45000',
proxyTimeout: 100
});
require('net').createServer().listen(45000);
var proxyServer = http.createServer(requestHandler);
var started = new Date().getTime();
function requestHandler(req, res) {
proxy.once('error', function (err, errReq, errRes) {
proxyServer.close();
expect(err).to.be.an(Error);
expect(errReq).to.be.equal(req);
expect(errRes).to.be.equal(res);
expect(new Date().getTime() - started).to.be.greaterThan(99);
expect(err.code).to.be('ECONNRESET');
done();
});
proxy.web(req, res);
}
proxyServer.listen('8084');
http.request({
hostname: '127.0.0.1',
port: '8084',
method: 'GET',
}, function() {}).end();
});
it('should proxy the request and handle timeout error', function(done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:45001',
timeout: 100
});
require('net').createServer().listen(45001);
var proxyServer = http.createServer(requestHandler);
var cnt = 0;
var doneOne = function() {
cnt += 1;
if(cnt === 2) done();
}
var started = new Date().getTime();
function requestHandler(req, res) {
proxy.once('econnreset', function (err, errReq, errRes) {
proxyServer.close();
expect(err).to.be.an(Error);
expect(errReq).to.be.equal(req);
expect(errRes).to.be.equal(res);
expect(err.code).to.be('ECONNRESET');
doneOne();
});
proxy.web(req, res);
}
proxyServer.listen('8085');
var req = http.request({
hostname: '127.0.0.1',
port: '8085',
method: 'GET',
}, function() {});
req.on('error', function(err) {
expect(err).to.be.an(Error);
expect(err.code).to.be('ECONNRESET');
expect(new Date().getTime() - started).to.be.greaterThan(99);
doneOne();
});
req.end();
});
it('should proxy the request and provide a proxyRes event with the request and response parameters', function(done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080'
});
function requestHandler(req, res) {
proxy.once('proxyRes', function (proxyRes, pReq, pRes) {
source.close();
proxyServer.close();
expect(pReq).to.be.equal(req);
expect(pRes).to.be.equal(res);
done();
});
proxy.web(req, res);
}
var proxyServer = http.createServer(requestHandler);
var source = http.createServer(function(req, res) {
res.end('Response');
});
proxyServer.listen('8086');
source.listen('8080');
http.request('http://127.0.0.1:8086', function() {}).end();
});
it('should proxy the request and provide and respond to manual user response when using modifyResponse', function(done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080',
selfHandleResponse: true
});
function requestHandler(req, res) {
proxy.once('proxyRes', function (proxyRes, pReq, pRes) {
proxyRes.pipe(concat(function (body) {
expect(body.toString('utf8')).eql('Response');
pRes.end(Buffer.from('my-custom-response'));
}))
});
proxy.web(req, res);
}
var proxyServer = http.createServer(requestHandler);
var source = http.createServer(function(req, res) {
res.end('Response');
});
async.parallel([
next => proxyServer.listen(8086, next),
next => source.listen(8080, next)
], function (err) {
http.get('http://127.0.0.1:8086', function(res) {
res.pipe(concat(function(body) {
expect(body.toString('utf8')).eql('my-custom-response');
source.close();
proxyServer.close();
done();
}));
}).once('error', done);
})
});
it('should proxy the request and handle changeOrigin option', function (done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080',
changeOrigin: true
});
function requestHandler(req, res) {
proxy.web(req, res);
}
var proxyServer = http.createServer(requestHandler);
var source = http.createServer(function(req, res) {
source.close();
proxyServer.close();
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql('8080');
done();
});
proxyServer.listen('8081');
source.listen('8080');
http.request('http://127.0.0.1:8081', function() {}).end();
});
it('should proxy the request with the Authorization header set', function (done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080',
auth: 'user:pass'
});
function requestHandler(req, res) {
proxy.web(req, res);
}
var proxyServer = http.createServer(requestHandler);
var source = http.createServer(function(req, res) {
source.close();
proxyServer.close();
var auth = new Buffer(req.headers.authorization.split(' ')[1], 'base64');
expect(req.method).to.eql('GET');
expect(auth.toString()).to.eql('user:pass');
done();
});
proxyServer.listen('8081');
source.listen('8080');
http.request('http://127.0.0.1:8081', function() {}).end();
});
it('should proxy requests to multiple servers with different options', function (done) {
var proxy = httpProxy.createProxyServer();
// proxies to two servers depending on url, rewriting the url as well
// http://127.0.0.1:8080/s1/ -> http://127.0.0.1:8081/
// http://127.0.0.1:8080/ -> http://127.0.0.1:8082/
function requestHandler(req, res) {
if (req.url.indexOf('/s1/') === 0) {
proxy.web(req, res, {
ignorePath: true,
target: 'http://127.0.0.1:8081' + req.url.substring(3)
});
} else {
proxy.web(req, res, {
target: 'http://127.0.0.1:8082'
});
}
}
var proxyServer = http.createServer(requestHandler);
var source1 = http.createServer(function(req, res) {
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql('8080');
expect(req.url).to.eql('/test1');
});
var source2 = http.createServer(function(req, res) {
source1.close();
source2.close();
proxyServer.close();
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql('8080');
expect(req.url).to.eql('/test2');
done();
});
proxyServer.listen('8080');
source1.listen('8081');
source2.listen('8082');
http.request('http://127.0.0.1:8080/s1/test1', function() {}).end();
http.request('http://127.0.0.1:8080/test2', function() {}).end();
});
});
describe('#followRedirects', function () {
it('should proxy the request follow redirects', function (done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080',
followRedirects: true
});
function requestHandler(req, res) {
proxy.web(req, res);
}
var proxyServer = http.createServer(requestHandler);
var source = http.createServer(function(req, res) {
if (url.parse(req.url).pathname === '/redirect') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('ok');
}
res.writeHead(301, { 'Location': '/redirect' });
res.end();
});
proxyServer.listen('8081');
source.listen('8080');
http.request('http://127.0.0.1:8081', function(res) {
source.close();
proxyServer.close();
expect(res.statusCode).to.eql(200);
done();
}).end();
});
});

View File

@ -0,0 +1,423 @@
var httpProxy = require('../lib/http-proxy/passes/web-outgoing'),
expect = require('expect.js');
describe('lib/http-proxy/passes/web-outgoing.js', function () {
describe('#setRedirectHostRewrite', function () {
beforeEach(function() {
this.req = {
headers: {
host: 'ext-auto.com'
}
};
this.proxyRes = {
statusCode: 301,
headers: {
location: 'http://backend.com/'
}
};
this.options = {
target: 'http://backend.com'
};
});
context('rewrites location host with hostRewrite', function() {
beforeEach(function() {
this.options.hostRewrite = 'ext-manual.com';
});
[201, 301, 302, 307, 308].forEach(function(code) {
it('on ' + code, function() {
this.proxyRes.statusCode = code;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://ext-manual.com/');
});
});
it('not on 200', function() {
this.proxyRes.statusCode = 200;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
});
it('not when hostRewrite is unset', function() {
delete this.options.hostRewrite;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
});
it('takes precedence over autoRewrite', function() {
this.options.autoRewrite = true;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://ext-manual.com/');
});
it('not when the redirected location does not match target host', function() {
this.proxyRes.statusCode = 302;
this.proxyRes.headers.location = 'http://some-other/';
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://some-other/');
});
it('not when the redirected location does not match target port', function() {
this.proxyRes.statusCode = 302;
this.proxyRes.headers.location = 'http://backend.com:8080/';
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://backend.com:8080/');
});
});
context('rewrites location host with autoRewrite', function() {
beforeEach(function() {
this.options.autoRewrite = true;
});
[201, 301, 302, 307, 308].forEach(function(code) {
it('on ' + code, function() {
this.proxyRes.statusCode = code;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://ext-auto.com/');
});
});
it('not on 200', function() {
this.proxyRes.statusCode = 200;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
});
it('not when autoRewrite is unset', function() {
delete this.options.autoRewrite;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
});
it('not when the redirected location does not match target host', function() {
this.proxyRes.statusCode = 302;
this.proxyRes.headers.location = 'http://some-other/';
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://some-other/');
});
it('not when the redirected location does not match target port', function() {
this.proxyRes.statusCode = 302;
this.proxyRes.headers.location = 'http://backend.com:8080/';
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://backend.com:8080/');
});
});
context('rewrites location protocol with protocolRewrite', function() {
beforeEach(function() {
this.options.protocolRewrite = 'https';
});
[201, 301, 302, 307, 308].forEach(function(code) {
it('on ' + code, function() {
this.proxyRes.statusCode = code;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('https://backend.com/');
});
});
it('not on 200', function() {
this.proxyRes.statusCode = 200;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
});
it('not when protocolRewrite is unset', function() {
delete this.options.protocolRewrite;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
});
it('works together with hostRewrite', function() {
this.options.hostRewrite = 'ext-manual.com';
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('https://ext-manual.com/');
});
it('works together with autoRewrite', function() {
this.options.autoRewrite = true;
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
expect(this.proxyRes.headers.location).to.eql('https://ext-auto.com/');
});
});
});
describe('#setConnection', function () {
it('set the right connection with 1.0 - `close`', function() {
var proxyRes = { headers: {} };
httpProxy.setConnection({
httpVersion: '1.0',
headers: {
connection: null
}
}, {}, proxyRes);
expect(proxyRes.headers.connection).to.eql('close');
});
it('set the right connection with 1.0 - req.connection', function() {
var proxyRes = { headers: {} };
httpProxy.setConnection({
httpVersion: '1.0',
headers: {
connection: 'hey'
}
}, {}, proxyRes);
expect(proxyRes.headers.connection).to.eql('hey');
});
it('set the right connection - req.connection', function() {
var proxyRes = { headers: {} };
httpProxy.setConnection({
httpVersion: null,
headers: {
connection: 'hola'
}
}, {}, proxyRes);
expect(proxyRes.headers.connection).to.eql('hola');
});
it('set the right connection - `keep-alive`', function() {
var proxyRes = { headers: {} };
httpProxy.setConnection({
httpVersion: null,
headers: {
connection: null
}
}, {}, proxyRes);
expect(proxyRes.headers.connection).to.eql('keep-alive');
});
it('don`t set connection with 2.0 if exist', function() {
var proxyRes = { headers: {} };
httpProxy.setConnection({
httpVersion: '2.0',
headers: {
connection: 'namstey'
}
}, {}, proxyRes);
expect(proxyRes.headers.connection).to.eql(undefined);
});
it('don`t set connection with 2.0 if doesn`t exist', function() {
var proxyRes = { headers: {} };
httpProxy.setConnection({
httpVersion: '2.0',
headers: {}
}, {}, proxyRes);
expect(proxyRes.headers.connection).to.eql(undefined);
})
});
describe('#writeStatusCode', function () {
it('should write status code', function() {
var res = {
writeHead: function(n) {
expect(n).to.eql(200);
}
};
httpProxy.writeStatusCode({}, res, { statusCode: 200 });
});
});
describe('#writeHeaders', function() {
beforeEach(function() {
this.proxyRes = {
headers: {
hey: 'hello',
how: 'are you?',
'set-cookie': [
'hello; domain=my.domain; path=/',
'there; domain=my.domain; path=/'
]
}
};
this.rawProxyRes = {
headers: {
hey: 'hello',
how: 'are you?',
'set-cookie': [
'hello; domain=my.domain; path=/',
'there; domain=my.domain; path=/'
]
},
rawHeaders: [
'Hey', 'hello',
'How', 'are you?',
'Set-Cookie', 'hello; domain=my.domain; path=/',
'Set-Cookie', 'there; domain=my.domain; path=/'
]
};
this.res = {
setHeader: function(k, v) {
// https://nodejs.org/api/http.html#http_message_headers
// Header names are lower-cased
this.headers[k.toLowerCase()] = v;
},
headers: {}
};
});
it('writes headers', function() {
var options = {};
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
expect(this.res.headers.hey).to.eql('hello');
expect(this.res.headers.how).to.eql('are you?');
expect(this.res.headers).to.have.key('set-cookie');
expect(this.res.headers['set-cookie']).to.be.an(Array);
expect(this.res.headers['set-cookie']).to.have.length(2);
});
it('writes raw headers', function() {
var options = {};
httpProxy.writeHeaders({}, this.res, this.rawProxyRes, options);
expect(this.res.headers.hey).to.eql('hello');
expect(this.res.headers.how).to.eql('are you?');
expect(this.res.headers).to.have.key('set-cookie');
expect(this.res.headers['set-cookie']).to.be.an(Array);
expect(this.res.headers['set-cookie']).to.have.length(2);
});
it('rewrites path', function() {
var options = {
cookiePathRewrite: '/dummyPath'
};
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
expect(this.res.headers['set-cookie'])
.to.contain('hello; domain=my.domain; path=/dummyPath');
});
it('does not rewrite path', function() {
var options = {};
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
expect(this.res.headers['set-cookie'])
.to.contain('hello; domain=my.domain; path=/');
});
it('removes path', function() {
var options = {
cookiePathRewrite: ''
};
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
expect(this.res.headers['set-cookie'])
.to.contain('hello; domain=my.domain');
});
it('does not rewrite domain', function() {
var options = {};
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
expect(this.res.headers['set-cookie'])
.to.contain('hello; domain=my.domain; path=/');
});
it('rewrites domain', function() {
var options = {
cookieDomainRewrite: 'my.new.domain'
};
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
expect(this.res.headers['set-cookie'])
.to.contain('hello; domain=my.new.domain; path=/');
});
it('removes domain', function() {
var options = {
cookieDomainRewrite: ''
};
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
expect(this.res.headers['set-cookie'])
.to.contain('hello; path=/');
});
it('rewrites headers with advanced configuration', function() {
var options = {
cookieDomainRewrite: {
'*': '',
'my.old.domain': 'my.new.domain',
'my.special.domain': 'my.special.domain'
}
};
this.proxyRes.headers['set-cookie'] = [
'hello-on-my.domain; domain=my.domain; path=/',
'hello-on-my.old.domain; domain=my.old.domain; path=/',
'hello-on-my.special.domain; domain=my.special.domain; path=/'
];
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
expect(this.res.headers['set-cookie'])
.to.contain('hello-on-my.domain; path=/');
expect(this.res.headers['set-cookie'])
.to.contain('hello-on-my.old.domain; domain=my.new.domain; path=/');
expect(this.res.headers['set-cookie'])
.to.contain('hello-on-my.special.domain; domain=my.special.domain; path=/');
});
it('rewrites raw headers with advanced configuration', function() {
var options = {
cookieDomainRewrite: {
'*': '',
'my.old.domain': 'my.new.domain',
'my.special.domain': 'my.special.domain'
}
};
this.rawProxyRes.headers['set-cookie'] = [
'hello-on-my.domain; domain=my.domain; path=/',
'hello-on-my.old.domain; domain=my.old.domain; path=/',
'hello-on-my.special.domain; domain=my.special.domain; path=/'
];
this.rawProxyRes.rawHeaders = this.rawProxyRes.rawHeaders.concat([
'Set-Cookie',
'hello-on-my.domain; domain=my.domain; path=/',
'Set-Cookie',
'hello-on-my.old.domain; domain=my.old.domain; path=/',
'Set-Cookie',
'hello-on-my.special.domain; domain=my.special.domain; path=/'
]);
httpProxy.writeHeaders({}, this.res, this.rawProxyRes, options);
expect(this.res.headers['set-cookie'])
.to.contain('hello-on-my.domain; path=/');
expect(this.res.headers['set-cookie'])
.to.contain('hello-on-my.old.domain; domain=my.new.domain; path=/');
expect(this.res.headers['set-cookie'])
.to.contain('hello-on-my.special.domain; domain=my.special.domain; path=/');
});
});
describe('#removeChunked', function() {
var proxyRes = {
headers: {
'transfer-encoding': 'hello'
}
};
httpProxy.removeChunked({ httpVersion: '1.0' }, {}, proxyRes);
expect(proxyRes.headers['transfer-encoding']).to.eql(undefined);
});
});

Some files were not shown because too many files have changed in this diff Show More