mirror of
https://github.com/zebrajr/express.git
synced 2025-12-06 12:19:51 +01:00
Compare commits
642 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4453d83cca | ||
|
|
db507669ca | ||
|
|
374fc1a0f9 | ||
|
|
1b196c8b82 | ||
|
|
64e7373d69 | ||
|
|
e4fb370ad8 | ||
|
|
60d4c16cc9 | ||
|
|
9e6760e186 | ||
|
|
ffa89f2ccf | ||
|
|
b9b9f52b2f | ||
|
|
9a7afb2886 | ||
|
|
2eb42059f3 | ||
|
|
aa907945cd | ||
|
|
89f198c6a5 | ||
|
|
d9a62f9833 | ||
|
|
8f21493cc5 | ||
|
|
6616e39d4d | ||
|
|
ed64290e4a | ||
|
|
b52ff7ca60 | ||
|
|
9420cd3f9b | ||
|
|
ef5f2e13ef | ||
|
|
c5b8d55a6a | ||
|
|
7a9311216a | ||
|
|
b0ed15b452 | ||
|
|
3910323d09 | ||
|
|
98c85eb0dd | ||
|
|
a039e49175 | ||
|
|
ffc562c7d1 | ||
|
|
52872b84ca | ||
|
|
b8ab46594d | ||
|
|
fedd60e642 | ||
|
|
99a0bd3354 | ||
|
|
dfd1851245 | ||
|
|
9f4dbe3a13 | ||
|
|
9784321e89 | ||
|
|
ee1ef41bd3 | ||
|
|
1ca803dd55 | ||
|
|
73555815b9 | ||
|
|
a1161b4686 | ||
|
|
f9954dd317 | ||
|
|
5da5a11a49 | ||
|
|
3dc96995df | ||
|
|
fa40ecfe76 | ||
|
|
cd7d4397c3 | ||
|
|
4c4f3ea105 | ||
|
|
cb4c56e9a7 | ||
|
|
7b44e1d850 | ||
|
|
eb6d12587a | ||
|
|
f1a2dc884d | ||
|
|
6b51e8ef97 | ||
|
|
1f311c59d4 | ||
|
|
9e97144222 | ||
|
|
29d09803c1 | ||
|
|
1d63162dbf | ||
|
|
4a2175dfc9 | ||
|
|
0bb00e1906 | ||
|
|
1e359f57fc | ||
|
|
9cbe2c2cbb | ||
|
|
35e15362ab | ||
|
|
90e522ac90 | ||
|
|
59703c2321 | ||
|
|
caa4f68ee8 | ||
|
|
6ed3439584 | ||
|
|
327af123a1 | ||
|
|
d2de128a32 | ||
|
|
2a53336e5d | ||
|
|
a42413d4e3 | ||
|
|
c2f576cbe9 | ||
|
|
99473c593a | ||
|
|
2d589b644a | ||
|
|
85e48bb8c1 | ||
|
|
55869f49a6 | ||
|
|
af7cd90893 | ||
|
|
ae6a4621bc | ||
|
|
8d39345902 | ||
|
|
a5cb681eb8 | ||
|
|
511d9dfca8 | ||
|
|
7f13d572c1 | ||
|
|
62336717bf | ||
|
|
3bbffdc41c | ||
|
|
ff86319ed5 | ||
|
|
1c5cf0fead | ||
|
|
256a3d1527 | ||
|
|
4f952a953b | ||
|
|
41113599af | ||
|
|
6a40af8293 | ||
|
|
246f6f5aee | ||
|
|
b11122be85 | ||
|
|
43020ff275 | ||
|
|
e4a61bd88e | ||
|
|
39f5d633b5 | ||
|
|
52ed64606f | ||
|
|
4e92ac9031 | ||
|
|
9f8589e31c | ||
|
|
cc751cff8f | ||
|
|
805ef52ae6 | ||
|
|
9e3dbb4374 | ||
|
|
b31910c542 | ||
|
|
c70197ad33 | ||
|
|
8cb53ea5c3 | ||
|
|
e162764f0f | ||
|
|
508c74091f | ||
|
|
b274047a5d | ||
|
|
082d6d1253 | ||
|
|
94546a3cc5 | ||
|
|
ab02240336 | ||
|
|
a46cfdc37f | ||
|
|
d14b2de782 | ||
|
|
2027b87a27 | ||
|
|
2cbf22721d | ||
|
|
3e1a1cedb2 | ||
|
|
6340d1509f | ||
|
|
344b022fc7 | ||
|
|
0c49926a9b | ||
|
|
b3906cbdde | ||
|
|
fed8c2a885 | ||
|
|
bdd81f8670 | ||
|
|
6c98f80b6a | ||
|
|
f9256ef36f | ||
|
|
e5feb9fcc9 | ||
|
|
21df421ebc | ||
|
|
4c9ddc1c47 | ||
|
|
9ebe5d500d | ||
|
|
ec4a01b6b8 | ||
|
|
54271f69b5 | ||
|
|
0264908903 | ||
|
|
4d713d2b76 | ||
|
|
125bb742a3 | ||
|
|
accafc652e | ||
|
|
05f40f4321 | ||
|
|
402e7f653f | ||
|
|
4e61d0100d | ||
|
|
7748475747 | ||
|
|
91a58b5b03 | ||
|
|
13e6894393 | ||
|
|
65b62065d2 | ||
|
|
2a980ad160 | ||
|
|
0b243b1aee | ||
|
|
a3e7e05e0a | ||
|
|
c5addb9a17 | ||
|
|
e35380a39d | ||
|
|
f5b6e67aed | ||
|
|
09831580ec | ||
|
|
41c054cff1 | ||
|
|
ecf762ff38 | ||
|
|
63992bb1d7 | ||
|
|
ea49706052 | ||
|
|
dde1f7d6e8 | ||
|
|
82fc12a40b | ||
|
|
9c756b0105 | ||
|
|
160b91cbf7 | ||
|
|
d106bf5324 | ||
|
|
723b5451bb | ||
|
|
2177f67f54 | ||
|
|
f4bd86ed36 | ||
|
|
c96c690dc0 | ||
|
|
088856c3f8 | ||
|
|
2ec589c113 | ||
|
|
4cf7eed927 | ||
|
|
6d084715ba | ||
|
|
61421a8c0c | ||
|
|
f42b160bbc | ||
|
|
689073d657 | ||
|
|
2803a2b35a | ||
|
|
ee40a881f5 | ||
|
|
a7d6d29ed3 | ||
|
|
897290b685 | ||
|
|
700349ffaf | ||
|
|
4b9cd2fd0e | ||
|
|
b44191eb3d | ||
|
|
8417c60fcf | ||
|
|
bf91946bd4 | ||
|
|
26801a0afd | ||
|
|
14439731f9 | ||
|
|
d97d79ed9a | ||
|
|
26e53f0fbc | ||
|
|
6abec204c0 | ||
|
|
4b3b8cc231 | ||
|
|
e9bcdd399b | ||
|
|
815f799310 | ||
|
|
7f9e5843b9 | ||
|
|
93cf646d5c | ||
|
|
2676a1f281 | ||
|
|
6da57c7819 | ||
|
|
d546f93f2f | ||
|
|
4771ba2bc3 | ||
|
|
3ae704f67f | ||
|
|
8b6d34963d | ||
|
|
36b8148110 | ||
|
|
6d98d2e110 | ||
|
|
51a76366e3 | ||
|
|
4e3f95c0ea | ||
|
|
88bd6d8e3a | ||
|
|
51595d402b | ||
|
|
94669f9289 | ||
|
|
cd7d79f92a | ||
|
|
5e2345e966 | ||
|
|
6415f7035b | ||
|
|
b28db2c12c | ||
|
|
0b746953c4 | ||
|
|
04bc62787b | ||
|
|
da4d763ff6 | ||
|
|
7091ec17f0 | ||
|
|
416ba025a1 | ||
|
|
60fb1d2acd | ||
|
|
e9f9aaeebd | ||
|
|
4f0f6cc67d | ||
|
|
a003cfab03 | ||
|
|
a1fa90fcea | ||
|
|
11f2b1db22 | ||
|
|
084e36506a | ||
|
|
0867302ddb | ||
|
|
567c9c665d | ||
|
|
69a4cf2819 | ||
|
|
4ee853e837 | ||
|
|
414854b82e | ||
|
|
06c6b88808 | ||
|
|
1b51edac7c | ||
|
|
b625132864 | ||
|
|
e3eca80584 | ||
|
|
23b44b3ddd | ||
|
|
b9fea12245 | ||
|
|
c259c3407f | ||
|
|
fdeb1d3176 | ||
|
|
734b281900 | ||
|
|
0e3ab6ec21 | ||
|
|
59af63ac2e | ||
|
|
e720c5a21b | ||
|
|
3abea7f818 | ||
|
|
2a89eb5c74 | ||
|
|
59aae7686b | ||
|
|
c4fe7de7bc | ||
|
|
a22920707b | ||
|
|
02d1c3916e | ||
|
|
8d8bfaac7b | ||
|
|
13df1de857 | ||
|
|
2a00da2067 | ||
|
|
24e4a2570d | ||
|
|
91b6fb83b4 | ||
|
|
3531987844 | ||
|
|
f540c3b019 | ||
|
|
b8b2eff3c3 | ||
|
|
f4e48bc43e | ||
|
|
8c24fa8f7b | ||
|
|
0debedf4f3 | ||
|
|
74beeac071 | ||
|
|
9bc1742937 | ||
|
|
5ad95419ba | ||
|
|
8a76f39d98 | ||
|
|
60b7c672c1 | ||
|
|
1e42a98db6 | ||
|
|
506fbd63be | ||
|
|
b9f7a97fe1 | ||
|
|
546969d198 | ||
|
|
f05b5d0e9c | ||
|
|
3c1d605da7 | ||
|
|
6b4c4f5426 | ||
|
|
a1efd9d6cf | ||
|
|
c6ee8d6e7f | ||
|
|
442fd46799 | ||
|
|
723b67766f | ||
|
|
29e117e676 | ||
|
|
06b2b1416d | ||
|
|
8368dc178a | ||
|
|
61f4049122 | ||
|
|
bb7907b932 | ||
|
|
f56ce73186 | ||
|
|
24b3dc5516 | ||
|
|
689d175b8b | ||
|
|
340be0f79a | ||
|
|
33e8dc303a | ||
|
|
644f6464b9 | ||
|
|
ecd7572f1e | ||
|
|
97131bcda8 | ||
|
|
8d98e86d7f | ||
|
|
2c47827053 | ||
|
|
97f0a518d8 | ||
|
|
7ec5dd2b3c | ||
|
|
ab2c70b954 | ||
|
|
745a63f825 | ||
|
|
a2dfc56a49 | ||
|
|
d854c43ea1 | ||
|
|
b02a95c693 | ||
|
|
631ada0c64 | ||
|
|
75e0c7a2c9 | ||
|
|
e2482b7e36 | ||
|
|
2df96e349f | ||
|
|
a38fae126a | ||
|
|
547fdd41dc | ||
|
|
0b330ef57c | ||
|
|
158a17031a | ||
|
|
29ea1b2f74 | ||
|
|
11a209e4b7 | ||
|
|
fd8e45c344 | ||
|
|
708ac4cdf5 | ||
|
|
92c5ce59f5 | ||
|
|
8880ddad1c | ||
|
|
b91c7ffb28 | ||
|
|
ecaf67c930 | ||
|
|
99175c3ef6 | ||
|
|
1b2e097be2 | ||
|
|
04da4aaf1a | ||
|
|
2e2d78c4d9 | ||
|
|
980d881e3b | ||
|
|
1df75763e3 | ||
|
|
32c558d414 | ||
|
|
a10770286e | ||
|
|
5855339455 | ||
|
|
1cc8169938 | ||
|
|
9482b82d0b | ||
|
|
10b9b507b7 | ||
|
|
03dc367187 | ||
|
|
f739b162d9 | ||
|
|
c92420648e | ||
|
|
dd69eedd18 | ||
|
|
0def9bb659 | ||
|
|
4847d0efa1 | ||
|
|
c17fe05861 | ||
|
|
87279c08aa | ||
|
|
8bf0720391 | ||
|
|
eb4c930d5f | ||
|
|
947b6b7d57 | ||
|
|
bf4c3ee00f | ||
|
|
2a7417dd84 | ||
|
|
490f1a1738 | ||
|
|
446046f886 | ||
|
|
291993d73c | ||
|
|
e8594c3571 | ||
|
|
07aa91f7cb | ||
|
|
4ed35b4202 | ||
|
|
ea66a9b81b | ||
|
|
d0e166c3c6 | ||
|
|
cf9f662655 | ||
|
|
8da8f79c44 | ||
|
|
18f782bba9 | ||
|
|
bc5ca05509 | ||
|
|
9967ffbdc2 | ||
|
|
7df0c840e0 | ||
|
|
d8ed591117 | ||
|
|
8ee3420f0f | ||
|
|
318fd4b543 | ||
|
|
3d7fce56a3 | ||
|
|
f9063712e0 | ||
|
|
6381bc6317 | ||
|
|
a007863096 | ||
|
|
6faf26d59f | ||
|
|
e98f5848a0 | ||
|
|
a65913776d | ||
|
|
5213bd9fe7 | ||
|
|
a39e409cf3 | ||
|
|
82de4de5ab | ||
|
|
669c805615 | ||
|
|
620df0e35e | ||
|
|
f6db4ee805 | ||
|
|
12310c5294 | ||
|
|
884657d546 | ||
|
|
7511d08328 | ||
|
|
a0276c6c91 | ||
|
|
2585f209f9 | ||
|
|
9d0976229d | ||
|
|
43cc56eb9e | ||
|
|
1c7bbcc143 | ||
|
|
9cbbc8ae74 | ||
|
|
6fbc269563 | ||
|
|
2bc734aa3f | ||
|
|
89bb531b31 | ||
|
|
744564fcf8 | ||
|
|
da6cb0ed8a | ||
|
|
00ad5bee96 | ||
|
|
141914e817 | ||
|
|
bd4fdfe5f7 | ||
|
|
215f484fb4 | ||
|
|
20047bb6e4 | ||
|
|
8b9757e8b8 | ||
|
|
a84e73b958 | ||
|
|
69997cbdbe | ||
|
|
3d05e85b0c | ||
|
|
c221b8596e | ||
|
|
450c468d04 | ||
|
|
af341b0f09 | ||
|
|
1574925cad | ||
|
|
c7d528cdc0 | ||
|
|
ea537d907d | ||
|
|
eee93a2760 | ||
|
|
b35773cf19 | ||
|
|
c8a42006b8 | ||
|
|
21cf522dcd | ||
|
|
a24f27aba7 | ||
|
|
a33266a206 | ||
|
|
6fe271e8aa | ||
|
|
cbe25d66b3 | ||
|
|
3bb6d96ba9 | ||
|
|
6660649f1b | ||
|
|
a75e4707b9 | ||
|
|
db05a741f0 | ||
|
|
c2e23ece2e | ||
|
|
96850e872a | ||
|
|
b8d59d5c98 | ||
|
|
59d695c447 | ||
|
|
e242796eb3 | ||
|
|
aaa9690bcf | ||
|
|
f275e87dff | ||
|
|
9dd0e7afdb | ||
|
|
1b2f3a0698 | ||
|
|
519126d732 | ||
|
|
99a369f3d5 | ||
|
|
a1dbb11377 | ||
|
|
353348a83e | ||
|
|
dab6ee5822 | ||
|
|
fc138c108f | ||
|
|
61a23e801f | ||
|
|
313d54f033 | ||
|
|
de081eb70f | ||
|
|
06d11755c9 | ||
|
|
6f2afd3d80 | ||
|
|
d5a1cbee70 | ||
|
|
f9a0560a9c | ||
|
|
821b7f0624 | ||
|
|
f490f78563 | ||
|
|
884e080a19 | ||
|
|
eb76236e2f | ||
|
|
52e9bd67b7 | ||
|
|
135a05c524 | ||
|
|
30afebf8da | ||
|
|
8e4add7f74 | ||
|
|
0fbbc29632 | ||
|
|
2402126988 | ||
|
|
ca3c863428 | ||
|
|
28db2c2c5c | ||
|
|
685d4665fd | ||
|
|
280a8d39ec | ||
|
|
5c4f3e7cc7 | ||
|
|
de122c14f5 | ||
|
|
2a2dd5d32b | ||
|
|
508936853a | ||
|
|
5596222f6a | ||
|
|
fe67523b9c | ||
|
|
4486fa6324 | ||
|
|
ecd8a08c1c | ||
|
|
a75728432e | ||
|
|
9007dcbdba | ||
|
|
c519886be5 | ||
|
|
8aabecaf1f | ||
|
|
3ff1dbeb73 | ||
|
|
18da651c5b | ||
|
|
1b48a5cc3c | ||
|
|
561b4b601e | ||
|
|
67e64ca4c1 | ||
|
|
bd04d8a87f | ||
|
|
922e9a4615 | ||
|
|
323a38965a | ||
|
|
3f1dcb96e0 | ||
|
|
4b4fa26298 | ||
|
|
47c1d2a816 | ||
|
|
65aff94ec6 | ||
|
|
2d519077ea | ||
|
|
d967675852 | ||
|
|
22d5b7ed10 | ||
|
|
872aa4741c | ||
|
|
87bc4ef763 | ||
|
|
f0cbdeadf6 | ||
|
|
f1e8a877f4 | ||
|
|
55831bbd08 | ||
|
|
e757fa0039 | ||
|
|
95735a6fcc | ||
|
|
668d029a14 | ||
|
|
866ffd67d7 | ||
|
|
741e3f81af | ||
|
|
4efb49866d | ||
|
|
6506fb578c | ||
|
|
dfa7b80642 | ||
|
|
121fe9982b | ||
|
|
e1b45ebd05 | ||
|
|
0a48e18056 | ||
|
|
eed05a1464 | ||
|
|
10c7756764 | ||
|
|
9dadca2c64 | ||
|
|
b8e50568af | ||
|
|
94e48a16f2 | ||
|
|
efcb17dcb2 | ||
|
|
b9ecb9afe3 | ||
|
|
5266f3a5cb | ||
|
|
e502dde3c8 | ||
|
|
da6f701317 | ||
|
|
88f9733ffa | ||
|
|
8267c4b724 | ||
|
|
bc07a41693 | ||
|
|
c754c8ad7b | ||
|
|
e917028729 | ||
|
|
7b076bd8e1 | ||
|
|
bb5211fa1c | ||
|
|
7f4e37f3ea | ||
|
|
11192bd168 | ||
|
|
0bcdd88dd0 | ||
|
|
60aacac167 | ||
|
|
70a19472f1 | ||
|
|
6f7a8301a1 | ||
|
|
8b71f39516 | ||
|
|
955f2a5f78 | ||
|
|
2f782d8478 | ||
|
|
32f5293afa | ||
|
|
6d9dd2da49 | ||
|
|
40dbfa2de2 | ||
|
|
9afa1cfc85 | ||
|
|
7eacdcef19 | ||
|
|
b02d3a1744 | ||
|
|
03341204ff | ||
|
|
50eb5e4377 | ||
|
|
952484f73a | ||
|
|
4218d04183 | ||
|
|
cf5c813d2f | ||
|
|
9e5d1a30c3 | ||
|
|
8a97346eaf | ||
|
|
6eda52a3dc | ||
|
|
b9b1b19758 | ||
|
|
6f12eee8ab | ||
|
|
186a206a0a | ||
|
|
02f3933b69 | ||
|
|
0ae10bb154 | ||
|
|
95c31f7041 | ||
|
|
b93ffd4bdc | ||
|
|
8da51108e7 | ||
|
|
6bcdfef6ad | ||
|
|
44e539e1dc | ||
|
|
003459b795 | ||
|
|
6295b45920 | ||
|
|
a6b119d27a | ||
|
|
d0421ac7e1 | ||
|
|
5f0c829d7c | ||
|
|
c82fa19447 | ||
|
|
fa22245cc6 | ||
|
|
302a6152b4 | ||
|
|
dc538f6e81 | ||
|
|
62a59b6ace | ||
|
|
451ee5d9c1 | ||
|
|
f07f368fba | ||
|
|
09d5654488 | ||
|
|
3d10279826 | ||
|
|
5e9de5dcb6 | ||
|
|
5de1a08ebf | ||
|
|
4480fb997e | ||
|
|
b8fb6a7fb1 | ||
|
|
b4eb1f59d3 | ||
|
|
431f65305e | ||
|
|
f3fa758af9 | ||
|
|
ede24da964 | ||
|
|
d5b33cfad8 | ||
|
|
c39d7d9339 | ||
|
|
f95dbc28fd | ||
|
|
ac89f6f121 | ||
|
|
3d8ca8ad4a | ||
|
|
02c753583e | ||
|
|
3ed5090ca9 | ||
|
|
76bf96e9ce | ||
|
|
d3bdc3b663 | ||
|
|
0e88dceac2 | ||
|
|
e69a29d9c2 | ||
|
|
0083372bed | ||
|
|
f3c5f7ee29 | ||
|
|
40e04ec7a6 | ||
|
|
972ada9079 | ||
|
|
80e64691e1 | ||
|
|
98b0b66b6c | ||
|
|
cbaa04629a | ||
|
|
276a80895c | ||
|
|
94a6cbfbfe | ||
|
|
f8fba68ec0 | ||
|
|
c6f12a8971 | ||
|
|
323572610b | ||
|
|
f448a96685 | ||
|
|
68e824cbff | ||
|
|
086e56f1c4 | ||
|
|
b4020ec92b | ||
|
|
fe0bc4082d | ||
|
|
1780ed1091 | ||
|
|
b49af6a674 | ||
|
|
a743d5be4d | ||
|
|
187d1f57c9 | ||
|
|
950f4423f0 | ||
|
|
53bee2506d | ||
|
|
659fcc1598 | ||
|
|
a163e2cdf4 | ||
|
|
62e12fe710 | ||
|
|
8fabed82aa | ||
|
|
351396f971 | ||
|
|
b97faff6e2 | ||
|
|
b7817ab1b0 | ||
|
|
48aba21ea4 | ||
|
|
de129c289d | ||
|
|
f4120a6453 | ||
|
|
19c8d64855 | ||
|
|
71395f5933 | ||
|
|
e3bd14dcca | ||
|
|
c319fe260a | ||
|
|
21f725e0ef | ||
|
|
e5dbb0cb4e | ||
|
|
a3a9166c52 | ||
|
|
06f423d4f5 | ||
|
|
501e24e0a9 | ||
|
|
c8d9223e93 | ||
|
|
4b39a01e6a | ||
|
|
ad4d52de29 | ||
|
|
07077c4457 | ||
|
|
bcbb9d56c5 | ||
|
|
ab1c9e924e | ||
|
|
25fdefac45 | ||
|
|
a856456a95 | ||
|
|
1dbfee6623 | ||
|
|
8a387d3ede | ||
|
|
943f28f05f | ||
|
|
7cafdb5824 | ||
|
|
2c668f87c7 | ||
|
|
6343288bef | ||
|
|
694869d2aa | ||
|
|
cec5780db4 | ||
|
|
21d52daafb | ||
|
|
a7d15f382e | ||
|
|
6c751191dd | ||
|
|
1e2951a832 | ||
|
|
3a1f27fcde | ||
|
|
b309b873f1 | ||
|
|
f90e045334 | ||
|
|
f6ec710534 | ||
|
|
a9ef9e13fb | ||
|
|
f56e2a2503 | ||
|
|
8a5ecd3d89 | ||
|
|
4052c15c7f | ||
|
|
97ccc52207 | ||
|
|
0fc4f0735a | ||
|
|
ccdbe4ea37 | ||
|
|
59f2b4048a | ||
|
|
7f2532808a | ||
|
|
be35e4927c | ||
|
|
f31dcff10c | ||
|
|
509ebb1aff | ||
|
|
78e50547f1 | ||
|
|
dcc4eaabe8 | ||
|
|
8c6f9c4253 | ||
|
|
88103063fe | ||
|
|
164638b24f | ||
|
|
e66625be50 | ||
|
|
085a29685a |
|
|
@ -1,4 +1,4 @@
|
||||||
# http://editorconfig.org
|
# https://editorconfig.org
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"rules": {
|
|
||||||
"eol-last": "error",
|
|
||||||
"indent": ["error", 2, { "SwitchCase": 1 }],
|
|
||||||
"no-trailing-spaces": "error",
|
|
||||||
"no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
.eslintrc.yml
Normal file
14
.eslintrc.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
root: true
|
||||||
|
env:
|
||||||
|
es2022: true
|
||||||
|
node: true
|
||||||
|
rules:
|
||||||
|
eol-last: error
|
||||||
|
eqeqeq: [error, allow-null]
|
||||||
|
indent: [error, 2, { MemberExpression: "off", SwitchCase: 1 }]
|
||||||
|
no-trailing-spaces: error
|
||||||
|
no-unused-vars: [error, { vars: all, args: none, ignoreRestSiblings: true }]
|
||||||
|
no-restricted-globals:
|
||||||
|
- error
|
||||||
|
- name: Buffer
|
||||||
|
message: Use `import { Buffer } from "node:buffer"` instead of the global Buffer.
|
||||||
17
.github/dependabot.yml
vendored
Normal file
17
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: monthly
|
||||||
|
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: monthly
|
||||||
|
time: "23:00"
|
||||||
|
timezone: Europe/London
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
ignore:
|
||||||
|
- dependency-name: "*"
|
||||||
|
update-types: ["version-update:semver-major"]
|
||||||
117
.github/workflows/ci.yml
vendored
Normal file
117
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
- '4.x'
|
||||||
|
- '5.x'
|
||||||
|
- '5.0'
|
||||||
|
paths-ignore:
|
||||||
|
- '*.md'
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
# Cancel in progress workflows
|
||||||
|
# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run
|
||||||
|
concurrency:
|
||||||
|
group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
name: Lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
|
with:
|
||||||
|
node-version: 'lts/*'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install --ignore-scripts --include=dev
|
||||||
|
|
||||||
|
- name: Run lint
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
node-version: [18, 19, 20, 21, 22, 23, 24, 25]
|
||||||
|
# Node.js release schedule: https://nodejs.org/en/about/releases/
|
||||||
|
|
||||||
|
name: Node.js ${{ matrix.node-version }} - ${{matrix.os}}
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Setup Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
|
- name: Configure npm loglevel
|
||||||
|
run: |
|
||||||
|
npm config set loglevel error
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Output Node and NPM versions
|
||||||
|
run: |
|
||||||
|
echo "Node.js version: $(node -v)"
|
||||||
|
echo "NPM version: $(npm -v)"
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
shell: bash
|
||||||
|
run: npm run test-ci
|
||||||
|
|
||||||
|
- name: Upload code coverage
|
||||||
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
|
with:
|
||||||
|
name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }}
|
||||||
|
path: ./coverage/lcov.info
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
needs: test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
checks: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Install lcov
|
||||||
|
shell: bash
|
||||||
|
run: sudo apt-get -y install lcov
|
||||||
|
|
||||||
|
- name: Collect coverage reports
|
||||||
|
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
||||||
|
with:
|
||||||
|
path: ./coverage
|
||||||
|
pattern: coverage-node-*
|
||||||
|
|
||||||
|
- name: Merge coverage reports
|
||||||
|
shell: bash
|
||||||
|
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info
|
||||||
|
|
||||||
|
- name: Upload coverage report
|
||||||
|
uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2.3.6
|
||||||
|
with:
|
||||||
|
file: ./lcov.info
|
||||||
74
.github/workflows/codeql.yml
vendored
Normal file
74
.github/workflows/codeql.yml
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["master"]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: ["master"]
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * 1"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [javascript, actions]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
config: |
|
||||||
|
paths-ignore:
|
||||||
|
- test
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
# - name: Autobuild
|
||||||
|
# uses: github/codeql-action/autobuild@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
|
|
||||||
|
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||||
|
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||||
|
|
||||||
|
# - run: |
|
||||||
|
# echo "Run, Build Application using script"
|
||||||
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5
|
||||||
101
.github/workflows/legacy.yml
vendored
Normal file
101
.github/workflows/legacy.yml
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
name: legacy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
- '4.x'
|
||||||
|
- '5.x'
|
||||||
|
- '5.0'
|
||||||
|
paths-ignore:
|
||||||
|
- '*.md'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- '*.md'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
# Cancel in progress workflows
|
||||||
|
# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run
|
||||||
|
concurrency:
|
||||||
|
group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
node-version: [16, 17]
|
||||||
|
# Node.js release schedule: https://nodejs.org/en/about/releases/
|
||||||
|
|
||||||
|
name: Node.js ${{ matrix.node-version }} - ${{matrix.os}}
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Setup Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
|
- name: Configure npm loglevel
|
||||||
|
run: |
|
||||||
|
npm config set loglevel error
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Output Node and NPM versions
|
||||||
|
run: |
|
||||||
|
echo "Node.js version: $(node -v)"
|
||||||
|
echo "NPM version: $(npm -v)"
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
shell: bash
|
||||||
|
run: npm run test-ci
|
||||||
|
|
||||||
|
- name: Upload code coverage
|
||||||
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
|
with:
|
||||||
|
name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }}
|
||||||
|
path: ./coverage/lcov.info
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
needs: test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
checks: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Install lcov
|
||||||
|
shell: bash
|
||||||
|
run: sudo apt-get -y install lcov
|
||||||
|
|
||||||
|
- name: Collect coverage reports
|
||||||
|
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
||||||
|
with:
|
||||||
|
path: ./coverage
|
||||||
|
pattern: coverage-node-*
|
||||||
|
|
||||||
|
- name: Merge coverage reports
|
||||||
|
shell: bash
|
||||||
|
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info
|
||||||
|
|
||||||
|
- name: Upload coverage report
|
||||||
|
uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2.3.6
|
||||||
|
with:
|
||||||
|
file: ./lcov.info
|
||||||
72
.github/workflows/scorecard.yml
vendored
Normal file
72
.github/workflows/scorecard.yml
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
# This workflow uses actions that are not certified by GitHub. They are provided
|
||||||
|
# by a third-party and are governed by separate terms of service, privacy
|
||||||
|
# policy, and support documentation.
|
||||||
|
|
||||||
|
name: Scorecard supply-chain security
|
||||||
|
on:
|
||||||
|
# For Branch-Protection check. Only the default branch is supported. See
|
||||||
|
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||||
|
branch_protection_rule:
|
||||||
|
# To guarantee Maintained check is occasionally updated. See
|
||||||
|
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||||
|
schedule:
|
||||||
|
- cron: '16 21 * * 1'
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
# Declare default permissions as read only.
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analysis:
|
||||||
|
name: Scorecard analysis
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
# Needed to upload the results to code-scanning dashboard.
|
||||||
|
security-events: write
|
||||||
|
# Needed to publish results and get a badge (see publish_results below).
|
||||||
|
id-token: write
|
||||||
|
# Uncomment the permissions below if installing in a private repository.
|
||||||
|
# contents: read
|
||||||
|
# actions: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: "Checkout code"
|
||||||
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: "Run analysis"
|
||||||
|
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
|
||||||
|
with:
|
||||||
|
results_file: results.sarif
|
||||||
|
results_format: sarif
|
||||||
|
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||||
|
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||||
|
# - you are installing Scorecard on a *private* repository
|
||||||
|
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
||||||
|
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||||
|
|
||||||
|
# Public repositories:
|
||||||
|
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||||
|
# - Allows the repository to include the Scorecard badge.
|
||||||
|
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||||
|
# For private repositories:
|
||||||
|
# - `publish_results` will always be set to `false`, regardless
|
||||||
|
# of the value entered here.
|
||||||
|
publish_results: true
|
||||||
|
|
||||||
|
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||||
|
# format to the repository Actions tab.
|
||||||
|
- name: "Upload artifact"
|
||||||
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
|
with:
|
||||||
|
name: SARIF file
|
||||||
|
path: results.sarif
|
||||||
|
retention-days: 5
|
||||||
|
|
||||||
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
|
- name: "Upload to code-scanning"
|
||||||
|
uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5
|
||||||
|
with:
|
||||||
|
sarif_file: results.sarif
|
||||||
23
.gitignore
vendored
23
.gitignore
vendored
|
|
@ -1,27 +1,20 @@
|
||||||
# OS X
|
|
||||||
.DS_Store*
|
|
||||||
Icon?
|
|
||||||
._*
|
|
||||||
|
|
||||||
# Windows
|
|
||||||
Thumbs.db
|
|
||||||
ehthumbs.db
|
|
||||||
Desktop.ini
|
|
||||||
|
|
||||||
# Linux
|
|
||||||
.directory
|
|
||||||
*~
|
|
||||||
|
|
||||||
|
|
||||||
# npm
|
# npm
|
||||||
node_modules
|
node_modules
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
npm-shrinkwrap.json
|
||||||
*.log
|
*.log
|
||||||
*.gz
|
*.gz
|
||||||
|
|
||||||
|
# Yarn
|
||||||
|
yarn-error.log
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
# Coveralls
|
# Coveralls
|
||||||
|
.nyc_output
|
||||||
coverage
|
coverage
|
||||||
|
|
||||||
# Benchmarking
|
# Benchmarking
|
||||||
benchmarks/graphs
|
benchmarks/graphs
|
||||||
|
|
||||||
|
# ignore additional files using core.excludesFile
|
||||||
|
# https://git-scm.com/docs/gitignore
|
||||||
|
|
|
||||||
39
.travis.yml
39
.travis.yml
|
|
@ -1,39 +0,0 @@
|
||||||
language: node_js
|
|
||||||
node_js:
|
|
||||||
- "0.10"
|
|
||||||
- "0.12"
|
|
||||||
- "1.8"
|
|
||||||
- "2.5"
|
|
||||||
- "3.3"
|
|
||||||
- "4.8"
|
|
||||||
- "5.12"
|
|
||||||
- "6.11"
|
|
||||||
- "7.10"
|
|
||||||
- "8.4"
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- node_js: "8"
|
|
||||||
env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
|
|
||||||
- node_js: "9"
|
|
||||||
env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
|
|
||||||
allow_failures:
|
|
||||||
# Allow the nightly installs to fail
|
|
||||||
- env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
|
|
||||||
sudo: false
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- node_modules
|
|
||||||
before_install:
|
|
||||||
# Skip updating shrinkwrap / lock
|
|
||||||
- "npm config set shrinkwrap false"
|
|
||||||
|
|
||||||
# Remove all non-test dependencies
|
|
||||||
- "npm rm --save-dev connect-redis"
|
|
||||||
|
|
||||||
# Update Node.js modules
|
|
||||||
- "test ! -d node_modules || npm prune"
|
|
||||||
- "test ! -d node_modules || npm rebuild"
|
|
||||||
script:
|
|
||||||
- "npm run test-ci"
|
|
||||||
- "npm run lint"
|
|
||||||
after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
|
|
||||||
## Website Issues
|
|
||||||
|
|
||||||
Open issues for the expressjs.com website in https://github.com/expressjs/expressjs.com.
|
|
||||||
|
|
||||||
## PRs and Code contributions
|
|
||||||
|
|
||||||
* Tests must pass.
|
|
||||||
* Follow the [JavaScript Standard Style](http://standardjs.com/) and `npm run lint`.
|
|
||||||
* If you fix a bug, add a test.
|
|
||||||
|
|
||||||
## Branches
|
|
||||||
|
|
||||||
Use the `master` branch for bug fixes or minor work that is intended for the
|
|
||||||
current release stream.
|
|
||||||
|
|
||||||
Use the correspondingly named branch, e.g. `5.0`, for anything intended for
|
|
||||||
a future release of Express.
|
|
||||||
|
|
||||||
## Steps for contributing
|
|
||||||
|
|
||||||
1. [Create an issue](https://github.com/expressjs/express/issues/new) for the
|
|
||||||
bug you want to fix or the feature that you want to add.
|
|
||||||
2. Create your own [fork](https://github.com/expressjs/express) on github, then
|
|
||||||
checkout your fork.
|
|
||||||
3. Write your code in your local copy. It's good practice to create a branch for
|
|
||||||
each new issue you work on, although not compulsory.
|
|
||||||
4. To run the test suite, first install the dependencies by running `npm install`,
|
|
||||||
then run `npm test`.
|
|
||||||
5. Ensure your code is linted by running `npm run lint` -- fix any issue you
|
|
||||||
see listed.
|
|
||||||
6. If the tests pass, you can commit your changes to your fork and then create
|
|
||||||
a pull request from there. Make sure to reference your issue from the pull
|
|
||||||
request comments by including the issue number e.g. `#123`.
|
|
||||||
|
|
||||||
## Issues which are questions
|
|
||||||
|
|
||||||
We will typically close any vague issues or questions that are specific to some
|
|
||||||
app you are writing. Please double check the docs and other references before
|
|
||||||
being trigger happy with posting a question issue.
|
|
||||||
|
|
||||||
Things that will help get your question issue looked at:
|
|
||||||
|
|
||||||
* Full and runnable JS code.
|
|
||||||
* Clear description of the problem or unexpected behavior.
|
|
||||||
* Clear description of the expected result.
|
|
||||||
* Steps you have taken to debug it yourself.
|
|
||||||
|
|
||||||
If you post a question and do not outline the above items or make it easy for
|
|
||||||
us to understand and reproduce your issue, it will be closed.
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
# Express.js Community Contributing Guide 1.0
|
|
||||||
|
|
||||||
The goal of this document is to create a contribution process that:
|
|
||||||
|
|
||||||
* Encourages new contributions.
|
|
||||||
* Encourages contributors to remain involved.
|
|
||||||
* Avoids unnecessary processes and bureaucracy whenever possible.
|
|
||||||
* Creates a transparent decision making process that makes it clear how
|
|
||||||
contributors can be involved in decision making.
|
|
||||||
|
|
||||||
## Vocabulary
|
|
||||||
|
|
||||||
* A **Contributor** is any individual creating or commenting on an issue or pull request.
|
|
||||||
* A **Committer** is a subset of contributors who have been given write access to the repository.
|
|
||||||
* A **TC (Technical Committee)** is a group of committers representing the required technical
|
|
||||||
expertise to resolve rare disputes.
|
|
||||||
|
|
||||||
# Logging Issues
|
|
||||||
|
|
||||||
Log an issue for any question or problem you might have. When in doubt, log an issue, and
|
|
||||||
any additional policies about what to include will be provided in the responses. The only
|
|
||||||
exception is security dislosures which should be sent privately.
|
|
||||||
|
|
||||||
Committers may direct you to another repository, ask for additional clarifications, and
|
|
||||||
add appropriate metadata before the issue is addressed.
|
|
||||||
|
|
||||||
Please be courteous and respectful. Every participant is expected to follow the
|
|
||||||
project's Code of Conduct.
|
|
||||||
|
|
||||||
# Contributions
|
|
||||||
|
|
||||||
Any change to resources in this repository must be through pull requests. This applies to all changes
|
|
||||||
to documentation, code, binary files, etc. Even long term committers and TC members must use
|
|
||||||
pull requests.
|
|
||||||
|
|
||||||
No pull request can be merged without being reviewed.
|
|
||||||
|
|
||||||
For non-trivial contributions, pull requests should sit for at least 36 hours to ensure that
|
|
||||||
contributors in other timezones have time to review. Consideration should also be given to
|
|
||||||
weekends and other holiday periods to ensure active committers all have reasonable time to
|
|
||||||
become involved in the discussion and review process if they wish.
|
|
||||||
|
|
||||||
The default for each contribution is that it is accepted once no committer has an objection.
|
|
||||||
During review committers may also request that a specific contributor who is most versed in a
|
|
||||||
particular area gives a "LGTM" before the PR can be merged. There is no additional "sign off"
|
|
||||||
process for contributions to land. Once all issues brought by committers are addressed it can
|
|
||||||
be landed by any committer.
|
|
||||||
|
|
||||||
In the case of an objection being raised in a pull request by another committer, all involved
|
|
||||||
committers should seek to arrive at a consensus by way of addressing concerns being expressed
|
|
||||||
by discussion, compromise on the proposed change, or withdrawal of the proposed change.
|
|
||||||
|
|
||||||
If a contribution is controversial and committers cannot agree about how to get it to land
|
|
||||||
or if it should land then it should be escalated to the TC. TC members should regularly
|
|
||||||
discuss pending contributions in order to find a resolution. It is expected that only a
|
|
||||||
small minority of issues be brought to the TC for resolution and that discussion and
|
|
||||||
compromise among committers be the default resolution mechanism.
|
|
||||||
|
|
||||||
# Becoming a Committer
|
|
||||||
|
|
||||||
All contributors who land a non-trivial contribution should be on-boarded in a timely manner,
|
|
||||||
and added as a committer, and be given write access to the repository.
|
|
||||||
|
|
||||||
Committers are expected to follow this policy and continue to send pull requests, go through
|
|
||||||
proper review, and have other committers merge their pull requests.
|
|
||||||
|
|
||||||
# TC Process
|
|
||||||
|
|
||||||
The TC uses a "consensus seeking" process for issues that are escalated to the TC.
|
|
||||||
The group tries to find a resolution that has no open objections among TC members.
|
|
||||||
If a consensus cannot be reached that has no objections then a majority wins vote
|
|
||||||
is called. It is also expected that the majority of decisions made by the TC are via
|
|
||||||
a consensus seeking process and that voting is only used as a last-resort.
|
|
||||||
|
|
||||||
Resolution may involve returning the issue to committers with suggestions on how to
|
|
||||||
move forward towards a consensus. It is not expected that a meeting of the TC
|
|
||||||
will resolve all issues on its agenda during that meeting and may prefer to continue
|
|
||||||
the discussion happening among the committers.
|
|
||||||
|
|
||||||
Members can be added to the TC at any time. Any committer can nominate another committer
|
|
||||||
to the TC and the TC uses its standard consensus seeking process to evaluate whether or
|
|
||||||
not to add this new member. Members who do not participate consistently at the level of
|
|
||||||
a majority of the other members are expected to resign.
|
|
||||||
|
|
||||||
|
|
||||||
519
History.md
519
History.md
|
|
@ -1,3 +1,493 @@
|
||||||
|
5.1.0 / 2025-03-31
|
||||||
|
========================
|
||||||
|
|
||||||
|
* Add support for `Uint8Array` in `res.send()`
|
||||||
|
* Add support for ETag option in `res.sendFile()`
|
||||||
|
* Add support for multiple links with the same rel in `res.links()`
|
||||||
|
* Add funding field to package.json
|
||||||
|
* perf: use loop for acceptParams
|
||||||
|
* refactor: prefix built-in node module imports
|
||||||
|
* deps: remove `setprototypeof`
|
||||||
|
* deps: remove `safe-buffer`
|
||||||
|
* deps: remove `utils-merge`
|
||||||
|
* deps: remove `methods`
|
||||||
|
* deps: remove `depd`
|
||||||
|
* deps: `debug@^4.4.0`
|
||||||
|
* deps: `body-parser@^2.2.0`
|
||||||
|
* deps: `router@^2.2.0`
|
||||||
|
* deps: `content-type@^1.0.5`
|
||||||
|
* deps: `finalhandler@^2.1.0`
|
||||||
|
* deps: `qs@^6.14.0`
|
||||||
|
* deps: `server-static@2.2.0`
|
||||||
|
* deps: `type-is@2.0.1`
|
||||||
|
|
||||||
|
5.0.1 / 2024-10-08
|
||||||
|
==========
|
||||||
|
|
||||||
|
* Update `cookie` semver lock to address [CVE-2024-47764](https://nvd.nist.gov/vuln/detail/CVE-2024-47764)
|
||||||
|
|
||||||
|
5.0.0 / 2024-09-10
|
||||||
|
=========================
|
||||||
|
* remove:
|
||||||
|
- `path-is-absolute` dependency - use `path.isAbsolute` instead
|
||||||
|
* breaking:
|
||||||
|
* `res.status()` accepts only integers, and input must be greater than 99 and less than 1000
|
||||||
|
* will throw a `RangeError: Invalid status code: ${code}. Status code must be greater than 99 and less than 1000.` for inputs outside this range
|
||||||
|
* will throw a `TypeError: Invalid status code: ${code}. Status code must be an integer.` for non integer inputs
|
||||||
|
* deps: send@1.0.0
|
||||||
|
* `res.redirect('back')` and `res.location('back')` is no longer a supported magic string, explicitly use `req.get('Referrer') || '/'`.
|
||||||
|
* change:
|
||||||
|
- `res.clearCookie` will ignore user provided `maxAge` and `expires` options
|
||||||
|
* deps: cookie-signature@^1.2.1
|
||||||
|
* deps: debug@4.3.6
|
||||||
|
* deps: merge-descriptors@^2.0.0
|
||||||
|
* deps: serve-static@^2.1.0
|
||||||
|
* deps: qs@6.13.0
|
||||||
|
* deps: accepts@^2.0.0
|
||||||
|
* deps: mime-types@^3.0.0
|
||||||
|
- `application/javascript` => `text/javascript`
|
||||||
|
* deps: type-is@^2.0.0
|
||||||
|
* deps: content-disposition@^1.0.0
|
||||||
|
* deps: finalhandler@^2.0.0
|
||||||
|
* deps: fresh@^2.0.0
|
||||||
|
* deps: body-parser@^2.0.1
|
||||||
|
* deps: send@^1.1.0
|
||||||
|
|
||||||
|
5.0.0-beta.3 / 2024-03-25
|
||||||
|
=========================
|
||||||
|
|
||||||
|
This incorporates all changes after 4.19.1 up to 4.19.2.
|
||||||
|
|
||||||
|
5.0.0-beta.2 / 2024-03-20
|
||||||
|
=========================
|
||||||
|
|
||||||
|
This incorporates all changes after 4.17.2 up to 4.19.1.
|
||||||
|
|
||||||
|
5.0.0-beta.1 / 2022-02-14
|
||||||
|
=========================
|
||||||
|
|
||||||
|
This is the first Express 5.0 beta release, based off 4.17.2 and includes
|
||||||
|
changes from 5.0.0-alpha.8.
|
||||||
|
|
||||||
|
* change:
|
||||||
|
- Default "query parser" setting to `'simple'`
|
||||||
|
- Requires Node.js 4+
|
||||||
|
- Use `mime-types` for file to content type mapping
|
||||||
|
* deps: array-flatten@3.0.0
|
||||||
|
* deps: body-parser@2.0.0-beta.1
|
||||||
|
- `req.body` is no longer always initialized to `{}`
|
||||||
|
- `urlencoded` parser now defaults `extended` to `false`
|
||||||
|
- Use `on-finished` to determine when body read
|
||||||
|
* deps: router@2.0.0-beta.1
|
||||||
|
- Add new `?`, `*`, and `+` parameter modifiers
|
||||||
|
- Internalize private `router.process_params` method
|
||||||
|
- Matching group expressions are only RegExp syntax
|
||||||
|
- Named matching groups no longer available by position in `req.params`
|
||||||
|
- Regular expressions can only be used in a matching group
|
||||||
|
- Remove `debug` dependency
|
||||||
|
- Special `*` path segment behavior removed
|
||||||
|
- deps: array-flatten@3.0.0
|
||||||
|
- deps: parseurl@~1.3.3
|
||||||
|
- deps: path-to-regexp@3.2.0
|
||||||
|
- deps: setprototypeof@1.2.0
|
||||||
|
* deps: send@1.0.0-beta.1
|
||||||
|
- Change `dotfiles` option default to `'ignore'`
|
||||||
|
- Remove `hidden` option; use `dotfiles` option instead
|
||||||
|
- Use `mime-types` for file to content type mapping
|
||||||
|
- deps: debug@3.1.0
|
||||||
|
* deps: serve-static@2.0.0-beta.1
|
||||||
|
- Change `dotfiles` option default to `'ignore'`
|
||||||
|
- Remove `hidden` option; use `dotfiles` option instead
|
||||||
|
- Use `mime-types` for file to content type mapping
|
||||||
|
- Remove `express.static.mime` export; use `mime-types` package instead
|
||||||
|
- deps: send@1.0.0-beta.1
|
||||||
|
|
||||||
|
5.0.0-alpha.8 / 2020-03-25
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This is the eighth Express 5.0 alpha release, based off 4.17.1 and includes
|
||||||
|
changes from 5.0.0-alpha.7.
|
||||||
|
|
||||||
|
5.0.0-alpha.7 / 2018-10-26
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This is the seventh Express 5.0 alpha release, based off 4.16.4 and includes
|
||||||
|
changes from 5.0.0-alpha.6.
|
||||||
|
|
||||||
|
The major change with this alpha is the basic support for returned, rejected
|
||||||
|
Promises in the router.
|
||||||
|
|
||||||
|
* remove:
|
||||||
|
- `path-to-regexp` dependency
|
||||||
|
* deps: debug@3.1.0
|
||||||
|
- Add `DEBUG_HIDE_DATE` environment variable
|
||||||
|
- Change timer to per-namespace instead of global
|
||||||
|
- Change non-TTY date format
|
||||||
|
- Remove `DEBUG_FD` environment variable support
|
||||||
|
- Support 256 namespace colors
|
||||||
|
* deps: router@2.0.0-alpha.1
|
||||||
|
- Add basic support for returned, rejected Promises
|
||||||
|
- Fix JSDoc for `Router` constructor
|
||||||
|
- deps: debug@3.1.0
|
||||||
|
- deps: parseurl@~1.3.2
|
||||||
|
- deps: setprototypeof@1.1.0
|
||||||
|
- deps: utils-merge@1.0.1
|
||||||
|
|
||||||
|
5.0.0-alpha.6 / 2017-09-24
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This is the sixth Express 5.0 alpha release, based off 4.15.5 and includes
|
||||||
|
changes from 5.0.0-alpha.5.
|
||||||
|
|
||||||
|
* remove:
|
||||||
|
- `res.redirect(url, status)` signature - use `res.redirect(status, url)`
|
||||||
|
- `res.send(status, body)` signature - use `res.status(status).send(body)`
|
||||||
|
* deps: router@~1.3.1
|
||||||
|
- deps: debug@2.6.8
|
||||||
|
|
||||||
|
5.0.0-alpha.5 / 2017-03-06
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This is the fifth Express 5.0 alpha release, based off 4.15.2 and includes
|
||||||
|
changes from 5.0.0-alpha.4.
|
||||||
|
|
||||||
|
5.0.0-alpha.4 / 2017-03-01
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This is the fourth Express 5.0 alpha release, based off 4.15.0 and includes
|
||||||
|
changes from 5.0.0-alpha.3.
|
||||||
|
|
||||||
|
* remove:
|
||||||
|
- Remove Express 3.x middleware error stubs
|
||||||
|
* deps: router@~1.3.0
|
||||||
|
- Add `next("router")` to exit from router
|
||||||
|
- Fix case where `router.use` skipped requests routes did not
|
||||||
|
- Skip routing when `req.url` is not set
|
||||||
|
- Use `%o` in path debug to tell types apart
|
||||||
|
- deps: debug@2.6.1
|
||||||
|
- deps: setprototypeof@1.0.3
|
||||||
|
- perf: add fast match path for `*` route
|
||||||
|
|
||||||
|
5.0.0-alpha.3 / 2017-01-28
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This is the third Express 5.0 alpha release, based off 4.14.1 and includes
|
||||||
|
changes from 5.0.0-alpha.2.
|
||||||
|
|
||||||
|
* remove:
|
||||||
|
- `res.json(status, obj)` signature - use `res.status(status).json(obj)`
|
||||||
|
- `res.jsonp(status, obj)` signature - use `res.status(status).jsonp(obj)`
|
||||||
|
- `res.vary()` (no arguments) -- provide a field name as an argument
|
||||||
|
* deps: array-flatten@2.1.1
|
||||||
|
* deps: path-is-absolute@1.0.1
|
||||||
|
* deps: router@~1.1.5
|
||||||
|
- deps: array-flatten@2.0.1
|
||||||
|
- deps: methods@~1.1.2
|
||||||
|
- deps: parseurl@~1.3.1
|
||||||
|
- deps: setprototypeof@1.0.2
|
||||||
|
|
||||||
|
5.0.0-alpha.2 / 2015-07-06
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This is the second Express 5.0 alpha release, based off 4.13.1 and includes
|
||||||
|
changes from 5.0.0-alpha.1.
|
||||||
|
|
||||||
|
* remove:
|
||||||
|
- `app.param(fn)`
|
||||||
|
- `req.param()` -- use `req.params`, `req.body`, or `req.query` instead
|
||||||
|
* change:
|
||||||
|
- `res.render` callback is always async, even for sync view engines
|
||||||
|
- The leading `:` character in `name` for `app.param(name, fn)` is no longer removed
|
||||||
|
- Use `router` module for routing
|
||||||
|
- Use `path-is-absolute` module for absolute path detection
|
||||||
|
|
||||||
|
5.0.0-alpha.1 / 2014-11-06
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This is the first Express 5.0 alpha release, based off 4.10.1.
|
||||||
|
|
||||||
|
* remove:
|
||||||
|
- `app.del` - use `app.delete`
|
||||||
|
- `req.acceptsCharset` - use `req.acceptsCharsets`
|
||||||
|
- `req.acceptsEncoding` - use `req.acceptsEncodings`
|
||||||
|
- `req.acceptsLanguage` - use `req.acceptsLanguages`
|
||||||
|
- `res.json(obj, status)` signature - use `res.json(status, obj)`
|
||||||
|
- `res.jsonp(obj, status)` signature - use `res.jsonp(status, obj)`
|
||||||
|
- `res.send(body, status)` signature - use `res.send(status, body)`
|
||||||
|
- `res.send(status)` signature - use `res.sendStatus(status)`
|
||||||
|
- `res.sendfile` - use `res.sendFile` instead
|
||||||
|
- `express.query` middleware
|
||||||
|
* change:
|
||||||
|
- `req.host` now returns host (`hostname:port`) - use `req.hostname` for only hostname
|
||||||
|
- `req.query` is now a getter instead of a plain property
|
||||||
|
* add:
|
||||||
|
- `app.router` is a reference to the base router
|
||||||
|
|
||||||
|
4.20.0 / 2024-09-10
|
||||||
|
==========
|
||||||
|
* deps: serve-static@0.16.0
|
||||||
|
* Remove link renderization in html while redirecting
|
||||||
|
* deps: send@0.19.0
|
||||||
|
* Remove link renderization in html while redirecting
|
||||||
|
* deps: body-parser@0.6.0
|
||||||
|
* add `depth` option to customize the depth level in the parser
|
||||||
|
* IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`)
|
||||||
|
* Remove link renderization in html while using `res.redirect`
|
||||||
|
* deps: path-to-regexp@0.1.10
|
||||||
|
- Adds support for named matching groups in the routes using a regex
|
||||||
|
- Adds backtracking protection to parameters without regexes defined
|
||||||
|
* deps: encodeurl@~2.0.0
|
||||||
|
- Removes encoding of `\`, `|`, and `^` to align better with URL spec
|
||||||
|
* Deprecate passing `options.maxAge` and `options.expires` to `res.clearCookie`
|
||||||
|
- Will be ignored in v5, clearCookie will set a cookie with an expires in the past to instruct clients to delete the cookie
|
||||||
|
|
||||||
|
4.19.2 / 2024-03-25
|
||||||
|
==========
|
||||||
|
|
||||||
|
* Improved fix for open redirect allow list bypass
|
||||||
|
|
||||||
|
4.19.1 / 2024-03-20
|
||||||
|
==========
|
||||||
|
|
||||||
|
* Allow passing non-strings to res.location with new encoding handling checks
|
||||||
|
|
||||||
|
4.19.0 / 2024-03-20
|
||||||
|
==========
|
||||||
|
|
||||||
|
* Prevent open redirect allow list bypass due to encodeurl
|
||||||
|
* deps: cookie@0.6.0
|
||||||
|
|
||||||
|
4.18.3 / 2024-02-29
|
||||||
|
==========
|
||||||
|
|
||||||
|
* Fix routing requests without method
|
||||||
|
* deps: body-parser@1.20.2
|
||||||
|
- Fix strict json error message on Node.js 19+
|
||||||
|
- deps: content-type@~1.0.5
|
||||||
|
- deps: raw-body@2.5.2
|
||||||
|
* deps: cookie@0.6.0
|
||||||
|
- Add `partitioned` option
|
||||||
|
|
||||||
|
4.18.2 / 2022-10-08
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix regression routing a large stack in a single route
|
||||||
|
* deps: body-parser@1.20.1
|
||||||
|
- deps: qs@6.11.0
|
||||||
|
- perf: remove unnecessary object clone
|
||||||
|
* deps: qs@6.11.0
|
||||||
|
|
||||||
|
4.18.1 / 2022-04-29
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix hanging on large stack of sync routes
|
||||||
|
|
||||||
|
4.18.0 / 2022-04-25
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Add "root" option to `res.download`
|
||||||
|
* Allow `options` without `filename` in `res.download`
|
||||||
|
* Deprecate string and non-integer arguments to `res.status`
|
||||||
|
* Fix behavior of `null`/`undefined` as `maxAge` in `res.cookie`
|
||||||
|
* Fix handling very large stacks of sync middleware
|
||||||
|
* Ignore `Object.prototype` values in settings through `app.set`/`app.get`
|
||||||
|
* Invoke `default` with same arguments as types in `res.format`
|
||||||
|
* Support proper 205 responses using `res.send`
|
||||||
|
* Use `http-errors` for `res.format` error
|
||||||
|
* deps: body-parser@1.20.0
|
||||||
|
- Fix error message for json parse whitespace in `strict`
|
||||||
|
- Fix internal error when inflated body exceeds limit
|
||||||
|
- Prevent loss of async hooks context
|
||||||
|
- Prevent hanging when request already read
|
||||||
|
- deps: depd@2.0.0
|
||||||
|
- deps: http-errors@2.0.0
|
||||||
|
- deps: on-finished@2.4.1
|
||||||
|
- deps: qs@6.10.3
|
||||||
|
- deps: raw-body@2.5.1
|
||||||
|
* deps: cookie@0.5.0
|
||||||
|
- Add `priority` option
|
||||||
|
- Fix `expires` option to reject invalid dates
|
||||||
|
* deps: depd@2.0.0
|
||||||
|
- Replace internal `eval` usage with `Function` constructor
|
||||||
|
- Use instance methods on `process` to check for listeners
|
||||||
|
* deps: finalhandler@1.2.0
|
||||||
|
- Remove set content headers that break response
|
||||||
|
- deps: on-finished@2.4.1
|
||||||
|
- deps: statuses@2.0.1
|
||||||
|
* deps: on-finished@2.4.1
|
||||||
|
- Prevent loss of async hooks context
|
||||||
|
* deps: qs@6.10.3
|
||||||
|
* deps: send@0.18.0
|
||||||
|
- Fix emitted 416 error missing headers property
|
||||||
|
- Limit the headers removed for 304 response
|
||||||
|
- deps: depd@2.0.0
|
||||||
|
- deps: destroy@1.2.0
|
||||||
|
- deps: http-errors@2.0.0
|
||||||
|
- deps: on-finished@2.4.1
|
||||||
|
- deps: statuses@2.0.1
|
||||||
|
* deps: serve-static@1.15.0
|
||||||
|
- deps: send@0.18.0
|
||||||
|
* deps: statuses@2.0.1
|
||||||
|
- Remove code 306
|
||||||
|
- Rename `425 Unordered Collection` to standard `425 Too Early`
|
||||||
|
|
||||||
|
4.17.3 / 2022-02-16
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: accepts@~1.3.8
|
||||||
|
- deps: mime-types@~2.1.34
|
||||||
|
- deps: negotiator@0.6.3
|
||||||
|
* deps: body-parser@1.19.2
|
||||||
|
- deps: bytes@3.1.2
|
||||||
|
- deps: qs@6.9.7
|
||||||
|
- deps: raw-body@2.4.3
|
||||||
|
* deps: cookie@0.4.2
|
||||||
|
* deps: qs@6.9.7
|
||||||
|
* Fix handling of `__proto__` keys
|
||||||
|
* pref: remove unnecessary regexp for trust proxy
|
||||||
|
|
||||||
|
4.17.2 / 2021-12-16
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix handling of `undefined` in `res.jsonp`
|
||||||
|
* Fix handling of `undefined` when `"json escape"` is enabled
|
||||||
|
* Fix incorrect middleware execution with unanchored `RegExp`s
|
||||||
|
* Fix `res.jsonp(obj, status)` deprecation message
|
||||||
|
* Fix typo in `res.is` JSDoc
|
||||||
|
* deps: body-parser@1.19.1
|
||||||
|
- deps: bytes@3.1.1
|
||||||
|
- deps: http-errors@1.8.1
|
||||||
|
- deps: qs@6.9.6
|
||||||
|
- deps: raw-body@2.4.2
|
||||||
|
- deps: safe-buffer@5.2.1
|
||||||
|
- deps: type-is@~1.6.18
|
||||||
|
* deps: content-disposition@0.5.4
|
||||||
|
- deps: safe-buffer@5.2.1
|
||||||
|
* deps: cookie@0.4.1
|
||||||
|
- Fix `maxAge` option to reject invalid values
|
||||||
|
* deps: proxy-addr@~2.0.7
|
||||||
|
- Use `req.socket` over deprecated `req.connection`
|
||||||
|
- deps: forwarded@0.2.0
|
||||||
|
- deps: ipaddr.js@1.9.1
|
||||||
|
* deps: qs@6.9.6
|
||||||
|
* deps: safe-buffer@5.2.1
|
||||||
|
* deps: send@0.17.2
|
||||||
|
- deps: http-errors@1.8.1
|
||||||
|
- deps: ms@2.1.3
|
||||||
|
- pref: ignore empty http tokens
|
||||||
|
* deps: serve-static@1.14.2
|
||||||
|
- deps: send@0.17.2
|
||||||
|
* deps: setprototypeof@1.2.0
|
||||||
|
|
||||||
|
4.17.1 / 2019-05-25
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Revert "Improve error message for `null`/`undefined` to `res.status`"
|
||||||
|
|
||||||
|
4.17.0 / 2019-05-16
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Add `express.raw` to parse bodies into `Buffer`
|
||||||
|
* Add `express.text` to parse bodies into string
|
||||||
|
* Improve error message for non-strings to `res.sendFile`
|
||||||
|
* Improve error message for `null`/`undefined` to `res.status`
|
||||||
|
* Support multiple hosts in `X-Forwarded-Host`
|
||||||
|
* deps: accepts@~1.3.7
|
||||||
|
* deps: body-parser@1.19.0
|
||||||
|
- Add encoding MIK
|
||||||
|
- Add petabyte (`pb`) support
|
||||||
|
- Fix parsing array brackets after index
|
||||||
|
- deps: bytes@3.1.0
|
||||||
|
- deps: http-errors@1.7.2
|
||||||
|
- deps: iconv-lite@0.4.24
|
||||||
|
- deps: qs@6.7.0
|
||||||
|
- deps: raw-body@2.4.0
|
||||||
|
- deps: type-is@~1.6.17
|
||||||
|
* deps: content-disposition@0.5.3
|
||||||
|
* deps: cookie@0.4.0
|
||||||
|
- Add `SameSite=None` support
|
||||||
|
* deps: finalhandler@~1.1.2
|
||||||
|
- Set stricter `Content-Security-Policy` header
|
||||||
|
- deps: parseurl@~1.3.3
|
||||||
|
- deps: statuses@~1.5.0
|
||||||
|
* deps: parseurl@~1.3.3
|
||||||
|
* deps: proxy-addr@~2.0.5
|
||||||
|
- deps: ipaddr.js@1.9.0
|
||||||
|
* deps: qs@6.7.0
|
||||||
|
- Fix parsing array brackets after index
|
||||||
|
* deps: range-parser@~1.2.1
|
||||||
|
* deps: send@0.17.1
|
||||||
|
- Set stricter CSP header in redirect & error responses
|
||||||
|
- deps: http-errors@~1.7.2
|
||||||
|
- deps: mime@1.6.0
|
||||||
|
- deps: ms@2.1.1
|
||||||
|
- deps: range-parser@~1.2.1
|
||||||
|
- deps: statuses@~1.5.0
|
||||||
|
- perf: remove redundant `path.normalize` call
|
||||||
|
* deps: serve-static@1.14.1
|
||||||
|
- Set stricter CSP header in redirect response
|
||||||
|
- deps: parseurl@~1.3.3
|
||||||
|
- deps: send@0.17.1
|
||||||
|
* deps: setprototypeof@1.1.1
|
||||||
|
* deps: statuses@~1.5.0
|
||||||
|
- Add `103 Early Hints`
|
||||||
|
* deps: type-is@~1.6.18
|
||||||
|
- deps: mime-types@~2.1.24
|
||||||
|
- perf: prevent internal `throw` on invalid type
|
||||||
|
|
||||||
|
4.16.4 / 2018-10-10
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix issue where `"Request aborted"` may be logged in `res.sendfile`
|
||||||
|
* Fix JSDoc for `Router` constructor
|
||||||
|
* deps: body-parser@1.18.3
|
||||||
|
- Fix deprecation warnings on Node.js 10+
|
||||||
|
- Fix stack trace for strict json parse error
|
||||||
|
- deps: depd@~1.1.2
|
||||||
|
- deps: http-errors@~1.6.3
|
||||||
|
- deps: iconv-lite@0.4.23
|
||||||
|
- deps: qs@6.5.2
|
||||||
|
- deps: raw-body@2.3.3
|
||||||
|
- deps: type-is@~1.6.16
|
||||||
|
* deps: proxy-addr@~2.0.4
|
||||||
|
- deps: ipaddr.js@1.8.0
|
||||||
|
* deps: qs@6.5.2
|
||||||
|
* deps: safe-buffer@5.1.2
|
||||||
|
|
||||||
|
4.16.3 / 2018-03-12
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: accepts@~1.3.5
|
||||||
|
- deps: mime-types@~2.1.18
|
||||||
|
* deps: depd@~1.1.2
|
||||||
|
- perf: remove argument reassignment
|
||||||
|
* deps: encodeurl@~1.0.2
|
||||||
|
- Fix encoding `%` as last character
|
||||||
|
* deps: finalhandler@1.1.1
|
||||||
|
- Fix 404 output for bad / missing pathnames
|
||||||
|
- deps: encodeurl@~1.0.2
|
||||||
|
- deps: statuses@~1.4.0
|
||||||
|
* deps: proxy-addr@~2.0.3
|
||||||
|
- deps: ipaddr.js@1.6.0
|
||||||
|
* deps: send@0.16.2
|
||||||
|
- Fix incorrect end tag in default error & redirects
|
||||||
|
- deps: depd@~1.1.2
|
||||||
|
- deps: encodeurl@~1.0.2
|
||||||
|
- deps: statuses@~1.4.0
|
||||||
|
* deps: serve-static@1.13.2
|
||||||
|
- Fix incorrect end tag in redirects
|
||||||
|
- deps: encodeurl@~1.0.2
|
||||||
|
- deps: send@0.16.2
|
||||||
|
* deps: statuses@~1.4.0
|
||||||
|
* deps: type-is@~1.6.16
|
||||||
|
- deps: mime-types@~2.1.18
|
||||||
|
|
||||||
|
4.16.2 / 2017-10-09
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix `TypeError` in `res.send` when given `Buffer` and `ETag` header set
|
||||||
|
* perf: skip parsing of entire `X-Forwarded-Proto` header
|
||||||
|
|
||||||
4.16.1 / 2017-09-29
|
4.16.1 / 2017-09-29
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
|
@ -11,6 +501,7 @@
|
||||||
|
|
||||||
* Add `"json escape"` setting for `res.json` and `res.jsonp`
|
* Add `"json escape"` setting for `res.json` and `res.jsonp`
|
||||||
* Add `express.json` and `express.urlencoded` to parse bodies
|
* Add `express.json` and `express.urlencoded` to parse bodies
|
||||||
|
* Add `options` argument to `res.download`
|
||||||
* Improve error message when autoloading invalid view engine
|
* Improve error message when autoloading invalid view engine
|
||||||
* Improve error messages when non-function provided as middleware
|
* Improve error messages when non-function provided as middleware
|
||||||
* Skip `Buffer` encoding when not generating ETag for small response
|
* Skip `Buffer` encoding when not generating ETag for small response
|
||||||
|
|
@ -240,7 +731,7 @@
|
||||||
- Fix including type extensions in parameters in `Accept` parsing
|
- Fix including type extensions in parameters in `Accept` parsing
|
||||||
- Fix parsing `Accept` parameters with quoted equals
|
- Fix parsing `Accept` parameters with quoted equals
|
||||||
- Fix parsing `Accept` parameters with quoted semicolons
|
- Fix parsing `Accept` parameters with quoted semicolons
|
||||||
- Many performance improvments
|
- Many performance improvements
|
||||||
- deps: mime-types@~2.1.11
|
- deps: mime-types@~2.1.11
|
||||||
- deps: negotiator@0.6.1
|
- deps: negotiator@0.6.1
|
||||||
* deps: content-type@~1.0.2
|
* deps: content-type@~1.0.2
|
||||||
|
|
@ -255,7 +746,7 @@
|
||||||
- perf: enable strict mode
|
- perf: enable strict mode
|
||||||
- perf: hoist regular expression
|
- perf: hoist regular expression
|
||||||
- perf: use for loop in parse
|
- perf: use for loop in parse
|
||||||
- perf: use string concatination for serialization
|
- perf: use string concatenation for serialization
|
||||||
* deps: finalhandler@0.5.0
|
* deps: finalhandler@0.5.0
|
||||||
- Change invalid or non-numeric status code to 500
|
- Change invalid or non-numeric status code to 500
|
||||||
- Overwrite status message to match set status code
|
- Overwrite status message to match set status code
|
||||||
|
|
@ -265,7 +756,7 @@
|
||||||
* deps: proxy-addr@~1.1.2
|
* deps: proxy-addr@~1.1.2
|
||||||
- Fix accepting various invalid netmasks
|
- Fix accepting various invalid netmasks
|
||||||
- Fix IPv6-mapped IPv4 validation edge cases
|
- Fix IPv6-mapped IPv4 validation edge cases
|
||||||
- IPv4 netmasks must be contingous
|
- IPv4 netmasks must be contiguous
|
||||||
- IPv6 addresses cannot be used as a netmask
|
- IPv6 addresses cannot be used as a netmask
|
||||||
- deps: ipaddr.js@1.1.1
|
- deps: ipaddr.js@1.1.1
|
||||||
* deps: qs@6.2.0
|
* deps: qs@6.2.0
|
||||||
|
|
@ -1043,13 +1534,13 @@
|
||||||
- deps: negotiator@0.4.6
|
- deps: negotiator@0.4.6
|
||||||
* deps: debug@1.0.2
|
* deps: debug@1.0.2
|
||||||
* deps: send@0.4.3
|
* deps: send@0.4.3
|
||||||
- Do not throw un-catchable error on file open race condition
|
- Do not throw uncatchable error on file open race condition
|
||||||
- Use `escape-html` for HTML escaping
|
- Use `escape-html` for HTML escaping
|
||||||
- deps: debug@1.0.2
|
- deps: debug@1.0.2
|
||||||
- deps: finished@1.2.2
|
- deps: finished@1.2.2
|
||||||
- deps: fresh@0.2.2
|
- deps: fresh@0.2.2
|
||||||
* deps: serve-static@1.2.3
|
* deps: serve-static@1.2.3
|
||||||
- Do not throw un-catchable error on file open race condition
|
- Do not throw uncatchable error on file open race condition
|
||||||
- deps: send@0.4.3
|
- deps: send@0.4.3
|
||||||
|
|
||||||
4.4.2 / 2014-06-09
|
4.4.2 / 2014-06-09
|
||||||
|
|
@ -1890,7 +2381,7 @@
|
||||||
* deps: connect@2.21.0
|
* deps: connect@2.21.0
|
||||||
- deprecate `connect(middleware)` -- use `app.use(middleware)` instead
|
- deprecate `connect(middleware)` -- use `app.use(middleware)` instead
|
||||||
- deprecate `connect.createServer()` -- use `connect()` instead
|
- deprecate `connect.createServer()` -- use `connect()` instead
|
||||||
- fix `res.setHeader()` patch to work with with get -> append -> set pattern
|
- fix `res.setHeader()` patch to work with get -> append -> set pattern
|
||||||
- deps: compression@~1.0.8
|
- deps: compression@~1.0.8
|
||||||
- deps: errorhandler@~1.1.1
|
- deps: errorhandler@~1.1.1
|
||||||
- deps: express-session@~1.5.0
|
- deps: express-session@~1.5.0
|
||||||
|
|
@ -1929,7 +2420,7 @@
|
||||||
- deps: serve-static@1.2.3
|
- deps: serve-static@1.2.3
|
||||||
* deps: debug@1.0.2
|
* deps: debug@1.0.2
|
||||||
* deps: send@0.4.3
|
* deps: send@0.4.3
|
||||||
- Do not throw un-catchable error on file open race condition
|
- Do not throw uncatchable error on file open race condition
|
||||||
- Use `escape-html` for HTML escaping
|
- Use `escape-html` for HTML escaping
|
||||||
- deps: debug@1.0.2
|
- deps: debug@1.0.2
|
||||||
- deps: finished@1.2.2
|
- deps: finished@1.2.2
|
||||||
|
|
@ -3101,8 +3592,8 @@ Shaw]
|
||||||
* Added node v0.1.97 compatibility
|
* Added node v0.1.97 compatibility
|
||||||
* Added support for deleting cookies via Request#cookie('key', null)
|
* Added support for deleting cookies via Request#cookie('key', null)
|
||||||
* Updated haml submodule
|
* Updated haml submodule
|
||||||
* Fixed not-found page, now using using charset utf-8
|
* Fixed not-found page, now using charset utf-8
|
||||||
* Fixed show-exceptions page, now using using charset utf-8
|
* Fixed show-exceptions page, now using charset utf-8
|
||||||
* Fixed view support due to fs.readFile Buffers
|
* Fixed view support due to fs.readFile Buffers
|
||||||
* Changed; mime.type() no longer accepts ".type" due to node extname() changes
|
* Changed; mime.type() no longer accepts ".type" due to node extname() changes
|
||||||
|
|
||||||
|
|
@ -3114,7 +3605,7 @@ Shaw]
|
||||||
* Updated haml submodule
|
* Updated haml submodule
|
||||||
* Changed ETag; removed inode, modified time only
|
* Changed ETag; removed inode, modified time only
|
||||||
* Fixed LF to CRLF for setting multiple cookies
|
* Fixed LF to CRLF for setting multiple cookies
|
||||||
* Fixed cookie complation; values are now urlencoded
|
* Fixed cookie compilation; values are now urlencoded
|
||||||
* Fixed cookies parsing; accepts quoted values and url escaped cookies
|
* Fixed cookies parsing; accepts quoted values and url escaped cookies
|
||||||
|
|
||||||
0.11.0 / 2010-05-06
|
0.11.0 / 2010-05-06
|
||||||
|
|
@ -3137,7 +3628,7 @@ Shaw]
|
||||||
==================
|
==================
|
||||||
|
|
||||||
* Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s
|
* Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s
|
||||||
encoding is set to 'utf8' or 'utf-8'.
|
encoding is set to 'utf8' or 'utf-8').
|
||||||
* Added "encoding" option to Request#render(). Closes #299
|
* Added "encoding" option to Request#render(). Closes #299
|
||||||
* Added "dump exceptions" setting, which is enabled by default.
|
* Added "dump exceptions" setting, which is enabled by default.
|
||||||
* Added simple ejs template engine support
|
* Added simple ejs template engine support
|
||||||
|
|
@ -3176,7 +3667,7 @@ Shaw]
|
||||||
* Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js
|
* Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js
|
||||||
* Added callback function support to Request#halt() as 3rd/4th arg
|
* Added callback function support to Request#halt() as 3rd/4th arg
|
||||||
* Added preprocessing of route param wildcards using param(). Closes #251
|
* Added preprocessing of route param wildcards using param(). Closes #251
|
||||||
* Added view partial support (with collections etc)
|
* Added view partial support (with collections etc.)
|
||||||
* Fixed bug preventing falsey params (such as ?page=0). Closes #286
|
* Fixed bug preventing falsey params (such as ?page=0). Closes #286
|
||||||
* Fixed setting of multiple cookies. Closes #199
|
* Fixed setting of multiple cookies. Closes #199
|
||||||
* Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml)
|
* Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml)
|
||||||
|
|
@ -3309,7 +3800,7 @@ Shaw]
|
||||||
|
|
||||||
* Added "plot" format option for Profiler (for gnuplot processing)
|
* Added "plot" format option for Profiler (for gnuplot processing)
|
||||||
* Added request number to Profiler plugin
|
* Added request number to Profiler plugin
|
||||||
* Fixed binary encoding for multi-part file uploads, was previously defaulting to UTF8
|
* Fixed binary encoding for multipart file uploads, was previously defaulting to UTF8
|
||||||
* Fixed issue with routes not firing when not files are present. Closes #184
|
* Fixed issue with routes not firing when not files are present. Closes #184
|
||||||
* Fixed process.Promise -> events.Promise
|
* Fixed process.Promise -> events.Promise
|
||||||
|
|
||||||
|
|
@ -3355,7 +3846,7 @@ Shaw]
|
||||||
* Updated sample chat app to show messages on load
|
* Updated sample chat app to show messages on load
|
||||||
* Updated libxmljs parseString -> parseHtmlString
|
* Updated libxmljs parseString -> parseHtmlString
|
||||||
* Fixed `make init` to work with older versions of git
|
* Fixed `make init` to work with older versions of git
|
||||||
* Fixed specs can now run independent specs for those who cant build deps. Closes #127
|
* Fixed specs can now run independent specs for those who can't build deps. Closes #127
|
||||||
* Fixed issues introduced by the node url module changes. Closes 126.
|
* Fixed issues introduced by the node url module changes. Closes 126.
|
||||||
* Fixed two assertions failing due to Collection#keys() returning strings
|
* Fixed two assertions failing due to Collection#keys() returning strings
|
||||||
* Fixed faulty Collection#toArray() spec due to keys() returning strings
|
* Fixed faulty Collection#toArray() spec due to keys() returning strings
|
||||||
|
|
|
||||||
125
Readme-Guide.md
125
Readme-Guide.md
|
|
@ -1,125 +0,0 @@
|
||||||
# README guidelines
|
|
||||||
|
|
||||||
Every module in the expressjs, pillarjs, and jshttp organizations should have
|
|
||||||
a README file named `README.md`. The purpose of the README is to:
|
|
||||||
|
|
||||||
- Explain the purpose of the module and how to use it.
|
|
||||||
- Act as a landing page (both on GitHub and npmjs.com) for the module to help
|
|
||||||
people find it via search. Middleware module READMEs are also incorporated
|
|
||||||
into https://expressjs.com/en/resources/middleware.html.
|
|
||||||
- Encourage community contributions and participation.
|
|
||||||
|
|
||||||
Use the [README template](https://github.com/expressjs/express/wiki/README-template)
|
|
||||||
to quickly create a new README file.
|
|
||||||
|
|
||||||
## Top-level items
|
|
||||||
|
|
||||||
**Badges** (optional): At the very top (with no subheading), include any
|
|
||||||
applicable badges, such as npm version/downloads, build status, test coverage,
|
|
||||||
and so on. Badges should resolve properly (not display a broken image).
|
|
||||||
|
|
||||||
Possible badges include:
|
|
||||||
- npm version: `[![NPM Version][npm-image]][npm-url]`
|
|
||||||
- npm downloads: `[![NPM Downloads][downloads-image]][downloads-url]`
|
|
||||||
- Build status: `[![Build Status][travis-image]][travis-url]`
|
|
||||||
- Test coverage: `[![Test Coverage][coveralls-image]][coveralls-url]`
|
|
||||||
- Tips: `[![Gratipay][gratipay-image]][gratipay-url]`
|
|
||||||
|
|
||||||
**Summary**: Following badges, provide a one- or two-sentence description of
|
|
||||||
what the module does. This should be the same as the npmjs.org blurb (which
|
|
||||||
comes from the description property of `package.json`). Since npm doesn't
|
|
||||||
handle markdown for the blurb, avoid using markdown in the summary sentence.
|
|
||||||
|
|
||||||
**TOC** (Optional): For longer READMEs, provide a table of contents that has
|
|
||||||
a relative link to each section. A tool such as
|
|
||||||
[doctoc](https://www.npmjs.com/package/doctoc) makes it very easy to generate
|
|
||||||
a TOC.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Optionally, include a section of one or two paragraphs with more high-level
|
|
||||||
information on what the module does, what problems it solves, why one would
|
|
||||||
use it and how. Don't just repeat what's in the summary.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Required. This section is typically just:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ npm install module-name
|
|
||||||
```
|
|
||||||
|
|
||||||
But include any other steps or requirements.
|
|
||||||
|
|
||||||
NOTE: Use the `sh` code block to make the shell command display properly on
|
|
||||||
the website.
|
|
||||||
|
|
||||||
## Basic use
|
|
||||||
|
|
||||||
- Provide a general description of how to use the module with code sample.
|
|
||||||
Include any important caveats or restrictions.
|
|
||||||
- Explain the most common use cases.
|
|
||||||
- Optional: a simple "hello world" type example (where applicable). This
|
|
||||||
example is in addition to the more comprehensive [example section](#examples)
|
|
||||||
later.
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
Provide complete API documentation.
|
|
||||||
|
|
||||||
Formatting conventions: Each function is listed in a 3rd-level heading (`###`),
|
|
||||||
like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
### Function_name(arg, options [, optional_arg] ... )
|
|
||||||
```
|
|
||||||
|
|
||||||
**Options objects**
|
|
||||||
|
|
||||||
For arguments that are objects (for example, options object), describe the
|
|
||||||
properties in a table, as follows. This matches the formatting used in the
|
|
||||||
[Express API docs](https://expressjs.com/en/4x/api.html).
|
|
||||||
|
|
||||||
|Property | Description | Type | Default|
|
|
||||||
|----------|-----------|------------|-------------|
|
|
||||||
|Name of the property in `monospace`. | Brief description | String, Number, Boolean, etc. | If applicable.|
|
|
||||||
|
|
||||||
If all the properties are required (i.e. there are no defaults), then you
|
|
||||||
can omit the default column.
|
|
||||||
|
|
||||||
Instead of very lengthy descriptions, link out to subsequent paragraphs for
|
|
||||||
more detailed explanation of specific cases (e.g. "When this property is set
|
|
||||||
to 'foobar', xyz happens; see <link to following section >.)
|
|
||||||
|
|
||||||
If there are options properties that are themselves options, use additional
|
|
||||||
tables. See [`trust proxy` and `etag` properties](https://expressjs.com/en/4x/api.html#app.settings.table).
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
Every README should have at least one example; ideally more. For code samples,
|
|
||||||
be sure to use the `js` code block, for proper display in the website, e.g.:
|
|
||||||
|
|
||||||
```js
|
|
||||||
var csurf = require('csurf')
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
What tests are included.
|
|
||||||
|
|
||||||
How to run them.
|
|
||||||
|
|
||||||
The convention for running tests is `npm test`. All our projects should follow
|
|
||||||
this convention.
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
Names of module "owners" (lead developers) and other developers who have
|
|
||||||
contributed.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Link to the license, with a short description of what it is, e.g. "MIT" or
|
|
||||||
whatever. Ideally, avoid putting the license text directly in the README; link
|
|
||||||
to it instead.
|
|
||||||
232
Readme.md
232
Readme.md
|
|
@ -1,22 +1,48 @@
|
||||||
[](http://expressjs.com/)
|
[](https://expressjs.com/)
|
||||||
|
|
||||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
|
**Fast, unopinionated, minimalist web framework for [Node.js](https://nodejs.org).**
|
||||||
|
|
||||||
|
**This project has a [Code of Conduct].**
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
- [Table of contents](#table-of-contents)
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [Features](#features)
|
||||||
|
- [Docs \& Community](#docs--community)
|
||||||
|
- [Quick Start](#quick-start)
|
||||||
|
- [Philosophy](#philosophy)
|
||||||
|
- [Examples](#examples)
|
||||||
|
- [Contributing](#contributing)
|
||||||
|
- [Security Issues](#security-issues)
|
||||||
|
- [Running Tests](#running-tests)
|
||||||
|
- [Current project team members](#current-project-team-members)
|
||||||
|
- [TC (Technical Committee)](#tc-technical-committee)
|
||||||
|
- [TC emeriti members](#tc-emeriti-members)
|
||||||
|
- [Triagers](#triagers)
|
||||||
|
- [Emeritus Triagers](#emeritus-triagers)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
|
|
||||||
|
[![NPM Version][npm-version-image]][npm-url]
|
||||||
|
[![NPM Downloads][npm-downloads-image]][npm-downloads-url]
|
||||||
|
[![Linux Build][github-actions-ci-image]][github-actions-ci-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
|
||||||
|
|
||||||
[![NPM Version][npm-image]][npm-url]
|
|
||||||
[![NPM Downloads][downloads-image]][downloads-url]
|
|
||||||
[![Linux Build][travis-image]][travis-url]
|
|
||||||
[![Windows Build][appveyor-image]][appveyor-url]
|
|
||||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var express = require('express')
|
import express from 'express'
|
||||||
var app = express()
|
|
||||||
|
|
||||||
app.get('/', function (req, res) {
|
const app = express()
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
res.send('Hello World')
|
res.send('Hello World')
|
||||||
})
|
})
|
||||||
|
|
||||||
app.listen(3000)
|
app.listen(3000, () => {
|
||||||
|
console.log('Server is running on http://localhost:3000')
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
@ -25,16 +51,19 @@ This is a [Node.js](https://nodejs.org/en/) module available through the
|
||||||
[npm registry](https://www.npmjs.com/).
|
[npm registry](https://www.npmjs.com/).
|
||||||
|
|
||||||
Before installing, [download and install Node.js](https://nodejs.org/en/download/).
|
Before installing, [download and install Node.js](https://nodejs.org/en/download/).
|
||||||
Node.js 0.10 or higher is required.
|
Node.js 18 or higher is required.
|
||||||
|
|
||||||
|
If this is a brand new project, make sure to create a `package.json` first with
|
||||||
|
the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file).
|
||||||
|
|
||||||
Installation is done using the
|
Installation is done using the
|
||||||
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install express
|
npm install express
|
||||||
```
|
```
|
||||||
|
|
||||||
Follow [our installing guide](http://expressjs.com/en/starter/installing.html)
|
Follow [our installing guide](https://expressjs.com/en/starter/installing.html)
|
||||||
for more information.
|
for more information.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
@ -49,18 +78,11 @@ for more information.
|
||||||
|
|
||||||
## Docs & Community
|
## Docs & Community
|
||||||
|
|
||||||
* [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]
|
* [Website and Documentation](https://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]
|
||||||
* [#express](https://webchat.freenode.net/?channels=express) on freenode IRC
|
|
||||||
* [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules
|
* [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules
|
||||||
* Visit the [Wiki](https://github.com/expressjs/express/wiki)
|
* [Github Discussions](https://github.com/expressjs/discussions) for discussion on the development and usage of Express
|
||||||
* [Google Group](https://groups.google.com/group/express-js) for discussion
|
|
||||||
* [Gitter](https://gitter.im/expressjs/express) for support and discussion
|
|
||||||
|
|
||||||
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/expressjs/express/wiki/New-features-in-4.x).
|
**PROTIP** Be sure to read the [migration guide to v5](https://expressjs.com/en/guide/migrating-5)
|
||||||
|
|
||||||
### Security Issues
|
|
||||||
|
|
||||||
If you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md).
|
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
|
|
@ -69,85 +91,185 @@ If you discover a security vulnerability in Express, please see [Security Polici
|
||||||
Install the executable. The executable's major version will match Express's:
|
Install the executable. The executable's major version will match Express's:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install -g express-generator@4
|
npm install -g express-generator@4
|
||||||
```
|
```
|
||||||
|
|
||||||
Create the app:
|
Create the app:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ express /tmp/foo && cd /tmp/foo
|
express /tmp/foo && cd /tmp/foo
|
||||||
```
|
```
|
||||||
|
|
||||||
Install dependencies:
|
Install dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
Start the server:
|
Start the server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
View the website at: http://localhost:3000
|
||||||
|
|
||||||
## Philosophy
|
## Philosophy
|
||||||
|
|
||||||
The Express philosophy is to provide small, robust tooling for HTTP servers, making
|
The Express philosophy is to provide small, robust tooling for HTTP servers, making
|
||||||
it a great solution for single page applications, web sites, hybrids, or public
|
it a great solution for single page applications, websites, hybrids, or public
|
||||||
HTTP APIs.
|
HTTP APIs.
|
||||||
|
|
||||||
Express does not force you to use any specific ORM or template engine. With support for over
|
Express does not force you to use any specific ORM or template engine. With support for over
|
||||||
14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js),
|
14 template engines via [@ladjs/consolidate](https://github.com/ladjs/consolidate),
|
||||||
you can quickly craft your perfect framework.
|
you can quickly craft your perfect framework.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
To view the examples, clone the Express repo and install the dependencies:
|
To view the examples, clone the Express repository:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ git clone git://github.com/expressjs/express.git --depth 1
|
git clone https://github.com/expressjs/express.git --depth 1 && cd express
|
||||||
$ cd express
|
```
|
||||||
$ npm install
|
|
||||||
|
Then install the dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
Then run whichever example you want:
|
Then run whichever example you want:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ node examples/content-negotiation
|
node examples/content-negotiation
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tests
|
## Contributing
|
||||||
|
|
||||||
To run the test suite, first install the dependencies, then run `npm test`:
|
The Express.js project welcomes all constructive contributions. Contributions take many forms,
|
||||||
|
from code for bug fixes and enhancements, to additions and fixes to documentation, additional
|
||||||
|
tests, triaging incoming pull requests and issues, and more!
|
||||||
|
|
||||||
|
See the [Contributing Guide] for more technical details on contributing.
|
||||||
|
|
||||||
|
### Security Issues
|
||||||
|
|
||||||
|
If you discover a security vulnerability in Express, please see [Security Policies and Procedures](SECURITY.md).
|
||||||
|
|
||||||
|
### Running Tests
|
||||||
|
|
||||||
|
To run the test suite, first install the dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install
|
npm install
|
||||||
$ npm test
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## People
|
Then run `npm test`:
|
||||||
|
|
||||||
The original author of Express is [TJ Holowaychuk](https://github.com/tj) [![TJ's Gratipay][gratipay-image-visionmedia]][gratipay-url-visionmedia]
|
```bash
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
The current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson) [![Doug's Gratipay][gratipay-image-dougwilson]][gratipay-url-dougwilson]
|
## Current project team members
|
||||||
|
|
||||||
|
For information about the governance of the express.js project, see [GOVERNANCE.md](https://github.com/expressjs/discussions/blob/HEAD/docs/GOVERNANCE.md).
|
||||||
|
|
||||||
|
The original author of Express is [TJ Holowaychuk](https://github.com/tj)
|
||||||
|
|
||||||
[List of all contributors](https://github.com/expressjs/express/graphs/contributors)
|
[List of all contributors](https://github.com/expressjs/express/graphs/contributors)
|
||||||
|
|
||||||
|
### TC (Technical Committee)
|
||||||
|
|
||||||
|
* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
|
||||||
|
* [jonchurch](https://github.com/jonchurch) - **Jon Church**
|
||||||
|
* [wesleytodd](https://github.com/wesleytodd) - **Wes Todd**
|
||||||
|
* [LinusU](https://github.com/LinusU) - **Linus Unnebäck**
|
||||||
|
* [blakeembrey](https://github.com/blakeembrey) - **Blake Embrey**
|
||||||
|
* [sheplu](https://github.com/sheplu) - **Jean Burellier**
|
||||||
|
* [crandmck](https://github.com/crandmck) - **Rand McKinney**
|
||||||
|
* [ctcpip](https://github.com/ctcpip) - **Chris de Almeida**
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>TC emeriti members</summary>
|
||||||
|
|
||||||
|
#### TC emeriti members
|
||||||
|
|
||||||
|
* [dougwilson](https://github.com/dougwilson) - **Douglas Wilson**
|
||||||
|
* [hacksparrow](https://github.com/hacksparrow) - **Hage Yaapa**
|
||||||
|
* [jonathanong](https://github.com/jonathanong) - **jongleberry**
|
||||||
|
* [niftylettuce](https://github.com/niftylettuce) - **niftylettuce**
|
||||||
|
* [troygoode](https://github.com/troygoode) - **Troy Goode**
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
### Triagers
|
||||||
|
|
||||||
|
* [aravindvnair99](https://github.com/aravindvnair99) - **Aravind Nair**
|
||||||
|
* [bjohansebas](https://github.com/bjohansebas) - **Sebastian Beltran**
|
||||||
|
* [carpasse](https://github.com/carpasse) - **Carlos Serrano**
|
||||||
|
* [CBID2](https://github.com/CBID2) - **Christine Belzie**
|
||||||
|
* [dpopp07](https://github.com/dpopp07) - **Dustin Popp**
|
||||||
|
* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
|
||||||
|
* [3imed-jaberi](https://github.com/3imed-jaberi) - **Imed Jaberi**
|
||||||
|
* [IamLizu](https://github.com/IamLizu) - **S M Mahmudul Hasan** (he/him)
|
||||||
|
* [Phillip9587](https://github.com/Phillip9587) - **Phillip Barta**
|
||||||
|
* [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger**
|
||||||
|
* [rxmarbles](https://github.com/rxmarbles) **Rick Markins** (He/him)
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Triagers emeriti members</summary>
|
||||||
|
|
||||||
|
#### Emeritus Triagers
|
||||||
|
|
||||||
|
* [AuggieH](https://github.com/AuggieH) - **Auggie Hudak**
|
||||||
|
* [G-Rath](https://github.com/G-Rath) - **Gareth Jones**
|
||||||
|
* [MohammadXroid](https://github.com/MohammadXroid) - **Mohammad Ayashi**
|
||||||
|
* [NawafSwe](https://github.com/NawafSwe) - **Nawaf Alsharqi**
|
||||||
|
* [NotMoni](https://github.com/NotMoni) - **Moni**
|
||||||
|
* [VigneshMurugan](https://github.com/VigneshMurugan) - **Vignesh Murugan**
|
||||||
|
* [davidmashe](https://github.com/davidmashe) - **David Ashe**
|
||||||
|
* [digitaIfabric](https://github.com/digitaIfabric) - **David**
|
||||||
|
* [e-l-i-s-e](https://github.com/e-l-i-s-e) - **Elise Bonner**
|
||||||
|
* [fed135](https://github.com/fed135) - **Frederic Charette**
|
||||||
|
* [firmanJS](https://github.com/firmanJS) - **Firman Abdul Hakim**
|
||||||
|
* [getspooky](https://github.com/getspooky) - **Yasser Ameur**
|
||||||
|
* [ghinks](https://github.com/ghinks) - **Glenn**
|
||||||
|
* [ghousemohamed](https://github.com/ghousemohamed) - **Ghouse Mohamed**
|
||||||
|
* [gireeshpunathil](https://github.com/gireeshpunathil) - **Gireesh Punathil**
|
||||||
|
* [jake32321](https://github.com/jake32321) - **Jake Reed**
|
||||||
|
* [jonchurch](https://github.com/jonchurch) - **Jon Church**
|
||||||
|
* [lekanikotun](https://github.com/lekanikotun) - **Troy Goode**
|
||||||
|
* [marsonya](https://github.com/marsonya) - **Lekan Ikotun**
|
||||||
|
* [mastermatt](https://github.com/mastermatt) - **Matt R. Wilson**
|
||||||
|
* [maxakuru](https://github.com/maxakuru) - **Max Edell**
|
||||||
|
* [mlrawlings](https://github.com/mlrawlings) - **Michael Rawlings**
|
||||||
|
* [rodion-arr](https://github.com/rodion-arr) - **Rodion Abdurakhimov**
|
||||||
|
* [sheplu](https://github.com/sheplu) - **Jean Burellier**
|
||||||
|
* [tarunyadav1](https://github.com/tarunyadav1) - **Tarun yadav**
|
||||||
|
* [tunniclm](https://github.com/tunniclm) - **Mike Tunnicliffe**
|
||||||
|
* [enyoghasim](https://github.com/enyoghasim) - **David Enyoghasim**
|
||||||
|
* [0ss](https://github.com/0ss) - **Salah**
|
||||||
|
* [import-brain](https://github.com/import-brain) - **Eric Cheng** (he/him)
|
||||||
|
* [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him)
|
||||||
|
* [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego**
|
||||||
|
* [mertcanaltin](https://github.com/mertcanaltin) - **Mert Can Altin**
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT](LICENSE)
|
[MIT](LICENSE)
|
||||||
|
|
||||||
[npm-image]: https://img.shields.io/npm/v/express.svg
|
[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/express/master
|
||||||
[npm-url]: https://npmjs.org/package/express
|
|
||||||
[downloads-image]: https://img.shields.io/npm/dm/express.svg
|
|
||||||
[downloads-url]: https://npmjs.org/package/express
|
|
||||||
[travis-image]: https://img.shields.io/travis/expressjs/express/master.svg?label=linux
|
|
||||||
[travis-url]: https://travis-ci.org/expressjs/express
|
|
||||||
[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows
|
|
||||||
[appveyor-url]: https://ci.appveyor.com/project/dougwilson/express
|
|
||||||
[coveralls-image]: https://img.shields.io/coveralls/expressjs/express/master.svg
|
|
||||||
[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master
|
[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master
|
||||||
[gratipay-image-visionmedia]: https://img.shields.io/gratipay/visionmedia.svg
|
[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/express/master?label=CI
|
||||||
[gratipay-url-visionmedia]: https://gratipay.com/visionmedia/
|
[github-actions-ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml
|
||||||
[gratipay-image-dougwilson]: https://img.shields.io/gratipay/dougwilson.svg
|
[npm-downloads-image]: https://badgen.net/npm/dm/express
|
||||||
[gratipay-url-dougwilson]: https://gratipay.com/dougwilson/
|
[npm-downloads-url]: https://npmcharts.com/compare/express?minimal=true
|
||||||
|
[npm-url]: https://npmjs.org/package/express
|
||||||
|
[npm-version-image]: https://badgen.net/npm/v/express
|
||||||
|
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/express/badge
|
||||||
|
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/express
|
||||||
|
[Code of Conduct]: https://github.com/expressjs/.github/blob/HEAD/CODE_OF_CONDUCT.md
|
||||||
|
[Contributing Guide]: https://github.com/expressjs/.github/blob/HEAD/CONTRIBUTING.md
|
||||||
|
|
|
||||||
|
|
@ -1,186 +0,0 @@
|
||||||
# Express Release Process
|
|
||||||
|
|
||||||
This document contains the technical aspects of the Express release process. The
|
|
||||||
intended audience is those who have been authorized by the Express Technical
|
|
||||||
Committee (TC) to create, promote and sign official release builds for Express,
|
|
||||||
as npm packages hosted on https://npmjs.com/package/express.
|
|
||||||
|
|
||||||
## Who can make releases?
|
|
||||||
|
|
||||||
Release authorization is given by the Express TC. Once authorized, an individual
|
|
||||||
must have the following access permissions:
|
|
||||||
|
|
||||||
### 1. Github release access
|
|
||||||
|
|
||||||
The individual making the release will need to be a member of the
|
|
||||||
expressjs/express team with Write permission level so they are able to tag the
|
|
||||||
release commit and push changes to the expressjs/express repository
|
|
||||||
(see Steps 4 and 5).
|
|
||||||
|
|
||||||
### 2. npmjs.com release access
|
|
||||||
|
|
||||||
The individual making the release will need to be made an owner on the
|
|
||||||
`express` package on npmjs.com so they are able to publish the release
|
|
||||||
(see Step 6).
|
|
||||||
|
|
||||||
## How to publish a release
|
|
||||||
|
|
||||||
Before publishing, the following preconditions should be met:
|
|
||||||
|
|
||||||
- A release proposal issue or tracking pull request (see "Proposal branch"
|
|
||||||
below) will exist documenting:
|
|
||||||
- the proposed changes
|
|
||||||
- the type of release: patch, minor or major
|
|
||||||
- the version number (according to semantic versioning - http://semver.org)
|
|
||||||
- The proposed changes should be complete.
|
|
||||||
|
|
||||||
There are two main release flows: patch and non-patch.
|
|
||||||
|
|
||||||
The patch flow is for making **patch releases**. As per semantic versioning,
|
|
||||||
patch releases are for simple changes, eg: typo fixes, patch dependency updates,
|
|
||||||
and simple/low-risk bug fixes. Every other type of change is made via the
|
|
||||||
non-patch flow.
|
|
||||||
|
|
||||||
### Branch terminology
|
|
||||||
|
|
||||||
"Master branch"
|
|
||||||
|
|
||||||
- There is a branch in git used for the current major version of Express, named
|
|
||||||
`master`.
|
|
||||||
- This branch contains the completed commits for the next patch release of the
|
|
||||||
current major version.
|
|
||||||
- Releases for the current major version are published from this branch.
|
|
||||||
|
|
||||||
"Version branch"
|
|
||||||
|
|
||||||
- For any given major version of Express (current, previous or next) there is
|
|
||||||
a branch in git for that release named `<major-version>.x` (eg: `4.x`).
|
|
||||||
- This branch points to the commit of the latest tag for the given major version.
|
|
||||||
|
|
||||||
"Release branch"
|
|
||||||
|
|
||||||
- For any given major version of Express, there is a branch used for publishing
|
|
||||||
releases.
|
|
||||||
- For the current major version of Express, the release branch is the
|
|
||||||
"Master branch" named `master`.
|
|
||||||
- For all other major versions of Express, the release branch is the
|
|
||||||
"Version branch" named `<major-version>.x`.
|
|
||||||
|
|
||||||
"Proposal branch"
|
|
||||||
|
|
||||||
- A branch in git representing a proposed new release of Express. This can be a
|
|
||||||
minor or major release, named `<major-version>.0` for a major release,
|
|
||||||
`<major-version>.<minor-version>` for a minor release.
|
|
||||||
- A tracking pull request should exist to document the proposed release,
|
|
||||||
targeted at the appropriate release branch. Prior to opening the tracking
|
|
||||||
pull request the content of the release may have be discussed in an issue.
|
|
||||||
- This branch contains the commits accepted so far that implement the proposal
|
|
||||||
in the tracking pull request.
|
|
||||||
|
|
||||||
### Patch flow
|
|
||||||
|
|
||||||
In the patch flow, simple changes are committed to the release branch which
|
|
||||||
acts as an ever-present branch for the next patch release of the associated
|
|
||||||
major version of Express.
|
|
||||||
|
|
||||||
The release branch is usually kept in a state where it is ready to release.
|
|
||||||
Releases are made when sufficient time or change has been made to warrant it.
|
|
||||||
This is usually proposed and decided using a github issue.
|
|
||||||
|
|
||||||
### Non-patch flow
|
|
||||||
|
|
||||||
In the non-patch flow, changes are committed to a temporary proposal branch
|
|
||||||
created specifically for that release proposal. The branch is based on the
|
|
||||||
most recent release of the major version of Express that the release targets.
|
|
||||||
|
|
||||||
Releases are made when all the changes on a proposal branch are complete and
|
|
||||||
approved. This is done by merging the proposal branch into the release branch
|
|
||||||
(using a fast-forward merge), tagging it with the new version number and
|
|
||||||
publishing the release package to npmjs.com.
|
|
||||||
|
|
||||||
### Flow
|
|
||||||
|
|
||||||
Below is a detailed description of the steps to publish a release.
|
|
||||||
|
|
||||||
#### Step 1. Check the release is ready to publish
|
|
||||||
|
|
||||||
Check any relevant information to ensure the release is ready, eg: any
|
|
||||||
milestone, label, issue or tracking pull request for the release. The release
|
|
||||||
is ready when all proposed code, tests and documentation updates are complete
|
|
||||||
(either merged, closed or re-targeted to another release).
|
|
||||||
|
|
||||||
#### Step 2. (Non-patch flow only) Merge the proposal branch into the release branch
|
|
||||||
|
|
||||||
In the patch flow: skip this step.
|
|
||||||
|
|
||||||
In the non-patch flow:
|
|
||||||
```sh
|
|
||||||
$ git checkout <release-branch>
|
|
||||||
$ git merge --ff-only <proposal-branch>
|
|
||||||
```
|
|
||||||
|
|
||||||
<release-branch> - see "Release branch" of "Branches" above.
|
|
||||||
<proposal-branch> - see "Proposal branch" of "Non-patch flow" above.
|
|
||||||
|
|
||||||
**NOTE:** You may need to rebase the proposal branch to allow a fast-forward
|
|
||||||
merge. Using a fast-forward merge keeps the history clean as it does
|
|
||||||
not introduce merge commits.
|
|
||||||
|
|
||||||
### Step 3. Update the History.md and package.json to the new version number
|
|
||||||
|
|
||||||
The changes so far for the release should already be documented under the
|
|
||||||
"unreleased" section at the top of the History.md file, as per the usual
|
|
||||||
development practice. Change "unreleased" to the new release version / date.
|
|
||||||
Example diff fragment:
|
|
||||||
|
|
||||||
```diff
|
|
||||||
-unreleased
|
|
||||||
-==========
|
|
||||||
+4.13.3 / 2015-08-02
|
|
||||||
+===================
|
|
||||||
```
|
|
||||||
|
|
||||||
The version property in the package.json should already contain the version of
|
|
||||||
the previous release. Change it to the new release version.
|
|
||||||
|
|
||||||
Commit these changes together under a single commit with the message set to
|
|
||||||
the new release version (eg: `4.13.3`):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ git checkout <release-branch>
|
|
||||||
<..edit files..>
|
|
||||||
$ git add History.md package.json
|
|
||||||
$ git commit -m '<version-number>'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4. Identify and tag the release commit with the new release version
|
|
||||||
|
|
||||||
Create a lightweight tag (rather than an annotated tag) named after the new
|
|
||||||
release version (eg: `4.13.3`).
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ git tag <version-number>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5. Push the release branch changes and tag to github
|
|
||||||
|
|
||||||
The branch and tag should be pushed directly to the main repository
|
|
||||||
(https://github.com/expressjs/express).
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ git push origin <release-branch>
|
|
||||||
$ git push origin <version-number>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 6. Publish to npmjs.com
|
|
||||||
|
|
||||||
Ensure your local working copy is completely clean (no extra or changed files).
|
|
||||||
You can use `git status` for this purpose.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ npm login <npm-username>
|
|
||||||
$ npm publish
|
|
||||||
```
|
|
||||||
|
|
||||||
**NOTE:** The version number to publish will be picked up automatically from
|
|
||||||
package.json.
|
|
||||||
|
|
@ -14,7 +14,11 @@ Thank you for improving the security of Express. We appreciate your efforts and
|
||||||
responsible disclosure and will make every effort to acknowledge your
|
responsible disclosure and will make every effort to acknowledge your
|
||||||
contributions.
|
contributions.
|
||||||
|
|
||||||
Report security bugs by emailing the lead maintainer in the Readme.md file.
|
Report security bugs by emailing `express-security@lists.openjsf.org`.
|
||||||
|
|
||||||
|
To ensure the timely response to your report, please ensure that the entirety
|
||||||
|
of the report is contained within the email body and not solely behind a web
|
||||||
|
link or an attachment.
|
||||||
|
|
||||||
The lead maintainer will acknowledge your email within 48 hours, and will send a
|
The lead maintainer will acknowledge your email within 48 hours, and will send a
|
||||||
more detailed response within 48 hours indicating the next steps in handling
|
more detailed response within 48 hours indicating the next steps in handling
|
||||||
|
|
@ -23,8 +27,13 @@ endeavor to keep you informed of the progress towards a fix and full
|
||||||
announcement, and may ask for additional information or guidance.
|
announcement, and may ask for additional information or guidance.
|
||||||
|
|
||||||
Report security bugs in third-party modules to the person or team maintaining
|
Report security bugs in third-party modules to the person or team maintaining
|
||||||
the module. You can also report a vulnerability through the
|
the module.
|
||||||
[Node Security Project](https://nodesecurity.io/report).
|
|
||||||
|
## Pre-release Versions
|
||||||
|
|
||||||
|
Alpha and Beta releases are unstable and **not suitable for production use**.
|
||||||
|
Vulnerabilities found in pre-releases should be reported according to the [Reporting a Bug](#reporting-a-bug) section.
|
||||||
|
Due to the unstable nature of the branch it is not guaranteed that any fixes will be released in the next pre-release.
|
||||||
|
|
||||||
## Disclosure Policy
|
## Disclosure Policy
|
||||||
|
|
||||||
|
|
@ -37,6 +46,10 @@ involving the following steps:
|
||||||
* Prepare fixes for all releases still under maintenance. These fixes will be
|
* Prepare fixes for all releases still under maintenance. These fixes will be
|
||||||
released as fast as possible to npm.
|
released as fast as possible to npm.
|
||||||
|
|
||||||
|
## The Express Threat Model
|
||||||
|
|
||||||
|
We are currently working on a new version of the security model, the most updated version can be found [here](https://github.com/expressjs/security-wg/blob/main/docs/ThreatModel.md)
|
||||||
|
|
||||||
## Comments on this Policy
|
## Comments on this Policy
|
||||||
|
|
||||||
If you have suggestions on how this process could be improved please submit a
|
If you have suggestions on how this process could be improved please submit a
|
||||||
28
appveyor.yml
28
appveyor.yml
|
|
@ -1,28 +0,0 @@
|
||||||
environment:
|
|
||||||
matrix:
|
|
||||||
- nodejs_version: "0.10"
|
|
||||||
- nodejs_version: "0.12"
|
|
||||||
- nodejs_version: "1.8"
|
|
||||||
- nodejs_version: "2.5"
|
|
||||||
- nodejs_version: "3.3"
|
|
||||||
- nodejs_version: "4.8"
|
|
||||||
- nodejs_version: "5.12"
|
|
||||||
- nodejs_version: "6.11"
|
|
||||||
- nodejs_version: "7.10"
|
|
||||||
- nodejs_version: "8.4"
|
|
||||||
cache:
|
|
||||||
- node_modules
|
|
||||||
install:
|
|
||||||
- ps: Install-Product node $env:nodejs_version
|
|
||||||
- npm config set shrinkwrap false
|
|
||||||
- npm rm --save-dev connect-redis
|
|
||||||
- if exist node_modules npm prune
|
|
||||||
- if exist node_modules npm rebuild
|
|
||||||
- npm install
|
|
||||||
build: off
|
|
||||||
test_script:
|
|
||||||
- node --version
|
|
||||||
- npm --version
|
|
||||||
- npm run test-ci
|
|
||||||
- npm run lint
|
|
||||||
version: "{build}"
|
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@./run 1 middleware
|
@./run 1 middleware 50
|
||||||
@./run 5 middleware
|
@./run 5 middleware 50
|
||||||
@./run 10 middleware
|
@./run 10 middleware 50
|
||||||
@./run 15 middleware
|
@./run 15 middleware 50
|
||||||
@./run 20 middleware
|
@./run 20 middleware 50
|
||||||
@./run 30 middleware
|
@./run 30 middleware 50
|
||||||
@./run 50 middleware
|
@./run 50 middleware 50
|
||||||
@./run 100 middleware
|
@./run 100 middleware 50
|
||||||
|
@./run 10 middleware 100
|
||||||
|
@./run 10 middleware 250
|
||||||
|
@./run 10 middleware 500
|
||||||
|
@./run 10 middleware 1000
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
|
|
|
||||||
34
benchmarks/README.md
Normal file
34
benchmarks/README.md
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Express Benchmarks
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
You will need to install [wrk](https://github.com/wg/wrk/blob/master/INSTALL) in order to run the benchmarks.
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
To run the benchmarks, first install the dependencies `npm i`, then run `make`
|
||||||
|
|
||||||
|
The output will look something like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
50 connections
|
||||||
|
1 middleware
|
||||||
|
7.15ms
|
||||||
|
6784.01
|
||||||
|
|
||||||
|
[...redacted...]
|
||||||
|
|
||||||
|
1000 connections
|
||||||
|
10 middleware
|
||||||
|
139.21ms
|
||||||
|
6155.19
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tip: Include Node.js version in output
|
||||||
|
|
||||||
|
You can use `make && node -v` to include the node.js version in the output.
|
||||||
|
|
||||||
|
### Tip: Save the results to a file
|
||||||
|
|
||||||
|
You can use `make > results.log` to save the results to a file `results.log`.
|
||||||
|
|
@ -13,7 +13,7 @@ while (n--) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(function(req, res, next){
|
app.use(function(req, res){
|
||||||
res.send('Hello World')
|
res.send('Hello World')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,15 @@ echo
|
||||||
MW=$1 node $2 &
|
MW=$1 node $2 &
|
||||||
pid=$!
|
pid=$!
|
||||||
|
|
||||||
|
echo " $3 connections"
|
||||||
|
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
wrk 'http://localhost:3333/?foo[bar]=baz' \
|
wrk 'http://localhost:3333/?foo[bar]=baz' \
|
||||||
-d 3 \
|
-d 3 \
|
||||||
-c 50 \
|
-c $3 \
|
||||||
-t 8 \
|
-t 8 \
|
||||||
| grep 'Requests/sec' \
|
| grep 'Requests/sec\|Latency' \
|
||||||
| awk '{ print " " $2 }'
|
| awk '{ print " " $2 }'
|
||||||
|
|
||||||
kill $pid
|
kill $pid
|
||||||
|
|
|
||||||
29
examples/README.md
Normal file
29
examples/README.md
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Express examples
|
||||||
|
|
||||||
|
This page contains list of examples using Express.
|
||||||
|
|
||||||
|
- [auth](./auth) - Authentication with login and password
|
||||||
|
- [content-negotiation](./content-negotiation) - HTTP content negotiation
|
||||||
|
- [cookie-sessions](./cookie-sessions) - Working with cookie-based sessions
|
||||||
|
- [cookies](./cookies) - Working with cookies
|
||||||
|
- [downloads](./downloads) - Transferring files to client
|
||||||
|
- [ejs](./ejs) - Working with Embedded JavaScript templating (ejs)
|
||||||
|
- [error-pages](./error-pages) - Creating error pages
|
||||||
|
- [error](./error) - Working with error middleware
|
||||||
|
- [hello-world](./hello-world) - Simple request handler
|
||||||
|
- [markdown](./markdown) - Markdown as template engine
|
||||||
|
- [multi-router](./multi-router) - Working with multiple Express routers
|
||||||
|
- [mvc](./mvc) - MVC-style controllers
|
||||||
|
- [online](./online) - Tracking online user activity with `online` and `redis` packages
|
||||||
|
- [params](./params) - Working with route parameters
|
||||||
|
- [resource](./resource) - Multiple HTTP operations on the same resource
|
||||||
|
- [route-map](./route-map) - Organizing routes using a map
|
||||||
|
- [route-middleware](./route-middleware) - Working with route middleware
|
||||||
|
- [route-separation](./route-separation) - Organizing routes per each resource
|
||||||
|
- [search](./search) - Search API
|
||||||
|
- [session](./session) - User sessions
|
||||||
|
- [static-files](./static-files) - Serving static files
|
||||||
|
- [vhost](./vhost) - Working with virtual hosts
|
||||||
|
- [view-constructor](./view-constructor) - Rendering views dynamically
|
||||||
|
- [view-locals](./view-locals) - Saving data in request object between middleware calls
|
||||||
|
- [web-service](./web-service) - Simple API service
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var express = require('../..');
|
var express = require('../..');
|
||||||
var hash = require('pbkdf2-password')()
|
var hash = require('pbkdf2-password')()
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
var session = require('express-session');
|
var session = require('express-session');
|
||||||
|
|
||||||
var app = module.exports = express();
|
var app = module.exports = express();
|
||||||
|
|
@ -16,7 +18,7 @@ app.set('views', path.join(__dirname, 'views'));
|
||||||
|
|
||||||
// middleware
|
// middleware
|
||||||
|
|
||||||
app.use(express.urlencoded({ extended: false }))
|
app.use(express.urlencoded())
|
||||||
app.use(session({
|
app.use(session({
|
||||||
resave: false, // don't save session if unmodified
|
resave: false, // don't save session if unmodified
|
||||||
saveUninitialized: false, // don't create session until something stored
|
saveUninitialized: false, // don't create session until something stored
|
||||||
|
|
@ -59,14 +61,14 @@ function authenticate(name, pass, fn) {
|
||||||
if (!module.parent) console.log('authenticating %s:%s', name, pass);
|
if (!module.parent) console.log('authenticating %s:%s', name, pass);
|
||||||
var user = users[name];
|
var user = users[name];
|
||||||
// query the db for the given username
|
// query the db for the given username
|
||||||
if (!user) return fn(new Error('cannot find user'));
|
if (!user) return fn(null, null)
|
||||||
// apply the same algorithm to the POSTed password, applying
|
// apply the same algorithm to the POSTed password, applying
|
||||||
// the hash against the pass / salt, if there is a match we
|
// the hash against the pass / salt, if there is a match we
|
||||||
// found the user
|
// found the user
|
||||||
hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) {
|
hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) {
|
||||||
if (err) return fn(err);
|
if (err) return fn(err);
|
||||||
if (hash == user.hash) return fn(null, user);
|
if (hash === user.hash) return fn(null, user)
|
||||||
fn(new Error('invalid password'));
|
fn(null, null)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,8 +101,10 @@ app.get('/login', function(req, res){
|
||||||
res.render('login');
|
res.render('login');
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/login', function(req, res){
|
app.post('/login', function (req, res, next) {
|
||||||
|
if (!req.body) return res.sendStatus(400)
|
||||||
authenticate(req.body.username, req.body.password, function(err, user){
|
authenticate(req.body.username, req.body.password, function(err, user){
|
||||||
|
if (err) return next(err)
|
||||||
if (user) {
|
if (user) {
|
||||||
// Regenerate session when signing in
|
// Regenerate session when signing in
|
||||||
// to prevent fixation
|
// to prevent fixation
|
||||||
|
|
@ -112,7 +116,7 @@ app.post('/login', function(req, res){
|
||||||
req.session.success = 'Authenticated as ' + user.name
|
req.session.success = 'Authenticated as ' + user.name
|
||||||
+ ' click to <a href="/logout">logout</a>. '
|
+ ' click to <a href="/logout">logout</a>. '
|
||||||
+ ' You may now access <a href="/restricted">/restricted</a>.';
|
+ ' You may now access <a href="/restricted">/restricted</a>.';
|
||||||
res.redirect('back');
|
res.redirect(req.get('Referrer') || '/');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
req.session.error = 'Authentication failed, please check your '
|
req.session.error = 'Authentication failed, please check your '
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title><%= title %></title>
|
<title><%= title %></title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
|
|
@ -8,7 +10,7 @@
|
||||||
font: 13px Helvetica, Arial, sans-serif;
|
font: 13px Helvetica, Arial, sans-serif;
|
||||||
}
|
}
|
||||||
.error {
|
.error {
|
||||||
color: red
|
color: red;
|
||||||
}
|
}
|
||||||
.success {
|
.success {
|
||||||
color: green;
|
color: green;
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,21 @@
|
||||||
|
|
||||||
<% var title = 'Authentication Example' %>
|
<%- include('head', { title: 'Authentication Example' }) -%>
|
||||||
<% include head %>
|
|
||||||
|
|
||||||
<h1>Login</h1>
|
<h1>Login</h1>
|
||||||
<%- message %>
|
<%- message %>
|
||||||
Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj" and "foobar".
|
Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj" and "foobar".
|
||||||
<form method="post" action="/login">
|
<form method="post" action="/login">
|
||||||
<p>
|
<p>
|
||||||
<label>Username:</label>
|
<label for="username">Username:</label>
|
||||||
<input type="text" name="username">
|
<input type="text" name="username" id="username">
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label>Password:</label>
|
<label for="password">Password:</label>
|
||||||
<input type="text" name="password">
|
<input type="text" name="password" id="password">
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<input type="submit" value="Login">
|
<input type="submit" value="Login">
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<% include foot %>
|
<%- include('foot') -%>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
var users = [];
|
var users = [];
|
||||||
|
|
||||||
users.push({ name: 'Tobi' });
|
users.push({ name: 'Tobi' });
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
var express = require('../../');
|
var express = require('../../');
|
||||||
var app = module.exports = express();
|
var app = module.exports = express();
|
||||||
var users = require('./db');
|
var users = require('./db');
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
var users = require('./db');
|
var users = require('./db');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
@ -11,13 +13,10 @@ var app = module.exports = express();
|
||||||
app.use(cookieSession({ secret: 'manny is cool' }));
|
app.use(cookieSession({ secret: 'manny is cool' }));
|
||||||
|
|
||||||
// do something with the session
|
// do something with the session
|
||||||
app.use(count);
|
app.get('/', function (req, res) {
|
||||||
|
|
||||||
// custom middleware
|
|
||||||
function count(req, res) {
|
|
||||||
req.session.count = (req.session.count || 0) + 1
|
req.session.count = (req.session.count || 0) + 1
|
||||||
res.send('viewed ' + req.session.count + ' times\n')
|
res.send('viewed ' + req.session.count + ' times\n')
|
||||||
}
|
})
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if (!module.parent) {
|
if (!module.parent) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
@ -8,7 +10,7 @@ var logger = require('morgan');
|
||||||
var cookieParser = require('cookie-parser');
|
var cookieParser = require('cookie-parser');
|
||||||
|
|
||||||
// custom log format
|
// custom log format
|
||||||
if ('test' != process.env.NODE_ENV) app.use(logger(':method :url'));
|
if (process.env.NODE_ENV !== 'test') app.use(logger(':method :url'))
|
||||||
|
|
||||||
// parses request cookies, populating
|
// parses request cookies, populating
|
||||||
// req.cookies and req.signedCookies
|
// req.cookies and req.signedCookies
|
||||||
|
|
@ -17,7 +19,7 @@ if ('test' != process.env.NODE_ENV) app.use(logger(':method :url'));
|
||||||
app.use(cookieParser('my secret here'));
|
app.use(cookieParser('my secret here'));
|
||||||
|
|
||||||
// parses x-www-form-urlencoded
|
// parses x-www-form-urlencoded
|
||||||
app.use(express.urlencoded({ extended: false }))
|
app.use(express.urlencoded())
|
||||||
|
|
||||||
app.get('/', function(req, res){
|
app.get('/', function(req, res){
|
||||||
if (req.cookies.remember) {
|
if (req.cookies.remember) {
|
||||||
|
|
@ -31,13 +33,17 @@ app.get('/', function(req, res){
|
||||||
|
|
||||||
app.get('/forget', function(req, res){
|
app.get('/forget', function(req, res){
|
||||||
res.clearCookie('remember');
|
res.clearCookie('remember');
|
||||||
res.redirect('back');
|
res.redirect(req.get('Referrer') || '/');
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/', function(req, res){
|
app.post('/', function(req, res){
|
||||||
var minute = 60000;
|
var minute = 60000;
|
||||||
if (req.body.remember) res.cookie('remember', 1, { maxAge: minute });
|
|
||||||
res.redirect('back');
|
if (req.body && req.body.remember) {
|
||||||
|
res.cookie('remember', 1, { maxAge: minute })
|
||||||
|
}
|
||||||
|
|
||||||
|
res.redirect(req.get('Referrer') || '/');
|
||||||
});
|
});
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
|
|
|
||||||
3
examples/downloads/files/notes/groceries.txt
Normal file
3
examples/downloads/files/notes/groceries.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
* milk
|
||||||
|
* eggs
|
||||||
|
* bread
|
||||||
|
|
@ -1,27 +1,32 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var express = require('../../');
|
var express = require('../../');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
|
|
||||||
var app = module.exports = express();
|
var app = module.exports = express();
|
||||||
|
|
||||||
|
// path to where the files are stored on disk
|
||||||
|
var FILES_DIR = path.join(__dirname, 'files')
|
||||||
|
|
||||||
app.get('/', function(req, res){
|
app.get('/', function(req, res){
|
||||||
res.send('<ul>'
|
res.send('<ul>' +
|
||||||
+ '<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>'
|
'<li>Download <a href="/files/notes/groceries.txt">notes/groceries.txt</a>.</li>' +
|
||||||
+ '<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>'
|
'<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>' +
|
||||||
+ '<li>Download <a href="/files/CCTV大赛上海分赛区.txt">CCTV大赛上海分赛区.txt</a>.</li>'
|
'<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>' +
|
||||||
+ '</ul>');
|
'<li>Download <a href="/files/CCTV大赛上海分赛区.txt">CCTV大赛上海分赛区.txt</a>.</li>' +
|
||||||
|
'</ul>')
|
||||||
});
|
});
|
||||||
|
|
||||||
// /files/* is accessed via req.params[0]
|
// /files/* is accessed via req.params[0]
|
||||||
// but here we name it :file
|
// but here we name it :file
|
||||||
app.get('/files/:file(*)', function(req, res, next){
|
app.get('/files/*file', function (req, res, next) {
|
||||||
var filePath = path.join(__dirname, 'files', req.params.file);
|
res.download(req.params.file.join('/'), { root: FILES_DIR }, function (err) {
|
||||||
|
|
||||||
res.download(filePath, function (err) {
|
|
||||||
if (!err) return; // file sent
|
if (!err) return; // file sent
|
||||||
if (err && err.status !== 404) return next(err); // non-404 error
|
if (err.status !== 404) return next(err); // non-404 error
|
||||||
// file for download not found
|
// file for download not found
|
||||||
res.statusCode = 404;
|
res.statusCode = 404;
|
||||||
res.send('Cant find that file, sorry!');
|
res.send('Cant find that file, sorry!');
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var express = require('../../');
|
var express = require('../../');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
|
|
||||||
var app = module.exports = express();
|
var app = module.exports = express();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
body {
|
body {
|
||||||
padding: 50px 80px;
|
padding: 50px 80px;
|
||||||
font: 14px "Helvetica Nueue", "Lucida Grande", Arial, sans-serif;
|
font: 14px "Helvetica Neue", "Lucida Grande", Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title><%= title %></title>
|
<title><%= title %></title>
|
||||||
<link rel="stylesheet" href="/stylesheets/style.css">
|
<link rel="stylesheet" href="/stylesheets/style.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<% include header.html %>
|
<%- include('header.html') -%>
|
||||||
|
|
||||||
<h1>Users</h1>
|
<h1>Users</h1>
|
||||||
<ul id="users">
|
<ul id="users">
|
||||||
|
|
@ -7,4 +7,4 @@
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<% include footer.html %>
|
<%- include('footer.html') -%>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var express = require('../../');
|
var express = require('../../');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
var app = module.exports = express();
|
var app = module.exports = express();
|
||||||
var logger = require('morgan');
|
var logger = require('morgan');
|
||||||
var silent = 'test' == process.env.NODE_ENV;
|
var silent = process.env.NODE_ENV === 'test'
|
||||||
|
|
||||||
// general config
|
// general config
|
||||||
app.set('views', path.join(__dirname, 'views'));
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
|
|
@ -19,7 +21,7 @@ app.enable('verbose errors');
|
||||||
|
|
||||||
// disable them in production
|
// disable them in production
|
||||||
// use $ NODE_ENV=production node examples/error-pages
|
// use $ NODE_ENV=production node examples/error-pages
|
||||||
if ('production' == app.settings.env) app.disable('verbose errors');
|
if (app.settings.env === 'production') app.disable('verbose errors')
|
||||||
|
|
||||||
silent || app.use(logger('dev'));
|
silent || app.use(logger('dev'));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
<% include error_header %>
|
<%- include('error_header') -%>
|
||||||
<h2>Cannot find <%= url %></h2>
|
<h2>Cannot find <%= url %></h2>
|
||||||
<% include footer %>
|
<%- include('footer') -%>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<% include error_header %>
|
<%- include('error_header') -%>
|
||||||
<h2>Error: <%= error.message %></h2>
|
<h2>Error: <%= error.message %></h2>
|
||||||
<% if (settings['verbose errors']) { %>
|
<% if (settings['verbose errors']) { %>
|
||||||
<pre><%= error.stack %></pre>
|
<pre><%= error.stack %></pre>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<p>An error occurred!</p>
|
<p>An error occurred!</p>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% include footer %>
|
<%- include('footer') -%>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Error</title>
|
<title>Error</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Custom Pages Example</title>
|
<title>Custom Pages Example</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
@ -5,7 +7,7 @@
|
||||||
var express = require('../../');
|
var express = require('../../');
|
||||||
var logger = require('morgan');
|
var logger = require('morgan');
|
||||||
var app = module.exports = express();
|
var app = module.exports = express();
|
||||||
var test = app.get('env') == 'test';
|
var test = app.get('env') === 'test'
|
||||||
|
|
||||||
if (!test) app.use(logger('dev'));
|
if (!test) app.use(logger('dev'));
|
||||||
|
|
||||||
|
|
@ -24,7 +26,7 @@ function error(err, req, res, next) {
|
||||||
res.send('Internal Server Error');
|
res.send('Internal Server Error');
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get('/', function(req, res){
|
app.get('/', function () {
|
||||||
// Caught and passed down to the errorHandler middleware
|
// Caught and passed down to the errorHandler middleware
|
||||||
throw new Error('something broke!');
|
throw new Error('something broke!');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
var express = require('../../');
|
var express = require('../../');
|
||||||
|
|
||||||
var app = express();
|
var app = module.exports = express()
|
||||||
|
|
||||||
app.get('/', function(req, res){
|
app.get('/', function(req, res){
|
||||||
res.send('Hello World');
|
res.send('Hello World');
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var escapeHtml = require('escape-html');
|
var escapeHtml = require('escape-html');
|
||||||
var express = require('../..');
|
var express = require('../..');
|
||||||
var fs = require('fs');
|
var fs = require('node:fs');
|
||||||
var marked = require('marked');
|
var marked = require('marked');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
|
|
||||||
var app = module.exports = express();
|
var app = module.exports = express();
|
||||||
|
|
||||||
|
|
@ -24,7 +26,7 @@ app.engine('md', function(path, options, fn){
|
||||||
|
|
||||||
app.set('views', path.join(__dirname, 'views'));
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
|
|
||||||
// make it the default so we dont need .md
|
// make it the default, so we don't need .md
|
||||||
app.set('view engine', 'md');
|
app.set('view engine', 'md');
|
||||||
|
|
||||||
app.get('/', function(req, res){
|
app.get('/', function(req, res){
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
var express = require('../../..');
|
var express = require('../../..');
|
||||||
|
|
||||||
var apiv1 = express.Router();
|
var apiv1 = express.Router();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
var express = require('../../..');
|
var express = require('../../..');
|
||||||
|
|
||||||
var apiv2 = express.Router();
|
var apiv2 = express.Router();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
var express = require('../..');
|
var express = require('../..');
|
||||||
|
|
||||||
var app = module.exports = express();
|
var app = module.exports = express();
|
||||||
|
|
@ -6,7 +8,7 @@ app.use('/api/v1', require('./controllers/api_v1'));
|
||||||
app.use('/api/v2', require('./controllers/api_v2'));
|
app.use('/api/v2', require('./controllers/api_v2'));
|
||||||
|
|
||||||
app.get('/', function(req, res) {
|
app.get('/', function(req, res) {
|
||||||
res.send('Hello form root route.');
|
res.send('Hello from root route.')
|
||||||
});
|
});
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
/**
|
|
||||||
* Module dependencies.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var express = require('../..');
|
|
||||||
var multiparty = require('multiparty');
|
|
||||||
var format = require('util').format;
|
|
||||||
|
|
||||||
var app = module.exports = express();
|
|
||||||
|
|
||||||
app.get('/', function(req, res){
|
|
||||||
res.send('<form method="post" enctype="multipart/form-data">'
|
|
||||||
+ '<p>Title: <input type="text" name="title" /></p>'
|
|
||||||
+ '<p>Image: <input type="file" name="image" /></p>'
|
|
||||||
+ '<p><input type="submit" value="Upload" /></p>'
|
|
||||||
+ '</form>');
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/', function(req, res, next){
|
|
||||||
// create a form to begin parsing
|
|
||||||
var form = new multiparty.Form();
|
|
||||||
var image;
|
|
||||||
var title;
|
|
||||||
|
|
||||||
form.on('error', next);
|
|
||||||
form.on('close', function(){
|
|
||||||
res.send(format('\nuploaded %s (%d Kb) as %s'
|
|
||||||
, image.filename
|
|
||||||
, image.size / 1024 | 0
|
|
||||||
, title));
|
|
||||||
});
|
|
||||||
|
|
||||||
// listen on field event for title
|
|
||||||
form.on('field', function(name, val){
|
|
||||||
if (name !== 'title') return;
|
|
||||||
title = val;
|
|
||||||
});
|
|
||||||
|
|
||||||
// listen on part event for image file
|
|
||||||
form.on('part', function(part){
|
|
||||||
if (!part.filename) return;
|
|
||||||
if (part.name !== 'image') return part.resume();
|
|
||||||
image = {};
|
|
||||||
image.filename = part.filename;
|
|
||||||
image.size = 0;
|
|
||||||
part.on('data', function(buf){
|
|
||||||
image.size += buf.length;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// parse the form
|
|
||||||
form.parse(req);
|
|
||||||
});
|
|
||||||
|
|
||||||
/* istanbul ignore next */
|
|
||||||
if (!module.parent) {
|
|
||||||
app.listen(4000);
|
|
||||||
console.log('Express started on port 4000');
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
exports.index = function(req, res){
|
exports.index = function(req, res){
|
||||||
res.redirect('/users');
|
res.redirect('/users');
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<link rel="stylesheet" href="/style.css">
|
<link rel="stylesheet" href="/style.css">
|
||||||
<title>Edit <%= pet.name %></title>
|
<title>Edit <%= pet.name %></title>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<link rel="stylesheet" href="/style.css">
|
<link rel="stylesheet" href="/style.css">
|
||||||
<title><%= pet.name %></title>
|
<title><%= pet.name %></title>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<link rel="stylesheet" href="/style.css">
|
<link rel="stylesheet" href="/style.css">
|
||||||
<title>Edit {{user.name}}</title>
|
<title>Edit {{user.name}}</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<link rel="stylesheet" href="/style.css">
|
<link rel="stylesheet" href="/style.css">
|
||||||
<title>Users</title>
|
<title>Users</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<link rel="stylesheet" href="/style.css">
|
<link rel="stylesheet" href="/style.css">
|
||||||
<title>{{user.name}}</title>
|
<title>{{user.name}}</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
// faux database
|
// faux database
|
||||||
|
|
||||||
var pets = exports.pets = [];
|
var pets = exports.pets = [];
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var express = require('../..');
|
var express = require('../..');
|
||||||
var logger = require('morgan');
|
var logger = require('morgan');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
var session = require('express-session');
|
var session = require('express-session');
|
||||||
var methodOverride = require('method-override');
|
var methodOverride = require('method-override');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var express = require('../../..');
|
var express = require('../../..');
|
||||||
var fs = require('fs');
|
var fs = require('node:fs');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
|
|
||||||
module.exports = function(parent, options){
|
module.exports = function(parent, options){
|
||||||
var dir = path.join(__dirname, '..', 'controllers');
|
var dir = path.join(__dirname, '..', 'controllers');
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
body {
|
body {
|
||||||
padding: 50px;
|
padding: 50px;
|
||||||
font: 16px "Helvetica Neue", Helvetica, Arial;
|
font: 16px "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
color: #107aff;
|
color: #107aff;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Not Found</title>
|
<title>Not Found</title>
|
||||||
<link rel="stylesheet" href="/style.css">
|
<link rel="stylesheet" href="/style.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Internal Server Error</title>
|
<title>Internal Server Error</title>
|
||||||
<link rel="stylesheet" href="/style.css">
|
<link rel="stylesheet" href="/style.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
// install redis first:
|
// install redis first:
|
||||||
// https://redis.io/
|
// https://redis.io/
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,23 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var createError = require('http-errors')
|
||||||
var express = require('../../');
|
var express = require('../../');
|
||||||
var app = module.exports = express();
|
var app = module.exports = express();
|
||||||
|
|
||||||
// Faux database
|
// Faux database
|
||||||
|
|
||||||
var users = [
|
var users = [
|
||||||
{ name: 'tj' }
|
{ name: 'tj' }
|
||||||
, { name: 'tobi' }
|
, { name: 'tobi' }
|
||||||
, { name: 'loki' }
|
, { name: 'loki' }
|
||||||
, { name: 'jane' }
|
, { name: 'jane' }
|
||||||
, { name: 'bandit' }
|
, { name: 'bandit' }
|
||||||
];
|
];
|
||||||
|
|
||||||
// Create HTTP error
|
|
||||||
|
|
||||||
function createError(status, message) {
|
|
||||||
var err = new Error(message);
|
|
||||||
err.status = status;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert :to and :from to integers
|
// Convert :to and :from to integers
|
||||||
|
|
||||||
app.param(['to', 'from'], function(req, res, next, num, name){
|
app.param(['to', 'from'], function(req, res, next, num, name){
|
||||||
|
|
@ -37,7 +32,8 @@ app.param(['to', 'from'], function(req, res, next, num, name){
|
||||||
// Load user by id
|
// Load user by id
|
||||||
|
|
||||||
app.param('user', function(req, res, next, id){
|
app.param('user', function(req, res, next, id){
|
||||||
if (req.user = users[id]) {
|
req.user = users[id]
|
||||||
|
if (req.user) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
next(createError(404, 'failed to find user'));
|
next(createError(404, 'failed to find user'));
|
||||||
|
|
@ -56,7 +52,7 @@ app.get('/', function(req, res){
|
||||||
* GET :user.
|
* GET :user.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.get('/user/:user', function(req, res, next){
|
app.get('/user/:user', function (req, res) {
|
||||||
res.send('user ' + req.user.name);
|
res.send('user ' + req.user.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -64,7 +60,7 @@ app.get('/user/:user', function(req, res, next){
|
||||||
* GET users :from - :to.
|
* GET users :from - :to.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.get('/users/:from-:to', function(req, res, next){
|
app.get('/users/:from-:to', function (req, res) {
|
||||||
var from = req.params.from;
|
var from = req.params.from;
|
||||||
var to = req.params.to;
|
var to = req.params.to;
|
||||||
var names = users.map(function(user){ return user.name; });
|
var names = users.map(function(user){ return user.name; });
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
@ -10,7 +12,7 @@ var app = module.exports = express();
|
||||||
|
|
||||||
app.resource = function(path, obj) {
|
app.resource = function(path, obj) {
|
||||||
this.get(path, obj.index);
|
this.get(path, obj.index);
|
||||||
this.get(path + '/:a..:b.:format?', function(req, res){
|
this.get(path + '/:a..:b{.:format}', function(req, res){
|
||||||
var a = parseInt(req.params.a, 10);
|
var a = parseInt(req.params.a, 10);
|
||||||
var b = parseInt(req.params.b, 10);
|
var b = parseInt(req.params.b, 10);
|
||||||
var format = req.params.format;
|
var format = req.params.format;
|
||||||
|
|
@ -26,7 +28,7 @@ app.resource = function(path, obj) {
|
||||||
// Fake records
|
// Fake records
|
||||||
|
|
||||||
var users = [
|
var users = [
|
||||||
{ name: 'tj' }
|
{ name: 'tj' }
|
||||||
, { name: 'ciaran' }
|
, { name: 'ciaran' }
|
||||||
, { name: 'aaron' }
|
, { name: 'aaron' }
|
||||||
, { name: 'guillermo' }
|
, { name: 'guillermo' }
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var escapeHtml = require('escape-html')
|
||||||
var express = require('../../lib/express');
|
var express = require('../../lib/express');
|
||||||
|
|
||||||
var verbose = process.env.NODE_ENV != 'test';
|
var verbose = process.env.NODE_ENV !== 'test'
|
||||||
|
|
||||||
var app = module.exports = express();
|
var app = module.exports = express();
|
||||||
|
|
||||||
|
|
@ -31,7 +34,7 @@ var users = {
|
||||||
},
|
},
|
||||||
|
|
||||||
get: function(req, res){
|
get: function(req, res){
|
||||||
res.send('user ' + req.params.uid);
|
res.send('user ' + escapeHtml(req.params.uid))
|
||||||
},
|
},
|
||||||
|
|
||||||
delete: function(req, res){
|
delete: function(req, res){
|
||||||
|
|
@ -41,11 +44,11 @@ var users = {
|
||||||
|
|
||||||
var pets = {
|
var pets = {
|
||||||
list: function(req, res){
|
list: function(req, res){
|
||||||
res.send('user ' + req.params.uid + '\'s pets');
|
res.send('user ' + escapeHtml(req.params.uid) + '\'s pets')
|
||||||
},
|
},
|
||||||
|
|
||||||
delete: function(req, res){
|
delete: function(req, res){
|
||||||
res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid);
|
res.send('delete ' + escapeHtml(req.params.uid) + '\'s pet ' + escapeHtml(req.params.pid))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
@ -15,7 +17,7 @@ var app = express();
|
||||||
|
|
||||||
// Dummy users
|
// Dummy users
|
||||||
var users = [
|
var users = [
|
||||||
{ id: 0, name: 'tj', email: 'tj@vision-media.ca', role: 'member' }
|
{ id: 0, name: 'tj', email: 'tj@vision-media.ca', role: 'member' }
|
||||||
, { id: 1, name: 'ciaran', email: 'ciaranj@gmail.com', role: 'member' }
|
, { id: 1, name: 'ciaran', email: 'ciaranj@gmail.com', role: 'member' }
|
||||||
, { id: 2, name: 'aaron', email: 'aaron.heckmann+github@gmail.com', role: 'admin' }
|
, { id: 2, name: 'aaron', email: 'aaron.heckmann+github@gmail.com', role: 'admin' }
|
||||||
];
|
];
|
||||||
|
|
@ -34,7 +36,7 @@ function loadUser(req, res, next) {
|
||||||
function andRestrictToSelf(req, res, next) {
|
function andRestrictToSelf(req, res, next) {
|
||||||
// If our authenticated user is the user we are viewing
|
// If our authenticated user is the user we are viewing
|
||||||
// then everything is fine :)
|
// then everything is fine :)
|
||||||
if (req.authenticatedUser.id == req.user.id) {
|
if (req.authenticatedUser.id === req.user.id) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
// You may want to implement specific exceptions
|
// You may want to implement specific exceptions
|
||||||
|
|
@ -47,7 +49,7 @@ function andRestrictToSelf(req, res, next) {
|
||||||
|
|
||||||
function andRestrictTo(role) {
|
function andRestrictTo(role) {
|
||||||
return function(req, res, next) {
|
return function(req, res, next) {
|
||||||
if (req.authenticatedUser.role == role) {
|
if (req.authenticatedUser.role === role) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
next(new Error('Unauthorized'));
|
next(new Error('Unauthorized'));
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var express = require('../..');
|
var express = require('../..');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
var app = express();
|
var app = express();
|
||||||
var logger = require('morgan');
|
var logger = require('morgan');
|
||||||
var cookieParser = require('cookie-parser');
|
var cookieParser = require('cookie-parser');
|
||||||
|
|
@ -36,7 +38,7 @@ app.get('/', site.index);
|
||||||
// User
|
// User
|
||||||
|
|
||||||
app.get('/users', user.list);
|
app.get('/users', user.list);
|
||||||
app.all('/user/:id/:op?', user.load);
|
app.all('/user/:id{/:op}', user.load);
|
||||||
app.get('/user/:id', user.view);
|
app.get('/user/:id', user.view);
|
||||||
app.get('/user/:id/view', user.view);
|
app.get('/user/:id/view', user.view);
|
||||||
app.get('/user/:id/edit', user.edit);
|
app.get('/user/:id/edit', user.edit);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
// Fake posts database
|
// Fake posts database
|
||||||
|
|
||||||
var posts = [
|
var posts = [
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
exports.index = function(req, res){
|
exports.index = function(req, res){
|
||||||
res.render('index', { title: 'Route Separation Example' });
|
res.render('index', { title: 'Route Separation Example' });
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
// Fake user database
|
// Fake user database
|
||||||
|
|
||||||
var users = [
|
var users = [
|
||||||
|
|
@ -41,5 +43,5 @@ exports.update = function(req, res){
|
||||||
var user = req.body.user;
|
var user = req.body.user;
|
||||||
req.user.name = user.name;
|
req.user.name = user.name;
|
||||||
req.user.email = user.email;
|
req.user.email = user.email;
|
||||||
res.redirect('back');
|
res.redirect(req.get('Referrer') || '/');
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title><%= title %></title>
|
<title><%= title %></title>
|
||||||
<link rel="stylesheet" href="/style.css">
|
<link rel="stylesheet" href="/style.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<% include header %>
|
<%- include('header') -%>
|
||||||
|
|
||||||
<h1><%= title %></h1>
|
<h1><%= title %></h1>
|
||||||
|
|
||||||
|
|
@ -7,4 +7,4 @@
|
||||||
<li>Visit the <a href="/posts">posts</a> page.</li>
|
<li>Visit the <a href="/posts">posts</a> page.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<% include footer %>
|
<%- include('footer') -%>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<% include ../header %>
|
<%- include('../header') -%>
|
||||||
|
|
||||||
<h1>Posts</h1>
|
<h1>Posts</h1>
|
||||||
|
|
||||||
|
|
@ -9,4 +9,4 @@
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<% include ../footer %>
|
<%- include('../footer') -%>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<% include ../header %>
|
<%- include('../header') -%>
|
||||||
|
|
||||||
<h1>Editing <%= user.name %></h1>
|
<h1>Editing <%= user.name %></h1>
|
||||||
|
|
||||||
<div id="user">
|
<div id="user">
|
||||||
<form action="?_method=put", method="post">
|
<form action="?_method=put" method="post">
|
||||||
<p>
|
<p>
|
||||||
Name:
|
Name:
|
||||||
<input type="text" value="<%= user.name %>" name="user[name]" />
|
<input type="text" value="<%= user.name %>" name="user[name]" />
|
||||||
|
|
@ -20,4 +20,4 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% include ../footer %>
|
<%- include('../footer') -%>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<% include ../header %>
|
<%- include('../header') -%>
|
||||||
|
|
||||||
<h1><%= title %></h1>
|
<h1><%= title %></h1>
|
||||||
|
|
||||||
|
|
@ -11,4 +11,4 @@
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% include ../footer %>
|
<%- include('../footer') -%>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<% include ../header %>
|
<%- include('../header') -%>
|
||||||
|
|
||||||
<h1><%= user.name %></h1>
|
<h1><%= user.name %></h1>
|
||||||
|
|
||||||
|
|
@ -6,4 +6,4 @@
|
||||||
<p>Email: <%= user.email %></p>
|
<p>Email: <%= user.email %></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% include ../footer %>
|
<%- include('../footer') -%>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
// install redis first:
|
// install redis first:
|
||||||
// https://redis.io/
|
// https://redis.io/
|
||||||
|
|
@ -11,7 +12,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var express = require('../..');
|
var express = require('../..');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
var redis = require('redis');
|
var redis = require('redis');
|
||||||
|
|
||||||
var db = redis.createClient();
|
var db = redis.createClient();
|
||||||
|
|
@ -34,10 +35,10 @@ db.sadd('cat', 'luna');
|
||||||
* GET search for :query.
|
* GET search for :query.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.get('/search/:query?', function(req, res){
|
app.get('/search/:query?', function(req, res, next){
|
||||||
var query = req.params.query;
|
var query = req.params.query;
|
||||||
db.smembers(query, function(err, vals){
|
db.smembers(query, function(err, vals){
|
||||||
if (err) return res.send(500);
|
if (err) return next(err);
|
||||||
res.send(vals);
|
res.send(vals);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
var search = document.querySelector('[type=search]');
|
var search = document.querySelector('[type=search]');
|
||||||
var code = document.querySelector('pre');
|
var code = document.querySelector('pre');
|
||||||
|
|
||||||
|
|
@ -5,7 +7,7 @@ search.addEventListener('keyup', function(){
|
||||||
var xhr = new XMLHttpRequest;
|
var xhr = new XMLHttpRequest;
|
||||||
xhr.open('GET', '/search/' + search.value, true);
|
xhr.open('GET', '/search/' + search.value, true);
|
||||||
xhr.onreadystatechange = function(){
|
xhr.onreadystatechange = function(){
|
||||||
if (4 == xhr.readyState) {
|
if (xhr.readyState === 4) {
|
||||||
code.textContent = xhr.responseText;
|
code.textContent = xhr.responseText;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Search example</title>
|
<title>Search example</title>
|
||||||
<style type="text/css">
|
<style>
|
||||||
body {
|
body {
|
||||||
font: 14px "Helvetica Neue", Helvetica;
|
font: 14px "Helvetica Neue", Helvetica;
|
||||||
padding: 50px;
|
padding: 50px;
|
||||||
|
|
@ -14,7 +15,7 @@
|
||||||
<h2>Search</h2>
|
<h2>Search</h2>
|
||||||
<p>Try searching for "ferret" or "cat".</p>
|
<p>Try searching for "ferret" or "cat".</p>
|
||||||
<input type="search" name="search" value="" />
|
<input type="search" name="search" value="" />
|
||||||
<pre />
|
<pre></pre>
|
||||||
<script src="/client.js" charset="utf-8"></script>
|
<script src="/client.js" charset="utf-8"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
// install redis first:
|
// install redis first:
|
||||||
// https://redis.io/
|
// https://redis.io/
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var express = require('../..');
|
var express = require('../..');
|
||||||
var logger = require('morgan');
|
var logger = require('morgan');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
var app = express();
|
var app = express();
|
||||||
|
|
||||||
// log requests
|
// log requests
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
foo
|
// foo
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var https = require('https');
|
var https = require('node:https');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
var extname = path.extname;
|
var extname = path.extname;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var express = require('../..');
|
var express = require('../..');
|
||||||
var path = require('path');
|
var path = require('node:path');
|
||||||
var User = require('./user');
|
var User = require('./user');
|
||||||
var app = express();
|
var app = express();
|
||||||
|
|
||||||
|
|
@ -13,7 +15,7 @@ app.set('view engine', 'ejs');
|
||||||
// filter ferrets only
|
// filter ferrets only
|
||||||
|
|
||||||
function ferrets(user) {
|
function ferrets(user) {
|
||||||
return user.species == 'ferret';
|
return user.species === 'ferret'
|
||||||
}
|
}
|
||||||
|
|
||||||
// naive nesting approach,
|
// naive nesting approach,
|
||||||
|
|
@ -59,7 +61,7 @@ function users(req, res, next) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get('/middleware', count, users, function(req, res, next){
|
app.get('/middleware', count, users, function (req, res) {
|
||||||
res.render('index', {
|
res.render('index', {
|
||||||
title: 'Users',
|
title: 'Users',
|
||||||
count: req.count,
|
count: req.count,
|
||||||
|
|
@ -97,7 +99,7 @@ function users2(req, res, next) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get('/middleware-locals', count2, users2, function(req, res, next){
|
app.get('/middleware-locals', count2, users2, function (req, res) {
|
||||||
// you can see now how we have much less
|
// you can see now how we have much less
|
||||||
// to pass to res.render(). If we have
|
// to pass to res.render(). If we have
|
||||||
// several routes related to users this
|
// several routes related to users this
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
module.exports = User;
|
module.exports = User;
|
||||||
|
|
||||||
// faux model
|
// faux model
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title><%= title %></title>
|
<title><%= title %></title>
|
||||||
<style media="screen">
|
<style media="screen">
|
||||||
body {
|
body {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
@ -8,7 +10,7 @@ var app = module.exports = express();
|
||||||
|
|
||||||
// create an error with .status. we
|
// create an error with .status. we
|
||||||
// can then use the property in our
|
// can then use the property in our
|
||||||
// custom error handler (Connect repects this prop as well)
|
// custom error handler (Connect respects this prop as well)
|
||||||
|
|
||||||
function error(status, msg) {
|
function error(status, msg) {
|
||||||
var err = new Error(msg);
|
var err = new Error(msg);
|
||||||
|
|
@ -32,7 +34,7 @@ app.use('/api', function(req, res, next){
|
||||||
if (!key) return next(error(400, 'api key required'));
|
if (!key) return next(error(400, 'api key required'));
|
||||||
|
|
||||||
// key is invalid
|
// key is invalid
|
||||||
if (!~apiKeys.indexOf(key)) return next(error(401, 'invalid api key'));
|
if (apiKeys.indexOf(key) === -1) return next(error(401, 'invalid api key'))
|
||||||
|
|
||||||
// all good, store req.key for route access
|
// all good, store req.key for route access
|
||||||
req.key = key;
|
req.key = key;
|
||||||
|
|
@ -49,13 +51,13 @@ var apiKeys = ['foo', 'bar', 'baz'];
|
||||||
// these two objects will serve as our faux database
|
// these two objects will serve as our faux database
|
||||||
|
|
||||||
var repos = [
|
var repos = [
|
||||||
{ name: 'express', url: 'http://github.com/expressjs/express' }
|
{ name: 'express', url: 'https://github.com/expressjs/express' },
|
||||||
, { name: 'stylus', url: 'http://github.com/learnboost/stylus' }
|
{ name: 'stylus', url: 'https://github.com/learnboost/stylus' },
|
||||||
, { name: 'cluster', url: 'http://github.com/learnboost/cluster' }
|
{ name: 'cluster', url: 'https://github.com/learnboost/cluster' }
|
||||||
];
|
];
|
||||||
|
|
||||||
var users = [
|
var users = [
|
||||||
{ name: 'tobi' }
|
{ name: 'tobi' }
|
||||||
, { name: 'loki' }
|
, { name: 'loki' }
|
||||||
, { name: 'jane' }
|
, { name: 'jane' }
|
||||||
];
|
];
|
||||||
|
|
@ -69,14 +71,17 @@ var userRepos = {
|
||||||
// we now can assume the api key is valid,
|
// we now can assume the api key is valid,
|
||||||
// and simply expose the data
|
// and simply expose the data
|
||||||
|
|
||||||
app.get('/api/users', function(req, res, next){
|
// example: http://localhost:3000/api/users/?api-key=foo
|
||||||
|
app.get('/api/users', function (req, res) {
|
||||||
res.send(users);
|
res.send(users);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/repos', function(req, res, next){
|
// example: http://localhost:3000/api/repos/?api-key=foo
|
||||||
|
app.get('/api/repos', function (req, res) {
|
||||||
res.send(repos);
|
res.send(repos);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// example: http://localhost:3000/api/user/tobi/repos/?api-key=foo
|
||||||
app.get('/api/user/:name/repos', function(req, res, next){
|
app.get('/api/user/:name/repos', function(req, res, next){
|
||||||
var name = req.params.name;
|
var name = req.params.name;
|
||||||
var user = userRepos[name];
|
var user = userRepos[name];
|
||||||
|
|
@ -102,7 +107,7 @@ app.use(function(err, req, res, next){
|
||||||
// invoke next() and do not respond.
|
// invoke next() and do not respond.
|
||||||
app.use(function(req, res){
|
app.use(function(req, res){
|
||||||
res.status(404);
|
res.status(404);
|
||||||
res.send({ error: "Lame, can't find that" });
|
res.send({ error: "Sorry, can't find that" })
|
||||||
});
|
});
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
|
|
|
||||||
|
|
@ -14,22 +14,24 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var finalhandler = require('finalhandler');
|
var finalhandler = require('finalhandler');
|
||||||
var Router = require('./router');
|
|
||||||
var methods = require('methods');
|
|
||||||
var middleware = require('./middleware/init');
|
|
||||||
var query = require('./middleware/query');
|
|
||||||
var debug = require('debug')('express:application');
|
var debug = require('debug')('express:application');
|
||||||
var View = require('./view');
|
var View = require('./view');
|
||||||
var http = require('http');
|
var http = require('node:http');
|
||||||
|
var methods = require('./utils').methods;
|
||||||
var compileETag = require('./utils').compileETag;
|
var compileETag = require('./utils').compileETag;
|
||||||
var compileQueryParser = require('./utils').compileQueryParser;
|
var compileQueryParser = require('./utils').compileQueryParser;
|
||||||
var compileTrust = require('./utils').compileTrust;
|
var compileTrust = require('./utils').compileTrust;
|
||||||
var deprecate = require('depd')('express');
|
var resolve = require('node:path').resolve;
|
||||||
var flatten = require('array-flatten');
|
var once = require('once')
|
||||||
var merge = require('utils-merge');
|
var Router = require('router');
|
||||||
var resolve = require('path').resolve;
|
|
||||||
var setPrototypeOf = require('setprototypeof')
|
/**
|
||||||
|
* Module variables.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
var slice = Array.prototype.slice;
|
var slice = Array.prototype.slice;
|
||||||
|
var flatten = Array.prototype.flat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application prototype.
|
* Application prototype.
|
||||||
|
|
@ -55,11 +57,29 @@ var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default';
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.init = function init() {
|
app.init = function init() {
|
||||||
this.cache = {};
|
var router = null;
|
||||||
this.engines = {};
|
|
||||||
this.settings = {};
|
this.cache = Object.create(null);
|
||||||
|
this.engines = Object.create(null);
|
||||||
|
this.settings = Object.create(null);
|
||||||
|
|
||||||
this.defaultConfiguration();
|
this.defaultConfiguration();
|
||||||
|
|
||||||
|
// Setup getting to lazily add base router
|
||||||
|
Object.defineProperty(this, 'router', {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
get: function getrouter() {
|
||||||
|
if (router === null) {
|
||||||
|
router = new Router({
|
||||||
|
caseSensitive: this.enabled('case sensitive routing'),
|
||||||
|
strict: this.enabled('strict routing')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -74,7 +94,7 @@ app.defaultConfiguration = function defaultConfiguration() {
|
||||||
this.enable('x-powered-by');
|
this.enable('x-powered-by');
|
||||||
this.set('etag', 'weak');
|
this.set('etag', 'weak');
|
||||||
this.set('env', env);
|
this.set('env', env);
|
||||||
this.set('query parser', 'extended');
|
this.set('query parser', 'simple')
|
||||||
this.set('subdomain offset', 2);
|
this.set('subdomain offset', 2);
|
||||||
this.set('trust proxy', false);
|
this.set('trust proxy', false);
|
||||||
|
|
||||||
|
|
@ -95,10 +115,10 @@ app.defaultConfiguration = function defaultConfiguration() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// inherit protos
|
// inherit protos
|
||||||
setPrototypeOf(this.request, parent.request)
|
Object.setPrototypeOf(this.request, parent.request)
|
||||||
setPrototypeOf(this.response, parent.response)
|
Object.setPrototypeOf(this.response, parent.response)
|
||||||
setPrototypeOf(this.engines, parent.engines)
|
Object.setPrototypeOf(this.engines, parent.engines)
|
||||||
setPrototypeOf(this.settings, parent.settings)
|
Object.setPrototypeOf(this.settings, parent.settings)
|
||||||
});
|
});
|
||||||
|
|
||||||
// setup locals
|
// setup locals
|
||||||
|
|
@ -118,32 +138,6 @@ app.defaultConfiguration = function defaultConfiguration() {
|
||||||
if (env === 'production') {
|
if (env === 'production') {
|
||||||
this.enable('view cache');
|
this.enable('view cache');
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(this, 'router', {
|
|
||||||
get: function() {
|
|
||||||
throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* lazily adds the base router if it has not yet been added.
|
|
||||||
*
|
|
||||||
* We cannot add the base router in the defaultConfiguration because
|
|
||||||
* it reads app settings which might be set after that has run.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
app.lazyrouter = function lazyrouter() {
|
|
||||||
if (!this._router) {
|
|
||||||
this._router = new Router({
|
|
||||||
caseSensitive: this.enabled('case sensitive routing'),
|
|
||||||
strict: this.enabled('strict routing')
|
|
||||||
});
|
|
||||||
|
|
||||||
this._router.use(query(this.get('query parser fn')));
|
|
||||||
this._router.use(middleware.init(this));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -156,22 +150,31 @@ app.lazyrouter = function lazyrouter() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.handle = function handle(req, res, callback) {
|
app.handle = function handle(req, res, callback) {
|
||||||
var router = this._router;
|
|
||||||
|
|
||||||
// final handler
|
// final handler
|
||||||
var done = callback || finalhandler(req, res, {
|
var done = callback || finalhandler(req, res, {
|
||||||
env: this.get('env'),
|
env: this.get('env'),
|
||||||
onerror: logerror.bind(this)
|
onerror: logerror.bind(this)
|
||||||
});
|
});
|
||||||
|
|
||||||
// no routes
|
// set powered by header
|
||||||
if (!router) {
|
if (this.enabled('x-powered-by')) {
|
||||||
debug('no routes defined on app');
|
res.setHeader('X-Powered-By', 'Express');
|
||||||
done();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
router.handle(req, res, done);
|
// set circular references
|
||||||
|
req.res = res;
|
||||||
|
res.req = req;
|
||||||
|
|
||||||
|
// alter the prototypes
|
||||||
|
Object.setPrototypeOf(req, this.request)
|
||||||
|
Object.setPrototypeOf(res, this.response)
|
||||||
|
|
||||||
|
// setup locals
|
||||||
|
if (!res.locals) {
|
||||||
|
res.locals = Object.create(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.router.handle(req, res, done);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -204,15 +207,14 @@ app.use = function use(fn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fns = flatten(slice.call(arguments, offset));
|
var fns = flatten.call(slice.call(arguments, offset), Infinity);
|
||||||
|
|
||||||
if (fns.length === 0) {
|
if (fns.length === 0) {
|
||||||
throw new TypeError('app.use() requires a middleware function')
|
throw new TypeError('app.use() requires a middleware function')
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup router
|
// get router
|
||||||
this.lazyrouter();
|
var router = this.router;
|
||||||
var router = this._router;
|
|
||||||
|
|
||||||
fns.forEach(function (fn) {
|
fns.forEach(function (fn) {
|
||||||
// non-express app
|
// non-express app
|
||||||
|
|
@ -228,8 +230,8 @@ app.use = function use(fn) {
|
||||||
router.use(path, function mounted_app(req, res, next) {
|
router.use(path, function mounted_app(req, res, next) {
|
||||||
var orig = req.app;
|
var orig = req.app;
|
||||||
fn.handle(req, res, function (err) {
|
fn.handle(req, res, function (err) {
|
||||||
setPrototypeOf(req, orig.request)
|
Object.setPrototypeOf(req, orig.request)
|
||||||
setPrototypeOf(res, orig.response)
|
Object.setPrototypeOf(res, orig.response)
|
||||||
next(err);
|
next(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -252,8 +254,7 @@ app.use = function use(fn) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.route = function route(path) {
|
app.route = function route(path) {
|
||||||
this.lazyrouter();
|
return this.router.route(path);
|
||||||
return this._router.route(path);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -276,7 +277,7 @@ app.route = function route(path) {
|
||||||
* In this case EJS provides a `.renderFile()` method with
|
* In this case EJS provides a `.renderFile()` method with
|
||||||
* the same signature that Express expects: `(path, options, callback)`,
|
* the same signature that Express expects: `(path, options, callback)`,
|
||||||
* though note that it aliases this method as `ejs.__express` internally
|
* though note that it aliases this method as `ejs.__express` internally
|
||||||
* so if you're using ".ejs" extensions you dont need to do anything.
|
* so if you're using ".ejs" extensions you don't need to do anything.
|
||||||
*
|
*
|
||||||
* Some template engines do not follow this convention, the
|
* Some template engines do not follow this convention, the
|
||||||
* [Consolidate.js](https://github.com/tj/consolidate.js)
|
* [Consolidate.js](https://github.com/tj/consolidate.js)
|
||||||
|
|
@ -319,8 +320,6 @@ app.engine = function engine(ext, fn) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.param = function param(name, fn) {
|
app.param = function param(name, fn) {
|
||||||
this.lazyrouter();
|
|
||||||
|
|
||||||
if (Array.isArray(name)) {
|
if (Array.isArray(name)) {
|
||||||
for (var i = 0; i < name.length; i++) {
|
for (var i = 0; i < name.length; i++) {
|
||||||
this.param(name[i], fn);
|
this.param(name[i], fn);
|
||||||
|
|
@ -329,7 +328,7 @@ app.param = function param(name, fn) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._router.param(name, fn);
|
this.router.param(name, fn);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
@ -469,16 +468,14 @@ app.disable = function disable(setting) {
|
||||||
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
|
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
methods.forEach(function(method){
|
methods.forEach(function (method) {
|
||||||
app[method] = function(path){
|
app[method] = function (path) {
|
||||||
if (method === 'get' && arguments.length === 1) {
|
if (method === 'get' && arguments.length === 1) {
|
||||||
// app.get(setting)
|
// app.get(setting)
|
||||||
return this.set(path);
|
return this.set(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lazyrouter();
|
var route = this.route(path);
|
||||||
|
|
||||||
var route = this._router.route(path);
|
|
||||||
route[method].apply(route, slice.call(arguments, 1));
|
route[method].apply(route, slice.call(arguments, 1));
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
@ -495,9 +492,7 @@ methods.forEach(function(method){
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.all = function all(path) {
|
app.all = function all(path) {
|
||||||
this.lazyrouter();
|
var route = this.route(path);
|
||||||
|
|
||||||
var route = this._router.route(path);
|
|
||||||
var args = slice.call(arguments, 1);
|
var args = slice.call(arguments, 1);
|
||||||
|
|
||||||
for (var i = 0; i < methods.length; i++) {
|
for (var i = 0; i < methods.length; i++) {
|
||||||
|
|
@ -507,10 +502,6 @@ app.all = function all(path) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
// del -> delete alias
|
|
||||||
|
|
||||||
app.del = deprecate.function(app.delete, 'app.del: Use app.delete instead');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the given view `name` name with `options`
|
* Render the given view `name` name with `options`
|
||||||
* and a callback accepting an error and the
|
* and a callback accepting an error and the
|
||||||
|
|
@ -533,7 +524,6 @@ app.render = function render(name, options, callback) {
|
||||||
var done = callback;
|
var done = callback;
|
||||||
var engines = this.engines;
|
var engines = this.engines;
|
||||||
var opts = options;
|
var opts = options;
|
||||||
var renderOptions = {};
|
|
||||||
var view;
|
var view;
|
||||||
|
|
||||||
// support callback function as second arg
|
// support callback function as second arg
|
||||||
|
|
@ -542,16 +532,8 @@ app.render = function render(name, options, callback) {
|
||||||
opts = {};
|
opts = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge app.locals
|
|
||||||
merge(renderOptions, this.locals);
|
|
||||||
|
|
||||||
// merge options._locals
|
|
||||||
if (opts._locals) {
|
|
||||||
merge(renderOptions, opts._locals);
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge options
|
// merge options
|
||||||
merge(renderOptions, opts);
|
var renderOptions = { ...this.locals, ...opts._locals, ...opts };
|
||||||
|
|
||||||
// set .cache unless explicitly provided
|
// set .cache unless explicitly provided
|
||||||
if (renderOptions.cache == null) {
|
if (renderOptions.cache == null) {
|
||||||
|
|
@ -601,8 +583,8 @@ app.render = function render(name, options, callback) {
|
||||||
* and HTTPS server you may do so with the "http"
|
* and HTTPS server you may do so with the "http"
|
||||||
* and "https" modules as shown here:
|
* and "https" modules as shown here:
|
||||||
*
|
*
|
||||||
* var http = require('http')
|
* var http = require('node:http')
|
||||||
* , https = require('https')
|
* , https = require('node:https')
|
||||||
* , express = require('express')
|
* , express = require('express')
|
||||||
* , app = express();
|
* , app = express();
|
||||||
*
|
*
|
||||||
|
|
@ -614,9 +596,14 @@ app.render = function render(name, options, callback) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.listen = function listen() {
|
app.listen = function listen() {
|
||||||
var server = http.createServer(this);
|
var server = http.createServer(this)
|
||||||
return server.listen.apply(server, arguments);
|
var args = Array.prototype.slice.call(arguments)
|
||||||
};
|
if (typeof args[args.length - 1] === 'function') {
|
||||||
|
var done = args[args.length - 1] = once(args[args.length - 1])
|
||||||
|
server.once('error', done)
|
||||||
|
}
|
||||||
|
return server.listen.apply(server, args)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log error using console.error.
|
* Log error using console.error.
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var bodyParser = require('body-parser')
|
var bodyParser = require('body-parser')
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('node:events').EventEmitter;
|
||||||
var mixin = require('merge-descriptors');
|
var mixin = require('merge-descriptors');
|
||||||
var proto = require('./application');
|
var proto = require('./application');
|
||||||
var Route = require('./router/route');
|
var Router = require('router');
|
||||||
var Router = require('./router');
|
|
||||||
var req = require('./request');
|
var req = require('./request');
|
||||||
var res = require('./response');
|
var res = require('./response');
|
||||||
|
|
||||||
|
|
@ -68,7 +67,7 @@ exports.response = res;
|
||||||
* Expose constructors.
|
* Expose constructors.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.Route = Route;
|
exports.Route = Router.Route;
|
||||||
exports.Router = Router;
|
exports.Router = Router;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,37 +75,7 @@ exports.Router = Router;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.json = bodyParser.json
|
exports.json = bodyParser.json
|
||||||
exports.query = require('./middleware/query');
|
exports.raw = bodyParser.raw
|
||||||
exports.static = require('serve-static');
|
exports.static = require('serve-static');
|
||||||
|
exports.text = bodyParser.text
|
||||||
exports.urlencoded = bodyParser.urlencoded
|
exports.urlencoded = bodyParser.urlencoded
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace removed middleware with an appropriate error message.
|
|
||||||
*/
|
|
||||||
|
|
||||||
;[
|
|
||||||
'bodyParser',
|
|
||||||
'compress',
|
|
||||||
'cookieSession',
|
|
||||||
'session',
|
|
||||||
'logger',
|
|
||||||
'cookieParser',
|
|
||||||
'favicon',
|
|
||||||
'responseTime',
|
|
||||||
'errorHandler',
|
|
||||||
'timeout',
|
|
||||||
'methodOverride',
|
|
||||||
'vhost',
|
|
||||||
'csrf',
|
|
||||||
'directory',
|
|
||||||
'limit',
|
|
||||||
'multipart',
|
|
||||||
'staticCache',
|
|
||||||
].forEach(function (name) {
|
|
||||||
Object.defineProperty(exports, name, {
|
|
||||||
get: function () {
|
|
||||||
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
|
|
||||||
},
|
|
||||||
configurable: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
/*!
|
|
||||||
* express
|
|
||||||
* Copyright(c) 2009-2013 TJ Holowaychuk
|
|
||||||
* Copyright(c) 2013 Roman Shtylman
|
|
||||||
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
|
||||||
* MIT Licensed
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
var setPrototypeOf = require('setprototypeof')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialization middleware, exposing the
|
|
||||||
* request and response to each other, as well
|
|
||||||
* as defaulting the X-Powered-By header field.
|
|
||||||
*
|
|
||||||
* @param {Function} app
|
|
||||||
* @return {Function}
|
|
||||||
* @api private
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.init = function(app){
|
|
||||||
return function expressInit(req, res, next){
|
|
||||||
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
|
|
||||||
req.res = res;
|
|
||||||
res.req = req;
|
|
||||||
req.next = next;
|
|
||||||
|
|
||||||
setPrototypeOf(req, app.request)
|
|
||||||
setPrototypeOf(res, app.response)
|
|
||||||
|
|
||||||
res.locals = res.locals || Object.create(null);
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
/*!
|
|
||||||
* express
|
|
||||||
* Copyright(c) 2009-2013 TJ Holowaychuk
|
|
||||||
* Copyright(c) 2013 Roman Shtylman
|
|
||||||
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
|
||||||
* MIT Licensed
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var merge = require('utils-merge')
|
|
||||||
var parseUrl = require('parseurl');
|
|
||||||
var qs = require('qs');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object} options
|
|
||||||
* @return {Function}
|
|
||||||
* @api public
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function query(options) {
|
|
||||||
var opts = merge({}, options)
|
|
||||||
var queryparse = qs.parse;
|
|
||||||
|
|
||||||
if (typeof options === 'function') {
|
|
||||||
queryparse = options;
|
|
||||||
opts = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts !== undefined && opts.allowPrototypes === undefined) {
|
|
||||||
// back-compat for qs module
|
|
||||||
opts.allowPrototypes = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return function query(req, res, next){
|
|
||||||
if (!req.query) {
|
|
||||||
var val = parseUrl(req).query;
|
|
||||||
req.query = queryparse(val, opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
109
lib/request.js
109
lib/request.js
|
|
@ -14,10 +14,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var accepts = require('accepts');
|
var accepts = require('accepts');
|
||||||
var deprecate = require('depd')('express');
|
var isIP = require('node:net').isIP;
|
||||||
var isIP = require('net').isIP;
|
|
||||||
var typeis = require('type-is');
|
var typeis = require('type-is');
|
||||||
var http = require('http');
|
var http = require('node:http');
|
||||||
var fresh = require('fresh');
|
var fresh = require('fresh');
|
||||||
var parseRange = require('range-parser');
|
var parseRange = require('range-parser');
|
||||||
var parse = require('parseurl');
|
var parse = require('parseurl');
|
||||||
|
|
@ -147,9 +146,6 @@ req.acceptsEncodings = function(){
|
||||||
return accept.encodings.apply(accept, arguments);
|
return accept.encodings.apply(accept, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
req.acceptsEncoding = deprecate.function(req.acceptsEncodings,
|
|
||||||
'req.acceptsEncoding: Use acceptsEncodings instead');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the given `charset`s are acceptable,
|
* Check if the given `charset`s are acceptable,
|
||||||
* otherwise you should respond with 406 "Not Acceptable".
|
* otherwise you should respond with 406 "Not Acceptable".
|
||||||
|
|
@ -164,9 +160,6 @@ req.acceptsCharsets = function(){
|
||||||
return accept.charsets.apply(accept, arguments);
|
return accept.charsets.apply(accept, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
req.acceptsCharset = deprecate.function(req.acceptsCharsets,
|
|
||||||
'req.acceptsCharset: Use acceptsCharsets instead');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the given `lang`s are acceptable,
|
* Check if the given `lang`s are acceptable,
|
||||||
* otherwise you should respond with 406 "Not Acceptable".
|
* otherwise you should respond with 406 "Not Acceptable".
|
||||||
|
|
@ -176,14 +169,10 @@ req.acceptsCharset = deprecate.function(req.acceptsCharsets,
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
req.acceptsLanguages = function(){
|
req.acceptsLanguages = function(...languages) {
|
||||||
var accept = accepts(this);
|
return accepts(this).languages(...languages);
|
||||||
return accept.languages.apply(accept, arguments);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
req.acceptsLanguage = deprecate.function(req.acceptsLanguages,
|
|
||||||
'req.acceptsLanguage: Use acceptsLanguages instead');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse Range header field, capping to the given `size`.
|
* Parse Range header field, capping to the given `size`.
|
||||||
*
|
*
|
||||||
|
|
@ -216,42 +205,31 @@ req.range = function range(size, options) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the value of param `name` when present or `defaultValue`.
|
* Parse the query string of `req.url`.
|
||||||
*
|
*
|
||||||
* - Checks route placeholders, ex: _/user/:id_
|
* This uses the "query parser" setting to parse the raw
|
||||||
* - Checks body params, ex: id=12, {"id":12}
|
* string into an object.
|
||||||
* - Checks query string params, ex: ?id=12
|
|
||||||
*
|
*
|
||||||
* To utilize request bodies, `req.body`
|
|
||||||
* should be an object. This can be done by using
|
|
||||||
* the `bodyParser()` middleware.
|
|
||||||
*
|
|
||||||
* @param {String} name
|
|
||||||
* @param {Mixed} [defaultValue]
|
|
||||||
* @return {String}
|
* @return {String}
|
||||||
* @public
|
* @api public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
req.param = function param(name, defaultValue) {
|
defineGetter(req, 'query', function query(){
|
||||||
var params = this.params || {};
|
var queryparse = this.app.get('query parser fn');
|
||||||
var body = this.body || {};
|
|
||||||
var query = this.query || {};
|
|
||||||
|
|
||||||
var args = arguments.length === 1
|
if (!queryparse) {
|
||||||
? 'name'
|
// parsing is disabled
|
||||||
: 'name, default';
|
return Object.create(null);
|
||||||
deprecate('req.param(' + args + '): Use req.params, req.body, or req.query instead');
|
}
|
||||||
|
|
||||||
if (null != params[name] && params.hasOwnProperty(name)) return params[name];
|
var querystring = parse(this).query;
|
||||||
if (null != body[name]) return body[name];
|
|
||||||
if (null != query[name]) return query[name];
|
|
||||||
|
|
||||||
return defaultValue;
|
return queryparse(querystring);
|
||||||
};
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the incoming request contains the "Content-Type"
|
* Check if the incoming request contains the "Content-Type"
|
||||||
* header field, and it contains the give mime `type`.
|
* header field, and it contains the given mime `type`.
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
*
|
*
|
||||||
|
|
@ -304,19 +282,23 @@ req.is = function is(types) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
defineGetter(req, 'protocol', function protocol(){
|
defineGetter(req, 'protocol', function protocol(){
|
||||||
var proto = this.connection.encrypted
|
var proto = this.socket.encrypted
|
||||||
? 'https'
|
? 'https'
|
||||||
: 'http';
|
: 'http';
|
||||||
var trust = this.app.get('trust proxy fn');
|
var trust = this.app.get('trust proxy fn');
|
||||||
|
|
||||||
if (!trust(this.connection.remoteAddress, 0)) {
|
if (!trust(this.socket.remoteAddress, 0)) {
|
||||||
return proto;
|
return proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: X-Forwarded-Proto is normally only ever a
|
// Note: X-Forwarded-Proto is normally only ever a
|
||||||
// single value, but this is to be safe.
|
// single value, but this is to be safe.
|
||||||
proto = this.get('X-Forwarded-Proto') || proto;
|
var header = this.get('X-Forwarded-Proto') || proto
|
||||||
return proto.split(/\s*,\s*/)[0];
|
var index = header.indexOf(',')
|
||||||
|
|
||||||
|
return index !== -1
|
||||||
|
? header.substring(0, index).trim()
|
||||||
|
: header.trim()
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -410,7 +392,7 @@ defineGetter(req, 'path', function path() {
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the "Host" header field to a hostname.
|
* Parse the "Host" header field to a host.
|
||||||
*
|
*
|
||||||
* When the "trust proxy" setting trusts the socket
|
* When the "trust proxy" setting trusts the socket
|
||||||
* address, the "X-Forwarded-Host" header field will
|
* address, the "X-Forwarded-Host" header field will
|
||||||
|
|
@ -420,14 +402,35 @@ defineGetter(req, 'path', function path() {
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
defineGetter(req, 'hostname', function hostname(){
|
defineGetter(req, 'host', function host(){
|
||||||
var trust = this.app.get('trust proxy fn');
|
var trust = this.app.get('trust proxy fn');
|
||||||
var host = this.get('X-Forwarded-Host');
|
var val = this.get('X-Forwarded-Host');
|
||||||
|
|
||||||
if (!host || !trust(this.connection.remoteAddress, 0)) {
|
if (!val || !trust(this.socket.remoteAddress, 0)) {
|
||||||
host = this.get('Host');
|
val = this.get('Host');
|
||||||
|
} else if (val.indexOf(',') !== -1) {
|
||||||
|
// Note: X-Forwarded-Host is normally only ever a
|
||||||
|
// single value, but this is to be safe.
|
||||||
|
val = val.substring(0, val.indexOf(',')).trimRight()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return val || undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the "Host" header field to a hostname.
|
||||||
|
*
|
||||||
|
* When the "trust proxy" setting trusts the socket
|
||||||
|
* address, the "X-Forwarded-Host" header field will
|
||||||
|
* be trusted.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
defineGetter(req, 'hostname', function hostname(){
|
||||||
|
var host = this.host;
|
||||||
|
|
||||||
if (!host) return;
|
if (!host) return;
|
||||||
|
|
||||||
// IPv6 literal support
|
// IPv6 literal support
|
||||||
|
|
@ -441,15 +444,9 @@ defineGetter(req, 'hostname', function hostname(){
|
||||||
: host;
|
: host;
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: change req.host to return host in next major
|
|
||||||
|
|
||||||
defineGetter(req, 'host', deprecate.function(function host(){
|
|
||||||
return this.hostname;
|
|
||||||
}, 'req.host: Use req.hostname instead'));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the request is fresh, aka
|
* Check if the request is fresh, aka
|
||||||
* Last-Modified and/or the ETag
|
* Last-Modified or the ETag
|
||||||
* still match.
|
* still match.
|
||||||
*
|
*
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
|
|
|
||||||
356
lib/response.js
356
lib/response.js
|
|
@ -12,17 +12,17 @@
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Buffer = require('safe-buffer').Buffer
|
|
||||||
var contentDisposition = require('content-disposition');
|
var contentDisposition = require('content-disposition');
|
||||||
|
var createError = require('http-errors')
|
||||||
var deprecate = require('depd')('express');
|
var deprecate = require('depd')('express');
|
||||||
var encodeUrl = require('encodeurl');
|
var encodeUrl = require('encodeurl');
|
||||||
var escapeHtml = require('escape-html');
|
var escapeHtml = require('escape-html');
|
||||||
var http = require('http');
|
var http = require('node:http');
|
||||||
var isAbsolute = require('./utils').isAbsolute;
|
|
||||||
var onFinished = require('on-finished');
|
var onFinished = require('on-finished');
|
||||||
var path = require('path');
|
var mime = require('mime-types')
|
||||||
|
var path = require('node:path');
|
||||||
|
var pathIsAbsolute = require('node:path').isAbsolute;
|
||||||
var statuses = require('statuses')
|
var statuses = require('statuses')
|
||||||
var merge = require('utils-merge');
|
|
||||||
var sign = require('cookie-signature').sign;
|
var sign = require('cookie-signature').sign;
|
||||||
var normalizeType = require('./utils').normalizeType;
|
var normalizeType = require('./utils').normalizeType;
|
||||||
var normalizeTypes = require('./utils').normalizeTypes;
|
var normalizeTypes = require('./utils').normalizeTypes;
|
||||||
|
|
@ -30,9 +30,9 @@ var setCharset = require('./utils').setCharset;
|
||||||
var cookie = require('cookie');
|
var cookie = require('cookie');
|
||||||
var send = require('send');
|
var send = require('send');
|
||||||
var extname = path.extname;
|
var extname = path.extname;
|
||||||
var mime = send.mime;
|
|
||||||
var resolve = path.resolve;
|
var resolve = path.resolve;
|
||||||
var vary = require('vary');
|
var vary = require('vary');
|
||||||
|
const { Buffer } = require('node:buffer');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response prototype.
|
* Response prototype.
|
||||||
|
|
@ -49,21 +49,28 @@ var res = Object.create(http.ServerResponse.prototype)
|
||||||
module.exports = res
|
module.exports = res
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module variables.
|
* Set the HTTP status code for the response.
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
var charsetRegExp = /;\s*charset\s*=/;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set status `code`.
|
|
||||||
*
|
*
|
||||||
* @param {Number} code
|
* Expects an integer value between 100 and 999 inclusive.
|
||||||
* @return {ServerResponse}
|
* Throws an error if the provided status code is not an integer or if it's outside the allowable range.
|
||||||
|
*
|
||||||
|
* @param {number} code - The HTTP status code to set.
|
||||||
|
* @return {ServerResponse} - Returns itself for chaining methods.
|
||||||
|
* @throws {TypeError} If `code` is not an integer.
|
||||||
|
* @throws {RangeError} If `code` is outside the range 100 to 999.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res.status = function status(code) {
|
res.status = function status(code) {
|
||||||
|
// Check if the status code is not an integer
|
||||||
|
if (!Number.isInteger(code)) {
|
||||||
|
throw new TypeError(`Invalid status code: ${JSON.stringify(code)}. Status code must be an integer.`);
|
||||||
|
}
|
||||||
|
// Check if the status code is outside of Node's valid range
|
||||||
|
if (code < 100 || code > 999) {
|
||||||
|
throw new RangeError(`Invalid status code: ${JSON.stringify(code)}. Status code must be greater than 99 and less than 1000.`);
|
||||||
|
}
|
||||||
|
|
||||||
this.statusCode = code;
|
this.statusCode = code;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
@ -75,7 +82,11 @@ res.status = function status(code) {
|
||||||
*
|
*
|
||||||
* res.links({
|
* res.links({
|
||||||
* next: 'http://api.example.com/users?page=2',
|
* next: 'http://api.example.com/users?page=2',
|
||||||
* last: 'http://api.example.com/users?page=5'
|
* last: 'http://api.example.com/users?page=5',
|
||||||
|
* pages: [
|
||||||
|
* 'http://api.example.com/users?page=1',
|
||||||
|
* 'http://api.example.com/users?page=2'
|
||||||
|
* ]
|
||||||
* });
|
* });
|
||||||
*
|
*
|
||||||
* @param {Object} links
|
* @param {Object} links
|
||||||
|
|
@ -83,11 +94,18 @@ res.status = function status(code) {
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res.links = function(links){
|
res.links = function(links) {
|
||||||
var link = this.get('Link') || '';
|
var link = this.get('Link') || '';
|
||||||
if (link) link += ', ';
|
if (link) link += ', ';
|
||||||
return this.set('Link', link + Object.keys(links).map(function(rel){
|
return this.set('Link', link + Object.keys(links).map(function(rel) {
|
||||||
return '<' + links[rel] + '>; rel="' + rel + '"';
|
// Allow multiple links if links[rel] is an array
|
||||||
|
if (Array.isArray(links[rel])) {
|
||||||
|
return links[rel].map(function (singleLink) {
|
||||||
|
return `<${singleLink}>; rel="${rel}"`;
|
||||||
|
}).join(', ');
|
||||||
|
} else {
|
||||||
|
return `<${links[rel]}>; rel="${rel}"`;
|
||||||
|
}
|
||||||
}).join(', '));
|
}).join(', '));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -113,31 +131,6 @@ res.send = function send(body) {
|
||||||
// settings
|
// settings
|
||||||
var app = this.app;
|
var app = this.app;
|
||||||
|
|
||||||
// allow status / body
|
|
||||||
if (arguments.length === 2) {
|
|
||||||
// res.send(body, status) backwards compat
|
|
||||||
if (typeof arguments[0] !== 'number' && typeof arguments[1] === 'number') {
|
|
||||||
deprecate('res.send(body, status): Use res.status(status).send(body) instead');
|
|
||||||
this.statusCode = arguments[1];
|
|
||||||
} else {
|
|
||||||
deprecate('res.send(status, body): Use res.status(status).send(body) instead');
|
|
||||||
this.statusCode = arguments[0];
|
|
||||||
chunk = arguments[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// disambiguate res.send(status) and res.send(status, num)
|
|
||||||
if (typeof chunk === 'number' && arguments.length === 1) {
|
|
||||||
// res.send(status) will set status message as text string
|
|
||||||
if (!this.get('Content-Type')) {
|
|
||||||
this.type('txt');
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecate('res.send(status): Use res.sendStatus(status) instead');
|
|
||||||
this.statusCode = chunk;
|
|
||||||
chunk = statuses[chunk]
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (typeof chunk) {
|
switch (typeof chunk) {
|
||||||
// string defaulting to html
|
// string defaulting to html
|
||||||
case 'string':
|
case 'string':
|
||||||
|
|
@ -150,7 +143,7 @@ res.send = function send(body) {
|
||||||
case 'object':
|
case 'object':
|
||||||
if (chunk === null) {
|
if (chunk === null) {
|
||||||
chunk = '';
|
chunk = '';
|
||||||
} else if (Buffer.isBuffer(chunk)) {
|
} else if (ArrayBuffer.isView(chunk)) {
|
||||||
if (!this.get('Content-Type')) {
|
if (!this.get('Content-Type')) {
|
||||||
this.type('bin');
|
this.type('bin');
|
||||||
}
|
}
|
||||||
|
|
@ -178,17 +171,17 @@ res.send = function send(body) {
|
||||||
// populate Content-Length
|
// populate Content-Length
|
||||||
var len
|
var len
|
||||||
if (chunk !== undefined) {
|
if (chunk !== undefined) {
|
||||||
if (!generateETag && chunk.length < 1000) {
|
if (Buffer.isBuffer(chunk)) {
|
||||||
|
// get length of Buffer
|
||||||
|
len = chunk.length
|
||||||
|
} else if (!generateETag && chunk.length < 1000) {
|
||||||
// just calculate length when no ETag + small chunk
|
// just calculate length when no ETag + small chunk
|
||||||
len = Buffer.byteLength(chunk, encoding)
|
len = Buffer.byteLength(chunk, encoding)
|
||||||
} else if (!Buffer.isBuffer(chunk)) {
|
} else {
|
||||||
// convert chunk to Buffer and calculate
|
// convert chunk to Buffer and calculate
|
||||||
chunk = Buffer.from(chunk, encoding)
|
chunk = Buffer.from(chunk, encoding)
|
||||||
encoding = undefined;
|
encoding = undefined;
|
||||||
len = chunk.length
|
len = chunk.length
|
||||||
} else {
|
|
||||||
// get length of Buffer
|
|
||||||
len = chunk.length
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set('Content-Length', len);
|
this.set('Content-Length', len);
|
||||||
|
|
@ -203,7 +196,7 @@ res.send = function send(body) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// freshness
|
// freshness
|
||||||
if (req.fresh) this.statusCode = 304;
|
if (req.fresh) this.status(304);
|
||||||
|
|
||||||
// strip irrelevant headers
|
// strip irrelevant headers
|
||||||
if (204 === this.statusCode || 304 === this.statusCode) {
|
if (204 === this.statusCode || 304 === this.statusCode) {
|
||||||
|
|
@ -213,6 +206,13 @@ res.send = function send(body) {
|
||||||
chunk = '';
|
chunk = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// alter headers for 205
|
||||||
|
if (this.statusCode === 205) {
|
||||||
|
this.set('Content-Length', '0')
|
||||||
|
this.removeHeader('Transfer-Encoding')
|
||||||
|
chunk = ''
|
||||||
|
}
|
||||||
|
|
||||||
if (req.method === 'HEAD') {
|
if (req.method === 'HEAD') {
|
||||||
// skip body for HEAD
|
// skip body for HEAD
|
||||||
this.end();
|
this.end();
|
||||||
|
|
@ -237,27 +237,12 @@ res.send = function send(body) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res.json = function json(obj) {
|
res.json = function json(obj) {
|
||||||
var val = obj;
|
|
||||||
|
|
||||||
// allow status / body
|
|
||||||
if (arguments.length === 2) {
|
|
||||||
// res.json(body, status) backwards compat
|
|
||||||
if (typeof arguments[1] === 'number') {
|
|
||||||
deprecate('res.json(obj, status): Use res.status(status).json(obj) instead');
|
|
||||||
this.statusCode = arguments[1];
|
|
||||||
} else {
|
|
||||||
deprecate('res.json(status, obj): Use res.status(status).json(obj) instead');
|
|
||||||
this.statusCode = arguments[0];
|
|
||||||
val = arguments[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
var app = this.app;
|
var app = this.app;
|
||||||
var escape = app.get('json escape')
|
var escape = app.get('json escape')
|
||||||
var replacer = app.get('json replacer');
|
var replacer = app.get('json replacer');
|
||||||
var spaces = app.get('json spaces');
|
var spaces = app.get('json spaces');
|
||||||
var body = stringify(val, replacer, spaces, escape)
|
var body = stringify(obj, replacer, spaces, escape)
|
||||||
|
|
||||||
// content-type
|
// content-type
|
||||||
if (!this.get('Content-Type')) {
|
if (!this.get('Content-Type')) {
|
||||||
|
|
@ -280,27 +265,12 @@ res.json = function json(obj) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res.jsonp = function jsonp(obj) {
|
res.jsonp = function jsonp(obj) {
|
||||||
var val = obj;
|
|
||||||
|
|
||||||
// allow status / body
|
|
||||||
if (arguments.length === 2) {
|
|
||||||
// res.json(body, status) backwards compat
|
|
||||||
if (typeof arguments[1] === 'number') {
|
|
||||||
deprecate('res.jsonp(obj, status): Use res.status(status).json(obj) instead');
|
|
||||||
this.statusCode = arguments[1];
|
|
||||||
} else {
|
|
||||||
deprecate('res.jsonp(status, obj): Use res.status(status).jsonp(obj) instead');
|
|
||||||
this.statusCode = arguments[0];
|
|
||||||
val = arguments[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
var app = this.app;
|
var app = this.app;
|
||||||
var escape = app.get('json escape')
|
var escape = app.get('json escape')
|
||||||
var replacer = app.get('json replacer');
|
var replacer = app.get('json replacer');
|
||||||
var spaces = app.get('json spaces');
|
var spaces = app.get('json spaces');
|
||||||
var body = stringify(val, replacer, spaces, escape)
|
var body = stringify(obj, replacer, spaces, escape)
|
||||||
var callback = this.req.query[app.get('jsonp callback name')];
|
var callback = this.req.query[app.get('jsonp callback name')];
|
||||||
|
|
||||||
// content-type
|
// content-type
|
||||||
|
|
@ -322,10 +292,15 @@ res.jsonp = function jsonp(obj) {
|
||||||
// restrict callback charset
|
// restrict callback charset
|
||||||
callback = callback.replace(/[^\[\]\w$.]/g, '');
|
callback = callback.replace(/[^\[\]\w$.]/g, '');
|
||||||
|
|
||||||
// replace chars not allowed in JavaScript that are in JSON
|
if (body === undefined) {
|
||||||
body = body
|
// empty argument
|
||||||
.replace(/\u2028/g, '\\u2028')
|
body = ''
|
||||||
.replace(/\u2029/g, '\\u2029');
|
} else if (typeof body === 'string') {
|
||||||
|
// replace chars not allowed in JavaScript that are in JSON
|
||||||
|
body = body
|
||||||
|
.replace(/\u2028/g, '\\u2028')
|
||||||
|
.replace(/\u2029/g, '\\u2029')
|
||||||
|
}
|
||||||
|
|
||||||
// the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse"
|
// the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse"
|
||||||
// the typeof check is just to reduce client error noise
|
// the typeof check is just to reduce client error noise
|
||||||
|
|
@ -351,9 +326,9 @@ res.jsonp = function jsonp(obj) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res.sendStatus = function sendStatus(statusCode) {
|
res.sendStatus = function sendStatus(statusCode) {
|
||||||
var body = statuses[statusCode] || String(statusCode)
|
var body = statuses.message[statusCode] || String(statusCode)
|
||||||
|
|
||||||
this.statusCode = statusCode;
|
this.status(statusCode);
|
||||||
this.type('txt');
|
this.type('txt');
|
||||||
|
|
||||||
return this.send(body);
|
return this.send(body);
|
||||||
|
|
@ -364,7 +339,7 @@ res.sendStatus = function sendStatus(statusCode) {
|
||||||
*
|
*
|
||||||
* Automatically sets the _Content-Type_ response header field.
|
* Automatically sets the _Content-Type_ response header field.
|
||||||
* The callback `callback(err)` is invoked when the transfer is complete
|
* The callback `callback(err)` is invoked when the transfer is complete
|
||||||
* or when an error occurs. Be sure to check `res.sentHeader`
|
* or when an error occurs. Be sure to check `res.headersSent`
|
||||||
* if you wish to attempt responding, as the header and some data
|
* if you wish to attempt responding, as the header and some data
|
||||||
* may have already been transferred.
|
* may have already been transferred.
|
||||||
*
|
*
|
||||||
|
|
@ -411,18 +386,25 @@ res.sendFile = function sendFile(path, options, callback) {
|
||||||
throw new TypeError('path argument is required to res.sendFile');
|
throw new TypeError('path argument is required to res.sendFile');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof path !== 'string') {
|
||||||
|
throw new TypeError('path must be a string to res.sendFile')
|
||||||
|
}
|
||||||
|
|
||||||
// support function as second arg
|
// support function as second arg
|
||||||
if (typeof options === 'function') {
|
if (typeof options === 'function') {
|
||||||
done = options;
|
done = options;
|
||||||
opts = {};
|
opts = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opts.root && !isAbsolute(path)) {
|
if (!opts.root && !pathIsAbsolute(path)) {
|
||||||
throw new TypeError('path must be absolute or specify root to res.sendFile');
|
throw new TypeError('path must be absolute or specify root to res.sendFile');
|
||||||
}
|
}
|
||||||
|
|
||||||
// create file stream
|
// create file stream
|
||||||
var pathname = encodeURI(path);
|
var pathname = encodeURI(path);
|
||||||
|
|
||||||
|
// wire application etag option to send
|
||||||
|
opts.etag = this.app.enabled('etag');
|
||||||
var file = send(req, pathname, opts);
|
var file = send(req, pathname, opts);
|
||||||
|
|
||||||
// transfer
|
// transfer
|
||||||
|
|
@ -437,85 +419,13 @@ res.sendFile = function sendFile(path, options, callback) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Transfer the file at the given `path`.
|
|
||||||
*
|
|
||||||
* Automatically sets the _Content-Type_ response header field.
|
|
||||||
* The callback `callback(err)` is invoked when the transfer is complete
|
|
||||||
* or when an error occurs. Be sure to check `res.sentHeader`
|
|
||||||
* if you wish to attempt responding, as the header and some data
|
|
||||||
* may have already been transferred.
|
|
||||||
*
|
|
||||||
* Options:
|
|
||||||
*
|
|
||||||
* - `maxAge` defaulting to 0 (can be string converted by `ms`)
|
|
||||||
* - `root` root directory for relative filenames
|
|
||||||
* - `headers` object of headers to serve with file
|
|
||||||
* - `dotfiles` serve dotfiles, defaulting to false; can be `"allow"` to send them
|
|
||||||
*
|
|
||||||
* Other options are passed along to `send`.
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
*
|
|
||||||
* The following example illustrates how `res.sendfile()` may
|
|
||||||
* be used as an alternative for the `static()` middleware for
|
|
||||||
* dynamic situations. The code backing `res.sendfile()` is actually
|
|
||||||
* the same code, so HTTP cache support etc is identical.
|
|
||||||
*
|
|
||||||
* app.get('/user/:uid/photos/:file', function(req, res){
|
|
||||||
* var uid = req.params.uid
|
|
||||||
* , file = req.params.file;
|
|
||||||
*
|
|
||||||
* req.user.mayViewFilesFrom(uid, function(yes){
|
|
||||||
* if (yes) {
|
|
||||||
* res.sendfile('/uploads/' + uid + '/' + file);
|
|
||||||
* } else {
|
|
||||||
* res.send(403, 'Sorry! you cant see that.');
|
|
||||||
* }
|
|
||||||
* });
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
|
|
||||||
res.sendfile = function (path, options, callback) {
|
|
||||||
var done = callback;
|
|
||||||
var req = this.req;
|
|
||||||
var res = this;
|
|
||||||
var next = req.next;
|
|
||||||
var opts = options || {};
|
|
||||||
|
|
||||||
// support function as second arg
|
|
||||||
if (typeof options === 'function') {
|
|
||||||
done = options;
|
|
||||||
opts = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// create file stream
|
|
||||||
var file = send(req, path, opts);
|
|
||||||
|
|
||||||
// transfer
|
|
||||||
sendfile(res, file, opts, function (err) {
|
|
||||||
if (done) return done(err);
|
|
||||||
if (err && err.code === 'EISDIR') return next();
|
|
||||||
|
|
||||||
// next() all but write errors
|
|
||||||
if (err && err.code !== 'ECONNABORT' && err.syscall !== 'write') {
|
|
||||||
next(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
res.sendfile = deprecate.function(res.sendfile,
|
|
||||||
'res.sendfile: Use res.sendFile instead');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transfer the file at the given `path` as an attachment.
|
* Transfer the file at the given `path` as an attachment.
|
||||||
*
|
*
|
||||||
* Optionally providing an alternate attachment `filename`,
|
* Optionally providing an alternate attachment `filename`,
|
||||||
* and optional callback `callback(err)`. The callback is invoked
|
* and optional callback `callback(err)`. The callback is invoked
|
||||||
* when the data transfer is complete, or when an error has
|
* when the data transfer is complete, or when an error has
|
||||||
* ocurred. Be sure to check `res.headersSent` if you plan to respond.
|
* occurred. Be sure to check `res.headersSent` if you plan to respond.
|
||||||
*
|
*
|
||||||
* Optionally providing an `options` object to use with `res.sendFile()`.
|
* Optionally providing an `options` object to use with `res.sendFile()`.
|
||||||
* This function will set the `Content-Disposition` header, overriding
|
* This function will set the `Content-Disposition` header, overriding
|
||||||
|
|
@ -542,6 +452,13 @@ res.download = function download (path, filename, options, callback) {
|
||||||
opts = null
|
opts = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// support optional filename, where options may be in it's place
|
||||||
|
if (typeof filename === 'object' &&
|
||||||
|
(typeof options === 'function' || options === undefined)) {
|
||||||
|
name = null
|
||||||
|
opts = filename
|
||||||
|
}
|
||||||
|
|
||||||
// set Content-Disposition when file is sent
|
// set Content-Disposition when file is sent
|
||||||
var headers = {
|
var headers = {
|
||||||
'Content-Disposition': contentDisposition(name || path)
|
'Content-Disposition': contentDisposition(name || path)
|
||||||
|
|
@ -563,15 +480,19 @@ res.download = function download (path, filename, options, callback) {
|
||||||
opts.headers = headers
|
opts.headers = headers
|
||||||
|
|
||||||
// Resolve the full path for sendFile
|
// Resolve the full path for sendFile
|
||||||
var fullPath = resolve(path);
|
var fullPath = !opts.root
|
||||||
|
? resolve(path)
|
||||||
|
: path
|
||||||
|
|
||||||
// send file
|
// send file
|
||||||
return this.sendFile(fullPath, opts, done)
|
return this.sendFile(fullPath, opts, done)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set _Content-Type_ response header with `type` through `mime.lookup()`
|
* Set _Content-Type_ response header with `type` through `mime.contentType()`
|
||||||
* when it does not contain "/", or set the Content-Type to `type` otherwise.
|
* when it does not contain "/", or set the Content-Type to `type` otherwise.
|
||||||
|
* When no mapping is found though `mime.contentType()`, the type is set to
|
||||||
|
* "application/octet-stream".
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
*
|
*
|
||||||
|
|
@ -589,7 +510,7 @@ res.download = function download (path, filename, options, callback) {
|
||||||
res.contentType =
|
res.contentType =
|
||||||
res.type = function contentType(type) {
|
res.type = function contentType(type) {
|
||||||
var ct = type.indexOf('/') === -1
|
var ct = type.indexOf('/') === -1
|
||||||
? mime.lookup(type)
|
? (mime.contentType(type) || 'application/octet-stream')
|
||||||
: type;
|
: type;
|
||||||
|
|
||||||
return this.set('Content-Type', ct);
|
return this.set('Content-Type', ct);
|
||||||
|
|
@ -619,7 +540,7 @@ res.type = function contentType(type) {
|
||||||
* res.send('<p>hey</p>');
|
* res.send('<p>hey</p>');
|
||||||
* },
|
* },
|
||||||
*
|
*
|
||||||
* 'appliation/json': function(){
|
* 'application/json': function () {
|
||||||
* res.send({ message: 'hey' });
|
* res.send({ message: 'hey' });
|
||||||
* }
|
* }
|
||||||
* });
|
* });
|
||||||
|
|
@ -656,9 +577,8 @@ res.format = function(obj){
|
||||||
var req = this.req;
|
var req = this.req;
|
||||||
var next = req.next;
|
var next = req.next;
|
||||||
|
|
||||||
var fn = obj.default;
|
var keys = Object.keys(obj)
|
||||||
if (fn) delete obj.default;
|
.filter(function (v) { return v !== 'default' })
|
||||||
var keys = Object.keys(obj);
|
|
||||||
|
|
||||||
var key = keys.length > 0
|
var key = keys.length > 0
|
||||||
? req.accepts(keys)
|
? req.accepts(keys)
|
||||||
|
|
@ -669,13 +589,12 @@ res.format = function(obj){
|
||||||
if (key) {
|
if (key) {
|
||||||
this.set('Content-Type', normalizeType(key).value);
|
this.set('Content-Type', normalizeType(key).value);
|
||||||
obj[key](req, this, next);
|
obj[key](req, this, next);
|
||||||
} else if (fn) {
|
} else if (obj.default) {
|
||||||
fn();
|
obj.default(req, this, next)
|
||||||
} else {
|
} else {
|
||||||
var err = new Error('Not Acceptable');
|
next(createError(406, {
|
||||||
err.status = err.statusCode = 406;
|
types: normalizeTypes(keys).map(function (o) { return o.value })
|
||||||
err.types = normalizeTypes(keys).map(function(o){ return o.value });
|
}))
|
||||||
next(err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -722,7 +641,7 @@ res.append = function append(field, val) {
|
||||||
// concat the new and prev vals
|
// concat the new and prev vals
|
||||||
value = Array.isArray(prev) ? prev.concat(val)
|
value = Array.isArray(prev) ? prev.concat(val)
|
||||||
: Array.isArray(val) ? [prev].concat(val)
|
: Array.isArray(val) ? [prev].concat(val)
|
||||||
: [prev, val];
|
: [prev, val]
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.set(field, value);
|
return this.set(field, value);
|
||||||
|
|
@ -740,6 +659,9 @@ res.append = function append(field, val) {
|
||||||
*
|
*
|
||||||
* Aliased as `res.header()`.
|
* Aliased as `res.header()`.
|
||||||
*
|
*
|
||||||
|
* When the set header is "Content-Type", the type is expanded to include
|
||||||
|
* the charset if not present using `mime.contentType()`.
|
||||||
|
*
|
||||||
* @param {String|Object} field
|
* @param {String|Object} field
|
||||||
* @param {String|Array} val
|
* @param {String|Array} val
|
||||||
* @return {ServerResponse} for chaining
|
* @return {ServerResponse} for chaining
|
||||||
|
|
@ -758,10 +680,7 @@ res.header = function header(field, val) {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
throw new TypeError('Content-Type cannot be set to an Array');
|
throw new TypeError('Content-Type cannot be set to an Array');
|
||||||
}
|
}
|
||||||
if (!charsetRegExp.test(value)) {
|
value = mime.contentType(value)
|
||||||
var charset = mime.charsets.lookup(value.split(';')[0]);
|
|
||||||
if (charset) value += '; charset=' + charset.toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setHeader(field, value);
|
this.setHeader(field, value);
|
||||||
|
|
@ -795,7 +714,10 @@ res.get = function(field){
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res.clearCookie = function clearCookie(name, options) {
|
res.clearCookie = function clearCookie(name, options) {
|
||||||
var opts = merge({ expires: new Date(1), path: '/' }, options);
|
// Force cookie expiration by setting expires to the past
|
||||||
|
const opts = { path: '/', ...options, expires: new Date(1)};
|
||||||
|
// ensure maxAge is not passed
|
||||||
|
delete opts.maxAge
|
||||||
|
|
||||||
return this.cookie(name, '', opts);
|
return this.cookie(name, '', opts);
|
||||||
};
|
};
|
||||||
|
|
@ -814,7 +736,7 @@ res.clearCookie = function clearCookie(name, options) {
|
||||||
* // "Remember Me" for 15 minutes
|
* // "Remember Me" for 15 minutes
|
||||||
* res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
|
* res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
|
||||||
*
|
*
|
||||||
* // save as above
|
* // same as above
|
||||||
* res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
|
* res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
|
||||||
*
|
*
|
||||||
* @param {String} name
|
* @param {String} name
|
||||||
|
|
@ -825,7 +747,7 @@ res.clearCookie = function clearCookie(name, options) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res.cookie = function (name, value, options) {
|
res.cookie = function (name, value, options) {
|
||||||
var opts = merge({}, options);
|
var opts = { ...options };
|
||||||
var secret = this.req.secret;
|
var secret = this.req.secret;
|
||||||
var signed = opts.signed;
|
var signed = opts.signed;
|
||||||
|
|
||||||
|
|
@ -841,9 +763,13 @@ res.cookie = function (name, value, options) {
|
||||||
val = 's:' + sign(val, secret);
|
val = 's:' + sign(val, secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('maxAge' in opts) {
|
if (opts.maxAge != null) {
|
||||||
opts.expires = new Date(Date.now() + opts.maxAge);
|
var maxAge = opts.maxAge - 0
|
||||||
opts.maxAge /= 1000;
|
|
||||||
|
if (!isNaN(maxAge)) {
|
||||||
|
opts.expires = new Date(Date.now() + maxAge)
|
||||||
|
opts.maxAge = Math.floor(maxAge / 1000)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.path == null) {
|
if (opts.path == null) {
|
||||||
|
|
@ -873,25 +799,13 @@ res.cookie = function (name, value, options) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res.location = function location(url) {
|
res.location = function location(url) {
|
||||||
var loc = url;
|
return this.set('Location', encodeUrl(url));
|
||||||
|
|
||||||
// "back" is an alias for the referrer
|
|
||||||
if (url === 'back') {
|
|
||||||
loc = this.req.get('Referrer') || '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
// set location
|
|
||||||
return this.set('Location', encodeUrl(loc));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redirect to the given `url` with optional response `status`
|
* Redirect to the given `url` with optional response `status`
|
||||||
* defaulting to 302.
|
* defaulting to 302.
|
||||||
*
|
*
|
||||||
* The resulting `url` is determined by `res.location()`, so
|
|
||||||
* it will play nicely with mounted apps, relative paths,
|
|
||||||
* `"back"` etc.
|
|
||||||
*
|
|
||||||
* Examples:
|
* Examples:
|
||||||
*
|
*
|
||||||
* res.redirect('/foo/bar');
|
* res.redirect('/foo/bar');
|
||||||
|
|
@ -909,13 +823,20 @@ res.redirect = function redirect(url) {
|
||||||
|
|
||||||
// allow status / url
|
// allow status / url
|
||||||
if (arguments.length === 2) {
|
if (arguments.length === 2) {
|
||||||
if (typeof arguments[0] === 'number') {
|
status = arguments[0]
|
||||||
status = arguments[0];
|
address = arguments[1]
|
||||||
address = arguments[1];
|
}
|
||||||
} else {
|
|
||||||
deprecate('res.redirect(url, status): Use res.redirect(status, url) instead');
|
if (!address) {
|
||||||
status = arguments[1];
|
deprecate('Provide a url argument');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof address !== 'string') {
|
||||||
|
deprecate('Url must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof status !== 'number') {
|
||||||
|
deprecate('Status must be a number');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set location header
|
// Set location header
|
||||||
|
|
@ -924,12 +845,12 @@ res.redirect = function redirect(url) {
|
||||||
// Support text/{plain,html} by default
|
// Support text/{plain,html} by default
|
||||||
this.format({
|
this.format({
|
||||||
text: function(){
|
text: function(){
|
||||||
body = statuses[status] + '. Redirecting to ' + address
|
body = statuses.message[status] + '. Redirecting to ' + address
|
||||||
},
|
},
|
||||||
|
|
||||||
html: function(){
|
html: function(){
|
||||||
var u = escapeHtml(address);
|
var u = escapeHtml(address);
|
||||||
body = '<p>' + statuses[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>'
|
body = '<p>' + statuses.message[status] + '. Redirecting to ' + u + '</p>'
|
||||||
},
|
},
|
||||||
|
|
||||||
default: function(){
|
default: function(){
|
||||||
|
|
@ -938,7 +859,7 @@ res.redirect = function redirect(url) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Respond
|
// Respond
|
||||||
this.statusCode = status;
|
this.status(status);
|
||||||
this.set('Content-Length', Buffer.byteLength(body));
|
this.set('Content-Length', Buffer.byteLength(body));
|
||||||
|
|
||||||
if (this.req.method === 'HEAD') {
|
if (this.req.method === 'HEAD') {
|
||||||
|
|
@ -958,12 +879,6 @@ res.redirect = function redirect(url) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res.vary = function(field){
|
res.vary = function(field){
|
||||||
// checks for back-compat
|
|
||||||
if (!field || (Array.isArray(field) && !field.length)) {
|
|
||||||
deprecate('res.vary(): Provide a field name');
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
vary(this, field);
|
vary(this, field);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -1104,7 +1019,7 @@ function sendfile(res, file, options, callback) {
|
||||||
* ability to escape characters that can trigger HTML sniffing.
|
* ability to escape characters that can trigger HTML sniffing.
|
||||||
*
|
*
|
||||||
* @param {*} value
|
* @param {*} value
|
||||||
* @param {function} replaces
|
* @param {function} replacer
|
||||||
* @param {number} spaces
|
* @param {number} spaces
|
||||||
* @param {boolean} escape
|
* @param {boolean} escape
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
|
|
@ -1118,7 +1033,7 @@ function stringify (value, replacer, spaces, escape) {
|
||||||
? JSON.stringify(value, replacer, spaces)
|
? JSON.stringify(value, replacer, spaces)
|
||||||
: JSON.stringify(value);
|
: JSON.stringify(value);
|
||||||
|
|
||||||
if (escape) {
|
if (escape && typeof json === 'string') {
|
||||||
json = json.replace(/[<>&]/g, function (c) {
|
json = json.replace(/[<>&]/g, function (c) {
|
||||||
switch (c.charCodeAt(0)) {
|
switch (c.charCodeAt(0)) {
|
||||||
case 0x3c:
|
case 0x3c:
|
||||||
|
|
@ -1127,6 +1042,7 @@ function stringify (value, replacer, spaces, escape) {
|
||||||
return '\\u003e'
|
return '\\u003e'
|
||||||
case 0x26:
|
case 0x26:
|
||||||
return '\\u0026'
|
return '\\u0026'
|
||||||
|
/* istanbul ignore next: unreachable default */
|
||||||
default:
|
default:
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user