passenger 5.0.0.beta2 → 5.0.0.beta3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- checksums.yaml +8 -8
 - checksums.yaml.gz.asc +7 -7
 - data.tar.gz.asc +7 -7
 - data/CHANGELOG +30 -0
 - data/CONTRIBUTORS +2 -0
 - data/Gemfile.lock +1 -1
 - data/bin/passenger-status +13 -15
 - data/build/cxx_tests.rb +14 -1
 - data/build/preprocessor.rb +4 -2
 - data/debian.template/control.template +2 -2
 - data/doc/Security of user switching support.txt +2 -2
 - data/doc/Users guide Apache.idmap.txt +6 -4
 - data/doc/Users guide Apache.txt +20 -1
 - data/doc/Users guide Nginx.idmap.txt +5 -3
 - data/doc/Users guide Nginx.txt +22 -2
 - data/ext/apache2/Configuration.cpp +6 -0
 - data/ext/apache2/Configuration.hpp +4 -1
 - data/ext/apache2/Hooks.cpp +1 -0
 - data/ext/common/Constants.h +4 -2
 - data/ext/common/Constants.h.erb +1 -1
 - data/ext/common/DataStructures/LString.h +10 -0
 - data/ext/common/ServerKit/Channel.h +1 -1
 - data/ext/common/ServerKit/Context.h +2 -21
 - data/ext/common/ServerKit/CookieUtils.h +246 -0
 - data/ext/common/ServerKit/FdSourceChannel.h +10 -0
 - data/ext/common/ServerKit/FileBufferedChannel.h +173 -17
 - data/ext/common/ServerKit/FileBufferedFdSinkChannel.h +33 -1
 - data/ext/common/ServerKit/HeaderTable.h +3 -1
 - data/ext/common/ServerKit/HttpServer.h +36 -8
 - data/ext/common/ServerKit/Server.h +1 -0
 - data/ext/common/Utils.cpp +2 -1
 - data/ext/common/Utils/DateParsing.h +15 -2
 - data/ext/common/Utils/JsonUtils.h +39 -1
 - data/ext/common/agents/HelperAgent/Main.cpp +4 -2
 - data/ext/common/agents/HelperAgent/OptionParser.h +14 -2
 - data/ext/common/agents/HelperAgent/RequestHandler.h +22 -8
 - data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +92 -11
 - data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +3 -1
 - data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +9 -5
 - data/ext/common/agents/HelperAgent/RequestHandler/Request.h +1 -0
 - data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +27 -13
 - data/ext/common/agents/HelperAgent/ResponseCache.h +91 -34
 - data/ext/common/agents/LoggingAgent/AdminServer.h +21 -1
 - data/ext/nginx/CacheLocationConfig.c +20 -0
 - data/ext/nginx/Configuration.c +130 -24
 - data/ext/nginx/Configuration.h +2 -1
 - data/ext/nginx/ConfigurationCommands.c +10 -0
 - data/ext/nginx/ConfigurationFields.h +2 -0
 - data/ext/nginx/ContentHandler.c +1 -6
 - data/ext/nginx/CreateLocationConfig.c +5 -0
 - data/ext/nginx/MergeLocationConfig.c +6 -0
 - data/ext/nginx/StaticContentHandler.c +3 -9
 - data/ext/nginx/ngx_http_passenger_module.c +2 -1
 - data/ext/ruby/extconf.rb +5 -4
 - data/lib/phusion_passenger.rb +2 -2
 - data/lib/phusion_passenger/constants.rb +2 -1
 - data/lib/phusion_passenger/nginx/config_options.rb +5 -1
 - data/lib/phusion_passenger/rack/thread_handler_extension.rb +3 -1
 - data/lib/phusion_passenger/ruby_core_enhancements.rb +3 -4
 - data/lib/phusion_passenger/standalone/start_command.rb +5 -1
 - data/lib/phusion_passenger/standalone/start_command/builtin_engine.rb +10 -3
 - data/resources/templates/standalone/config.erb +2 -1
 - data/test/cxx/DateParsingTest.cpp +75 -0
 - data/test/cxx/ResponseCacheTest.cpp +322 -0
 - data/test/cxx/ServerKit/CookieUtilsTest.cpp +274 -0
 - data/test/cxx/ServerKit/HttpServerTest.cpp +77 -0
 - data/test/stub/rails3.0/Gemfile.lock +2 -2
 - data/test/stub/rails3.1/Gemfile.lock +2 -2
 - data/test/stub/rails3.2/Gemfile.lock +2 -2
 - data/test/stub/rails4.0/Gemfile.lock +2 -2
 - data/test/stub/rails4.1/Gemfile.lock +2 -2
 - metadata +6 -2
 - metadata.gz.asc +7 -7
 
    
        data/ext/apache2/Hooks.cpp
    CHANGED
    
    | 
         @@ -1224,6 +1224,7 @@ public: 
     | 
|
| 
       1224 
1224 
     | 
    
         
             
            			.set    ("default_ruby", serverConfig.defaultRuby)
         
     | 
| 
       1225 
1225 
     | 
    
         
             
            			.setInt ("max_pool_size", serverConfig.maxPoolSize)
         
     | 
| 
       1226 
1226 
     | 
    
         
             
            			.setInt ("pool_idle_time", serverConfig.poolIdleTime)
         
     | 
| 
      
 1227 
     | 
    
         
            +
            			.setInt ("response_buffer_high_watermark", serverConfig.responseBufferHighWatermark)
         
     | 
| 
       1227 
1228 
     | 
    
         
             
            			.setInt ("stat_throttle_rate", serverConfig.statThrottleRate)
         
     | 
| 
       1228 
1229 
     | 
    
         
             
            			.set    ("analytics_log_user", serverConfig.analyticsLogUser)
         
     | 
| 
       1229 
1230 
     | 
    
         
             
            			.set    ("analytics_log_group", serverConfig.analyticsLogGroup)
         
     | 
    
        data/ext/common/Constants.h
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
2 
     | 
    
         
             
             *  Phusion Passenger - https://www.phusionpassenger.com/
         
     | 
| 
       3 
     | 
    
         
            -
             *  Copyright (c) 2010- 
     | 
| 
      
 3 
     | 
    
         
            +
             *  Copyright (c) 2010-2015 Phusion
         
     | 
| 
       4 
4 
     | 
    
         
             
             *
         
     | 
| 
       5 
5 
     | 
    
         
             
             *  "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
         
     | 
| 
       6 
6 
     | 
    
         
             
             *
         
     | 
| 
         @@ -78,6 +78,8 @@ 
     | 
|
| 
       78 
78 
     | 
    
         | 
| 
       79 
79 
     | 
    
         
             
            	#define DEFAULT_PYTHON "python"
         
     | 
| 
       80 
80 
     | 
    
         | 
| 
      
 81 
     | 
    
         
            +
            	#define DEFAULT_RESPONSE_BUFFER_HIGH_WATERMARK 134217728
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
       81 
83 
     | 
    
         
             
            	#define DEFAULT_RUBY "ruby"
         
     | 
| 
       82 
84 
     | 
    
         | 
| 
       83 
85 
     | 
    
         
             
            	#define DEFAULT_SPAWN_METHOD "smart"
         
     | 
| 
         @@ -110,7 +112,7 @@ 
     | 
|
| 
       110 
112 
     | 
    
         | 
| 
       111 
113 
     | 
    
         
             
            	#define NGINX_DOC_URL "https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx.html"
         
     | 
| 
       112 
114 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
            	#define PASSENGER_VERSION "5.0.0. 
     | 
| 
      
 115 
     | 
    
         
            +
            	#define PASSENGER_VERSION "5.0.0.beta3"
         
     | 
| 
       114 
116 
     | 
    
         | 
| 
       115 
117 
     | 
    
         
             
            	#define POOL_HELPER_THREAD_STACK_SIZE 262144
         
     | 
| 
       116 
118 
     | 
    
         | 
    
        data/ext/common/Constants.h.erb
    CHANGED
    
    
| 
         @@ -117,6 +117,16 @@ psg_lstr_append_part(LString *str, LString::Part *part) { 
     | 
|
| 
       117 
117 
     | 
    
         
             
            	part->next = NULL;
         
     | 
| 
       118 
118 
     | 
    
         
             
            }
         
     | 
| 
       119 
119 
     | 
    
         | 
| 
      
 120 
     | 
    
         
            +
            inline void
         
     | 
| 
      
 121 
     | 
    
         
            +
            psg_lstr_append_part_from_another_lstr(LString *str, psg_pool_t *pool, const LString::Part *part) {
         
     | 
| 
      
 122 
     | 
    
         
            +
            	LString::Part *copy = (LString::Part *) psg_palloc(pool, sizeof(LString::Part));
         
     | 
| 
      
 123 
     | 
    
         
            +
            	*copy = *part;
         
     | 
| 
      
 124 
     | 
    
         
            +
            	if (part->mbuf_block != NULL) {
         
     | 
| 
      
 125 
     | 
    
         
            +
            		mbuf_block_ref(part->mbuf_block);
         
     | 
| 
      
 126 
     | 
    
         
            +
            	}
         
     | 
| 
      
 127 
     | 
    
         
            +
            	psg_lstr_append_part(str, copy);
         
     | 
| 
      
 128 
     | 
    
         
            +
            }
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
       120 
130 
     | 
    
         
             
            inline void
         
     | 
| 
       121 
131 
     | 
    
         
             
            psg_lstr_append(LString *str, psg_pool_t *pool, const MemoryKit::mbuf &buffer,
         
     | 
| 
       122 
132 
     | 
    
         
             
            	const char *data, unsigned int size)
         
     | 
| 
         @@ -133,7 +133,7 @@ using namespace boost; 
     | 
|
| 
       133 
133 
     | 
    
         
             
             *
         
     | 
| 
       134 
134 
     | 
    
         
             
             *             ...process buffer....
         
     | 
| 
       135 
135 
     | 
    
         
             
             *
         
     | 
| 
       136 
     | 
    
         
            -
             *             return Channel::Result(bytesProcessed, acceptFurtherData);
         
     | 
| 
      
 136 
     | 
    
         
            +
             *             return Channel::Result(bytesProcessed, !acceptFurtherData);
         
     | 
| 
       137 
137 
     | 
    
         
             
             *         } else if (errcode == 0) {
         
     | 
| 
       138 
138 
     | 
    
         
             
             *             // EOF reached. Result doesn't matter in this case.
         
     | 
| 
       139 
139 
     | 
    
         
             
             *             return Channel::Result(0, false);
         
     | 
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
2 
     | 
    
         
             
             *  Phusion Passenger - https://www.phusionpassenger.com/
         
     | 
| 
       3 
     | 
    
         
            -
             *  Copyright (c) 2014 Phusion
         
     | 
| 
      
 3 
     | 
    
         
            +
             *  Copyright (c) 2014-2015 Phusion
         
     | 
| 
       4 
4 
     | 
    
         
             
             *
         
     | 
| 
       5 
5 
     | 
    
         
             
             *  "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
         
     | 
| 
       6 
6 
     | 
    
         
             
             *
         
     | 
| 
         @@ -33,6 +33,7 @@ 
     | 
|
| 
       33 
33 
     | 
    
         
             
            #include <Constants.h>
         
     | 
| 
       34 
34 
     | 
    
         
             
            #include <Utils/StrIntUtils.h>
         
     | 
| 
       35 
35 
     | 
    
         
             
            #include <Utils/json.h>
         
     | 
| 
      
 36 
     | 
    
         
            +
            #include <Utils/JsonUtils.h>
         
     | 
| 
       36 
37 
     | 
    
         | 
| 
       37 
38 
     | 
    
         
             
            namespace Passenger {
         
     | 
| 
       38 
39 
     | 
    
         
             
            namespace ServerKit {
         
     | 
| 
         @@ -61,26 +62,6 @@ private: 
     | 
|
| 
       61 
62 
     | 
    
         
             
            		MemoryKit::mbuf_pool_init(&mbuf_pool);
         
     | 
| 
       62 
63 
     | 
    
         
             
            	}
         
     | 
| 
       63 
64 
     | 
    
         | 
| 
       64 
     | 
    
         
            -
            	string formatFloat(double val) const {
         
     | 
| 
       65 
     | 
    
         
            -
            		char buf[64];
         
     | 
| 
       66 
     | 
    
         
            -
            		int size = snprintf(buf, sizeof(buf), "%.1f", val);
         
     | 
| 
       67 
     | 
    
         
            -
            		return string(buf, size);
         
     | 
| 
       68 
     | 
    
         
            -
            	}
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
            	Json::Value
         
     | 
| 
       71 
     | 
    
         
            -
            	byteSizeToJson(size_t size) const {
         
     | 
| 
       72 
     | 
    
         
            -
            		Json::Value doc;
         
     | 
| 
       73 
     | 
    
         
            -
            		doc["bytes"] = (Json::UInt64) size;
         
     | 
| 
       74 
     | 
    
         
            -
            		if (size < 1024) {
         
     | 
| 
       75 
     | 
    
         
            -
            			doc["human_readable"] = toString(size) + " bytes";
         
     | 
| 
       76 
     | 
    
         
            -
            		} else if (size < 1024 * 1024) {
         
     | 
| 
       77 
     | 
    
         
            -
            			doc["human_readable"] = formatFloat(size / 1024.0) + " KB";
         
     | 
| 
       78 
     | 
    
         
            -
            		} else {
         
     | 
| 
       79 
     | 
    
         
            -
            			doc["human_readable"] = formatFloat(size / 1024.0 / 1024.0) + " MB";
         
     | 
| 
       80 
     | 
    
         
            -
            		}
         
     | 
| 
       81 
     | 
    
         
            -
            		return doc;
         
     | 
| 
       82 
     | 
    
         
            -
            	}
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
65 
     | 
    
         
             
            public:
         
     | 
| 
       85 
66 
     | 
    
         
             
            	SafeLibevPtr libev;
         
     | 
| 
       86 
67 
     | 
    
         
             
            	struct MemoryKit::mbuf_pool mbuf_pool;
         
     | 
| 
         @@ -0,0 +1,246 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /*
         
     | 
| 
      
 2 
     | 
    
         
            +
             *  Phusion Passenger - https://www.phusionpassenger.com/
         
     | 
| 
      
 3 
     | 
    
         
            +
             *  Copyright (c) 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 
     | 
    
         
            +
            #ifndef _PASSENGER_SERVER_KIT_COOKIE_UTILS_H_
         
     | 
| 
      
 26 
     | 
    
         
            +
            #define _PASSENGER_SERVER_KIT_COOKIE_UTILS_H_
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            #include <cstring>
         
     | 
| 
      
 29 
     | 
    
         
            +
            #include <cassert>
         
     | 
| 
      
 30 
     | 
    
         
            +
            #include <MemoryKit/palloc.h>
         
     | 
| 
      
 31 
     | 
    
         
            +
            #include <DataStructures/LString.h>
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            namespace Passenger {
         
     | 
| 
      
 34 
     | 
    
         
            +
            namespace ServerKit {
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            inline bool findCookieNameValueSeparator(const LString::Part *part, size_t index,
         
     | 
| 
      
 38 
     | 
    
         
            +
            	const LString::Part **separatorPart, size_t *separatorIndex);
         
     | 
| 
      
 39 
     | 
    
         
            +
            inline bool findCookieEnd(const LString::Part *separatorPart, size_t separatorIndex,
         
     | 
| 
      
 40 
     | 
    
         
            +
            	const LString::Part **endPart, size_t *endIndex);
         
     | 
| 
      
 41 
     | 
    
         
            +
            inline bool matchCookieName(psg_pool_t *pool, const LString::Part *part, size_t index,
         
     | 
| 
      
 42 
     | 
    
         
            +
            	const LString::Part *separatorPart, size_t separatorIndex,
         
     | 
| 
      
 43 
     | 
    
         
            +
            	const LString *name);
         
     | 
| 
      
 44 
     | 
    
         
            +
            inline LString *extractCookieValue(psg_pool_t *pool,
         
     | 
| 
      
 45 
     | 
    
         
            +
            	const LString::Part *separatorPart, size_t separatorIndex,
         
     | 
| 
      
 46 
     | 
    
         
            +
            	const LString::Part *endPart, size_t endIndex);
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            /**
         
     | 
| 
      
 50 
     | 
    
         
            +
             * Given the value of an HTTP cookie header, returns the value of the cookie
         
     | 
| 
      
 51 
     | 
    
         
            +
             * of the given name, or NULL if not found.
         
     | 
| 
      
 52 
     | 
    
         
            +
             */
         
     | 
| 
      
 53 
     | 
    
         
            +
            inline LString *
         
     | 
| 
      
 54 
     | 
    
         
            +
            findCookie(psg_pool_t *pool, const LString *cookieHeaderValue, const LString *name) {
         
     | 
| 
      
 55 
     | 
    
         
            +
            	const LString::Part *part = cookieHeaderValue->start;
         
     | 
| 
      
 56 
     | 
    
         
            +
            	const LString::Part *separatorPart, *endPart;
         
     | 
| 
      
 57 
     | 
    
         
            +
            	size_t index = 0, separatorIndex, endIndex;
         
     | 
| 
      
 58 
     | 
    
         
            +
            	bool done = part == NULL;
         
     | 
| 
      
 59 
     | 
    
         
            +
            	LString *result = NULL;
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            	while (!done) {
         
     | 
| 
      
 62 
     | 
    
         
            +
            		if (findCookieNameValueSeparator(part, index, &separatorPart, &separatorIndex)) {
         
     | 
| 
      
 63 
     | 
    
         
            +
            			if (!findCookieEnd(separatorPart, separatorIndex, &endPart, &endIndex)) {
         
     | 
| 
      
 64 
     | 
    
         
            +
            				done = true;
         
     | 
| 
      
 65 
     | 
    
         
            +
            			} else if (matchCookieName(pool, part, index, separatorPart, separatorIndex, name)) {
         
     | 
| 
      
 66 
     | 
    
         
            +
            				result = extractCookieValue(pool, separatorPart, separatorIndex, endPart, endIndex);
         
     | 
| 
      
 67 
     | 
    
         
            +
            				done   = true;
         
     | 
| 
      
 68 
     | 
    
         
            +
            			} else {
         
     | 
| 
      
 69 
     | 
    
         
            +
            				part  = endPart;
         
     | 
| 
      
 70 
     | 
    
         
            +
            				index = endIndex;
         
     | 
| 
      
 71 
     | 
    
         
            +
            				done  = endIndex >= endPart->size;
         
     | 
| 
      
 72 
     | 
    
         
            +
            			}
         
     | 
| 
      
 73 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 74 
     | 
    
         
            +
            			done = true;
         
     | 
| 
      
 75 
     | 
    
         
            +
            		}
         
     | 
| 
      
 76 
     | 
    
         
            +
            	}
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            	return result;
         
     | 
| 
      
 79 
     | 
    
         
            +
            }
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            inline bool
         
     | 
| 
      
 82 
     | 
    
         
            +
            findCookieNameValueSeparator(const LString::Part *part, size_t index,
         
     | 
| 
      
 83 
     | 
    
         
            +
            	const LString::Part **separatorPart, size_t *separatorIndex)
         
     | 
| 
      
 84 
     | 
    
         
            +
            {
         
     | 
| 
      
 85 
     | 
    
         
            +
            	const char *pos;
         
     | 
| 
      
 86 
     | 
    
         
            +
            	bool result = false;
         
     | 
| 
      
 87 
     | 
    
         
            +
            	bool done = part == NULL;
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            	while (!done) {
         
     | 
| 
      
 90 
     | 
    
         
            +
            		pos = (const char *) memchr(part->data + index, '=', part->size - index);
         
     | 
| 
      
 91 
     | 
    
         
            +
            		if (pos == NULL) {
         
     | 
| 
      
 92 
     | 
    
         
            +
            			part  = part->next;
         
     | 
| 
      
 93 
     | 
    
         
            +
            			index = 0;
         
     | 
| 
      
 94 
     | 
    
         
            +
            			done  = part == NULL;
         
     | 
| 
      
 95 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 96 
     | 
    
         
            +
            			*separatorPart  = part;
         
     | 
| 
      
 97 
     | 
    
         
            +
            			*separatorIndex = pos - part->data;
         
     | 
| 
      
 98 
     | 
    
         
            +
            			result = true;
         
     | 
| 
      
 99 
     | 
    
         
            +
            			done   = true;
         
     | 
| 
      
 100 
     | 
    
         
            +
            		}
         
     | 
| 
      
 101 
     | 
    
         
            +
            	}
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            	return result;
         
     | 
| 
      
 104 
     | 
    
         
            +
            }
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
            inline bool
         
     | 
| 
      
 107 
     | 
    
         
            +
            findCookieEnd(const LString::Part *separatorPart, size_t separatorIndex,
         
     | 
| 
      
 108 
     | 
    
         
            +
            	const LString::Part **endPart, size_t *endIndex)
         
     | 
| 
      
 109 
     | 
    
         
            +
            {
         
     | 
| 
      
 110 
     | 
    
         
            +
            	const LString::Part *part = separatorPart;
         
     | 
| 
      
 111 
     | 
    
         
            +
            	size_t index = separatorIndex;
         
     | 
| 
      
 112 
     | 
    
         
            +
            	const char *pos;
         
     | 
| 
      
 113 
     | 
    
         
            +
            	bool result = false;
         
     | 
| 
      
 114 
     | 
    
         
            +
            	bool done = part == NULL;
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
            	while (!done) {
         
     | 
| 
      
 117 
     | 
    
         
            +
            		pos = (const char *) memchr(part->data + index, ';', part->size - index);
         
     | 
| 
      
 118 
     | 
    
         
            +
            		if (pos == NULL) {
         
     | 
| 
      
 119 
     | 
    
         
            +
            			if (part->next == NULL) {
         
     | 
| 
      
 120 
     | 
    
         
            +
            				// Semicolon not found in entire LString. Return end-of-LString
         
     | 
| 
      
 121 
     | 
    
         
            +
            				// as cookie end.
         
     | 
| 
      
 122 
     | 
    
         
            +
            				*endPart = part;
         
     | 
| 
      
 123 
     | 
    
         
            +
            				*endIndex = part->size;
         
     | 
| 
      
 124 
     | 
    
         
            +
            				result = true;
         
     | 
| 
      
 125 
     | 
    
         
            +
            				done   = true;
         
     | 
| 
      
 126 
     | 
    
         
            +
            			} else {
         
     | 
| 
      
 127 
     | 
    
         
            +
            				part  = part->next;
         
     | 
| 
      
 128 
     | 
    
         
            +
            				index = 0;
         
     | 
| 
      
 129 
     | 
    
         
            +
            				done  = part == NULL;
         
     | 
| 
      
 130 
     | 
    
         
            +
            			}
         
     | 
| 
      
 131 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 132 
     | 
    
         
            +
            			// Semicolon found.
         
     | 
| 
      
 133 
     | 
    
         
            +
            			*endPart = part;
         
     | 
| 
      
 134 
     | 
    
         
            +
            			*endIndex = pos - part->data;
         
     | 
| 
      
 135 
     | 
    
         
            +
            			result = true;
         
     | 
| 
      
 136 
     | 
    
         
            +
            			done   = true;
         
     | 
| 
      
 137 
     | 
    
         
            +
            		}
         
     | 
| 
      
 138 
     | 
    
         
            +
            	}
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
            	return result;
         
     | 
| 
      
 141 
     | 
    
         
            +
            }
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
            inline void
         
     | 
| 
      
 144 
     | 
    
         
            +
            _matchCookieName_skipWhitespace(LString *str) {
         
     | 
| 
      
 145 
     | 
    
         
            +
            	LString::Part *part = str->start;
         
     | 
| 
      
 146 
     | 
    
         
            +
            	size_t pos = 0;
         
     | 
| 
      
 147 
     | 
    
         
            +
            	bool done = false;
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
            	while (!done) {
         
     | 
| 
      
 150 
     | 
    
         
            +
            		while (part->data[pos] == ' ' || part->data[pos] == ';') {
         
     | 
| 
      
 151 
     | 
    
         
            +
            			pos++;
         
     | 
| 
      
 152 
     | 
    
         
            +
            		}
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
            		if (pos == part->size) {
         
     | 
| 
      
 155 
     | 
    
         
            +
            			str->start = part->next;
         
     | 
| 
      
 156 
     | 
    
         
            +
            			str->size -= part->size;
         
     | 
| 
      
 157 
     | 
    
         
            +
            			part = part->next;
         
     | 
| 
      
 158 
     | 
    
         
            +
            			if (part == NULL) {
         
     | 
| 
      
 159 
     | 
    
         
            +
            				assert(str->size == 0);
         
     | 
| 
      
 160 
     | 
    
         
            +
            				done = true;
         
     | 
| 
      
 161 
     | 
    
         
            +
            				str->end = NULL;
         
     | 
| 
      
 162 
     | 
    
         
            +
            			}
         
     | 
| 
      
 163 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 164 
     | 
    
         
            +
            			part->data += pos;
         
     | 
| 
      
 165 
     | 
    
         
            +
            			part->size -= pos;
         
     | 
| 
      
 166 
     | 
    
         
            +
            			str->size  -= pos;
         
     | 
| 
      
 167 
     | 
    
         
            +
            			done = true;
         
     | 
| 
      
 168 
     | 
    
         
            +
            		}
         
     | 
| 
      
 169 
     | 
    
         
            +
            	}
         
     | 
| 
      
 170 
     | 
    
         
            +
            }
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
            inline bool
         
     | 
| 
      
 173 
     | 
    
         
            +
            matchCookieName(psg_pool_t *pool, const LString::Part *part, size_t index,
         
     | 
| 
      
 174 
     | 
    
         
            +
            	const LString::Part *separatorPart, size_t separatorIndex,
         
     | 
| 
      
 175 
     | 
    
         
            +
            	const LString *name)
         
     | 
| 
      
 176 
     | 
    
         
            +
            {
         
     | 
| 
      
 177 
     | 
    
         
            +
            	LString *str = (LString *) psg_palloc(pool, sizeof(LString));
         
     | 
| 
      
 178 
     | 
    
         
            +
            	psg_lstr_init(str);
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
            	if (part == separatorPart) {
         
     | 
| 
      
 181 
     | 
    
         
            +
            		assert(index < separatorIndex);
         
     | 
| 
      
 182 
     | 
    
         
            +
            		psg_lstr_append(str, pool,
         
     | 
| 
      
 183 
     | 
    
         
            +
            			part->data + index,
         
     | 
| 
      
 184 
     | 
    
         
            +
            			separatorIndex - index);
         
     | 
| 
      
 185 
     | 
    
         
            +
            	} else {
         
     | 
| 
      
 186 
     | 
    
         
            +
            		psg_lstr_append(str, pool,
         
     | 
| 
      
 187 
     | 
    
         
            +
            			part->data + index,
         
     | 
| 
      
 188 
     | 
    
         
            +
            			part->size - index);
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
            		part = part->next;
         
     | 
| 
      
 191 
     | 
    
         
            +
            		while (part != separatorPart) {
         
     | 
| 
      
 192 
     | 
    
         
            +
            			psg_lstr_append(str, pool, part->data, part->size);
         
     | 
| 
      
 193 
     | 
    
         
            +
            			part = part->next;
         
     | 
| 
      
 194 
     | 
    
         
            +
            		}
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
            		if (separatorIndex != 0) {
         
     | 
| 
      
 197 
     | 
    
         
            +
            			psg_lstr_append(str, pool, separatorPart->data, separatorIndex);
         
     | 
| 
      
 198 
     | 
    
         
            +
            		}
         
     | 
| 
      
 199 
     | 
    
         
            +
            	}
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
            	_matchCookieName_skipWhitespace(str);
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
            	bool result = psg_lstr_cmp(str, name);
         
     | 
| 
      
 204 
     | 
    
         
            +
            	psg_lstr_deinit(str);
         
     | 
| 
      
 205 
     | 
    
         
            +
            	return result;
         
     | 
| 
      
 206 
     | 
    
         
            +
            }
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
            inline LString *
         
     | 
| 
      
 209 
     | 
    
         
            +
            extractCookieValue(psg_pool_t *pool,
         
     | 
| 
      
 210 
     | 
    
         
            +
            	const LString::Part *separatorPart, size_t separatorIndex,
         
     | 
| 
      
 211 
     | 
    
         
            +
            	const LString::Part *endPart, size_t endIndex)
         
     | 
| 
      
 212 
     | 
    
         
            +
            {
         
     | 
| 
      
 213 
     | 
    
         
            +
            	LString *str = (LString *) psg_palloc(pool, sizeof(LString));
         
     | 
| 
      
 214 
     | 
    
         
            +
            	psg_lstr_init(str);
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
            	if (separatorPart == endPart) {
         
     | 
| 
      
 217 
     | 
    
         
            +
            		assert(separatorIndex < endIndex);
         
     | 
| 
      
 218 
     | 
    
         
            +
            		psg_lstr_append(str, pool,
         
     | 
| 
      
 219 
     | 
    
         
            +
            			separatorPart->data + separatorIndex + 1,
         
     | 
| 
      
 220 
     | 
    
         
            +
            			endIndex - separatorIndex - 1);
         
     | 
| 
      
 221 
     | 
    
         
            +
            	} else {
         
     | 
| 
      
 222 
     | 
    
         
            +
            		if (separatorIndex < separatorPart->size - 1) {
         
     | 
| 
      
 223 
     | 
    
         
            +
            			psg_lstr_append(str, pool,
         
     | 
| 
      
 224 
     | 
    
         
            +
            				separatorPart->data + separatorIndex + 1,
         
     | 
| 
      
 225 
     | 
    
         
            +
            				separatorPart->size - separatorIndex - 1);
         
     | 
| 
      
 226 
     | 
    
         
            +
            		}
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
            		const LString::Part *part = separatorPart->next;
         
     | 
| 
      
 229 
     | 
    
         
            +
            		while (part != endPart) {
         
     | 
| 
      
 230 
     | 
    
         
            +
            			psg_lstr_append(str, pool, part->data, part->size);
         
     | 
| 
      
 231 
     | 
    
         
            +
            			part = part->next;
         
     | 
| 
      
 232 
     | 
    
         
            +
            		}
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
            		if (endIndex != 0) {
         
     | 
| 
      
 235 
     | 
    
         
            +
            			psg_lstr_append(str, pool, endPart->data, endIndex);
         
     | 
| 
      
 236 
     | 
    
         
            +
            		}
         
     | 
| 
      
 237 
     | 
    
         
            +
            	}
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
            	return str;
         
     | 
| 
      
 240 
     | 
    
         
            +
            }
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
            } // namespace ServerKit
         
     | 
| 
      
 244 
     | 
    
         
            +
            } // namespace Passenger
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
      
 246 
     | 
    
         
            +
            #endif /* _PASSENGER_SERVER_KIT_COOKIE_UTILS_H_ */
         
     | 
| 
         @@ -207,6 +207,16 @@ public: 
     | 
|
| 
       207 
207 
     | 
    
         
             
            		return watcher.fd;
         
     | 
| 
       208 
208 
     | 
    
         
             
            	}
         
     | 
| 
       209 
209 
     | 
    
         | 
| 
      
 210 
     | 
    
         
            +
            	OXT_FORCE_INLINE
         
     | 
| 
      
 211 
     | 
    
         
            +
            	State getState() const {
         
     | 
| 
      
 212 
     | 
    
         
            +
            		return Channel::getState();
         
     | 
| 
      
 213 
     | 
    
         
            +
            	}
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
      
 215 
     | 
    
         
            +
            	OXT_FORCE_INLINE
         
     | 
| 
      
 216 
     | 
    
         
            +
            	bool isStarted() const {
         
     | 
| 
      
 217 
     | 
    
         
            +
            		return Channel::isStarted();
         
     | 
| 
      
 218 
     | 
    
         
            +
            	}
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
       210 
220 
     | 
    
         
             
            	OXT_FORCE_INLINE
         
     | 
| 
       211 
221 
     | 
    
         
             
            	void setDataCallback(DataCallback callback) {
         
     | 
| 
       212 
222 
     | 
    
         
             
            		Channel::dataCallback = callback;
         
     | 
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
2 
     | 
    
         
             
             *  Phusion Passenger - https://www.phusionpassenger.com/
         
     | 
| 
       3 
     | 
    
         
            -
             *  Copyright (c) 2014 Phusion
         
     | 
| 
      
 3 
     | 
    
         
            +
             *  Copyright (c) 2014-2015 Phusion
         
     | 
| 
       4 
4 
     | 
    
         
             
             *
         
     | 
| 
       5 
5 
     | 
    
         
             
             *  "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
         
     | 
| 
       6 
6 
     | 
    
         
             
             *
         
     | 
| 
         @@ -43,6 +43,8 @@ 
     | 
|
| 
       43 
43 
     | 
    
         
             
            #include <ServerKit/Context.h>
         
     | 
| 
       44 
44 
     | 
    
         
             
            #include <ServerKit/Errors.h>
         
     | 
| 
       45 
45 
     | 
    
         
             
            #include <ServerKit/Channel.h>
         
     | 
| 
      
 46 
     | 
    
         
            +
            #include <Utils/json.h>
         
     | 
| 
      
 47 
     | 
    
         
            +
            #include <Utils/JsonUtils.h>
         
     | 
| 
       46 
48 
     | 
    
         | 
| 
       47 
49 
     | 
    
         
             
            namespace Passenger {
         
     | 
| 
       48 
50 
     | 
    
         
             
            namespace ServerKit {
         
     | 
| 
         @@ -187,8 +189,10 @@ public: 
     | 
|
| 
       187 
189 
     | 
    
         
             
            	typedef Channel::DataCallback DataCallback;
         
     | 
| 
       188 
190 
     | 
    
         
             
            	typedef void (*Callback)(FileBufferedChannel *channel);
         
     | 
| 
       189 
191 
     | 
    
         | 
| 
       190 
     | 
    
         
            -
            	//  
     | 
| 
       191 
     | 
    
         
            -
            	static const unsigned int MAX_MEMORY_BUFFERING =  
     | 
| 
      
 192 
     | 
    
         
            +
            	// 2^32-1 bytes.
         
     | 
| 
      
 193 
     | 
    
         
            +
            	static const unsigned int MAX_MEMORY_BUFFERING = 4294967295u;
         
     | 
| 
      
 194 
     | 
    
         
            +
            	// `nbuffers` is 27-bit. This is 2^27-1.
         
     | 
| 
      
 195 
     | 
    
         
            +
            	static const unsigned int MAX_BUFFERS = 134217727;
         
     | 
| 
       192 
196 
     | 
    
         | 
| 
       193 
197 
     | 
    
         | 
| 
       194 
198 
     | 
    
         
             
            private:
         
     | 
| 
         @@ -197,6 +201,13 @@ private: 
     | 
|
| 
       197 
201 
     | 
    
         
             
            		SafeLibevPtr libev;
         
     | 
| 
       198 
202 
     | 
    
         
             
            		eio_req *req;
         
     | 
| 
       199 
203 
     | 
    
         
             
            		boost::atomic<bool> canceled;
         
     | 
| 
      
 204 
     | 
    
         
            +
            		/**
         
     | 
| 
      
 205 
     | 
    
         
            +
            		 * Synchronizes access to `req`. Because all I/O callbacks call
         
     | 
| 
      
 206 
     | 
    
         
            +
            		 * `eioFinished()`, this mutex blocks callbacks until the main
         
     | 
| 
      
 207 
     | 
    
         
            +
            		 * thread is done assigning `req`.
         
     | 
| 
      
 208 
     | 
    
         
            +
            		 * See https://github.com/phusion/passenger/issues/1326
         
     | 
| 
      
 209 
     | 
    
         
            +
            		 */
         
     | 
| 
      
 210 
     | 
    
         
            +
            		boost::mutex syncher;
         
     | 
| 
       200 
211 
     | 
    
         | 
| 
       201 
212 
     | 
    
         
             
            		eio_ssize_t result;
         
     | 
| 
       202 
213 
     | 
    
         
             
            		int errcode;
         
     | 
| 
         @@ -213,6 +224,7 @@ private: 
     | 
|
| 
       213 
224 
     | 
    
         
             
            		virtual ~IOContext() { }
         
     | 
| 
       214 
225 
     | 
    
         | 
| 
       215 
226 
     | 
    
         
             
            		void cancel() {
         
     | 
| 
      
 227 
     | 
    
         
            +
            			boost::lock_guard<boost::mutex> l(syncher);
         
     | 
| 
       216 
228 
     | 
    
         
             
            			if (req != NULL) {
         
     | 
| 
       217 
229 
     | 
    
         
             
            				eio_cancel(req);
         
     | 
| 
       218 
230 
     | 
    
         
             
            			}
         
     | 
| 
         @@ -225,6 +237,7 @@ private: 
     | 
|
| 
       225 
237 
     | 
    
         
             
            		}
         
     | 
| 
       226 
238 
     | 
    
         | 
| 
       227 
239 
     | 
    
         
             
            		void eioFinished() {
         
     | 
| 
      
 240 
     | 
    
         
            +
            			boost::lock_guard<boost::mutex> l(syncher);
         
     | 
| 
       228 
241 
     | 
    
         
             
            			result = req->result;
         
     | 
| 
       229 
242 
     | 
    
         
             
            			errcode = req->errorno;
         
     | 
| 
       230 
243 
     | 
    
         
             
            			req = NULL;
         
     | 
| 
         @@ -337,10 +350,10 @@ private: 
     | 
|
| 
       337 
350 
     | 
    
         
             
            	};
         
     | 
| 
       338 
351 
     | 
    
         | 
| 
       339 
352 
     | 
    
         
             
            	FileBufferedChannelConfig *config;
         
     | 
| 
       340 
     | 
    
         
            -
            	Mode mode;
         
     | 
| 
       341 
     | 
    
         
            -
            	ReaderState readerState;
         
     | 
| 
      
 353 
     | 
    
         
            +
            	Mode mode: 2;
         
     | 
| 
      
 354 
     | 
    
         
            +
            	ReaderState readerState: 3;
         
     | 
| 
       342 
355 
     | 
    
         
             
            	/** Number of buffers in `firstBuffer` + `moreBuffers`. */
         
     | 
| 
       343 
     | 
    
         
            -
            	 
     | 
| 
      
 356 
     | 
    
         
            +
            	unsigned int nbuffers: 27;
         
     | 
| 
       344 
357 
     | 
    
         | 
| 
       345 
358 
     | 
    
         
             
            	/**
         
     | 
| 
       346 
359 
     | 
    
         
             
            	 * If an error is encountered, its details are stored here.
         
     | 
| 
         @@ -390,6 +403,7 @@ private: 
     | 
|
| 
       390 
403 
     | 
    
         | 
| 
       391 
404 
     | 
    
         
             
            	void pushBuffer(const MemoryKit::mbuf &buffer) {
         
     | 
| 
       392 
405 
     | 
    
         
             
            		assert(bytesBuffered + buffer.size() <= MAX_MEMORY_BUFFERING);
         
     | 
| 
      
 406 
     | 
    
         
            +
            		assert(nbuffers < MAX_BUFFERS);
         
     | 
| 
       393 
407 
     | 
    
         
             
            		if (nbuffers == 0) {
         
     | 
| 
       394 
408 
     | 
    
         
             
            			firstBuffer = buffer;
         
     | 
| 
       395 
409 
     | 
    
         
             
            		} else {
         
     | 
| 
         @@ -606,7 +620,6 @@ private: 
     | 
|
| 
       606 
620 
     | 
    
         
             
            	void channelHasBecomeIdle() {
         
     | 
| 
       607 
621 
     | 
    
         
             
            		FBC_DEBUG("Reader: underlying channel has become idle");
         
     | 
| 
       608 
622 
     | 
    
         
             
            		verifyInvariants();
         
     | 
| 
       609 
     | 
    
         
            -
            		//readerState = RS_INACTIVE;
         
     | 
| 
       610 
623 
     | 
    
         
             
            		readNext();
         
     | 
| 
       611 
624 
     | 
    
         
             
            	}
         
     | 
| 
       612 
625 
     | 
    
         | 
| 
         @@ -631,9 +644,9 @@ private: 
     | 
|
| 
       631 
644 
     | 
    
         
             
            	};
         
     | 
| 
       632 
645 
     | 
    
         | 
| 
       633 
646 
     | 
    
         
             
            	void readNextChunkFromFile() {
         
     | 
| 
      
 647 
     | 
    
         
            +
            		assert(inFileMode->written > 0);
         
     | 
| 
       634 
648 
     | 
    
         
             
            		size_t size = std::min<size_t>(inFileMode->written,
         
     | 
| 
       635 
     | 
    
         
            -
            			ctx->mbuf_pool 
     | 
| 
       636 
     | 
    
         
            -
            			ctx->mbuf_pool.mbuf_block_offset);
         
     | 
| 
      
 649 
     | 
    
         
            +
            			mbuf_pool_data_size(&ctx->mbuf_pool));
         
     | 
| 
       637 
650 
     | 
    
         
             
            		FBC_DEBUG("Reader: reading next chunk from file");
         
     | 
| 
       638 
651 
     | 
    
         
             
            		verifyInvariants();
         
     | 
| 
       639 
652 
     | 
    
         
             
            		ReadContext *readContext = new ReadContext(this);
         
     | 
| 
         @@ -641,16 +654,34 @@ private: 
     | 
|
| 
       641 
654 
     | 
    
         
             
            		readContext->inFileMode = inFileMode;
         
     | 
| 
       642 
655 
     | 
    
         
             
            		readerState = RS_READING_FROM_FILE;
         
     | 
| 
       643 
656 
     | 
    
         
             
            		inFileMode->readRequest = readContext;
         
     | 
| 
      
 657 
     | 
    
         
            +
            		boost::unique_lock<boost::mutex> l(readContext->syncher);
         
     | 
| 
       644 
658 
     | 
    
         
             
            		readContext->req = eio_read(inFileMode->fd, readContext->buffer.start,
         
     | 
| 
       645 
659 
     | 
    
         
             
            			size, inFileMode->readOffset, 0, _nextChunkDoneReading, readContext);
         
     | 
| 
      
 660 
     | 
    
         
            +
            		l.unlock();
         
     | 
| 
       646 
661 
     | 
    
         
             
            		verifyInvariants();
         
     | 
| 
       647 
662 
     | 
    
         
             
            	}
         
     | 
| 
       648 
663 
     | 
    
         | 
| 
      
 664 
     | 
    
         
            +
            	// Since a ReadContext contains an mbuf, we may only destroy it
         
     | 
| 
      
 665 
     | 
    
         
            +
            	// in the event loop thread.
         
     | 
| 
      
 666 
     | 
    
         
            +
            	static void destroyReadContext(ReadContext *readContext) {
         
     | 
| 
      
 667 
     | 
    
         
            +
            		if (readContext->libev->onEventLoopThread()) {
         
     | 
| 
      
 668 
     | 
    
         
            +
            			destroyReadContext_onEventLoopThread(readContext);
         
     | 
| 
      
 669 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 670 
     | 
    
         
            +
            			readContext->libev->runLater(boost::bind(
         
     | 
| 
      
 671 
     | 
    
         
            +
            				destroyReadContext_onEventLoopThread,
         
     | 
| 
      
 672 
     | 
    
         
            +
            				readContext));
         
     | 
| 
      
 673 
     | 
    
         
            +
            		}
         
     | 
| 
      
 674 
     | 
    
         
            +
            	}
         
     | 
| 
      
 675 
     | 
    
         
            +
             
     | 
| 
      
 676 
     | 
    
         
            +
            	static void destroyReadContext_onEventLoopThread(ReadContext *readContext) {
         
     | 
| 
      
 677 
     | 
    
         
            +
            		delete readContext;
         
     | 
| 
      
 678 
     | 
    
         
            +
            	}
         
     | 
| 
      
 679 
     | 
    
         
            +
             
     | 
| 
       649 
680 
     | 
    
         
             
            	static int _nextChunkDoneReading(eio_req *req) {
         
     | 
| 
       650 
681 
     | 
    
         
             
            		ReadContext *readContext = (ReadContext *) req->data;
         
     | 
| 
       651 
682 
     | 
    
         
             
            		readContext->eioFinished();
         
     | 
| 
       652 
683 
     | 
    
         
             
            		if (readContext->isCanceled()) {
         
     | 
| 
       653 
     | 
    
         
            -
            			 
     | 
| 
      
 684 
     | 
    
         
            +
            			destroyReadContext(readContext);
         
     | 
| 
       654 
685 
     | 
    
         
             
            			return 0;
         
     | 
| 
       655 
686 
     | 
    
         
             
            		}
         
     | 
| 
       656 
687 
     | 
    
         | 
| 
         @@ -666,7 +697,7 @@ private: 
     | 
|
| 
       666 
697 
     | 
    
         | 
| 
       667 
698 
     | 
    
         
             
            	static void _nextChunkDoneReading_onEventLoopThread(ReadContext *readContext) {
         
     | 
| 
       668 
699 
     | 
    
         
             
            		if (readContext->isCanceled()) {
         
     | 
| 
       669 
     | 
    
         
            -
            			 
     | 
| 
      
 700 
     | 
    
         
            +
            			destroyReadContext(readContext);
         
     | 
| 
       670 
701 
     | 
    
         
             
            			return;
         
     | 
| 
       671 
702 
     | 
    
         
             
            		}
         
     | 
| 
       672 
703 
     | 
    
         | 
| 
         @@ -683,7 +714,7 @@ private: 
     | 
|
| 
       683 
714 
     | 
    
         
             
            		int fd = readContext->result;
         
     | 
| 
       684 
715 
     | 
    
         
             
            		int errcode = readContext->errcode;
         
     | 
| 
       685 
716 
     | 
    
         
             
            		MemoryKit::mbuf buffer(boost::move(readContext->buffer));
         
     | 
| 
       686 
     | 
    
         
            -
            		 
     | 
| 
      
 717 
     | 
    
         
            +
            		destroyReadContext(readContext);
         
     | 
| 
       687 
718 
     | 
    
         
             
            		inFileMode->readRequest = NULL;
         
     | 
| 
       688 
719 
     | 
    
         | 
| 
       689 
720 
     | 
    
         
             
            		if (fd != -1) {
         
     | 
| 
         @@ -802,6 +833,7 @@ private: 
     | 
|
| 
       802 
833 
     | 
    
         
             
            		inFileMode->writerState = WS_CREATING_FILE;
         
     | 
| 
       803 
834 
     | 
    
         
             
            		inFileMode->writerRequest = fcContext;
         
     | 
| 
       804 
835 
     | 
    
         | 
| 
      
 836 
     | 
    
         
            +
            		boost::lock_guard<boost::mutex> l(fcContext->syncher);
         
     | 
| 
       805 
837 
     | 
    
         
             
            		if (config->delayInFileModeSwitching == 0) {
         
     | 
| 
       806 
838 
     | 
    
         
             
            			FBC_DEBUG("Writer: creating file " << fcContext->path);
         
     | 
| 
       807 
839 
     | 
    
         
             
            			fcContext->req = eio_open(fcContext->path.c_str(),
         
     | 
| 
         @@ -845,6 +877,7 @@ private: 
     | 
|
| 
       845 
877 
     | 
    
         
             
            	}
         
     | 
| 
       846 
878 
     | 
    
         | 
| 
       847 
879 
     | 
    
         
             
            	void bufferFileDoneDelaying(FileCreationContext *fcContext) {
         
     | 
| 
      
 880 
     | 
    
         
            +
            		boost::lock_guard<boost::mutex> l(fcContext->syncher);
         
     | 
| 
       848 
881 
     | 
    
         
             
            		FBC_DEBUG("Writer: done delaying in-file mode switching. "
         
     | 
| 
       849 
882 
     | 
    
         
             
            			"Creating file: " << fcContext->path);
         
     | 
| 
       850 
883 
     | 
    
         
             
            		fcContext->req = eio_open(fcContext->path.c_str(),
         
     | 
| 
         @@ -981,19 +1014,37 @@ private: 
     | 
|
| 
       981 
1014 
     | 
    
         | 
| 
       982 
1015 
     | 
    
         
             
            		inFileMode->writerState = WS_MOVING;
         
     | 
| 
       983 
1016 
     | 
    
         
             
            		inFileMode->writerRequest = moveContext;
         
     | 
| 
      
 1017 
     | 
    
         
            +
            		boost::unique_lock<boost::mutex> l(moveContext->syncher);
         
     | 
| 
       984 
1018 
     | 
    
         
             
            		moveContext->req = eio_write(inFileMode->fd,
         
     | 
| 
       985 
1019 
     | 
    
         
             
            			moveContext->buffer.start,
         
     | 
| 
       986 
1020 
     | 
    
         
             
            			moveContext->buffer.size(),
         
     | 
| 
       987 
1021 
     | 
    
         
             
            			inFileMode->readOffset + inFileMode->written,
         
     | 
| 
       988 
1022 
     | 
    
         
             
            			0, _bufferWrittenToFile, moveContext);
         
     | 
| 
      
 1023 
     | 
    
         
            +
            		l.unlock();
         
     | 
| 
       989 
1024 
     | 
    
         
             
            		verifyInvariants();
         
     | 
| 
       990 
1025 
     | 
    
         
             
            	}
         
     | 
| 
       991 
1026 
     | 
    
         | 
| 
      
 1027 
     | 
    
         
            +
            	// Since a MoveContext contains an mbuf, we may only destroy it
         
     | 
| 
      
 1028 
     | 
    
         
            +
            	// in the event loop thread.
         
     | 
| 
      
 1029 
     | 
    
         
            +
            	static void destroyMoveContext(MoveContext *moveContext) {
         
     | 
| 
      
 1030 
     | 
    
         
            +
            		if (moveContext->libev->onEventLoopThread()) {
         
     | 
| 
      
 1031 
     | 
    
         
            +
            			destroyMoveContext_onEventLoopThread(moveContext);
         
     | 
| 
      
 1032 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 1033 
     | 
    
         
            +
            			moveContext->libev->runLater(boost::bind(
         
     | 
| 
      
 1034 
     | 
    
         
            +
            				destroyMoveContext_onEventLoopThread,
         
     | 
| 
      
 1035 
     | 
    
         
            +
            				moveContext));
         
     | 
| 
      
 1036 
     | 
    
         
            +
            		}
         
     | 
| 
      
 1037 
     | 
    
         
            +
            	}
         
     | 
| 
      
 1038 
     | 
    
         
            +
             
     | 
| 
      
 1039 
     | 
    
         
            +
            	static void destroyMoveContext_onEventLoopThread(MoveContext *moveContext) {
         
     | 
| 
      
 1040 
     | 
    
         
            +
            		delete moveContext;
         
     | 
| 
      
 1041 
     | 
    
         
            +
            	}
         
     | 
| 
      
 1042 
     | 
    
         
            +
             
     | 
| 
       992 
1043 
     | 
    
         
             
            	static int _bufferWrittenToFile(eio_req *req) {
         
     | 
| 
       993 
1044 
     | 
    
         
             
            		MoveContext *moveContext = static_cast<MoveContext *>(req->data);
         
     | 
| 
       994 
1045 
     | 
    
         
             
            		moveContext->eioFinished();
         
     | 
| 
       995 
1046 
     | 
    
         
             
            		if (moveContext->isCanceled()) {
         
     | 
| 
       996 
     | 
    
         
            -
            			 
     | 
| 
      
 1047 
     | 
    
         
            +
            			destroyMoveContext(moveContext);
         
     | 
| 
       997 
1048 
     | 
    
         
             
            			return 0;
         
     | 
| 
       998 
1049 
     | 
    
         
             
            		}
         
     | 
| 
       999 
1050 
     | 
    
         | 
| 
         @@ -1009,7 +1060,7 @@ private: 
     | 
|
| 
       1009 
1060 
     | 
    
         | 
| 
       1010 
1061 
     | 
    
         
             
            	static void _bufferWrittenToFile_onEventLoopThread(MoveContext *moveContext) {
         
     | 
| 
       1011 
1062 
     | 
    
         
             
            		if (moveContext->isCanceled()) {
         
     | 
| 
       1012 
     | 
    
         
            -
            			 
     | 
| 
      
 1063 
     | 
    
         
            +
            			destroyMoveContext(moveContext);
         
     | 
| 
       1013 
1064 
     | 
    
         
             
            			return;
         
     | 
| 
       1014 
1065 
     | 
    
         
             
            		}
         
     | 
| 
       1015 
1066 
     | 
    
         | 
| 
         @@ -1040,27 +1091,29 @@ private: 
     | 
|
| 
       1040 
1091 
     | 
    
         
             
            				if (generation != this->generation || mode >= ERROR) {
         
     | 
| 
       1041 
1092 
     | 
    
         
             
            					// buffersFlushedCallback deinitialized this object, or callback
         
     | 
| 
       1042 
1093 
     | 
    
         
             
            					// called a method that encountered an error.
         
     | 
| 
       1043 
     | 
    
         
            -
            					 
     | 
| 
      
 1094 
     | 
    
         
            +
            					destroyMoveContext(moveContext);
         
     | 
| 
       1044 
1095 
     | 
    
         
             
            					return;
         
     | 
| 
       1045 
1096 
     | 
    
         
             
            				}
         
     | 
| 
       1046 
1097 
     | 
    
         | 
| 
       1047 
1098 
     | 
    
         
             
            				inFileMode->writerRequest = NULL;
         
     | 
| 
       1048 
     | 
    
         
            -
            				 
     | 
| 
      
 1099 
     | 
    
         
            +
            				destroyMoveContext(moveContext);
         
     | 
| 
       1049 
1100 
     | 
    
         
             
            				moveNextBufferToFile();
         
     | 
| 
       1050 
1101 
     | 
    
         
             
            			} else {
         
     | 
| 
       1051 
1102 
     | 
    
         
             
            				FBC_DEBUG("Writer: move incomplete, proceeding " <<
         
     | 
| 
       1052 
1103 
     | 
    
         
             
            					"with writing rest of buffer");
         
     | 
| 
      
 1104 
     | 
    
         
            +
            				boost::unique_lock<boost::mutex> l(moveContext->syncher);
         
     | 
| 
       1053 
1105 
     | 
    
         
             
            				moveContext->req = eio_write(inFileMode->fd,
         
     | 
| 
       1054 
1106 
     | 
    
         
             
            					moveContext->buffer.start + moveContext->written,
         
     | 
| 
       1055 
1107 
     | 
    
         
             
            					moveContext->buffer.size() - moveContext->written,
         
     | 
| 
       1056 
1108 
     | 
    
         
             
            					inFileMode->readOffset + inFileMode->written,
         
     | 
| 
       1057 
1109 
     | 
    
         
             
            					0, _bufferWrittenToFile, moveContext);
         
     | 
| 
      
 1110 
     | 
    
         
            +
            				l.unlock();
         
     | 
| 
       1058 
1111 
     | 
    
         
             
            				verifyInvariants();
         
     | 
| 
       1059 
1112 
     | 
    
         
             
            			}
         
     | 
| 
       1060 
1113 
     | 
    
         
             
            		} else {
         
     | 
| 
       1061 
1114 
     | 
    
         
             
            			FBC_DEBUG("Writer: file write failed");
         
     | 
| 
       1062 
1115 
     | 
    
         
             
            			int errcode = moveContext->errcode;
         
     | 
| 
       1063 
     | 
    
         
            -
            			 
     | 
| 
      
 1116 
     | 
    
         
            +
            			destroyMoveContext(moveContext);
         
     | 
| 
       1064 
1117 
     | 
    
         
             
            			inFileMode->writerRequest = NULL;
         
     | 
| 
       1065 
1118 
     | 
    
         
             
            			inFileMode->writerState = WS_TERMINATED;
         
     | 
| 
       1066 
1119 
     | 
    
         
             
            			setError(errcode, __FILE__, __LINE__);
         
     | 
| 
         @@ -1141,6 +1194,42 @@ private: 
     | 
|
| 
       1141 
1194 
     | 
    
         
             
            		inFileMode->writerState = WS_INACTIVE;
         
     | 
| 
       1142 
1195 
     | 
    
         
             
            	}
         
     | 
| 
       1143 
1196 
     | 
    
         | 
| 
      
 1197 
     | 
    
         
            +
            	const char *getReaderStateString() const {
         
     | 
| 
      
 1198 
     | 
    
         
            +
            		switch (readerState) {
         
     | 
| 
      
 1199 
     | 
    
         
            +
            		case RS_INACTIVE:
         
     | 
| 
      
 1200 
     | 
    
         
            +
            			return "RS_INACTIVE";
         
     | 
| 
      
 1201 
     | 
    
         
            +
            		case RS_FEEDING:
         
     | 
| 
      
 1202 
     | 
    
         
            +
            			return "RS_FEEDING";
         
     | 
| 
      
 1203 
     | 
    
         
            +
            		case RS_FEEDING_EOF:
         
     | 
| 
      
 1204 
     | 
    
         
            +
            			return "RS_FEEDING_EOF";
         
     | 
| 
      
 1205 
     | 
    
         
            +
            		case RS_WAITING_FOR_CHANNEL_IDLE:
         
     | 
| 
      
 1206 
     | 
    
         
            +
            			return "RS_WAITING_FOR_CHANNEL_IDLE";
         
     | 
| 
      
 1207 
     | 
    
         
            +
            		case RS_READING_FROM_FILE:
         
     | 
| 
      
 1208 
     | 
    
         
            +
            			return "RS_READING_FROM_FILE";
         
     | 
| 
      
 1209 
     | 
    
         
            +
            		case RS_TERMINATED:
         
     | 
| 
      
 1210 
     | 
    
         
            +
            			return "RS_TERMINATED";
         
     | 
| 
      
 1211 
     | 
    
         
            +
            		default:
         
     | 
| 
      
 1212 
     | 
    
         
            +
            			P_BUG("Unknown readerState");
         
     | 
| 
      
 1213 
     | 
    
         
            +
            			return NULL;
         
     | 
| 
      
 1214 
     | 
    
         
            +
            		}
         
     | 
| 
      
 1215 
     | 
    
         
            +
            	}
         
     | 
| 
      
 1216 
     | 
    
         
            +
             
     | 
| 
      
 1217 
     | 
    
         
            +
            	const char *getWriterStateString() const {
         
     | 
| 
      
 1218 
     | 
    
         
            +
            		switch (inFileMode->writerState) {
         
     | 
| 
      
 1219 
     | 
    
         
            +
            		case WS_INACTIVE:
         
     | 
| 
      
 1220 
     | 
    
         
            +
            			return "WS_INACTIVE";
         
     | 
| 
      
 1221 
     | 
    
         
            +
            		case WS_CREATING_FILE:
         
     | 
| 
      
 1222 
     | 
    
         
            +
            			return "WS_CREATING_FILE";
         
     | 
| 
      
 1223 
     | 
    
         
            +
            		case WS_MOVING:
         
     | 
| 
      
 1224 
     | 
    
         
            +
            			return "WS_MOVING";
         
     | 
| 
      
 1225 
     | 
    
         
            +
            		case WS_TERMINATED:
         
     | 
| 
      
 1226 
     | 
    
         
            +
            			return "WS_TERMINATED";
         
     | 
| 
      
 1227 
     | 
    
         
            +
            		default:
         
     | 
| 
      
 1228 
     | 
    
         
            +
            			P_BUG("Unknown writerState");
         
     | 
| 
      
 1229 
     | 
    
         
            +
            			return NULL;
         
     | 
| 
      
 1230 
     | 
    
         
            +
            		}
         
     | 
| 
      
 1231 
     | 
    
         
            +
            	}
         
     | 
| 
      
 1232 
     | 
    
         
            +
             
     | 
| 
       1144 
1233 
     | 
    
         
             
            	void verifyInvariants() const {
         
     | 
| 
       1145 
1234 
     | 
    
         
             
            		#ifndef NDEBUG
         
     | 
| 
       1146 
1235 
     | 
    
         
             
            			if (mode >= ERROR) {
         
     | 
| 
         @@ -1353,10 +1442,32 @@ public: 
     | 
|
| 
       1353 
1442 
     | 
    
         
             
            		return inFileMode->writerState;
         
     | 
| 
       1354 
1443 
     | 
    
         
             
            	}
         
     | 
| 
       1355 
1444 
     | 
    
         | 
| 
      
 1445 
     | 
    
         
            +
            	/**
         
     | 
| 
      
 1446 
     | 
    
         
            +
            	 * Returns the number of bytes buffered in memory.
         
     | 
| 
      
 1447 
     | 
    
         
            +
            	 */
         
     | 
| 
       1356 
1448 
     | 
    
         
             
            	unsigned int getBytesBuffered() const {
         
     | 
| 
       1357 
1449 
     | 
    
         
             
            		return bytesBuffered;
         
     | 
| 
       1358 
1450 
     | 
    
         
             
            	}
         
     | 
| 
       1359 
1451 
     | 
    
         | 
| 
      
 1452 
     | 
    
         
            +
            	/**
         
     | 
| 
      
 1453 
     | 
    
         
            +
            	 * Returns the number of bytes that are buffered on disk
         
     | 
| 
      
 1454 
     | 
    
         
            +
            	 * and have not yet been read.
         
     | 
| 
      
 1455 
     | 
    
         
            +
            	 */
         
     | 
| 
      
 1456 
     | 
    
         
            +
            	boost::uint64_t getBytesBufferedOnDisk() const {
         
     | 
| 
      
 1457 
     | 
    
         
            +
            		if (mode == IN_FILE_MODE && inFileMode->written >= 0) {
         
     | 
| 
      
 1458 
     | 
    
         
            +
            			return inFileMode->written;
         
     | 
| 
      
 1459 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 1460 
     | 
    
         
            +
            			return 0;
         
     | 
| 
      
 1461 
     | 
    
         
            +
            		}
         
     | 
| 
      
 1462 
     | 
    
         
            +
            	}
         
     | 
| 
      
 1463 
     | 
    
         
            +
             
     | 
| 
      
 1464 
     | 
    
         
            +
            	/**
         
     | 
| 
      
 1465 
     | 
    
         
            +
            	 * Returns the total bytes buffered, both in-memory and on disk.
         
     | 
| 
      
 1466 
     | 
    
         
            +
            	 */
         
     | 
| 
      
 1467 
     | 
    
         
            +
            	boost::uint64_t getTotalBytesBuffered() const {
         
     | 
| 
      
 1468 
     | 
    
         
            +
            		return bytesBuffered + getBytesBufferedOnDisk();
         
     | 
| 
      
 1469 
     | 
    
         
            +
            	}
         
     | 
| 
      
 1470 
     | 
    
         
            +
             
     | 
| 
       1360 
1471 
     | 
    
         
             
            	bool ended() const {
         
     | 
| 
       1361 
1472 
     | 
    
         
             
            		return (hasBuffers() && peekLastBuffer().empty())
         
     | 
| 
       1362 
1473 
     | 
    
         
             
            			|| mode >= ERROR || Channel::ended();
         
     | 
| 
         @@ -1370,14 +1481,27 @@ public: 
     | 
|
| 
       1370 
1481 
     | 
    
         
             
            		return bytesBuffered >= config->threshold;
         
     | 
| 
       1371 
1482 
     | 
    
         
             
            	}
         
     | 
| 
       1372 
1483 
     | 
    
         | 
| 
      
 1484 
     | 
    
         
            +
            	OXT_FORCE_INLINE
         
     | 
| 
       1373 
1485 
     | 
    
         
             
            	void setDataCallback(DataCallback callback) {
         
     | 
| 
       1374 
1486 
     | 
    
         
             
            		Channel::dataCallback = callback;
         
     | 
| 
       1375 
1487 
     | 
    
         
             
            	}
         
     | 
| 
       1376 
1488 
     | 
    
         | 
| 
      
 1489 
     | 
    
         
            +
            	OXT_FORCE_INLINE
         
     | 
| 
      
 1490 
     | 
    
         
            +
            	Callback getBuffersFlushedCallback() const {
         
     | 
| 
      
 1491 
     | 
    
         
            +
            		return buffersFlushedCallback;
         
     | 
| 
      
 1492 
     | 
    
         
            +
            	}
         
     | 
| 
      
 1493 
     | 
    
         
            +
             
     | 
| 
      
 1494 
     | 
    
         
            +
            	OXT_FORCE_INLINE
         
     | 
| 
       1377 
1495 
     | 
    
         
             
            	void setBuffersFlushedCallback(Callback callback) {
         
     | 
| 
       1378 
1496 
     | 
    
         
             
            		buffersFlushedCallback = callback;
         
     | 
| 
       1379 
1497 
     | 
    
         
             
            	}
         
     | 
| 
       1380 
1498 
     | 
    
         | 
| 
      
 1499 
     | 
    
         
            +
            	OXT_FORCE_INLINE
         
     | 
| 
      
 1500 
     | 
    
         
            +
            	Callback getDataFlushedCallback() const {
         
     | 
| 
      
 1501 
     | 
    
         
            +
            		return dataFlushedCallback;
         
     | 
| 
      
 1502 
     | 
    
         
            +
            	}
         
     | 
| 
      
 1503 
     | 
    
         
            +
             
     | 
| 
      
 1504 
     | 
    
         
            +
            	OXT_FORCE_INLINE
         
     | 
| 
       1381 
1505 
     | 
    
         
             
            	void setDataFlushedCallback(Callback callback) {
         
     | 
| 
       1382 
1506 
     | 
    
         
             
            		dataFlushedCallback = callback;
         
     | 
| 
       1383 
1507 
     | 
    
         
             
            	}
         
     | 
| 
         @@ -1387,9 +1511,41 @@ public: 
     | 
|
| 
       1387 
1511 
     | 
    
         
             
            		return Channel::hooks;
         
     | 
| 
       1388 
1512 
     | 
    
         
             
            	}
         
     | 
| 
       1389 
1513 
     | 
    
         | 
| 
      
 1514 
     | 
    
         
            +
            	OXT_FORCE_INLINE
         
     | 
| 
       1390 
1515 
     | 
    
         
             
            	void setHooks(Hooks *hooks) {
         
     | 
| 
       1391 
1516 
     | 
    
         
             
            		Channel::hooks = hooks;
         
     | 
| 
       1392 
1517 
     | 
    
         
             
            	}
         
     | 
| 
      
 1518 
     | 
    
         
            +
             
     | 
| 
      
 1519 
     | 
    
         
            +
            	Json::Value inspectAsJson() const {
         
     | 
| 
      
 1520 
     | 
    
         
            +
            		Json::Value doc;
         
     | 
| 
      
 1521 
     | 
    
         
            +
             
     | 
| 
      
 1522 
     | 
    
         
            +
            		switch (mode) {
         
     | 
| 
      
 1523 
     | 
    
         
            +
            		case IN_MEMORY_MODE:
         
     | 
| 
      
 1524 
     | 
    
         
            +
            			doc["mode"] = "IN_MEMORY_MODE";
         
     | 
| 
      
 1525 
     | 
    
         
            +
            			break;
         
     | 
| 
      
 1526 
     | 
    
         
            +
            		case IN_FILE_MODE:
         
     | 
| 
      
 1527 
     | 
    
         
            +
            			doc["mode"] = "IN_FILE_MODE";
         
     | 
| 
      
 1528 
     | 
    
         
            +
            			doc["writer_state"] = getWriterStateString();
         
     | 
| 
      
 1529 
     | 
    
         
            +
            			doc["read_offset"] = byteSizeToJson(inFileMode->readOffset);
         
     | 
| 
      
 1530 
     | 
    
         
            +
            			doc["written"] = signedByteSizeToJson(inFileMode->written);
         
     | 
| 
      
 1531 
     | 
    
         
            +
            			break;
         
     | 
| 
      
 1532 
     | 
    
         
            +
            		case ERROR:
         
     | 
| 
      
 1533 
     | 
    
         
            +
            			doc["mode"] = "ERROR";
         
     | 
| 
      
 1534 
     | 
    
         
            +
            			break;
         
     | 
| 
      
 1535 
     | 
    
         
            +
            		case ERROR_WAITING:
         
     | 
| 
      
 1536 
     | 
    
         
            +
            			doc["mode"] = "ERROR_WAITING";
         
     | 
| 
      
 1537 
     | 
    
         
            +
            			break;
         
     | 
| 
      
 1538 
     | 
    
         
            +
            		default:
         
     | 
| 
      
 1539 
     | 
    
         
            +
            			break;
         
     | 
| 
      
 1540 
     | 
    
         
            +
            		}
         
     | 
| 
      
 1541 
     | 
    
         
            +
             
     | 
| 
      
 1542 
     | 
    
         
            +
            		doc["reader_state"] = getReaderStateString();
         
     | 
| 
      
 1543 
     | 
    
         
            +
            		doc["nbuffers"] = nbuffers;
         
     | 
| 
      
 1544 
     | 
    
         
            +
            		doc["bytes_buffered"] = byteSizeToJson(getBytesBuffered());
         
     | 
| 
      
 1545 
     | 
    
         
            +
            		doc["callback_in_progress"] = !acceptingInput();
         
     | 
| 
      
 1546 
     | 
    
         
            +
             
     | 
| 
      
 1547 
     | 
    
         
            +
            		return doc;
         
     | 
| 
      
 1548 
     | 
    
         
            +
            	}
         
     | 
| 
       1393 
1549 
     | 
    
         
             
            };
         
     | 
| 
       1394 
1550 
     | 
    
         | 
| 
       1395 
1551 
     | 
    
         |