passenger 4.0.44 → 4.0.45

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (110) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.travis.yml +3 -0
  5. data/CHANGELOG +31 -0
  6. data/CONTRIBUTING.md +70 -10
  7. data/CONTRIBUTORS +4 -0
  8. data/README.md +1 -1
  9. data/Vagrantfile +50 -0
  10. data/bin/passenger-install-nginx-module +7 -2
  11. data/build/basics.rb +4 -1
  12. data/build/documentation.rb +6 -0
  13. data/build/node_tests.rb +7 -1
  14. data/build/packaging.rb +5 -0
  15. data/build/test_basics.rb +3 -3
  16. data/debian.template/copyright +1 -1
  17. data/debian.template/passenger.manpages +0 -1
  18. data/dev/rack.test/config.ru +5 -0
  19. data/dev/rack.test/public/asset.txt +1 -0
  20. data/dev/vagrant/apache_default_site.conf +35 -0
  21. data/dev/vagrant/apache_passenger.conf +5 -0
  22. data/dev/vagrant/apache_passenger.load +1 -0
  23. data/dev/vagrant/apache_ports.conf +24 -0
  24. data/dev/vagrant/apache_rack_test.conf +9 -0
  25. data/dev/vagrant/bashrc +21 -0
  26. data/dev/vagrant/nginx.conf +39 -0
  27. data/dev/vagrant/nginx_rakefile +34 -0
  28. data/dev/vagrant/nginx_start +32 -0
  29. data/dev/vagrant/provision.sh +115 -0
  30. data/dev/vagrant/sudoers.conf +5 -0
  31. data/doc/Design and Architecture.txt +515 -0
  32. data/doc/DeveloperQuickstart.md +70 -0
  33. data/doc/Users guide Apache.idmap.txt +24 -18
  34. data/doc/Users guide Apache.txt +200 -62
  35. data/doc/Users guide Nginx.idmap.txt +53 -45
  36. data/doc/Users guide Nginx.txt +501 -360
  37. data/doc/Users guide Standalone.txt +8 -0
  38. data/doc/images/direct_spawning.png +0 -0
  39. data/doc/images/direct_spawning.svg +16 -13
  40. data/doc/images/helper_agent_core_architecture.png +0 -0
  41. data/doc/images/passenger_architecture_overview.png +0 -0
  42. data/doc/images/smart_spawning.png +0 -0
  43. data/doc/images/{smart.svg → smart_spawning.svg} +23 -20
  44. data/doc/images/spawning_preparation_work.png +0 -0
  45. data/doc/images/startup_sequence.png +0 -0
  46. data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +82 -121
  47. data/doc/users_guide_snippets/environment_variables.txt +1 -1
  48. data/doc/users_guide_snippets/support_information.txt +2 -0
  49. data/doc/users_guide_snippets/tips.txt +117 -9
  50. data/ext/apache2/Configuration.hpp +4 -2
  51. data/ext/apache2/ConfigurationCommands.cpp +14 -0
  52. data/ext/apache2/ConfigurationFields.hpp +4 -0
  53. data/ext/apache2/ConfigurationSetters.cpp +22 -0
  54. data/ext/apache2/CreateDirConfig.cpp +2 -0
  55. data/ext/apache2/Hooks.cpp +30 -14
  56. data/ext/apache2/MergeDirConfig.cpp +14 -0
  57. data/ext/apache2/SetHeaders.cpp +8 -0
  58. data/ext/common/ApplicationPool2/AppTypes.cpp +6 -1
  59. data/ext/common/ApplicationPool2/Implementation.cpp +1 -1
  60. data/ext/common/ApplicationPool2/Session.h +1 -1
  61. data/ext/common/Constants.h +9 -7
  62. data/ext/common/Utils/HttpHeaderBufferer.h +23 -4
  63. data/ext/common/Utils/StrIntUtils.h +35 -0
  64. data/ext/common/Utils/StringScanning.h +4 -10
  65. data/ext/common/agents/HelperAgent/RequestHandler.h +90 -49
  66. data/ext/nginx/CacheLocationConfig.c +40 -0
  67. data/ext/nginx/ConfigurationCommands.c +20 -0
  68. data/ext/nginx/ConfigurationFields.h +4 -0
  69. data/ext/nginx/ContentHandler.c +1 -1
  70. data/ext/nginx/CreateLocationConfig.c +9 -0
  71. data/ext/nginx/MergeLocationConfig.c +12 -0
  72. data/ext/nginx/config +2 -2
  73. data/ext/nginx/ngx_http_passenger_module.c +4 -4
  74. data/helper-scripts/node-loader.js +40 -27
  75. data/lib/phusion_passenger.rb +1 -1
  76. data/lib/phusion_passenger/apache2/config_options.rb +14 -2
  77. data/lib/phusion_passenger/constants.rb +7 -6
  78. data/lib/phusion_passenger/loader_shared_helpers.rb +11 -1
  79. data/lib/phusion_passenger/nginx/config_options.rb +8 -0
  80. data/lib/phusion_passenger/packaging.rb +8 -3
  81. data/lib/phusion_passenger/platform_info/apache.rb +3 -0
  82. data/lib/phusion_passenger/platform_info/ruby.rb +4 -1
  83. data/lib/phusion_passenger/standalone/command.rb +0 -1
  84. data/lib/phusion_passenger/standalone/package_runtime_command.rb +1 -0
  85. data/lib/phusion_passenger/standalone/start_command.rb +80 -62
  86. data/lib/phusion_passenger/standalone/status_command.rb +1 -0
  87. data/lib/phusion_passenger/standalone/stop_command.rb +1 -0
  88. data/man/passenger-config.1 +1 -1
  89. data/man/passenger-memory-stats.8 +1 -1
  90. data/man/passenger-status.8 +1 -1
  91. data/npm-shrinkwrap.json +229 -0
  92. data/package.json +28 -0
  93. data/resources/templates/standalone/config.erb +2 -0
  94. data/rpm/Vagrantfile +0 -3
  95. data/test/config.json.vagrant +30 -0
  96. data/test/cxx/HttpHeaderBuffererTest.cpp +64 -10
  97. data/test/cxx/RequestHandlerTest.cpp +35 -13
  98. data/test/integration_tests/apache2_tests.rb +1 -0
  99. data/test/stub/node/app.js +26 -18
  100. metadata +28 -13
  101. metadata.gz.asc +7 -7
  102. data/doc/Architectural overview.idmap.txt +0 -36
  103. data/doc/Architectural overview.txt +0 -410
  104. data/doc/images/smart.png +0 -0
  105. data/ext/common/ApplicationPool2/README.md +0 -56
  106. data/man/passenger-stress-test.1 +0 -43
  107. data/node_lib/phusion_passenger/httplib_emulation.js +0 -215
  108. data/node_lib/phusion_passenger/request_handler.js +0 -73
  109. data/node_lib/phusion_passenger/session_protocol_parser.js +0 -113
  110. data/test/node/httplib_emulation_spec.js +0 -623
data/doc/images/smart.png DELETED
Binary file
@@ -1,56 +0,0 @@
1
- # Overview
2
-
3
- ApplicationPool2 is a subsystem in Phusion Passenger that takes care of
4
- dynamically calculating how many processes are needed, spawning application
5
- processes, shutting down processes, restarting processes, forwarding requests to
6
- the right process, etc. Pretty much all important application process management
7
- is encapculated in this subsystem.
8
-
9
- It does not handle the actual request/response I/O with the application
10
- processes: that's left to the caller of the ApplicationPool2 subsystem.
11
-
12
- Here's a quick rundown of the available classes:
13
-
14
- * Pool
15
- This is the core of the subsystem. It contains high-level process management
16
- logic but not the low-level details of spawning processes. The code is
17
- further divided into the following classes, each of which contain the core
18
- code managing its respective domain:
19
- * SuperGroup
20
- A logical collection of different applications. Can contain one or more
21
- Groups. In the current version of Phusion Passenger, a SuperGroup only
22
- contains exactly 1 Group.
23
- * Group
24
- Represents an application and can contains multiple processes, all
25
- belonging to the same application.
26
- * Process
27
- Represents an OS process; an instance of a certain application. A process
28
- may have multiple server sockets on which it listens. This is represented
29
- by the `Socket` class:
30
- * Socket
31
-
32
- * Spawner
33
- Encapsulates all low-level process spawning logic. Pool calls Spawner
34
- whenever it needs to spawn another application process.
35
-
36
- Spawner is an interface. There are multiple implementations that all
37
- spawn processes in a different way. These are:
38
- * DirectSpawner
39
- * SmartSpawner
40
- * DummySpawner
41
-
42
- The spawn method is user-configurable. To avoid convoluting the Pool code
43
- with spawner implementation selection logic, we have:
44
- * SpawnerFactory
45
-
46
- * Session
47
- A session represents a single interaction with an application process, e.g.
48
- a single request/response session.
49
-
50
- * Options
51
- A configuration object for the Pool::get() method.
52
-
53
- The `Pool` class's `get` method is the main interface into the ApplicationPool2
54
- subsystem. When an HTTP request comes in, call `Pool::get()` with the
55
- appropriate arguments, and it will automatically spawn a process for you when
56
- needed, open a session with that process and give you the session object.
@@ -1,43 +0,0 @@
1
- .TH "passenger-stress-test" "1" "2.0" "Phusion Passenger" "User Commands"
2
- .SH "NAME"
3
- .LP
4
- passenger\-stress\-test \- stress tests a Phusion Passenger powered website.
5
- .SH "SYNOPSIS"
6
- .LP
7
- \fBpassenger\-stress\-test\fR <\fIhostname\fR> <\fIapp_roo\fRt> [\fIoptions\fR]
8
- .SH "DESCRIPTION"
9
- .LP
10
- Stress test the given (Phusion Passenger\-powered) website by
11
- .LP
12
- \- crawling it with multiple concurrently running crawlers.
13
- .LP
14
- \- gracefully restarting Apache at random times
15
- .LP
16
- \- restarting the target (Phusion Passenger\-powered) application at random times
17
- .SH "OPTIONS"
18
- .LP
19
- .TP
20
- \fB\-c, \-\-concurrency\fR <\fInumber\fR>
21
- Number of crawlers to start (default = 20)
22
- .TP
23
- \fB\-p, \-\-apache\-restart\-interval\fR <\fIinterval\fR>
24
- Gracefully restart Apache after <\fIinterval\fR> minutes (default = 1440)
25
- .TP
26
- \fB\-a, \-\-app\-restart\-interval\fR <\fIinterval\fR>
27
- Restart the application after <\fIinterval\fR> minutes (default = 55)
28
- .TP
29
- \fB\-h, \-\-help\fR
30
- Output help information and exit.
31
-
32
- .SH "SEE ALSO"
33
- .LP
34
- passenger\-config(1), passenger\-memory\-stats(8), passenger\-status(8)
35
- .LP
36
- User guide at http://www.modrails.com/documentation.html
37
- .SH "AUTHOR"
38
- .LP
39
- Phusion Passenger is written by Phusion (http://www.phusion.nl)
40
- .LP
41
- "Phusion" and "Phusion Passenger" are trademarks of Hongli Lai & Ninh Bui.
42
- .LP
43
- This manual page was written by Neil Wilson <neil@brightbox.co.uk> for the Ubuntu project (but may be used by others).
@@ -1,215 +0,0 @@
1
- /*
2
- * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2013-2014 Phusion
4
- *
5
- * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
- *
7
- * Permission is hereby granted, free of charge, to any person obtaining a copy
8
- * of this software and associated documentation files (the "Software"), to deal
9
- * in the Software without restriction, including without limitation the rights
10
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- * copies of the Software, and to permit persons to whom the Software is
12
- * furnished to do so, subject to the following conditions:
13
- *
14
- * The above copyright notice and this permission notice shall be included in
15
- * all copies or substantial portions of the Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- * THE SOFTWARE.
24
- */
25
-
26
- /**
27
- * Provides helper functions for emulating the http.Server API.
28
- */
29
-
30
- var http = require('http');
31
-
32
- const HTTP_HEADERS_WITHOUT_PREFIX = {
33
- 'CONTENT_LENGTH': true,
34
- 'CONTENT_TYPE': true
35
- };
36
-
37
- function cgiKeyToHttpHeader(key) {
38
- if (HTTP_HEADERS_WITHOUT_PREFIX[key]) {
39
- return key.toLowerCase().replace(/_/g, '-');
40
- } else if (key.match(/^HTTP_/)) {
41
- return key.replace(/^HTTP_/, '').toLowerCase().replace(/_/g, '-');
42
- } else {
43
- return undefined;
44
- }
45
- }
46
-
47
- function setHttpHeaders(httpHeaders, cgiHeaders) {
48
- for (var i = 0; i < cgiHeaders.keys.length; i++) {
49
- var key = cgiHeaders.keys[i];
50
- var httpHeader = cgiKeyToHttpHeader(key);
51
- if (httpHeader !== undefined) {
52
- httpHeaders[httpHeader] = cgiHeaders[key];
53
- }
54
- }
55
-
56
- if (cgiHeaders['HTTPS']) {
57
- httpHeaders['x-forwarded-proto'] = 'https';
58
- }
59
- if (!httpHeaders['x-forwarded-for']) {
60
- httpHeaders['x-forwarded-for'] = cgiHeaders['REMOTE_ADDR'];
61
- }
62
- }
63
-
64
- function inferHttpVersion(protocolDescription) {
65
- var match = protocolDescription.match(/^HTTP\/(.+)/);
66
- if (match) {
67
- return match[1];
68
- }
69
- }
70
-
71
- function createIncomingMessage(headers, socket, bodyBegin) {
72
- /* Node's HTTP parser simulates an 'end' event if it determines that
73
- * the request should not have a request body. Currently (Node 0.10.18),
74
- * it thinks GET requests without an Upgrade header should not have a
75
- * request body, even though technically such GET requests are allowed
76
- * to have a request body. For compatibility reasons we implement the
77
- * same behavior as Node's HTTP parser.
78
- */
79
-
80
- var message = new http.IncomingMessage(socket);
81
- setHttpHeaders(message.headers, headers);
82
- message.cgiHeaders = headers;
83
- message.httpVersion = inferHttpVersion(headers['SERVER_PROTOCOL']);
84
- message.method = headers['REQUEST_METHOD'];
85
- message.url = headers['REQUEST_URI'];
86
- message.connection.remoteAddress = headers['REMOTE_ADDR'];
87
- message.connection.remotePort = parseInt(headers['REMOTE_PORT']);
88
- message.upgrade = !!headers['HTTP_UPGRADE'];
89
-
90
- if (message.upgrade) {
91
- // Emit end event as described above.
92
- message.push(null);
93
- return message;
94
- }
95
-
96
- message._emitEndEvent = IncomingMessage_emitEndEvent;
97
- resetIncomingMessageOverridedMethods(message);
98
-
99
- socket.on('end', function() {
100
- message._emitEndEvent();
101
- });
102
- socket.on('drain', function() {
103
- message.emit('drain');
104
- });
105
- socket.on('timeout', function() {
106
- message.emit('timeout');
107
- });
108
-
109
- if (headers['REQUEST_METHOD'] != 'GET') {
110
- if (bodyBegin.length > 0) {
111
- message.push(bodyBegin);
112
- }
113
- socket.ondata = function(buffer, offset, end) {
114
- if (!message.push(buffer.slice(offset, end))) {
115
- socket._handle.readStop();
116
- }
117
- }
118
- } else {
119
- // Emit end event as described above.
120
- message.push(null);
121
- }
122
-
123
- return message;
124
- }
125
-
126
- function IncomingMessage_pause() {
127
- this._flowing = false;
128
- this._orig_pause();
129
- resetIncomingMessageOverridedMethods(this);
130
- }
131
-
132
- function IncomingMessage_resume() {
133
- this._flowing = true;
134
- this._orig_resume();
135
- resetIncomingMessageOverridedMethods(this);
136
- }
137
-
138
- function IncomingMessage_on(event, listener) {
139
- if (event == 'data') {
140
- this._flowing = true;
141
- installDataEventHandler(this);
142
- } else if (event == 'readable') {
143
- installReadableEventHandler(this);
144
- }
145
- this._orig_on.call(this, event, listener);
146
- resetIncomingMessageOverridedMethods(this);
147
- return this;
148
- }
149
-
150
- function IncomingMessage_emitEndEvent() {
151
- if (!this._readableState.endEmitted) {
152
- this._readableState.endEmitted = true;
153
- this.emit('end');
154
- }
155
- }
156
-
157
- /*
158
- * Calling on(), pause() etc on the message object may cause our overrided
159
- * methods to be set to something else. This is probably becaused by the code
160
- * in Node.js responsible for switching a stream to flowing mode, e.g.
161
- * emitDataEvents() in _stream_readable.js. Thus, this function
162
- * should be called from on(), pause() etc.
163
- */
164
- function resetIncomingMessageOverridedMethods(message) {
165
- if (message.pause !== IncomingMessage_pause) {
166
- message._orig_pause = message.pause;
167
- message.pause = IncomingMessage_pause;
168
- }
169
- if (message.resume !== IncomingMessage_resume) {
170
- message._orig_resume = message.resume;
171
- message.resume = IncomingMessage_resume;
172
- }
173
- if (message.on !== IncomingMessage_on) {
174
- message._orig_on = message.on;
175
- message.on = IncomingMessage_on;
176
- message.addListener = IncomingMessage_on;
177
- }
178
- }
179
-
180
- function installDataEventHandler(message) {
181
- if (!message._dataEventHandlerInstalled) {
182
- message._dataEventHandlerInstalled = true;
183
- message.socket.on('data', function(chunk) {
184
- message.emit('data', chunk);
185
- });
186
- }
187
- }
188
-
189
- function installReadableEventHandler(message) {
190
- if (!message._readableEventHandlerInstalled) {
191
- message._readableEventHandlerInstalled = true;
192
- message.socket.on('readable', function() {
193
- message.emit('readable');
194
- });
195
- }
196
- }
197
-
198
- function createServerResponse(req) {
199
- var res = new http.ServerResponse(req);
200
- res.assignSocket(req.socket);
201
- res.shouldKeepAlive = false;
202
- req.socket.on('drain', function() {
203
- res.emit('drain');
204
- });
205
- req.socket.on('timeout', function() {
206
- res.emit('timeout');
207
- });
208
- res.once('finish', function() {
209
- req.socket.destroySoon();
210
- });
211
- return res;
212
- }
213
-
214
- exports.createIncomingMessage = createIncomingMessage;
215
- exports.createServerResponse = createServerResponse;
@@ -1,73 +0,0 @@
1
- /*
2
- * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2012-2013 Phusion
4
- *
5
- * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
- *
7
- * Permission is hereby granted, free of charge, to any person obtaining a copy
8
- * of this software and associated documentation files (the "Software"), to deal
9
- * in the Software without restriction, including without limitation the rights
10
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- * copies of the Software, and to permit persons to whom the Software is
12
- * furnished to do so, subject to the following conditions:
13
- *
14
- * The above copyright notice and this permission notice shall be included in
15
- * all copies or substantial portions of the Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- * THE SOFTWARE.
24
- */
25
-
26
- var net = require('net');
27
- var SessionProtocolParser = require('./session_protocol_parser').SessionProtocolParser;
28
-
29
- /**
30
- * Handles incoming Phusion Passenger requests and emits events.
31
- */
32
- function RequestHandler(readyCallback, clientCallback) {
33
- var self = this;
34
-
35
- function handleNewClient(socket) {
36
- var state = 'PARSING_HEADER';
37
- var parser = new SessionProtocolParser();
38
-
39
- function handleReadable() {
40
- // read(n) returns null unless the buffer is at least n bytes.
41
- // We just want to read whatever we can we poke into its buffer.
42
- // Hope they don't change the this.
43
- var len = socket._readableState.length;
44
- handleData(socket.read(len));
45
- }
46
-
47
- function handleData(data) {
48
- if (state == 'PARSING_HEADER') {
49
- var consumed = parser.feed(data);
50
- if (parser.state == SessionProtocolParser.SPP_DONE) {
51
- state = 'HEADER_SEEN';
52
- socket.removeListener('readable', handleReadable);
53
- PhusionPassenger.emit('request', parser, socket, data.slice(consumed));
54
- } else if (parser.state == SessionProtocolParser.SPP_ERROR) {
55
- console.error('Header parse error');
56
- socket.destroySoon();
57
- }
58
- } else {
59
- // Do nothing.
60
- }
61
- }
62
-
63
- socket.on('readable', handleReadable);
64
- }
65
-
66
- var server = net.createServer({ allowHalfOpen: true }, handleNewClient);
67
- this.server = server;
68
- server.listen(0, function() {
69
- readyCallback(self);
70
- });
71
- }
72
-
73
- exports.RequestHandler = RequestHandler;
@@ -1,113 +0,0 @@
1
- /*
2
- * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2012-2013 Phusion
4
- *
5
- * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
- *
7
- * Permission is hereby granted, free of charge, to any person obtaining a copy
8
- * of this software and associated documentation files (the "Software"), to deal
9
- * in the Software without restriction, including without limitation the rights
10
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- * copies of the Software, and to permit persons to whom the Software is
12
- * furnished to do so, subject to the following conditions:
13
- *
14
- * The above copyright notice and this permission notice shall be included in
15
- * all copies or substantial portions of the Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- * THE SOFTWARE.
24
- */
25
-
26
- const SPP_PARSING_SIZE = SessionProtocolParser.SPP_PARSING_SIZE = 0;
27
- const SPP_PARSING_HEADERS = SessionProtocolParser.SPP_PARSING_HEADERS = 1;
28
- const SPP_DONE = SessionProtocolParser.SPP_DONE = 10;
29
- const SPP_ERROR = SessionProtocolParser.SPP_ERROR = 11;
30
-
31
- const ENCODING = 'binary';
32
-
33
- function SessionProtocolParser() {
34
- this.state = SPP_PARSING_SIZE;
35
- this.processed = 0;
36
- this.size = 0;
37
- this.keys = [];
38
- }
39
-
40
- SessionProtocolParser.prototype.feed = function(buffer) {
41
- var consumed = 0;
42
- var locallyConsumed;
43
-
44
- while (consumed < buffer.length && this.state != SPP_ERROR && this.state != SPP_DONE) {
45
- switch (this.state) {
46
- case SPP_PARSING_SIZE:
47
- this.size += buffer[consumed] * Math.pow(256, 3 - this.processed);
48
- locallyConsumed = 1;
49
- this.processed++;
50
- if (this.processed == 4) {
51
- this.state = SPP_PARSING_HEADERS;
52
- this.buffer = new Buffer(this.size);
53
- this.processed = 0;
54
- }
55
- break;
56
-
57
- case SPP_PARSING_HEADERS:
58
- locallyConsumed = Math.min(buffer.length - consumed, this.buffer.length - this.processed);
59
- buffer.copy(this.buffer, this.processed, consumed, consumed + locallyConsumed);
60
- this.processed += locallyConsumed;
61
- if (this.processed == this.buffer.length) {
62
- this.state = SPP_DONE;
63
- this.parse();
64
- }
65
- break;
66
-
67
- default:
68
- console.assert(false);
69
- break;
70
- }
71
-
72
- consumed += locallyConsumed;
73
- }
74
-
75
- return consumed;
76
- }
77
-
78
- SessionProtocolParser.prototype.parse = function() {
79
- function findZero(buffer, start) {
80
- while (start < buffer.length) {
81
- if (buffer[start] == 0) {
82
- return start;
83
- } else {
84
- start++;
85
- }
86
- }
87
- return -1;
88
- }
89
-
90
- var start = 0;
91
- var key, value;
92
-
93
- while (start < this.buffer.length) {
94
- var keyEnd = findZero(this.buffer, start);
95
- if (keyEnd != -1 && keyEnd + 1 < this.buffer.length) {
96
- var valueStart = keyEnd + 1;
97
- var valueEnd = findZero(this.buffer, valueStart);
98
- if (valueEnd != -1) {
99
- key = this.buffer.toString(ENCODING, start, keyEnd);
100
- value = this.buffer.toString(ENCODING, valueStart, valueEnd);
101
- start = valueEnd + 1;
102
- this.keys.push(key);
103
- this[key] = value;
104
- } else {
105
- start = this.buffer.length;
106
- }
107
- } else {
108
- start = this.buffer.length;
109
- }
110
- }
111
- }
112
-
113
- exports.SessionProtocolParser = SessionProtocolParser;